Revert the detection floor: it guards the wrong resolution

Reverts 53f7cdf and e92d22d. The floor those added sat on
Detector::detect, refusing any buffer under 1025px on the reasoning that
a small buffer finds no faces. That reasoning does not survive §4.1:
the detector letterboxes every input to 640x640, so a face occupying 2%
of the frame presents at 12px to the model whether it is handed a 1024px
buffer or a 6000px one. Detector input is precisely the quantity that
does not matter.

Worse than merely useless, it blocks the design FR-CULL-8 now specifies,
where the detector is deliberately fed a downscale and the crop is taken
from the native render. A guard on detect() rejects exactly that call.

What the measurement actually supports is a floor on the *crop* source,
which is where resolution converts into embedding quality, and which
faces.crop_px already records: 47% of the reference library's faces were
upsampled to reach 112x112. That floor is a separate change against the
native-resolution path and does not belong on the detector.

The 23x faces-per-image gap by source_edge that motivated the original
commit is kept in faces.md §7b, restated as the unexplained observation
it is rather than the causal claim it was written as. V12 stands: those
runs cropped at 1024 whatever detection did, and that is reason enough
to look at them again.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-30 19:41:12 +02:00
co-authored by Claude Opus 5
parent 41c655c176
commit 144d2e4e84
4 changed files with 15 additions and 93 deletions
-33
View File
@@ -43,31 +43,6 @@ pub mod embedding;
pub mod naming;
pub mod neighbours;
/// Smallest proxy long edge detection will accept, in pixels.
///
/// # Why this exists, and why it is 1025 rather than 1024
///
/// A proxy is letterboxed into the detector's 640px input whatever size it
/// arrives at, so a small one does not fail — it silently finds almost
/// nothing, and the
/// caller records a run marker saying the image was examined. That marker is
/// the damage: it is indistinguishable from "examined properly, no faces
/// here", so the photograph is never looked at again.
///
/// The number is not a guess. Measured over a 23,500 image library, detection
/// against a 1024-edge proxy returned **0.078 faces per image**; the same
/// files — DNGs, 21 MB against 23 MB, so the same photographs in every respect
/// that matters — returned **1.82** against a proxy of 2048 or better. A
/// twenty-three fold difference, on identical source material and identical
/// weights. Ninety percent of the 1024-edge runs found nothing at all.
///
/// 1024 is exactly `dr_thumbs::ThumbSize::Large`, the tier a proxy is stored
/// at, and it was the tier one of the two sweeps detected on. So the floor has
/// to *exclude* 1024 rather than admit it, and the constant is one past it:
/// `edge < MIN_DETECT_EDGE` is then the whole test, with no off-by-one left at
/// the call sites to get wrong.
pub const MIN_DETECT_EDGE: u32 = 1025;
pub use align::{warp, Aligned112, Similarity, ALIGNED_EDGE, ARCFACE_TEMPLATE};
pub use assign::{identity_shares, RIVAL_FLOOR, TOP_MATCHES};
pub use calibrate::{Calibration, Pairs, ReliabilityBand};
@@ -105,14 +80,6 @@ pub enum FaceError {
#[error("image buffer is {got} floats, expected {expected} (RGB, three per pixel)")]
ImageShape { expected: usize, got: usize },
/// The proxy is too small to detect on, so nothing was attempted.
///
/// A distinct variant because the caller must treat it differently from a
/// failure: nothing is wrong with the image or the model, and the right
/// response is to find better pixels rather than to retry these.
#[error("proxy long edge is {edge}px, below the {needed}px detection floor")]
ProxyTooSmall { edge: u32, needed: u32 },
}
/// Install tract as `ort`'s backend.