Skip to content

Instantly share code, notes, and snippets.

@crackwitz
Created January 11, 2021 19:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crackwitz/413bbb458b88772f5912d8af978b0b53 to your computer and use it in GitHub Desktop.
Save crackwitz/413bbb458b88772f5912d8af978b0b53 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import os
import sys
import argparse
import numpy as np
import cv2 as cv
def draw_pattern(a, grain=1, tiled=False):
global ix, iy, gx, gy
h,w = a.shape[:2]
#ix = np.arange(w)
#iy = np.arange(h)
#gx, gy = np.meshgrid(ix, iy, indexing="xy")
(gy, gx) = np.indices((h,w))
if not tiled:
K = 2*grain
K = 2
gx //= grain
gy //= grain
gx %= 2
gy %= 2
a[:,:] = (gx ^ gy) * 255
else:
tx = (gx // tiled) & 1
ty = (gy // tiled) & 1
tt = ty*2 + tx
gx //= grain
gy //= grain
gx %= 2
gy %= 2
#a[tx != ty] = (255 * gx)[tx != ty]
#a[tx == ty] = (255 * gy)[tx == ty]
a[tt == 0] = (255 * (gx ^ gy))[tt == 0]
a[tt == 1] = (255 * gx)[tt == 1]
a[tt == 2] = (255 * gy)[tt == 2]
a[tt == 3] = 255 * 0.5**(1/2.2)
# https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse
def str2bool(v):
if isinstance(v, bool):
return v
if v.lower() in ('yes', 'true', 't', 'y', '1'):
return True
elif v.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else:
raise argparse.ArgumentTypeError('Boolean value expected.')
# or whatever is hardcoded in window_w32.cpp
parser = argparse.ArgumentParser(description="let's test imshow's gutter and resampling method")
parser.add_argument("--size", metavar="WxH", type=str, default="2560x1440",
help="assumed resolution")
#parser.set_defaults(size="1920x1080")
parser.add_argument("--fullscreen", metavar="Y/N", type=str2bool, default=True,
help="fullscreen or resizable window")
parser.add_argument("--gutter", metavar="PIXELS", type=int, default=0,
help="subtracted from picture size to compensate for imshow() gutter")
parser.add_argument("--opengl", metavar="Y/N", type=str2bool, default=True,
help="OpenGL uses linear interpolation, \"native\" may be nearest neighbor")
parser.add_argument("--grain", metavar="N", type=int, default=1,
help="size of checker fields")
parser.add_argument("--tiled", metavar="N", type=int, default=0,
help="show tiles of gray, horizontal, vertical, and checkered tiles")
args = parser.parse_args()
# pick your display's resolution
# (someone should test this with Windows' DPI scaling because I'm at 100%)
width, height = map(int, args.size.split('x'))
#width, height = 2560, 1440
#width, height = 1920, 1080
print(f"size: {width} x {height}")
#(width, height) = (width + 2*gutter, height + 2*gutter) # (approximately) simulate gutter when no gutter
(width, height) = (width - 2*args.gutter, height - 2*args.gutter) # simulate no gutter when gutter
print(f"size: {width} x {height} adjusted for gutter of {args.gutter} pixels")
checkers = np.zeros((height, width), np.uint8)
draw_pattern(checkers, grain=args.grain, tiled=args.tiled)
cv.imwrite("checkers.png", checkers)
# possible outputs:
# - pixel perfect checker pattern
# - same but cropped (border)
# - resampled nearest neighbor (pixel pattern but with breaks in it, may be hard to see)
# - resampled linearly, blurry but uniform brightness (gamma-aware)
# - resampled linearly, blurry and varying brightness (gamma-oblivious)
windowname = "press a key, any key"
print("namedWindow() with", ("WINDOW_OPENGL" if args.opengl else "WINDOW_NORMAL"))
cv.namedWindow(windowname,
flags=(cv.WINDOW_OPENGL if args.opengl else cv.WINDOW_NORMAL)
# flags=cv.WINDOW_NORMAL # WINDOW_NORMAL does nearest neighbor
# flags=cv.WINDOW_OPENGL # WINDOW_OPENGL does bilinear
)
if args.fullscreen:
print("setWindowProperty(..., WND_PROP_FULLSCREEN, True)")
cv.setWindowProperty(windowname,
prop_id=cv.WND_PROP_FULLSCREEN,
prop_value=cv.WINDOW_FULLSCREEN) # value is basically "true", is only member of WindowFlags for convenience
else:
print(f"resizeWindow(..., {width}, {height})")
cv.resizeWindow(windowname, width, height)
cv.imshow(windowname, checkers)
# 0 should stand for 0 milliseconds (polling), infinity should be strictly < 0
# that's currently not the case...
cv.waitKey(-1)
cv.destroyWindow(windowname)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment