Drop a rival pipeline's marker when an image is re-indexed
record_detections replaces every face on an image whatever model found them, but left the other models' face_index rows standing. With one model that was unobservable. With a second pipeline it leaves an image marked "done" under the first with none of its faces behind the marker — the state the V12 repair existed to undo — and a user who switched back would find those photographs permanently empty. An image now holds the faces of whichever pipeline looked at it last, and only that pipeline's marker. Confirmed names still carry across by box overlap, since they were read before the replacement.
This commit is contained in:
@@ -158,6 +158,16 @@ pub use dr_face::Calibration;
|
||||
/// part of the frame: a re-index with a better model must not discard the
|
||||
/// user's labelling (FR-CULL-10). Matching is by box overlap, since the face is
|
||||
/// in the same place even when the box moves a little.
|
||||
///
|
||||
/// **Every model's faces are replaced, and every other model's marker goes
|
||||
/// with them.** An image holds the faces of whichever pipeline looked at it
|
||||
/// last, never a mixture — two detectors drawing boxes over the same face is
|
||||
/// not two opinions but a duplicate. So the replacement is unconditional on
|
||||
/// `model_id`, and the run markers of the pipelines whose faces were just
|
||||
/// removed are dropped too: a marker that says "done" over an image with
|
||||
/// none of that model's faces is exactly the state that made the V12 repair
|
||||
/// necessary, and a user who switches their detector back would otherwise
|
||||
/// find those photographs permanently empty.
|
||||
pub fn record_detections(
|
||||
conn: &Connection,
|
||||
image_id: ImageId,
|
||||
@@ -192,6 +202,10 @@ pub fn record_detections(
|
||||
}
|
||||
|
||||
tx.execute("DELETE FROM faces WHERE image_id = ?1", [image_id.0 as i64])?;
|
||||
tx.execute(
|
||||
"DELETE FROM face_index WHERE image_id = ?1 AND model_id != ?2",
|
||||
rusqlite::params![image_id.0 as i64, model_id],
|
||||
)?;
|
||||
|
||||
let now = now_secs();
|
||||
let mut ids = Vec::with_capacity(faces.len());
|
||||
@@ -1608,6 +1622,25 @@ mod tests {
|
||||
assert_eq!(edge, 2048, "the marker should record the newer proxy");
|
||||
}
|
||||
|
||||
/// A user who switches detector and back must not find the images the
|
||||
/// second pipeline visited reported as done under the first with no
|
||||
/// faces behind the marker.
|
||||
#[test]
|
||||
fn re_indexing_under_another_model_drops_the_first_models_marker() {
|
||||
let c = db();
|
||||
let img = image(&c, 1);
|
||||
record_detections(&c, img, "w600k_mbf", 2048, &[face(1)]).unwrap();
|
||||
record_detections(&c, img, "scrfd_2.5g+w600k_mbf", 2048, &[face(2), face(3)]).unwrap();
|
||||
|
||||
assert!(is_indexed(&c, img, "scrfd_2.5g+w600k_mbf").unwrap());
|
||||
assert!(
|
||||
!is_indexed(&c, img, "w600k_mbf").unwrap(),
|
||||
"the first pipeline's marker outlived its faces"
|
||||
);
|
||||
assert_eq!(for_image(&c, img).unwrap().len(), 2);
|
||||
assert_eq!(coverage(&c, "w600k_mbf").unwrap().outstanding(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clearing_a_marker_puts_that_image_back_in_the_queue() {
|
||||
let c = db();
|
||||
|
||||
Reference in New Issue
Block a user