- Update ASR, face, OCR, pose processors - Add release pre-flight check script - Add synonym generation, chunk processing scripts - Add face recognition, stamp search utilities
87 lines
2.6 KiB
Python
87 lines
2.6 KiB
Python
#!/opt/homebrew/bin/python3.11
|
|
"""
|
|
Find the Red Inverted Triangle Stamp using OpenCV Color & Shape Detection
|
|
"""
|
|
|
|
import cv2
|
|
import numpy as np
|
|
import os
|
|
|
|
UUID = "384b0ff44aaaa1f1"
|
|
BASE_DIR = f"output/{UUID}/florence2_results"
|
|
IMG_NAME = "frame_6756.jpg" # Frame at 112:36
|
|
IMG_PATH = os.path.join(BASE_DIR, IMG_NAME)
|
|
OUT_PATH = os.path.join(BASE_DIR, "found_stamp_opencv.jpg")
|
|
|
|
print(f"📷 Loading image: {IMG_PATH}")
|
|
if not os.path.exists(IMG_PATH):
|
|
print("❌ Image not found.")
|
|
exit()
|
|
|
|
img = cv2.imread(IMG_PATH)
|
|
h, w, _ = img.shape
|
|
print(f"📐 Image Size: {w}x{h}")
|
|
|
|
# 1. Convert to HSV Color Space
|
|
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
|
|
|
|
# 2. Define Red Color Range in HSV
|
|
# Red wraps around 180, so we need two ranges
|
|
# Lower Red: Hue 0-10
|
|
lower_red1 = np.array([0, 70, 50])
|
|
upper_red1 = np.array([10, 255, 255])
|
|
mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
|
|
|
|
# Upper Red: Hue 170-180
|
|
lower_red2 = np.array([170, 70, 50])
|
|
upper_red2 = np.array([180, 255, 255])
|
|
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
|
|
|
|
# Combine Masks
|
|
mask = mask1 + mask2
|
|
|
|
# 3. Find Contours in the Mask
|
|
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
print(f"🔍 Found {len(contours)} red regions.")
|
|
|
|
# 4. Filter for Triangles (Stamp Shape)
|
|
found_stamps = []
|
|
for i, cnt in enumerate(contours):
|
|
# Calculate perimeter for approximation accuracy
|
|
peri = cv2.arcLength(cnt, True)
|
|
approx = cv2.approxPolyDP(cnt, 0.04 * peri, True)
|
|
|
|
# Check for triangle (3 vertices)
|
|
if len(approx) == 3:
|
|
area = cv2.contourArea(approx)
|
|
# Filter by size (ignore noise, ignore huge red walls)
|
|
# A stamp would likely be between 500 and 20000 pixels depending on zoom
|
|
if 200 < area < 50000:
|
|
# Get bounding box
|
|
x, y, w_box, h_box = cv2.boundingRect(approx)
|
|
found_stamps.append((x, y, w_box, h_box, approx))
|
|
print(
|
|
f"✅ Potential Stamp #{len(found_stamps)}: Area={area}, Box=({x},{y})"
|
|
)
|
|
|
|
# 5. Draw Results
|
|
result_img = img.copy()
|
|
for x, y, w_box, h_box, approx in found_stamps:
|
|
# Draw Box
|
|
cv2.rectangle(result_img, (x, y), (x + w_box, y + h_box), (0, 255, 0), 3)
|
|
# Draw Contour
|
|
cv2.drawContours(result_img, [approx], 0, (255, 0, 0), 2)
|
|
# Label
|
|
cv2.putText(
|
|
result_img, "STAMP?", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2
|
|
)
|
|
|
|
if found_stamps:
|
|
cv2.imwrite(OUT_PATH, result_img)
|
|
print(f"🎨 Result saved to: {OUT_PATH}")
|
|
else:
|
|
print(
|
|
"❌ No red triangles found. The stamp might not be visible or red in this frame."
|
|
)
|