Files
uniface/scripts/run_face_search.py
2025-11-26 00:05:24 +09:00

98 lines
3.1 KiB
Python

# Real-time face search: match webcam faces against a reference image
# Usage: python run_face_search.py --image reference.jpg
import argparse
import cv2
import numpy as np
from uniface.detection import SCRFD, RetinaFace
from uniface.face_utils import compute_similarity
from uniface.recognition import ArcFace, MobileFace, SphereFace
def get_recognizer(name: str):
if name == "arcface":
return ArcFace()
elif name == "mobileface":
return MobileFace()
else:
return SphereFace()
def extract_reference_embedding(detector, recognizer, image_path: str) -> np.ndarray:
image = cv2.imread(image_path)
if image is None:
raise RuntimeError(f"Failed to load image: {image_path}")
faces = detector.detect(image)
if not faces:
raise RuntimeError("No faces found in reference image.")
landmarks = np.array(faces[0]["landmarks"])
return recognizer.get_normalized_embedding(image, landmarks)
def run_webcam(detector, recognizer, ref_embedding: np.ndarray, threshold: float = 0.4):
cap = cv2.VideoCapture(0) # 0 = default webcam
if not cap.isOpened():
raise RuntimeError("Webcam could not be opened.")
print("Press 'q' to quit")
while True:
ret, frame = cap.read()
frame = cv2.flip(frame, 1) # mirror for natural interaction
if not ret:
break
faces = detector.detect(frame)
for face in faces:
bbox = face["bbox"]
landmarks = np.array(face["landmarks"])
x1, y1, x2, y2 = map(int, bbox)
embedding = recognizer.get_normalized_embedding(frame, landmarks)
sim = compute_similarity(ref_embedding, embedding) # compare with reference
# green = match, red = unknown
label = f"Match ({sim:.2f})" if sim > threshold else f"Unknown ({sim:.2f})"
color = (0, 255, 0) if sim > threshold else (0, 0, 255)
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
cv2.putText(frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
cv2.imshow("Face Recognition", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cap.release()
cv2.destroyAllWindows()
def main():
parser = argparse.ArgumentParser(description="Face search using a reference image")
parser.add_argument("--image", type=str, required=True, help="Reference face image")
parser.add_argument("--threshold", type=float, default=0.4, help="Match threshold")
parser.add_argument("--detector", type=str, default="scrfd", choices=["retinaface", "scrfd"])
parser.add_argument(
"--recognizer",
type=str,
default="arcface",
choices=["arcface", "mobileface", "sphereface"],
)
args = parser.parse_args()
detector = RetinaFace() if args.detector == "retinaface" else SCRFD()
recognizer = get_recognizer(args.recognizer)
print(f"Loading reference: {args.image}")
ref_embedding = extract_reference_embedding(detector, recognizer, args.image)
run_webcam(detector, recognizer, ref_embedding, args.threshold)
if __name__ == "__main__":
main()