Compare commits
2 Commits
34eaf9348a
...
3eec262076
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3eec262076 | ||
|
|
c758fd8d41 |
@@ -163,6 +163,21 @@ impl<T: Num, const D: usize> AxisAlignedBoundingBox<T, D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale_uniform(self, scalar: T) -> Self
|
||||||
|
where
|
||||||
|
T: core::ops::MulAssign,
|
||||||
|
T: core::ops::DivAssign,
|
||||||
|
T: core::ops::SubAssign,
|
||||||
|
{
|
||||||
|
let two = T::one() + T::one();
|
||||||
|
let new_size = self.size * scalar;
|
||||||
|
let new_point = self.point.coords - (new_size - self.size) / two;
|
||||||
|
Self {
|
||||||
|
point: Point::from(new_point),
|
||||||
|
size: new_size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn contains_bbox(&self, other: &Self) -> bool
|
pub fn contains_bbox(&self, other: &Self) -> bool
|
||||||
where
|
where
|
||||||
T: core::ops::AddAssign,
|
T: core::ops::AddAssign,
|
||||||
@@ -270,15 +285,17 @@ impl<T: Num, const D: usize> AxisAlignedBoundingBox<T, D> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn as_<T2>(&self) -> Option<Aabb<T2, D>>
|
pub fn as_<T2>(&self) -> Aabb<T2, D>
|
||||||
// where
|
where
|
||||||
// T2: Num + simba::scalar::SubsetOf<T>,
|
T2: Num,
|
||||||
// {
|
T: num::cast::AsPrimitive<T2>,
|
||||||
// Some(Aabb {
|
{
|
||||||
// point: Point::from(self.point.coords.as_()),
|
Aabb {
|
||||||
// size: self.size.as_(),
|
point: Point::from(self.point.coords.map(|x| x.as_())),
|
||||||
// })
|
size: self.size.map(|x| x.as_()),
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn measure(&self) -> T
|
pub fn measure(&self) -> T
|
||||||
where
|
where
|
||||||
T: core::ops::MulAssign,
|
T: core::ops::MulAssign,
|
||||||
|
|||||||
153
src/gui/app.rs
153
src/gui/app.rs
@@ -10,6 +10,7 @@ use std::path::PathBuf;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::gui::bridge::FaceDetectionBridge;
|
use crate::gui::bridge::FaceDetectionBridge;
|
||||||
|
use ::image::{DynamicImage, ImageFormat, RgbImage};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
@@ -43,6 +44,7 @@ pub enum Message {
|
|||||||
ImageLoaded(Option<Arc<Vec<u8>>>),
|
ImageLoaded(Option<Arc<Vec<u8>>>),
|
||||||
SecondImageLoaded(Option<Arc<Vec<u8>>>),
|
SecondImageLoaded(Option<Arc<Vec<u8>>>),
|
||||||
ProcessedImageUpdated(Option<Vec<u8>>),
|
ProcessedImageUpdated(Option<Vec<u8>>),
|
||||||
|
FaceRoisLoaded(Vec<image::Handle>, Vec<image::Handle>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@@ -76,6 +78,8 @@ pub enum ComparisonResult {
|
|||||||
Success {
|
Success {
|
||||||
image1_faces: usize,
|
image1_faces: usize,
|
||||||
image2_faces: usize,
|
image2_faces: usize,
|
||||||
|
image1_face_rois: Vec<ndarray::Array3<u8>>,
|
||||||
|
image2_face_rois: Vec<ndarray::Array3<u8>>,
|
||||||
best_similarity: f32,
|
best_similarity: f32,
|
||||||
processing_time: f64,
|
processing_time: f64,
|
||||||
},
|
},
|
||||||
@@ -110,6 +114,10 @@ pub struct FaceDetectorApp {
|
|||||||
current_image_handle: Option<image::Handle>,
|
current_image_handle: Option<image::Handle>,
|
||||||
processed_image_handle: Option<image::Handle>,
|
processed_image_handle: Option<image::Handle>,
|
||||||
second_image_handle: Option<image::Handle>,
|
second_image_handle: Option<image::Handle>,
|
||||||
|
|
||||||
|
// Face ROI handles for comparison display
|
||||||
|
image1_face_roi_handles: Vec<image::Handle>,
|
||||||
|
image2_face_roi_handles: Vec<image::Handle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FaceDetectorApp {
|
impl Default for FaceDetectorApp {
|
||||||
@@ -130,6 +138,8 @@ impl Default for FaceDetectorApp {
|
|||||||
current_image_handle: None,
|
current_image_handle: None,
|
||||||
processed_image_handle: None,
|
processed_image_handle: None,
|
||||||
second_image_handle: None,
|
second_image_handle: None,
|
||||||
|
image1_face_roi_handles: Vec::new(),
|
||||||
|
image2_face_roi_handles: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,6 +323,8 @@ impl FaceDetectorApp {
|
|||||||
self.detection_result = None;
|
self.detection_result = None;
|
||||||
self.comparison_result = None;
|
self.comparison_result = None;
|
||||||
self.processed_image_handle = None;
|
self.processed_image_handle = None;
|
||||||
|
self.image1_face_roi_handles.clear();
|
||||||
|
self.image2_face_roi_handles.clear();
|
||||||
self.status_message = "Results cleared".to_string();
|
self.status_message = "Results cleared".to_string();
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
@@ -356,6 +368,8 @@ impl FaceDetectorApp {
|
|||||||
ComparisonResult::Success {
|
ComparisonResult::Success {
|
||||||
best_similarity,
|
best_similarity,
|
||||||
processing_time,
|
processing_time,
|
||||||
|
image1_face_rois,
|
||||||
|
image2_face_rois,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let interpretation = if *best_similarity > 0.8 {
|
let interpretation = if *best_similarity > 0.8 {
|
||||||
@@ -372,6 +386,16 @@ impl FaceDetectorApp {
|
|||||||
"Comparison complete! Similarity: {:.3} - {} (Processing time: {:.2}s)",
|
"Comparison complete! Similarity: {:.3} - {} (Processing time: {:.2}s)",
|
||||||
best_similarity, interpretation, processing_time
|
best_similarity, interpretation, processing_time
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Convert face ROIs to image handles
|
||||||
|
let image1_handles = convert_face_rois_to_handles(image1_face_rois.clone());
|
||||||
|
let image2_handles = convert_face_rois_to_handles(image2_face_rois.clone());
|
||||||
|
|
||||||
|
self.comparison_result = Some(result);
|
||||||
|
return Task::perform(
|
||||||
|
async move { (image1_handles, image2_handles) },
|
||||||
|
|(h1, h2)| Message::FaceRoisLoaded(h1, h2),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ComparisonResult::Error(error) => {
|
ComparisonResult::Error(error) => {
|
||||||
self.status_message = format!("Comparison failed: {}", error);
|
self.status_message = format!("Comparison failed: {}", error);
|
||||||
@@ -382,6 +406,12 @@ impl FaceDetectorApp {
|
|||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::FaceRoisLoaded(image1_handles, image2_handles) => {
|
||||||
|
self.image1_face_roi_handles = image1_handles;
|
||||||
|
self.image2_face_roi_handles = image2_handles;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
Message::ProgressUpdate(progress) => {
|
Message::ProgressUpdate(progress) => {
|
||||||
self.progress = progress;
|
self.progress = progress;
|
||||||
Task::none()
|
Task::none()
|
||||||
@@ -765,6 +795,8 @@ impl FaceDetectorApp {
|
|||||||
ComparisonResult::Success {
|
ComparisonResult::Success {
|
||||||
image1_faces,
|
image1_faces,
|
||||||
image2_faces,
|
image2_faces,
|
||||||
|
image1_face_rois: _,
|
||||||
|
image2_face_rois: _,
|
||||||
best_similarity,
|
best_similarity,
|
||||||
processing_time,
|
processing_time,
|
||||||
} => {
|
} => {
|
||||||
@@ -790,7 +822,7 @@ impl FaceDetectorApp {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
column![
|
let mut result_column = column![
|
||||||
text("Comparison Results").size(18),
|
text("Comparison Results").size(18),
|
||||||
text(format!("First image faces: {}", image1_faces)),
|
text(format!("First image faces: {}", image1_faces)),
|
||||||
text(format!("Second image faces: {}", image2_faces)),
|
text(format!("Second image faces: {}", image2_faces)),
|
||||||
@@ -800,7 +832,89 @@ impl FaceDetectorApp {
|
|||||||
}),
|
}),
|
||||||
text(format!("Processing time: {:.2}s", processing_time)),
|
text(format!("Processing time: {:.2}s", processing_time)),
|
||||||
]
|
]
|
||||||
.spacing(5)
|
.spacing(5);
|
||||||
|
|
||||||
|
// Add face ROI displays if available
|
||||||
|
if !self.image1_face_roi_handles.is_empty()
|
||||||
|
|| !self.image2_face_roi_handles.is_empty()
|
||||||
|
{
|
||||||
|
result_column = result_column.push(text("Detected Faces").size(16));
|
||||||
|
|
||||||
|
// Create face ROI rows
|
||||||
|
let image1_faces_row = if !self.image1_face_roi_handles.is_empty() {
|
||||||
|
let faces: Element<'_, Message> = self
|
||||||
|
.image1_face_roi_handles
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.fold(row![].spacing(5), |row, (i, handle)| {
|
||||||
|
row.push(
|
||||||
|
column![
|
||||||
|
text(format!("Face {}", i + 1)).size(12),
|
||||||
|
container(
|
||||||
|
image(handle.clone())
|
||||||
|
.width(80)
|
||||||
|
.height(80)
|
||||||
|
.content_fit(iced::ContentFit::Cover)
|
||||||
|
)
|
||||||
|
.style(container::bordered_box)
|
||||||
|
.padding(2),
|
||||||
|
]
|
||||||
|
.spacing(2)
|
||||||
|
.align_x(Alignment::Center),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
|
||||||
|
column![
|
||||||
|
text("First Image Faces:").size(14),
|
||||||
|
scrollable(faces).direction(scrollable::Direction::Horizontal(
|
||||||
|
scrollable::Scrollbar::new()
|
||||||
|
)),
|
||||||
|
]
|
||||||
|
.spacing(5)
|
||||||
|
} else {
|
||||||
|
column![text("First Image Faces: None detected").size(14)]
|
||||||
|
};
|
||||||
|
|
||||||
|
let image2_faces_row = if !self.image2_face_roi_handles.is_empty() {
|
||||||
|
let faces: Element<'_, Message> = self
|
||||||
|
.image2_face_roi_handles
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.fold(row![].spacing(5), |row, (i, handle)| {
|
||||||
|
row.push(
|
||||||
|
column![
|
||||||
|
text(format!("Face {}", i + 1)).size(12),
|
||||||
|
container(
|
||||||
|
image(handle.clone())
|
||||||
|
.width(80)
|
||||||
|
.height(80)
|
||||||
|
.content_fit(iced::ContentFit::Cover)
|
||||||
|
)
|
||||||
|
.style(container::bordered_box)
|
||||||
|
.padding(2),
|
||||||
|
]
|
||||||
|
.spacing(2)
|
||||||
|
.align_x(Alignment::Center),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
|
||||||
|
column![
|
||||||
|
text("Second Image Faces:").size(14),
|
||||||
|
scrollable(faces).direction(scrollable::Direction::Horizontal(
|
||||||
|
scrollable::Scrollbar::new()
|
||||||
|
)),
|
||||||
|
]
|
||||||
|
.spacing(5)
|
||||||
|
} else {
|
||||||
|
column![text("Second Image Faces: None detected").size(14)]
|
||||||
|
};
|
||||||
|
|
||||||
|
result_column = result_column.push(image1_faces_row).push(image2_faces_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
result_column
|
||||||
}
|
}
|
||||||
ComparisonResult::Error(error) => column![
|
ComparisonResult::Error(error) => column![
|
||||||
text("Comparison Results").size(18),
|
text("Comparison Results").size(18),
|
||||||
@@ -816,10 +930,12 @@ impl FaceDetectorApp {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
column![file_section, comparison_image_section, controls, results]
|
scrollable(
|
||||||
.spacing(20)
|
column![file_section, comparison_image_section, controls, results]
|
||||||
.padding(20)
|
.spacing(20)
|
||||||
.into()
|
.padding(20),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn settings_view(&self) -> Element<'_, Message> {
|
fn settings_view(&self) -> Element<'_, Message> {
|
||||||
@@ -881,6 +997,31 @@ impl std::fmt::Display for ExecutorType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to convert face ROIs to image handles
|
||||||
|
fn convert_face_rois_to_handles(face_rois: Vec<ndarray::Array3<u8>>) -> Vec<image::Handle> {
|
||||||
|
face_rois
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|roi| {
|
||||||
|
// Convert ndarray to image::RgbImage
|
||||||
|
let (height, width, _) = roi.dim();
|
||||||
|
let (raw_data, _offset) = roi.into_raw_vec_and_offset();
|
||||||
|
|
||||||
|
if let Some(img) = RgbImage::from_raw(width as u32, height as u32, raw_data) {
|
||||||
|
// Convert to PNG bytes
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
let mut cursor = std::io::Cursor::new(&mut buffer);
|
||||||
|
if DynamicImage::ImageRgb8(img)
|
||||||
|
.write_to(&mut cursor, ImageFormat::Png)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
return Some(image::Handle::from_bytes(buffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run() -> iced::Result {
|
pub fn run() -> iced::Result {
|
||||||
iced::application(
|
iced::application(
|
||||||
"Face Detector",
|
"Face Detector",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::facedet::{FaceDetectionConfig, FaceDetector, retinaface};
|
use crate::facedet::{FaceDetectionConfig, FaceDetector, retinaface};
|
||||||
use crate::faceembed::{FaceNetEmbedder, facenet};
|
use crate::faceembed::facenet;
|
||||||
use crate::gui::app::{ComparisonResult, DetectionResult, ExecutorType};
|
use crate::gui::app::{ComparisonResult, DetectionResult, ExecutorType};
|
||||||
use bounding_box::Aabb2;
|
use bounding_box::Aabb2;
|
||||||
use bounding_box::roi::MultiRoi as _;
|
use bounding_box::roi::MultiRoi as _;
|
||||||
@@ -70,11 +70,19 @@ impl FaceDetectionBridge {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok((image1_faces, image2_faces, best_similarity)) => {
|
Ok((
|
||||||
|
image1_faces,
|
||||||
|
image2_faces,
|
||||||
|
image1_face_rois,
|
||||||
|
image2_face_rois,
|
||||||
|
best_similarity,
|
||||||
|
)) => {
|
||||||
let processing_time = start_time.elapsed().as_secs_f64();
|
let processing_time = start_time.elapsed().as_secs_f64();
|
||||||
ComparisonResult::Success {
|
ComparisonResult::Success {
|
||||||
image1_faces,
|
image1_faces,
|
||||||
image2_faces,
|
image2_faces,
|
||||||
|
image1_face_rois,
|
||||||
|
image2_face_rois,
|
||||||
best_similarity,
|
best_similarity,
|
||||||
processing_time,
|
processing_time,
|
||||||
}
|
}
|
||||||
@@ -180,53 +188,75 @@ impl FaceDetectionBridge {
|
|||||||
threshold: f32,
|
threshold: f32,
|
||||||
nms_threshold: f32,
|
nms_threshold: f32,
|
||||||
executor_type: ExecutorType,
|
executor_type: ExecutorType,
|
||||||
) -> Result<(usize, usize, f32), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<
|
||||||
|
(usize, usize, Vec<Array3<u8>>, Vec<Array3<u8>>, f32),
|
||||||
|
Box<dyn std::error::Error + Send + Sync>,
|
||||||
|
> {
|
||||||
// Create detector and embedder, detect faces and generate embeddings
|
// Create detector and embedder, detect faces and generate embeddings
|
||||||
let (faces1, faces2, best_similarity) = match executor_type {
|
let (image1_faces, image2_faces, image1_rois, image2_rois, best_similarity) =
|
||||||
ExecutorType::MnnCpu | ExecutorType::MnnMetal | ExecutorType::MnnCoreML => {
|
match executor_type {
|
||||||
let forward_type = match executor_type {
|
ExecutorType::MnnCpu | ExecutorType::MnnMetal | ExecutorType::MnnCoreML => {
|
||||||
ExecutorType::MnnCpu => mnn::ForwardType::CPU,
|
let forward_type = match executor_type {
|
||||||
ExecutorType::MnnMetal => mnn::ForwardType::Metal,
|
ExecutorType::MnnCpu => mnn::ForwardType::CPU,
|
||||||
ExecutorType::MnnCoreML => mnn::ForwardType::CoreML,
|
ExecutorType::MnnMetal => mnn::ForwardType::Metal,
|
||||||
_ => unreachable!(),
|
ExecutorType::MnnCoreML => mnn::ForwardType::CoreML,
|
||||||
};
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
let mut detector = retinaface::mnn::FaceDetection::builder(RETINAFACE_MODEL_MNN)
|
let mut detector =
|
||||||
.map_err(|e| format!("Failed to create MNN detector: {}", e))?
|
retinaface::mnn::FaceDetection::builder(RETINAFACE_MODEL_MNN)
|
||||||
.with_forward_type(forward_type.clone())
|
.map_err(|e| format!("Failed to create MNN detector: {}", e))?
|
||||||
.build()
|
.with_forward_type(forward_type.clone())
|
||||||
.map_err(|e| format!("Failed to build MNN detector: {}", e))?;
|
.build()
|
||||||
|
.map_err(|e| format!("Failed to build MNN detector: {}", e))?;
|
||||||
|
|
||||||
let mut embedder = facenet::mnn::EmbeddingGenerator::builder(FACENET_MODEL_MNN)
|
let mut embedder = facenet::mnn::EmbeddingGenerator::builder(FACENET_MODEL_MNN)
|
||||||
.map_err(|e| format!("Failed to create MNN embedder: {}", e))?
|
.map_err(|e| format!("Failed to create MNN embedder: {}", e))?
|
||||||
.with_forward_type(forward_type)
|
.with_forward_type(forward_type)
|
||||||
.build()
|
.build()
|
||||||
.map_err(|e| format!("Failed to build MNN embedder: {}", e))?;
|
.map_err(|e| format!("Failed to build MNN embedder: {}", e))?;
|
||||||
|
|
||||||
let img_1 = run_detection(
|
let img_1 = run_detection(
|
||||||
image1_path,
|
image1_path,
|
||||||
&mut detector,
|
&mut detector,
|
||||||
&mut embedder,
|
&mut embedder,
|
||||||
threshold,
|
threshold,
|
||||||
nms_threshold,
|
nms_threshold,
|
||||||
2,
|
2,
|
||||||
)?;
|
)?;
|
||||||
let img_2 = run_detection(
|
let img_2 = run_detection(
|
||||||
image2_path,
|
image2_path,
|
||||||
&mut detector,
|
&mut detector,
|
||||||
&mut embedder,
|
&mut embedder,
|
||||||
threshold,
|
threshold,
|
||||||
nms_threshold,
|
nms_threshold,
|
||||||
2,
|
2,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let best_similarity = compare_faces(&img_1.embeddings, &img_2.embeddings)?;
|
let image1_rois = img_1.rois;
|
||||||
(img_1, img_2, best_similarity)
|
let image2_rois = img_2.rois;
|
||||||
}
|
let image1_bbox_len = img_1.bbox.len();
|
||||||
ExecutorType::OnnxCpu => unimplemented!(),
|
let image2_bbox_len = img_2.bbox.len();
|
||||||
};
|
let best_similarity = compare_faces(&img_1.embeddings, &img_2.embeddings)?;
|
||||||
|
|
||||||
Ok((faces1.bbox.len(), faces2.bbox.len(), best_similarity))
|
(
|
||||||
|
image1_bbox_len,
|
||||||
|
image2_bbox_len,
|
||||||
|
image1_rois,
|
||||||
|
image2_rois,
|
||||||
|
best_similarity,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ExecutorType::OnnxCpu => unimplemented!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
image1_faces,
|
||||||
|
image2_faces,
|
||||||
|
image1_rois,
|
||||||
|
image2_rois,
|
||||||
|
best_similarity,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,19 +326,27 @@ where
|
|||||||
.change_context(errors::Error)
|
.change_context(errors::Error)
|
||||||
.attach_printable("Failed to detect faces")?;
|
.attach_printable("Failed to detect faces")?;
|
||||||
|
|
||||||
for bbox in &output.bbox {
|
let bboxes = output
|
||||||
|
.bbox
|
||||||
|
.iter()
|
||||||
|
.inspect(|bbox| tracing::info!("Raw bbox: {:?}", bbox))
|
||||||
|
.map(|bbox| bbox.as_::<f32>().scale_uniform(1.30).as_::<usize>())
|
||||||
|
.inspect(|bbox| tracing::info!("Padded bbox: {:?}", bbox))
|
||||||
|
.collect_vec();
|
||||||
|
for bbox in &bboxes {
|
||||||
tracing::info!("Detected face: {:?}", bbox);
|
tracing::info!("Detected face: {:?}", bbox);
|
||||||
use bounding_box::draw::*;
|
use bounding_box::draw::*;
|
||||||
array.draw(bbox, color::palette::css::GREEN_YELLOW.to_rgba8(), 1);
|
array.draw(bbox, color::palette::css::GREEN_YELLOW.to_rgba8(), 1);
|
||||||
}
|
}
|
||||||
|
use itertools::Itertools;
|
||||||
let face_rois = array
|
let face_rois = array
|
||||||
.view()
|
.view()
|
||||||
.multi_roi(&output.bbox)
|
.multi_roi(&bboxes)
|
||||||
.change_context(Error)?
|
.change_context(Error)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|roi| {
|
.map(|roi| {
|
||||||
roi.as_standard_layout()
|
roi.as_standard_layout()
|
||||||
.fast_resize(320, 320, &ResizeOptions::default())
|
.fast_resize(224, 224, &ResizeOptions::default())
|
||||||
.change_context(Error)
|
.change_context(Error)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
@@ -322,7 +360,7 @@ where
|
|||||||
let og_size = chunk.len();
|
let og_size = chunk.len();
|
||||||
if chunk.len() < chunk_size {
|
if chunk.len() < chunk_size {
|
||||||
tracing::warn!("Chunk size is less than 8, padding with zeros");
|
tracing::warn!("Chunk size is less than 8, padding with zeros");
|
||||||
let zeros = Array3::zeros((320, 320, 3));
|
let zeros = Array3::zeros((224, 224, 3));
|
||||||
let chunk: Vec<_> = chunk
|
let chunk: Vec<_> = chunk
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arr| arr.reborrow())
|
.map(|arr| arr.reborrow())
|
||||||
@@ -358,7 +396,7 @@ where
|
|||||||
.collect::<Vec<Array1<f32>>>();
|
.collect::<Vec<Array1<f32>>>();
|
||||||
|
|
||||||
Ok(DetectionOutput {
|
Ok(DetectionOutput {
|
||||||
bbox: output.bbox,
|
bbox: bboxes,
|
||||||
rois: face_rois,
|
rois: face_rois,
|
||||||
embeddings,
|
embeddings,
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user