feat(gui): add face ROIs to comparison results and update image size

This commit is contained in:
uttarayan21
2025-08-22 18:26:29 +05:30
parent 34eaf9348a
commit c758fd8d41
2 changed files with 79 additions and 45 deletions

View File

@@ -76,6 +76,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,
}, },
@@ -765,6 +767,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,
} => { } => {

View File

@@ -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,
))
} }
} }
@@ -308,7 +338,7 @@ where
.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 +352,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())