Refuse to detect faces on a proxy too small to find one
Detection was run on whatever proxy the caller happened to have. A small one does not fail -- the image is letterboxed into the detector's 640px input at any size -- so it comes back with almost nothing, and the caller then writes a face_index row saying the photograph was examined. That row is the damage. Nothing distinguishes it from "examined properly, no faces in this one", so the image is never looked at again. The measurement, on the reference library of 23,531 images. Runs against a 1024-edge proxy: 0.078 faces per image, 90% of them finding nothing at all. Runs against 2048 or better: 1.82. To rule out the obvious objection that small proxies just come from small photographs, the same comparison restricted to DNGs -- 1,592 of them averaging 21 MB against 7,724 averaging 23 MB, so the same kind of file in the same library -- gives 0.078 against 1.82 again. Twenty-three fold, on identical source material, identical weights, identical options. So the floor goes in the detector rather than in either sweep, because both of them, the example tool and any future job handler are equally entitled to get this wrong, and there is one place that sees every attempt. It is 1025, not 1024, and the odd-looking number is the point: 1024 is exactly ThumbSize::Large, the tier proxies are stored at and the tier one of the two sweeps was detecting on. A floor that admitted 1024 would admit precisely the population this exists to exclude. Written as a minimum rather than a maximum so the test at each call site is `edge < MIN_DETECT_EDGE` with no boundary left to get wrong. ProxyTooSmall is its own error variant rather than an empty result because the caller has to tell it apart from a failure: nothing is wrong with the image or the model, and the answer is to go and find better pixels, not to retry these ones. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
|
||||
use ndarray::Array4;
|
||||
|
||||
use crate::{install_backend, FaceError};
|
||||
use crate::{install_backend, FaceError, MIN_DETECT_EDGE};
|
||||
|
||||
/// The graph's input edge, in pixels. See the module note: not configurable.
|
||||
pub const INPUT_EDGE: usize = 640;
|
||||
@@ -213,6 +213,17 @@ impl Detector {
|
||||
if width == 0 || height == 0 {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
// Refused, not merely unproductive. Returning `Ok(vec![])` here would
|
||||
// let the caller write a run marker meaning "looked, found nothing",
|
||||
// which is the state that makes the image permanently invisible to
|
||||
// every later pass. See [`MIN_DETECT_EDGE`].
|
||||
let edge = width.max(height) as u32;
|
||||
if edge < MIN_DETECT_EDGE {
|
||||
return Err(FaceError::ProxyTooSmall {
|
||||
edge,
|
||||
needed: MIN_DETECT_EDGE,
|
||||
});
|
||||
}
|
||||
if rgb.len() != width * height * 3 {
|
||||
return Err(FaceError::ImageShape {
|
||||
expected: width * height * 3,
|
||||
|
||||
Reference in New Issue
Block a user