Record that face detection has run, not just what it found
An image with no faces in it was indistinguishable from one that had never been looked at, so every landscape, still life and document scan in the library was re-detected on every pass, for ever. In a real library that is most of it: on the 23,527-image test library, 64 of the first 110 images indexed contain no face at all. Schema v9 adds face_index, a run marker per (image, model) carrying the face count and the proxy edge it read. Keyed on the model, so a model change puts every image back in the queue by itself. That makes a coverage figure possible, which is the thing a user actually wants to see. The audit also splits the outstanding set by whether a proxy exists, because 23,417 awaiting a proxy and 110 ready to index are different problems, and telling the user to run indexing again would not fix the first. The Identity screen gains Index faces, Stop, and the coverage line. examples/face_index.rs is the same check and sweep without a window, which is the right shape for an overnight pass. Measured on the real library in release: 3.5 images/second, 110 images and 125 faces in 30 seconds, and a second run correctly finds nothing left to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2892,6 +2892,36 @@ pub fn thumbs_dir(server: &str, user_id: &str) -> PathBuf {
|
||||
.unwrap_or_else(|| std::env::temp_dir().join("darkroom-thumbs"))
|
||||
}
|
||||
|
||||
/// Where the face models live, beside the catalog and the thumbnails.
|
||||
///
|
||||
/// **Not shipped with the application** and not a build input: the InsightFace
|
||||
/// weights carry a non-commercial research grant incompatible with this
|
||||
/// project's licence, so the user obtains them and the app loads them from here
|
||||
/// (docs/faces.md §2). An absent directory is the ordinary state of a fresh
|
||||
/// install, not an error.
|
||||
pub fn face_models_dir(server: &str, user_id: &str) -> PathBuf {
|
||||
catalog_path(server, user_id)
|
||||
.parent()
|
||||
.map(|p| p.join("models"))
|
||||
.unwrap_or_else(|| std::env::temp_dir().join("darkroom-models"))
|
||||
}
|
||||
|
||||
/// The detector and embedder files, if both are present.
|
||||
///
|
||||
/// Both or neither: an embedder with no detector has nothing to embed, and a
|
||||
/// detector with no embedder finds faces it cannot tell apart. Reporting the
|
||||
/// pair missing is more useful than half-starting.
|
||||
///
|
||||
/// The names are the **shape-fixed** exports, not what InsightFace ships:
|
||||
/// `tools/fix-face-model-shapes.sh` has to run over the originals first,
|
||||
/// because tract cannot parse either graph with a dynamic input.
|
||||
pub fn face_models(server: &str, user_id: &str) -> Option<(PathBuf, PathBuf)> {
|
||||
let dir = face_models_dir(server, user_id);
|
||||
let detector = dir.join("scrfd_500m_640.onnx");
|
||||
let embedder = dir.join("arcface_mbf_b1.onnx");
|
||||
(detector.is_file() && embedder.is_file()).then_some((detector, embedder))
|
||||
}
|
||||
|
||||
/// One grid cell's data, read from the catalog.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct LibraryCell {
|
||||
|
||||
Reference in New Issue
Block a user