pub fn merge_tiled_detections(
dets: Vec<DetectBox>,
cfg: &MergeConfig,
) -> Vec<DetectBox>Expand description
Greedy Non-Max Merge of lifted full-frame detections. Mirrors
metrics/tiled.py::merge_tiled_detections:
- Sort descending by score (ties broken by ascending original index so the
result is deterministic — this differs from NumPy’s unstable
argsortonly on exact ties). - For each unused
basein order, find later unused boxes (same class unlessclass_agnostic) whosemetric.value(base, cand) >= threshold— matched against the original base box. Replace the group with its enclosing union carrying the group’s max score and the base’s label. - Drop groups below
score_thresholdand truncate tomax_det.
Operates in pixel space (the metric’s 1e-9 epsilon is calibrated to pixel
areas).
§Examples
use edgefirst_decoder::tiling::{merge_tiled_detections, MatchMetric, MergeConfig};
use edgefirst_decoder::{BoundingBox, DetectBox};
// A fragment (B) fully inside the full detection (A): IoS=1.0, IoU≈0.17.
let a = DetectBox { bbox: BoundingBox::new(100.0, 100.0, 400.0, 300.0), score: 0.9, label: 0 };
let b = DetectBox { bbox: BoundingBox::new(350.0, 100.0, 400.0, 300.0), score: 0.7, label: 0 };
// IOS merges the fragment into one box carrying the group's max score…
let ios = merge_tiled_detections(vec![a, b], &MergeConfig::default());
assert_eq!(ios.len(), 1);
assert_eq!(ios[0].score, 0.9);
// …while IOU leaves the two separate.
let cfg = MergeConfig { metric: MatchMetric::Iou, ..MergeConfig::default() };
assert_eq!(merge_tiled_detections(vec![a, b], &cfg).len(), 2);