Use InsightFace for landmark-based face crop alignment
Immich's /api/faces endpoint only returns bounding boxes, not facial landmarks. This meant align_face() never fired and all crops fell back to a plain bbox rectangle — producing partial crops (forehead-only, off-angle faces) when Immich's detection was slightly off. Now, when ENABLE_FACE_ALIGNMENT is true and InsightFace is loaded, execute_jobs() passes the app to process_face_mode(). For each face, it expands the Immich bbox by 50%, crops that search region, runs InsightFace detection within it, and aligns the nearest face to the standard ArcFace 112×112 format using norm_crop(). Falls back to bbox crop if InsightFace finds no face in the search region. The InsightFace model is already in GPU memory from the diversity/ embedding phase, so the singleton lookup adds no load cost.
This commit is contained in:
+13
-1
@@ -155,6 +155,18 @@ def execute_jobs(jobs: list[dict]) -> None:
|
||||
|
||||
use_full_res = Config.USE_FULL_RESOLUTION
|
||||
|
||||
# Load InsightFace app for landmark-based crop alignment (face mode only).
|
||||
# The model is already resident from the diversity/embedding phase, so this
|
||||
# is just a singleton lookup — no load cost.
|
||||
insightface_app = None
|
||||
if any(j["config"].get("mode", "face") == "face" for j in jobs) and Config.ENABLE_FACE_ALIGNMENT:
|
||||
try:
|
||||
from .embeddings import get_insightface_app
|
||||
|
||||
insightface_app = get_insightface_app()
|
||||
except Exception as e:
|
||||
logger.debug(f"InsightFace unavailable for crop alignment: {e}")
|
||||
|
||||
with Progress(
|
||||
SpinnerColumn(),
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
@@ -216,7 +228,7 @@ def execute_jobs(jobs: list[dict]) -> None:
|
||||
progress.console.print(f"[red]Failed download {asset['id']}[/red]")
|
||||
else:
|
||||
saved = (
|
||||
process_face_mode(img, asset, person, person_dir, count)
|
||||
process_face_mode(img, asset, person, person_dir, count, insightface_app=insightface_app)
|
||||
if mode == "face"
|
||||
else process_object_mode(img, config, person_dir, count)
|
||||
if mode == "object"
|
||||
|
||||
Reference in New Issue
Block a user