catalog.md §8.2 still said confirmed and rejected faces were matched to local faces "by box", and that the merge reads only a remote face's box and model; faces.md said `match_faces` "still matches by overlap alone across devices". Since #77 the match falls back to embeddings, on the photographs where a box leaves a remote face over, and since #78 `dedup_people` folds people of one name whose faces agree after every sync. Both now say so, with the thresholds and the reason a less decisive pair stays unmatched, taken from the code's own documentation.
This commit is contained in:
+34
-2
@@ -1575,5 +1575,37 @@ It is a match, not an update in place, and that is why the per-face repairs exis
|
||||
detection: where nothing about a face but one field needs doing, `record_updates` keeps the id and
|
||||
there is nothing to judge.
|
||||
|
||||
The merge's `match_faces` still matches by overlap alone across devices. It is the same question,
|
||||
and the same answer would serve it; it is not changed here.
|
||||
Since #77 (0.18.0) the merge's `match_faces` answers it too, within a photograph's `file_id` and
|
||||
one embedder: box IoU ≥ 0.5, unique on both sides, first; then, only for photographs where a remote
|
||||
face is left over and a local face is free, embedding cosine ≥ 0.7, mutual best, with a lead of
|
||||
≥ 0.2 over the runner-up on both sides. A box match is never overruled by a low cosine (about 150
|
||||
genuine cross-device pairs of tiny faces score below 0.45). On the reference desktop/tablet pair this
|
||||
recovers 20 of 631 unmatched faces with no false matches; the rest are faces one device alone found.
|
||||
The merge also keeps one person to one face per photograph: an incoming assignment is refused when
|
||||
another local face already holds that person, unless it is a remote confirmation over a local
|
||||
suggestion, which moves the suggestion. Refusals are counted in `faces_one_per_photograph`.
|
||||
|
||||
The threshold differs from `SAME_FACE_COSINE` (0.45) above on purpose: re-detection additionally
|
||||
requires the boxes to overlap, while the merge's embedding route exists for boxes that don't.
|
||||
|
||||
## 19. Deduplicating people · 2026-09-26
|
||||
|
||||
`dr_catalog::dedup_people::run` runs after every successful sync merge (`sync::merge_remote`, on the
|
||||
sync worker), in one transaction, and logs one `dedup:` line (#78).
|
||||
|
||||
**People.** Named people with the same name, trimmed and case-folded, merge into the one with the
|
||||
most confirmed faces (ties go to the smaller uuid) when every shared embedder's confirmed-face
|
||||
centroids agree at cosine ≥ 0.7 (distance < 0.3). Each side needs at least two confirmed faces to
|
||||
compare; a namesake holding no faces merges outright; a face confirmed as one and rejected as the
|
||||
other keeps them apart; unnamed and set-aside people are never touched. On the reference library the
|
||||
same-person centroid median is 0.91, and different named people have a 99.9th percentile of 0.41.
|
||||
|
||||
**Faces.** Two faces in the same image and embedder with IoU ≥ 0.5 and cosine ≥ 0.7 are one: the
|
||||
job keeps the stronger detector's face (`FaceDetector::outranks`), then the confirmed one, then the
|
||||
lower id, and it takes both faces' assignment and rejections.
|
||||
|
||||
**Propagation.** The merge is `faces::merge_people`, whose `merged_into` redirect a 0.17.0 peer
|
||||
already honours, so an older device never resurrects the duplicate. The job also follows redirects
|
||||
left by earlier manual merges, moving this device's own assignments onto the person kept, and
|
||||
breaks a mutual redirect at the smaller uuid, which every device computes alike. A merge now also
|
||||
carries the merged-away person's rejections to the person kept.
|
||||
|
||||
Reference in New Issue
Block a user