backup: broken backup

This commit is contained in:
uttarayan21
2025-08-07 13:30:34 +05:30
parent 8d07b0846c
commit 2c43f657aa
6 changed files with 292 additions and 181 deletions

View File

@@ -2,7 +2,7 @@ pub mod draw;
pub mod nms; pub mod nms;
pub mod roi; pub mod roi;
use nalgebra::{Point, Point2, Point3, SVector, SimdPartialOrd, SimdValue}; use nalgebra::{Point, Point2, SVector, Vector2};
pub trait Num: pub trait Num:
num::Num num::Num
+ core::ops::AddAssign + core::ops::AddAssign
@@ -212,13 +212,9 @@ impl<T: Num, const D: usize> AxisAlignedBoundingBox<T, D> {
T: nalgebra::SimdValue, T: nalgebra::SimdValue,
T: nalgebra::SimdPartialOrd, T: nalgebra::SimdPartialOrd,
{ {
let self_min = self.min_vertex(); let min = self.min_vertex().inf(&other.min_vertex());
let self_max = self.max_vertex(); let max = self.min_vertex().sup(&other.max_vertex());
let other_min = other.min_vertex(); Self::new(min, max)
let other_max = other.max_vertex();
let min = self_min.inf(&other_min);
let max = self_max.sup(&other_max);
Self::from_min_max_vertices(min, max)
} }
pub fn union(&self, other: &Self) -> T pub fn union(&self, other: &Self) -> T
@@ -244,13 +240,9 @@ impl<T: Num, const D: usize> AxisAlignedBoundingBox<T, D> {
T: nalgebra::SimdPartialOrd, T: nalgebra::SimdPartialOrd,
T: nalgebra::SimdValue, T: nalgebra::SimdValue,
{ {
let inter_min = self.min_vertex().inf(&other.min_vertex()); let inter_min = self.min_vertex().sup(&other.min_vertex());
let inter_max = self.max_vertex().sup(&other.max_vertex()); let inter_max = self.max_vertex().inf(&other.max_vertex());
Self::try_new(inter_min, inter_max)
if inter_max < inter_min {
return None; // No intersection
}
Some(Self::new(inter_min, inter_max))
} }
pub fn denormalize(&self, factor: nalgebra::SVector<T, D>) -> Self pub fn denormalize(&self, factor: nalgebra::SVector<T, D>) -> Self
@@ -302,12 +294,19 @@ impl<T: Num, const D: usize> AxisAlignedBoundingBox<T, D> {
T: nalgebra::SimdValue, T: nalgebra::SimdValue,
T: core::ops::MulAssign, T: core::ops::MulAssign,
{ {
let intersection = self let lhs_min = self.min_vertex();
.intersection(other) let lhs_max = self.max_vertex();
.map(|v| v.measure()) let rhs_min = other.min_vertex();
.unwrap_or(T::zero()); let rhs_max = other.max_vertex();
let union = self.union(other);
intersection / union let inter_min = lhs_min.sup(&rhs_min);
let inter_max = lhs_max.inf(&rhs_max);
if inter_max < inter_min {
return T::zero();
} else {
let intersection = Aabb::new(inter_min, inter_max).measure();
intersection / (self.measure() + other.measure() - intersection)
}
} }
} }
@@ -318,8 +317,15 @@ impl<T: Num> Aabb2<T> {
{ {
let point1 = Point2::new(x1, y1); let point1 = Point2::new(x1, y1);
let point2 = Point2::new(x2, y2); let point2 = Point2::new(x2, y2);
Self::from_min_max_vertices(point1, point2) Self::new(point1, point2)
} }
pub fn from_xywh(x: T, y: T, w: T, h: T) -> Self {
let point = Point2::new(x, y);
let size = Vector2::new(w, h);
Self::new_point_size(point, size)
}
pub fn x1y1(&self) -> Point2<T> { pub fn x1y1(&self) -> Point2<T> {
self.point self.point
} }
@@ -391,156 +397,219 @@ impl<T: Num> Aabb3<T> {
} }
} }
#[test] #[cfg(test)]
fn test_bbox_new() { mod boudning_box_tests {
use nalgebra::{Point2, Vector2}; use super::*;
use nalgebra::*;
let point1 = Point2::new(1.0, 2.0); #[test]
let point2 = Point2::new(4.0, 6.0); fn test_bbox_new() {
let bbox = AxisAlignedBoundingBox::new(point1, point2); let point1 = Point2::new(1.0, 2.0);
let point2 = Point2::new(4.0, 6.0);
let bbox = AxisAlignedBoundingBox::new(point1, point2);
assert_eq!(bbox.min_vertex(), point1); assert_eq!(bbox.min_vertex(), point1);
assert_eq!(bbox.size(), Vector2::new(3.0, 4.0)); assert_eq!(bbox.size(), Vector2::new(3.0, 4.0));
assert_eq!(bbox.center(), Point2::new(2.5, 4.0)); assert_eq!(bbox.center(), Point2::new(2.5, 4.0));
} }
#[test] #[test]
fn test_bounding_box_center_2d() { fn test_intersection_and_merge() {
use nalgebra::{Point2, Vector2}; let point1 = Point2::new(1, 5);
let point2 = Point2::new(3, 2);
let size1 = Vector2::new(3, 4);
let size2 = Vector2::new(1, 3);
let point = Point2::new(1.0, 2.0); let this = Aabb2::new_point_size(point1, size1);
let size = Vector2::new(3.0, 4.0); let other = Aabb2::new_point_size(point2, size2);
let bbox = AxisAlignedBoundingBox::new(point, size); let inter = this.intersection(&other);
let merged = this.merge(&other);
assert_ne!(inter, Some(merged))
}
assert_eq!(bbox.min_vertex(), point); #[test]
assert_eq!(bbox.size(), size); fn test_bounding_box_center_2d() {
assert_eq!(bbox.center(), Point2::new(2.5, 4.0)); let point = Point2::new(1.0, 2.0);
} let size = Vector2::new(3.0, 4.0);
let bbox = AxisAlignedBoundingBox::new_point_size(point, size);
#[test] assert_eq!(bbox.min_vertex(), point);
fn test_bounding_box_center_3d() { assert_eq!(bbox.size(), size);
use nalgebra::{Point3, Vector3}; assert_eq!(bbox.center(), Point2::new(2.5, 4.0));
}
let point = Point3::new(1.0, 2.0, 3.0); #[test]
let size = Vector3::new(4.0, 5.0, 6.0); fn test_bounding_box_center_3d() {
let bbox = AxisAlignedBoundingBox::new(point, size); let point = Point3::new(1.0, 2.0, 3.0);
let size = Vector3::new(4.0, 5.0, 6.0);
let bbox = AxisAlignedBoundingBox::new_point_size(point, size);
assert_eq!(bbox.min_vertex(), point); assert_eq!(bbox.min_vertex(), point);
assert_eq!(bbox.size(), size); assert_eq!(bbox.size(), size);
assert_eq!(bbox.center(), Point3::new(3.0, 4.5, 6.0)); assert_eq!(bbox.center(), Point3::new(3.0, 4.5, 6.0));
} }
#[test] #[test]
fn test_bounding_box_padding_2d() { fn test_bounding_box_padding_2d() {
use nalgebra::{Point2, Vector2}; let point = Point2::new(1.0, 2.0);
let size = Vector2::new(3.0, 4.0);
let bbox = AxisAlignedBoundingBox::new_point_size(point, size);
let point = Point2::new(1.0, 2.0); let padded_bbox = bbox.padding(1.0);
let size = Vector2::new(3.0, 4.0); assert_eq!(padded_bbox.min_vertex(), Point2::new(0.5, 1.5));
let bbox = AxisAlignedBoundingBox::new(point, size); assert_eq!(padded_bbox.size(), Vector2::new(4.0, 5.0));
}
let padded_bbox = bbox.padding(1.0); #[test]
assert_eq!(padded_bbox.min_vertex(), Point2::new(0.5, 1.5)); fn test_bounding_box_scaling_2d() {
assert_eq!(padded_bbox.size(), Vector2::new(4.0, 5.0)); let point = Point2::new(1.0, 1.0);
} let size = Vector2::new(3.0, 4.0);
let bbox = AxisAlignedBoundingBox::new_point_size(point, size);
#[test] let padded_bbox = bbox.scale(Vector2::new(2.0, 2.0));
fn test_bounding_box_scaling_2d() { assert_eq!(padded_bbox.min_vertex(), Point2::new(-2.0, -3.0));
use nalgebra::{Point2, Vector2}; assert_eq!(padded_bbox.size(), Vector2::new(6.0, 8.0));
}
let point = Point2::new(1.0, 1.0); #[test]
let size = Vector2::new(3.0, 4.0); fn test_bounding_box_contains_2d() {
let bbox = AxisAlignedBoundingBox::new(point, size); let point1 = Point2::new(1.0, 2.0);
let point2 = Point2::new(4.0, 6.0);
let bbox = AxisAlignedBoundingBox::new(point1, point2);
let padded_bbox = bbox.scale(Vector2::new(2.0, 2.0)); assert!(bbox.contains_point(&Point2::new(2.0, 3.0)));
assert_eq!(padded_bbox.min_vertex(), Point2::new(-2.0, -3.0)); assert!(!bbox.contains_point(&Point2::new(5.0, 7.0)));
assert_eq!(padded_bbox.size(), Vector2::new(6.0, 8.0)); }
}
#[test] #[test]
fn test_bounding_box_contains_2d() { fn test_bounding_box_union_2d() {
use nalgebra::Point2; let point1 = Point2::new(1.0, 2.0);
let point2 = Point2::new(4.0, 6.0);
let bbox1 = AxisAlignedBoundingBox::new(point1, point2);
let point1 = Point2::new(1.0, 2.0); let point3 = Point2::new(3.0, 5.0);
let point2 = Point2::new(4.0, 6.0); let point4 = Point2::new(7.0, 8.0);
let bbox = AxisAlignedBoundingBox::new(point1, point2); let bbox2 = AxisAlignedBoundingBox::new(point3, point4);
assert!(bbox.contains_point(&Point2::new(2.0, 3.0))); let union_bbox = bbox1.merge(&bbox2);
assert!(!bbox.contains_point(&Point2::new(5.0, 7.0))); assert_eq!(union_bbox.min_vertex(), Point2::new(1.0, 2.0));
} assert_eq!(union_bbox.size(), Vector2::new(6.0, 6.0));
}
#[test] #[test]
fn test_bounding_box_union_2d() { fn test_bounding_box_intersection_2d() {
use nalgebra::{Point2, Vector2}; let point1 = Point2::new(1.0, 2.0);
let point2 = Point2::new(4.0, 6.0);
let bbox1 = AxisAlignedBoundingBox::new(point1, point2);
let point1 = Point2::new(1.0, 2.0); let point3 = Point2::new(3.0, 5.0);
let point2 = Point2::new(4.0, 6.0); let point4 = Point2::new(5.0, 7.0);
let bbox1 = AxisAlignedBoundingBox::new(point1, point2); let bbox2 = AxisAlignedBoundingBox::new(point3, point4);
let point3 = Point2::new(3.0, 5.0); let intersection_bbox = bbox1.intersection(&bbox2).unwrap();
let point4 = Point2::new(7.0, 8.0); assert_eq!(intersection_bbox.min_vertex(), Point2::new(3.0, 5.0));
let bbox2 = AxisAlignedBoundingBox::new(point3, point4); assert_eq!(intersection_bbox.size(), Vector2::new(1.0, 1.0));
}
let union_bbox = bbox1.merge(&bbox2); #[test]
assert_eq!(union_bbox.min_vertex(), Point2::new(1.0, 2.0)); fn test_bounding_box_contains_point() {
assert_eq!(union_bbox.size(), Vector2::new(6.0, 6.0)); let point1 = Point2::new(2, 3);
} let point2 = Point2::new(5, 4);
let bbox = AxisAlignedBoundingBox::new(point1, point2);
#[test] use itertools::Itertools;
fn test_bounding_box_intersection_2d() { for (i, j) in (0..=10).cartesian_product(0..=10) {
use nalgebra::{Point2, Vector2}; if bbox.contains_point(&Point2::new(i, j)) {
if !(2..=5).contains(&i) && !(3..=4).contains(&j) {
let point1 = Point2::new(1.0, 2.0); panic!(
let point2 = Point2::new(4.0, 6.0); "Point ({}, {}) should not be contained in the bounding box",
let bbox1 = AxisAlignedBoundingBox::new(point1, point2); i, j
);
let point3 = Point2::new(3.0, 5.0); }
let point4 = Point2::new(5.0, 7.0); } else {
let bbox2 = AxisAlignedBoundingBox::new(point3, point4); if (2..=5).contains(&i) && (3..=4).contains(&j) {
panic!(
let intersection_bbox = bbox1.intersection(&bbox2).unwrap(); "Point ({}, {}) should be contained in the bounding box",
assert_eq!(intersection_bbox.min_vertex(), Point2::new(3.0, 5.0)); i, j
assert_eq!(intersection_bbox.size(), Vector2::new(1.0, 1.0)); );
} }
#[test]
fn test_bounding_box_contains_point() {
use nalgebra::Point2;
let point1 = Point2::new(2, 3);
let point2 = Point2::new(5, 4);
let bbox = AxisAlignedBoundingBox::new(point1, point2);
use itertools::Itertools;
for (i, j) in (0..=10).cartesian_product(0..=10) {
if bbox.contains_point(&Point2::new(i, j)) {
if !(2..=5).contains(&i) && !(3..=4).contains(&j) {
panic!(
"Point ({}, {}) should not be contained in the bounding box",
i, j
);
}
} else {
if (2..=5).contains(&i) && (3..=4).contains(&j) {
panic!(
"Point ({}, {}) should be contained in the bounding box",
i, j
);
} }
} }
} }
}
#[test] #[test]
fn test_bounding_box_clamp_box_2d() { fn test_bounding_box_clamp_box_2d() {
let bbox1 = Aabb2::from_x1y1x2y2(1, 1, 4, 4); let bbox1 = Aabb2::from_x1y1x2y2(1, 1, 4, 4);
let bbox2 = Aabb2::from_x1y1x2y2(2, 2, 3, 3); let bbox2 = Aabb2::from_x1y1x2y2(2, 2, 3, 3);
let clamped = bbox2.clamp(&bbox1).unwrap(); let clamped = bbox2.clamp(&bbox1).unwrap();
assert_eq!(bbox2, clamped); assert_eq!(bbox2, clamped);
let clamped = bbox1.clamp(&bbox2).unwrap(); let clamped = bbox1.clamp(&bbox2).unwrap();
assert_eq!(bbox2, clamped); assert_eq!(bbox2, clamped);
let bbox1 = Aabb2::from_x1y1x2y2(4, 5, 7, 8); let bbox1 = Aabb2::from_x1y1x2y2(4, 5, 7, 8);
let bbox2 = Aabb2::from_x1y1x2y2(5, 4, 8, 7); let bbox2 = Aabb2::from_x1y1x2y2(5, 4, 8, 7);
let clamped = bbox1.clamp(&bbox2).unwrap(); let clamped = bbox1.clamp(&bbox2).unwrap();
let expected = Aabb2::from_x1y1x2y2(5, 5, 7, 7); let expected = Aabb2::from_x1y1x2y2(5, 5, 7, 7);
assert_eq!(clamped, expected) assert_eq!(clamped, expected)
}
#[test]
fn test_iou_identical_boxes() {
let a = Aabb2::from_x1y1x2y2(1.0, 2.0, 4.0, 6.0);
let b = Aabb2::from_x1y1x2y2(1.0, 2.0, 4.0, 6.0);
assert_eq!(a.iou(&b), 1.0);
}
#[test]
fn test_iou_non_overlapping_boxes() {
let a = Aabb2::from_x1y1x2y2(0.0, 0.0, 1.0, 1.0);
let b = Aabb2::from_x1y1x2y2(2.0, 2.0, 3.0, 3.0);
assert_eq!(a.iou(&b), 0.0);
}
#[test]
fn test_iou_partial_overlap() {
let a = Aabb2::from_x1y1x2y2(0.0, 0.0, 2.0, 2.0);
let b = Aabb2::from_x1y1x2y2(1.0, 1.0, 3.0, 3.0);
// Intersection area = 1, Union area = 7
assert!((a.iou(&b) - 1.0 / 7.0).abs() < 1e-6);
}
#[test]
fn test_iou_one_inside_another() {
let a = Aabb2::from_x1y1x2y2(0.0, 0.0, 4.0, 4.0);
let b = Aabb2::from_x1y1x2y2(1.0, 1.0, 3.0, 3.0);
// Intersection area = 4, Union area = 16
assert!((a.iou(&b) - 0.25).abs() < 1e-6);
}
#[test]
fn test_iou_edge_touching() {
let a = Aabb2::from_x1y1x2y2(0.0, 0.0, 1.0, 1.0);
let b = Aabb2::from_x1y1x2y2(1.0, 0.0, 2.0, 1.0);
assert_eq!(a.iou(&b), 0.0);
}
#[test]
fn test_iou_corner_touching() {
let a = Aabb2::from_x1y1x2y2(0.0, 0.0, 1.0, 1.0);
let b = Aabb2::from_x1y1x2y2(1.0, 1.0, 2.0, 2.0);
assert_eq!(a.iou(&b), 0.0);
}
#[test]
fn test_iou_zero_area_box() {
let a = Aabb2::from_x1y1x2y2(0.0, 0.0, 0.0, 0.0);
let b = Aabb2::from_x1y1x2y2(0.0, 0.0, 1.0, 1.0);
assert_eq!(a.iou(&b), 0.0);
}
#[test]
fn test_specific_values() {
let res = Vector2::new(1920, 1080).cast();
let box1 = Aabb2::from_xywh(0.69482, 0.6716774, 0.07493961, 0.14968264).denormalize(res);
let box2 =
Aabb2::from_xywh(0.41546485, 0.70290875, 0.06197411, 0.08818436).denormalize(res);
dbg!(box1, box2);
assert!(box1.iou(&box2) > 0.0);
}
} }

View File

@@ -33,11 +33,7 @@ where
.filter(|&i| scores[i] >= score_threshold) .filter(|&i| scores[i] >= score_threshold)
.collect(); .collect();
indices.sort_by(|&i, &j| { indices.sort_by(|&i, &j| scores[j].partial_cmp(&scores[i]).unwrap());
scores[j]
.partial_cmp(&scores[i])
.unwrap_or(std::cmp::Ordering::Equal)
});
let mut selected_indices = HashSet::new(); let mut selected_indices = HashSet::new();
@@ -46,8 +42,12 @@ where
indices.remove(0); indices.remove(0);
indices.retain(|&i| { indices.retain(|&i| {
// let iou = calculate_iou(&boxes[current], &boxes[i]); let iou = calculate_iou(&boxes[current], &boxes[i]);
let iou = boxes[current].iou(&boxes[i]); let iou_ = boxes[current].iou(&boxes[i]);
if iou != iou_ {
dbg!(boxes[current], boxes[i]);
panic!()
};
iou < nms_threshold iou < nms_threshold
}); });
} }
@@ -55,7 +55,7 @@ where
selected_indices selected_indices
} }
/// Calculate the Intersection over Union (IoU) between two bounding boxes. /// Calculate the Intersection over Union (IoU) of two bounding boxes.
/// ///
/// # Arguments /// # Arguments
/// ///
@@ -64,36 +64,36 @@ where
/// ///
/// # Returns /// # Returns
/// ///
/// The IoU value as a floating-point number. /// The IoU as a value between 0 and 1.
fn calculate_iou<T>(box1: &Aabb2<T>, box2: &Aabb2<T>) -> T fn calculate_iou<T>(box1: &Aabb2<T>, box2: &Aabb2<T>) -> T
where where
T: Num + num::Float, T: Num
T: core::ops::MulAssign, + num::Float
T: core::ops::AddAssign, + core::iter::Product<T>
T: core::ops::SubAssign, + core::ops::AddAssign
T: nalgebra::SimdValue, + core::ops::SubAssign
T: nalgebra::SimdPartialOrd, + core::ops::MulAssign
+ nalgebra::SimdValue
+ nalgebra::SimdPartialOrd,
{ {
// let inter_min_x = box1.min_vertex().x.max(box2.min_vertex().x); let x_left = box1.min_vertex().x.max(box2.min_vertex().x);
// let inter_min_y = box1.min_vertex().y.max(box2.min_vertex().y); let y_top = box1.min_vertex().y.max(box2.min_vertex().y);
// let inter_max_x = box1.maxs.x.min(box2.max_vertex().x); let x_right = box1.max_vertex().x.min(box2.max_vertex().x);
// let inter_max_y = box1.maxs.y.min(box2.max_vertex().y); let y_bottom = box1.max_vertex().y.min(box2.max_vertex().y);
let inter_min = box1.min_vertex().inf(&box2.min_vertex());
let inter_max = box1.max_vertex().sup(&box2.max_vertex());
// let inter_width = (inter_max_x - inter_min_x).max(T::zero()); let zero = T::zero();
// let inter_height = (inter_max_y - inter_min_y).max(T::zero()); let inter_width = (x_right - x_left).max(zero);
// let inter_width = (inter_max.x - inter_min.x).max(T::zero()); let inter_height = (y_bottom - y_top).max(zero);
// let inter_height = (inter_max.y - inter_min.y).max(T::zero()); let intersection = inter_width * inter_height;
// let inter_area = inter_width * inter_height;
let inter_area = Aabb2::new(inter_min, inter_max); let area1 = box1.area();
let inter_area_2 = box1.intersection(box2); let area2 = box2.area();
let union = box1.area() + box2.area() - inter_area.area();
assert_eq!(Some(inter_area), inter_area_2);
assert_eq!(box1.union(&box2), union);
let inter_area = inter_area.area(); let union = area1 + area2 - intersection;
inter_area / (box1.area() + box2.area() - inter_area) if union > zero {
intersection / union
} else {
zero
}
} }

View File

@@ -77,6 +77,7 @@ impl Default for FaceDetectionConfig {
} }
} }
#[derive(Debug)]
pub struct FaceDetection { pub struct FaceDetection {
handle: mnn_sync::SessionHandle, handle: mnn_sync::SessionHandle,
} }

1
src/faceembed.rs Normal file
View File

@@ -0,0 +1 @@
pub mod facenet;

39
src/faceembed/facenet.rs Normal file
View File

@@ -0,0 +1,39 @@
use crate::errors::*;
use ndarray::{Array1, ArrayView3};
use std::path::Path;
#[derive(Debug)]
pub struct EmbeddingGenerator {
handle: mnn_sync::SessionHandle,
}
impl EmbeddingGenerator {
pub fn new(path: impl AsRef<Path>) -> Result<Self> {
let model = std::fs::read(path)
.change_context(Error)
.attach_printable("Failed to read model file")?;
Self::new_from_bytes(&model)
}
pub fn new_from_bytes(model: &[u8]) -> Result<Self> {
tracing::info!("Loading face embedding model from bytes");
let mut model = mnn::Interpreter::from_bytes(model)
.map_err(|e| e.into_inner())
.change_context(Error)
.attach_printable("Failed to load model from bytes")?;
model.set_session_mode(mnn::SessionMode::Release);
let bc = mnn::BackendConfig::default().with_memory_mode(mnn::MemoryMode::High);
let sc = mnn::ScheduleConfig::new()
.with_type(mnn::ForwardType::CPU)
.with_backend_config(bc);
tracing::info!("Creating session handle for face embedding model");
let handle = mnn_sync::SessionHandle::new(model, sc)
.change_context(Error)
.attach_printable("Failed to create session handle")?;
Ok(Self { handle })
}
pub fn embedding(&self, roi: ArrayView3<u8>) -> Result<Array1<u8>> {
todo!()
}
}

View File

@@ -1,4 +1,5 @@
pub mod errors; pub mod errors;
pub mod facedet; pub mod facedet;
pub mod faceembed;
pub mod image; pub mod image;
use errors::*; use errors::*;