Spaces:
Running
Running
Update landmarkdiff/face_verifier.py to v0.3.2
Browse files
landmarkdiff/face_verifier.py
CHANGED
|
@@ -15,6 +15,7 @@ Designed for:
|
|
| 15 |
|
| 16 |
from __future__ import annotations
|
| 17 |
|
|
|
|
| 18 |
from dataclasses import dataclass, field
|
| 19 |
from pathlib import Path
|
| 20 |
from typing import Any
|
|
@@ -22,6 +23,8 @@ from typing import Any
|
|
| 22 |
import cv2
|
| 23 |
import numpy as np
|
| 24 |
|
|
|
|
|
|
|
| 25 |
# ---------------------------------------------------------------------------
|
| 26 |
# Data structures
|
| 27 |
# ---------------------------------------------------------------------------
|
|
@@ -706,7 +709,11 @@ def get_face_embedding(image: np.ndarray) -> np.ndarray | None:
|
|
| 706 |
try:
|
| 707 |
faces = app.get(image)
|
| 708 |
if faces:
|
| 709 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 710 |
except Exception:
|
| 711 |
pass
|
| 712 |
return None
|
|
@@ -715,12 +722,12 @@ def get_face_embedding(image: np.ndarray) -> np.ndarray | None:
|
|
| 715 |
def verify_identity(
|
| 716 |
original: np.ndarray,
|
| 717 |
restored: np.ndarray,
|
| 718 |
-
threshold: float = 0.
|
| 719 |
) -> tuple[float, bool]:
|
| 720 |
"""Compare identity between original and restored using ArcFace.
|
| 721 |
|
| 722 |
Returns (cosine_similarity, passed).
|
| 723 |
-
Similarity > threshold means same person (
|
| 724 |
"""
|
| 725 |
emb_orig = get_face_embedding(original)
|
| 726 |
emb_rest = get_face_embedding(restored)
|
|
@@ -743,11 +750,11 @@ def verify_identity(
|
|
| 743 |
def verify_and_restore(
|
| 744 |
image: np.ndarray,
|
| 745 |
quality_threshold: float = 60.0,
|
| 746 |
-
identity_threshold: float = 0.
|
| 747 |
restore_mode: str = "auto",
|
| 748 |
codeformer_fidelity: float = 0.7,
|
| 749 |
) -> RestorationResult:
|
| 750 |
-
"""Full pipeline: analyze
|
| 751 |
|
| 752 |
This is the main entry point for the face verifier. It:
|
| 753 |
1. Analyzes the input for distortions
|
|
@@ -830,7 +837,7 @@ def verify_batch(
|
|
| 830 |
image_dir: str,
|
| 831 |
output_dir: str | None = None,
|
| 832 |
quality_threshold: float = 60.0,
|
| 833 |
-
identity_threshold: float = 0.
|
| 834 |
restore_mode: str = "auto",
|
| 835 |
save_rejected: bool = False,
|
| 836 |
extensions: tuple[str, ...] = (".jpg", ".jpeg", ".png", ".webp", ".bmp"),
|
|
@@ -882,7 +889,7 @@ def verify_batch(
|
|
| 882 |
|
| 883 |
for i, img_file in enumerate(image_files):
|
| 884 |
if (i + 1) % 50 == 0 or i == 0:
|
| 885 |
-
|
| 886 |
|
| 887 |
image = cv2.imread(str(img_file))
|
| 888 |
if image is None:
|
|
@@ -934,7 +941,7 @@ def verify_batch(
|
|
| 934 |
# Save report
|
| 935 |
report_text = report.summary()
|
| 936 |
(out_path / "report.txt").write_text(report_text)
|
| 937 |
-
|
| 938 |
-
|
| 939 |
|
| 940 |
return report
|
|
|
|
| 15 |
|
| 16 |
from __future__ import annotations
|
| 17 |
|
| 18 |
+
import logging
|
| 19 |
from dataclasses import dataclass, field
|
| 20 |
from pathlib import Path
|
| 21 |
from typing import Any
|
|
|
|
| 23 |
import cv2
|
| 24 |
import numpy as np
|
| 25 |
|
| 26 |
+
logger = logging.getLogger(__name__)
|
| 27 |
+
|
| 28 |
# ---------------------------------------------------------------------------
|
| 29 |
# Data structures
|
| 30 |
# ---------------------------------------------------------------------------
|
|
|
|
| 709 |
try:
|
| 710 |
faces = app.get(image)
|
| 711 |
if faces:
|
| 712 |
+
emb = faces[0].embedding
|
| 713 |
+
if np.linalg.norm(emb) < 1e-6:
|
| 714 |
+
logger.warning("ArcFace returned near-zero embedding (occluded face?)")
|
| 715 |
+
return None
|
| 716 |
+
return emb
|
| 717 |
except Exception:
|
| 718 |
pass
|
| 719 |
return None
|
|
|
|
| 722 |
def verify_identity(
|
| 723 |
original: np.ndarray,
|
| 724 |
restored: np.ndarray,
|
| 725 |
+
threshold: float = 0.5,
|
| 726 |
) -> tuple[float, bool]:
|
| 727 |
"""Compare identity between original and restored using ArcFace.
|
| 728 |
|
| 729 |
Returns (cosine_similarity, passed).
|
| 730 |
+
Similarity > threshold means same person (0.5 accommodates non-frontal poses).
|
| 731 |
"""
|
| 732 |
emb_orig = get_face_embedding(original)
|
| 733 |
emb_rest = get_face_embedding(restored)
|
|
|
|
| 750 |
def verify_and_restore(
|
| 751 |
image: np.ndarray,
|
| 752 |
quality_threshold: float = 60.0,
|
| 753 |
+
identity_threshold: float = 0.5,
|
| 754 |
restore_mode: str = "auto",
|
| 755 |
codeformer_fidelity: float = 0.7,
|
| 756 |
) -> RestorationResult:
|
| 757 |
+
"""Full pipeline: analyze -> restore -> verify identity.
|
| 758 |
|
| 759 |
This is the main entry point for the face verifier. It:
|
| 760 |
1. Analyzes the input for distortions
|
|
|
|
| 837 |
image_dir: str,
|
| 838 |
output_dir: str | None = None,
|
| 839 |
quality_threshold: float = 60.0,
|
| 840 |
+
identity_threshold: float = 0.5,
|
| 841 |
restore_mode: str = "auto",
|
| 842 |
save_rejected: bool = False,
|
| 843 |
extensions: tuple[str, ...] = (".jpg", ".jpeg", ".png", ".webp", ".bmp"),
|
|
|
|
| 889 |
|
| 890 |
for i, img_file in enumerate(image_files):
|
| 891 |
if (i + 1) % 50 == 0 or i == 0:
|
| 892 |
+
logger.info("Processing %d/%d: %s", i + 1, len(image_files), img_file.name)
|
| 893 |
|
| 894 |
image = cv2.imread(str(img_file))
|
| 895 |
if image is None:
|
|
|
|
| 941 |
# Save report
|
| 942 |
report_text = report.summary()
|
| 943 |
(out_path / "report.txt").write_text(report_text)
|
| 944 |
+
logger.info("\n%s", report_text)
|
| 945 |
+
logger.info("Results saved to %s/", out_path)
|
| 946 |
|
| 947 |
return report
|