use crate::errors::*; use crate::facedet::*; use error_stack::ResultExt; use mnn_bridge::ndarray::*; use ndarray_resize::NdFir; use std::path::Path; #[derive(Debug)] pub struct FaceDetection { handle: mnn_sync::SessionHandle, } pub struct FaceDetectionBuilder { schedule_config: Option, backend_config: Option, model: mnn::Interpreter, } impl FaceDetectionBuilder { pub fn new(model: impl AsRef<[u8]>) -> Result { Ok(Self { schedule_config: None, backend_config: None, model: mnn::Interpreter::from_bytes(model.as_ref()) .map_err(|e| e.into_inner()) .change_context(Error) .attach_printable("Failed to load model from bytes")?, }) } pub fn with_forward_type(mut self, forward_type: mnn::ForwardType) -> Self { self.schedule_config .get_or_insert_default() .set_type(forward_type); self } pub fn with_schedule_config(mut self, config: mnn::ScheduleConfig) -> Self { self.schedule_config = Some(config); self } pub fn with_backend_config(mut self, config: mnn::BackendConfig) -> Self { self.backend_config = Some(config); self } pub fn build(self) -> Result { let model = self.model; let sc = self.schedule_config.unwrap_or_default(); let handle = mnn_sync::SessionHandle::new(model, sc) .change_context(Error) .attach_printable("Failed to create session handle")?; Ok(FaceDetection { handle }) } } impl FaceDetection { pub fn builder>( model: T, ) -> std::result::Result> { FaceDetectionBuilder::new(model) } } impl FaceDetector for FaceDetection { fn run_model(&mut self, image: ndarray::ArrayView3) -> Result { #[rustfmt::skip] let mut resized = image .fast_resize(1024, 1024, None) .change_context(Error)? .mapv(|f| f as f32); // Apply mean subtraction: [104, 117, 123] resized .axis_iter_mut(ndarray::Axis(2)) .zip([104, 117, 123]) .for_each(|(mut array, pixel)| { let pixel = pixel as f32; array.map_inplace(|v| *v -= pixel); }); let mut resized = resized .permuted_axes((2, 0, 1)) .insert_axis(ndarray::Axis(0)) .as_standard_layout() .into_owned(); use ::tap::*; let output = self .handle .run(move |sr| { let tensor = resized .as_mnn_tensor_mut() .attach_printable("Failed to convert ndarray to mnn tensor") .change_context(mnn::error::ErrorKind::TensorError)?; tracing::trace!("Image Tensor shape: {:?}", tensor.shape()); let (intptr, session) = sr.both_mut(); tracing::trace!("Copying input tensor to host"); unsafe { let mut input = intptr.input_unresized::(session, "input")?; tracing::trace!("Input shape: {:?}", input.shape()); intptr.resize_tensor_by_nchw::, _>( input.view_mut(), 1, 3, 1024, 1024, ); } intptr.resize_session(session); let mut input = intptr.input::(session, "input")?; tracing::trace!("Input shape: {:?}", input.shape()); input.copy_from_host_tensor(tensor.view())?; tracing::info!("Running face detection session"); intptr.run_session(&session)?; let output_tensor = intptr .output::(&session, "bbox")? .create_host_tensor_from_device(true) .as_ndarray() .to_owned(); tracing::trace!("Output Bbox: \t\t{:?}", output_tensor.shape()); let output_confidence = intptr .output::(&session, "confidence")? .create_host_tensor_from_device(true) .as_ndarray::() .to_owned(); tracing::trace!("Output Confidence: \t{:?}", output_confidence.shape()); let output_landmark = intptr .output::(&session, "landmark")? .create_host_tensor_from_device(true) .as_ndarray::() .to_owned(); tracing::trace!("Output Landmark: \t{:?}", output_landmark.shape()); Ok(FaceDetectionModelOutput { bbox: output_tensor, confidence: output_confidence, landmark: output_landmark, }) }) .map_err(|e| e.into_inner()) .change_context(Error)?; Ok(output) } }