#!/opt/homebrew/bin/python3.11 """ Find Inverted Jenny Stamp (Blue Rectangle in Hands) """ import cv2 import numpy as np import os UUID = "384b0ff44aaaa1f1" BASE_DIR = f"output/{UUID}/florence2_results" # Frames to check FRAMES = [ "scan_6756.jpg", # 112:36 "scan_6763.jpg", # 112:43 "scan_6790.jpg", # 113:10 "scan_6813.jpg", # 113:33 "scan_6832.jpg", # 113:52 ] print("šŸ” Searching for SMALL BLUE RECTANGLES in hands (Inverted Jenny)...") for frame_name in FRAMES: img_path = os.path.join(BASE_DIR, frame_name) if not os.path.exists(img_path): continue img = cv2.imread(img_path) hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 1. Hand Detection (Skin Tone) - Broad range skin_mask = cv2.inRange(hsv, np.array([0, 20, 40]), np.array([25, 150, 255])) # Clean up mask kernel = np.ones((5, 5), np.uint8) skin_mask = cv2.morphologyEx(skin_mask, cv2.MORPH_CLOSE, kernel) skin_mask = cv2.morphologyEx(skin_mask, cv2.MORPH_OPEN, kernel) # 2. Blue Detection (Stamp Background) # Inverted Jenny is Blue and Red. We look for the Blue part. blue_mask = cv2.inRange(hsv, np.array([90, 40, 40]), np.array([130, 255, 255])) # 3. Intersection: Blue INSIDE/NEAR Hands # We dilate the skin mask to include things held IN the hand skin_dilated = cv2.dilate(skin_mask, kernel, iterations=3) # Find blue things touching hands stamp_candidate_mask = cv2.bitwise_and(blue_mask, skin_dilated) # 4. Find contours in the intersection contours, _ = cv2.findContours( stamp_candidate_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE ) print(f"\nšŸŽžļø Scanning {frame_name}...") found_count = 0 for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) area = cv2.contourArea(cnt) # Stamp size: Small rectangle (bigger than a dot, smaller than a face) # Area: 200 - 5000 pixels if 200 < area < 5000: aspect_ratio = float(w) / h # Check if it looks like a stamp (rectangular, aspect ratio 0.8 - 1.5 roughly) if 0.6 < aspect_ratio < 1.8: found_count += 1 print(f" āœ… Candidate: Area={int(area)}, Pos=({x},{y}), Size={w}x{h}") # Crop with padding pad = 5 crop = img[ max(0, y - pad) : min(img.shape[0], y + h + pad), max(0, x - pad) : min(img.shape[1], x + w + pad), ] crop_path = os.path.join( BASE_DIR, f"blue_stamp_{frame_name}_{x}_{y}.jpg" ) cv2.imwrite(crop_path, crop) # Draw on main image cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 3) cv2.putText( img, "BLUE STAMP?", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2, ) if found_count == 0: print(" āŒ No blue stamp candidates found in hands.") else: res_path = os.path.join(BASE_DIR, f"result_blue_{frame_name}") cv2.imwrite(res_path, img)