use crate::BBox;
use darknet_sys as sys;
use std::cmp::Ordering::Less;
use std::{
iter::{ExactSizeIterator, FusedIterator, Iterator},
os::raw::c_int,
ptr::NonNull,
slice,
};
#[derive(Debug)]
pub struct Detection<'a> {
detection: &'a sys::detection,
}
impl<'a> Detection<'a> {
pub fn bbox(&self) -> &BBox {
&self.detection.bbox
}
pub fn num_classes(&self) -> usize {
self.detection.classes as usize
}
pub fn probabilities(&self) -> &[f32] {
unsafe { slice::from_raw_parts(self.detection.prob, self.num_classes()) }
}
pub fn best_class(&self, prob_threshold: Option<f32>) -> Option<(usize, f32)> {
self.probabilities()
.iter()
.enumerate()
.filter(|(_, prob)| prob_threshold.map_or(true, |thresh| thresh.lt(prob)))
.max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Less))
.map(|(idx, prob)| (idx, *prob))
}
pub fn uc(&self) -> Option<&[f32]> {
let ptr = self.detection.uc;
if ptr.is_null() {
None
} else {
unsafe { Some(slice::from_raw_parts(ptr, 4)) }
}
}
pub fn objectness(&self) -> f32 {
self.detection.objectness
}
pub fn sort_class(&self) -> usize {
self.detection.sort_class as usize
}
}
#[derive(Debug)]
pub struct Detections {
pub(crate) detections: NonNull<sys::detection>,
pub(crate) n_detections: usize,
}
impl Detections {
pub fn get(&self, index: usize) -> Option<Detection> {
if index >= self.n_detections {
return None;
}
let slice = unsafe { slice::from_raw_parts(self.detections.as_ptr(), self.n_detections) };
Some(Detection {
detection: &slice[index],
})
}
pub fn len(&self) -> usize {
self.n_detections
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn iter(&self) -> DetectionsIter {
DetectionsIter {
detections: self,
index: 0,
}
}
}
impl<'a> IntoIterator for &'a Detections {
type Item = Detection<'a>;
type IntoIter = DetectionsIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl Drop for Detections {
fn drop(&mut self) {
unsafe {
sys::free_detections(self.detections.as_mut(), self.n_detections as c_int);
}
}
}
unsafe impl Send for Detections {}
#[derive(Debug, Clone)]
pub struct DetectionsIter<'a> {
detections: &'a Detections,
index: usize,
}
impl<'a> Iterator for DetectionsIter<'a> {
type Item = Detection<'a>;
fn next(&mut self) -> Option<Self::Item> {
let opt = self.detections.get(self.index);
if opt.is_some() {
self.index += 1;
}
opt
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.detections.len(), Some(self.detections.len()))
}
}
impl<'a> FusedIterator for DetectionsIter<'a> {}
impl<'a> ExactSizeIterator for DetectionsIter<'a> {}