|
use ndarray::{Array, Axis, IxDyn}; |
|
|
|
#[derive(Clone, PartialEq, Default)] |
|
pub struct YOLOResult { |
|
|
|
pub probs: Option<Embedding>, |
|
pub bboxes: Option<Vec<Bbox>>, |
|
pub keypoints: Option<Vec<Vec<Point2>>>, |
|
pub masks: Option<Vec<Vec<u8>>>, |
|
} |
|
|
|
impl std::fmt::Debug for YOLOResult { |
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
|
f.debug_struct("YOLOResult") |
|
.field( |
|
"Probs(top5)", |
|
&format_args!("{:?}", self.probs().map(|probs| probs.topk(5))), |
|
) |
|
.field("Bboxes", &self.bboxes) |
|
.field("Keypoints", &self.keypoints) |
|
.field( |
|
"Masks", |
|
&format_args!("{:?}", self.masks().map(|masks| masks.len())), |
|
) |
|
.finish() |
|
} |
|
} |
|
|
|
impl YOLOResult { |
|
pub fn new( |
|
probs: Option<Embedding>, |
|
bboxes: Option<Vec<Bbox>>, |
|
keypoints: Option<Vec<Vec<Point2>>>, |
|
masks: Option<Vec<Vec<u8>>>, |
|
) -> Self { |
|
Self { |
|
probs, |
|
bboxes, |
|
keypoints, |
|
masks, |
|
} |
|
} |
|
|
|
pub fn probs(&self) -> Option<&Embedding> { |
|
self.probs.as_ref() |
|
} |
|
|
|
pub fn keypoints(&self) -> Option<&Vec<Vec<Point2>>> { |
|
self.keypoints.as_ref() |
|
} |
|
|
|
pub fn masks(&self) -> Option<&Vec<Vec<u8>>> { |
|
self.masks.as_ref() |
|
} |
|
|
|
pub fn bboxes(&self) -> Option<&Vec<Bbox>> { |
|
self.bboxes.as_ref() |
|
} |
|
|
|
pub fn bboxes_mut(&mut self) -> Option<&mut Vec<Bbox>> { |
|
self.bboxes.as_mut() |
|
} |
|
} |
|
|
|
#[derive(Debug, PartialEq, Clone, Default)] |
|
pub struct Point2 { |
|
|
|
x: f32, |
|
y: f32, |
|
confidence: f32, |
|
} |
|
|
|
impl Point2 { |
|
pub fn new_with_conf(x: f32, y: f32, confidence: f32) -> Self { |
|
Self { x, y, confidence } |
|
} |
|
|
|
pub fn new(x: f32, y: f32) -> Self { |
|
Self { |
|
x, |
|
y, |
|
..Default::default() |
|
} |
|
} |
|
|
|
pub fn x(&self) -> f32 { |
|
self.x |
|
} |
|
|
|
pub fn y(&self) -> f32 { |
|
self.y |
|
} |
|
|
|
pub fn confidence(&self) -> f32 { |
|
self.confidence |
|
} |
|
} |
|
|
|
#[derive(Debug, Clone, PartialEq, Default)] |
|
pub struct Embedding { |
|
|
|
data: Array<f32, IxDyn>, |
|
} |
|
|
|
impl Embedding { |
|
pub fn new(data: Array<f32, IxDyn>) -> Self { |
|
Self { data } |
|
} |
|
|
|
pub fn data(&self) -> &Array<f32, IxDyn> { |
|
&self.data |
|
} |
|
|
|
pub fn topk(&self, k: usize) -> Vec<(usize, f32)> { |
|
let mut probs = self |
|
.data |
|
.iter() |
|
.enumerate() |
|
.map(|(a, b)| (a, *b)) |
|
.collect::<Vec<_>>(); |
|
probs.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); |
|
let mut topk = Vec::new(); |
|
for &(id, confidence) in probs.iter().take(k) { |
|
topk.push((id, confidence)); |
|
} |
|
topk |
|
} |
|
|
|
pub fn norm(&self) -> Array<f32, IxDyn> { |
|
let std_ = self.data.mapv(|x| x * x).sum_axis(Axis(0)).mapv(f32::sqrt); |
|
self.data.clone() / std_ |
|
} |
|
|
|
pub fn top1(&self) -> (usize, f32) { |
|
self.topk(1)[0] |
|
} |
|
} |
|
|
|
#[derive(Debug, Clone, PartialEq, Default)] |
|
pub struct Bbox { |
|
|
|
xmin: f32, |
|
ymin: f32, |
|
width: f32, |
|
height: f32, |
|
id: usize, |
|
confidence: f32, |
|
} |
|
|
|
impl Bbox { |
|
pub fn new_from_xywh(xmin: f32, ymin: f32, width: f32, height: f32) -> Self { |
|
Self { |
|
xmin, |
|
ymin, |
|
width, |
|
height, |
|
..Default::default() |
|
} |
|
} |
|
|
|
pub fn new(xmin: f32, ymin: f32, width: f32, height: f32, id: usize, confidence: f32) -> Self { |
|
Self { |
|
xmin, |
|
ymin, |
|
width, |
|
height, |
|
id, |
|
confidence, |
|
} |
|
} |
|
|
|
pub fn width(&self) -> f32 { |
|
self.width |
|
} |
|
|
|
pub fn height(&self) -> f32 { |
|
self.height |
|
} |
|
|
|
pub fn xmin(&self) -> f32 { |
|
self.xmin |
|
} |
|
|
|
pub fn ymin(&self) -> f32 { |
|
self.ymin |
|
} |
|
|
|
pub fn xmax(&self) -> f32 { |
|
self.xmin + self.width |
|
} |
|
|
|
pub fn ymax(&self) -> f32 { |
|
self.ymin + self.height |
|
} |
|
|
|
pub fn tl(&self) -> Point2 { |
|
Point2::new(self.xmin, self.ymin) |
|
} |
|
|
|
pub fn br(&self) -> Point2 { |
|
Point2::new(self.xmax(), self.ymax()) |
|
} |
|
|
|
pub fn cxcy(&self) -> Point2 { |
|
Point2::new(self.xmin + self.width / 2., self.ymin + self.height / 2.) |
|
} |
|
|
|
pub fn id(&self) -> usize { |
|
self.id |
|
} |
|
|
|
pub fn confidence(&self) -> f32 { |
|
self.confidence |
|
} |
|
|
|
pub fn area(&self) -> f32 { |
|
self.width * self.height |
|
} |
|
|
|
pub fn intersection_area(&self, another: &Bbox) -> f32 { |
|
let l = self.xmin.max(another.xmin); |
|
let r = (self.xmin + self.width).min(another.xmin + another.width); |
|
let t = self.ymin.max(another.ymin); |
|
let b = (self.ymin + self.height).min(another.ymin + another.height); |
|
(r - l + 1.).max(0.) * (b - t + 1.).max(0.) |
|
} |
|
|
|
pub fn union(&self, another: &Bbox) -> f32 { |
|
self.area() + another.area() - self.intersection_area(another) |
|
} |
|
|
|
pub fn iou(&self, another: &Bbox) -> f32 { |
|
self.intersection_area(another) / self.union(another) |
|
} |
|
} |
|
|