Skip to content

Instantly share code, notes, and snippets.

@dmd
Last active April 2, 2026 14:37
Show Gist options
  • Select an option

  • Save dmd/94019afcd63a6606566e1ae70f742f04 to your computer and use it in GitHub Desktop.

Select an option

Save dmd/94019afcd63a6606566e1ae70f742f04 to your computer and use it in GitHub Desktop.
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = [
# "opencv-python",
# "pyvirtualcam",
# "numpy",
# "pillow",
# ]
# ///
"""
CUSeeMe-style virtual camera filter for Zoom.
120x120, 1bpp with Atkinson dithering, scaled up with nearest-neighbor.
Requires OBS virtual camera (install OBS, start virtual camera once).
"""
import cv2
import numpy as np
import pyvirtualcam
CUSEEME_SIZE = 240
OUTPUT_W, OUTPUT_H = 640, 480
FPS = 15
def atkinson_dither(gray: np.ndarray) -> np.ndarray:
"""Apply Atkinson dithering to produce 1bpp output."""
img = gray.astype(np.float32)
h, w = img.shape
for y in range(h):
for x in range(w):
old = img[y, x]
new = 255.0 if old >= 128 else 0.0
img[y, x] = new
err = (old - new) / 8.0
# Atkinson distributes 6/8 of error (loses 2/8 intentionally)
if x + 1 < w:
img[y, x + 1] += err
if x + 2 < w:
img[y, x + 2] += err
if y + 1 < h:
if x - 1 >= 0:
img[y + 1, x - 1] += err
img[y + 1, x] += err
if x + 1 < w:
img[y + 1, x + 1] += err
if y + 2 < h:
img[y + 2, x] += err
return np.clip(img, 0, 255).astype(np.uint8)
def crop_center_square(frame: np.ndarray) -> np.ndarray:
"""Crop the largest centered square from the frame."""
h, w = frame.shape[:2]
side = min(h, w)
x = (w - side) // 2
y = (h - side) // 2
return frame[y:y+side, x:x+side]
def cuseeme_filter(frame: np.ndarray) -> np.ndarray:
"""Apply CUSeeMe look: crop square, shrink, grayscale, 4-bit quantize, scale back up."""
# Crop to square
square = crop_center_square(frame)
# Convert to grayscale
gray = cv2.cvtColor(square, cv2.COLOR_BGR2GRAY)
# Shrink to CUSeeMe resolution
small = cv2.resize(gray, (CUSEEME_SIZE, CUSEEME_SIZE), interpolation=cv2.INTER_AREA)
# Atkinson dither to 1bpp
small = atkinson_dither(small)
# Scale up with nearest-neighbor for blocky look
scale = OUTPUT_H // CUSEEME_SIZE # 480 / 160 = 3x
big = cv2.resize(small, (OUTPUT_H, OUTPUT_H), interpolation=cv2.INTER_NEAREST)
# Embed in standard 640x480 frame with black pillarboxing
frame_out = np.zeros((OUTPUT_H, OUTPUT_W), dtype=np.uint8)
x_offset = (OUTPUT_W - OUTPUT_H) // 2
frame_out[:, x_offset:x_offset+OUTPUT_H] = big
# Convert back to RGB (3-channel gray) for virtual camera
rgb = cv2.cvtColor(frame_out, cv2.COLOR_GRAY2RGB)
return rgb
def main():
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Error: cannot open webcam")
return
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
print(f"Starting CUSeeMe filter: {CUSEEME_SIZE}x{CUSEEME_SIZE}, 1bpp Atkinson dithered")
print("Select 'OBS Virtual Camera' in Zoom's camera settings.")
print("Press Ctrl+C to stop.")
with pyvirtualcam.Camera(width=OUTPUT_W, height=OUTPUT_H, fps=FPS) as cam:
print(f"Virtual camera: {cam.device}")
frame_count = 0
while True:
ret, frame = cap.read()
if not ret:
break
if frame_count == 0:
h, w = frame.shape[:2]
print(f"Webcam raw frame: {w}x{h}")
filtered = cuseeme_filter(frame)
if frame_count == 30:
# Save debug images to verify sizing
gray = cv2.cvtColor(crop_center_square(frame), cv2.COLOR_BGR2GRAY)
small = cv2.resize(gray, (CUSEEME_SIZE, CUSEEME_SIZE), interpolation=cv2.INTER_AREA)
small = atkinson_dither(small)
cv2.imwrite("/Users/dmd/zoomfilter/debug_160.png", small)
cv2.imwrite("/Users/dmd/zoomfilter/debug_output.png", cv2.cvtColor(filtered, cv2.COLOR_RGB2BGR))
print(f"Debug images saved. small shape: {small.shape}, output shape: {filtered.shape}")
cam.send(filtered)
cam.sleep_until_next_frame()
frame_count += 1
cap.release()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment