pub struct OrtDetector<F> { /* private fields */ }ort only.Expand description
Terminal sink that runs a YOLOv8/v11-style ONNX object-detection model
(an Ultralytics export: one image input, one [1, 4 + num_classes, num_boxes] output, box coordinates as center/width/height) on every
incoming frame via ort, then hands the decoded, NMS-filtered
detections to a plain closure — same “bring your own closure” shape as
crate::elements::AppSink, except the closure gets structured
Detections instead of a raw MediaBuffer.
Expects every frame’s pixel dimensions to already match the model’s own
input resolution (e.g. 640x640 for stock YOLOv8/11 weights) and its
format to be Pixel::RGB24 — put a crate::elements::Scaler
configured that way directly upstream. Because of that, a detection’s
box coordinates need no rescaling back to some “original” resolution:
they come straight out of the model in the exact same pixel space as
the frame handed to the closure.
Input/output tensors are bound by position, not by name (images /
output0 aren’t assumed) — whatever the export happens to call its
single input and single output, this binds to index 0 of each.
NMS is per-class (a box only suppresses another box of the same
class_id), matching Ultralytics’ own default (non-agnostic) NMS.
Implementations§
Source§impl<F> OrtDetector<F>
impl<F> OrtDetector<F>
Sourcepub fn new(
name: impl Into<String>,
model_path: impl AsRef<Path>,
conf_threshold: f32,
iou_threshold: f32,
on_detections: F,
) -> Result<Self>
pub fn new( name: impl Into<String>, model_path: impl AsRef<Path>, conf_threshold: f32, iou_threshold: f32, on_detections: F, ) -> Result<Self>
conf_threshold drops candidate boxes below that class score before
NMS ever sees them; iou_threshold is how much two same-class boxes
may overlap before the lower-scoring one is suppressed as a
duplicate of the other.
Trait Implementations§
Source§impl<F> Element for OrtDetector<F>
impl<F> Element for OrtDetector<F>
Source§fn name(&self) -> Arc<str> ⓘ
fn name(&self) -> Arc<str> ⓘ
crate::bus::BusEvent stores names as
Arc<str> for exactly this reason: a hot path like
crate::queue::Queue posting BusEvent::Dropped once per
overflowed buffer shouldn’t pay for a fresh heap allocation every
time it wants to report which element it is.Source§fn element_type(&self) -> ElementType
fn element_type(&self) -> ElementType
ElementType.Source§fn pp_log(&self) -> &PpLog
fn pp_log(&self) -> &PpLog
crate::bus::Bus::post — same
id/name as Element::name, just already wrapped as the
crate::pp_log::PpLog its pp_info!/pp_warn!/pp_error! macros need. A
stored private field, not built fresh per call, for the same reason
name() returns a cheap Arc<str> clone instead of a fresh String
— see its own docs.Source§fn pp_log_mut(&mut self) -> &mut PpLog
fn pp_log_mut(&mut self) -> &mut PpLog
Element::pp_log reads — used by
crate::pipeline::ChainBuilder to stamp the owning
crate::pipeline::Pipeline’s id onto every element that
passes through it, via element_pp_log. Not meant to be called
from anywhere else.Source§impl<F> Sink for OrtDetector<F>
impl<F> Sink for OrtDetector<F>
fn consume(&mut self, buf: MediaBuffer) -> Result<()>
Source§fn control(&mut self, _msg: ControlMsg) -> Result<()>
fn control(&mut self, _msg: ControlMsg) -> Result<()>
ControlMsg (pause/resume/stop) and, for anything
with a downstream of its own, forwards it on — same shape as
consume, just a separate channel from MediaBuffer so it can
reach every element (not just ones that already know how to
interpret a data buffer) and, at a crate::queue::Queue, jump
ahead of whatever data is backed up instead of waiting behind it.
No default: every Sink has to consciously decide what this means
for it, rather than silently dropping it.