use crate::core::OCRError;
use crate::models::classification::PPLCNetPreprocessConfig;
use crate::models::detection::db::DBPreprocessConfig;
use crate::processors::{ImageScaleInfo, LimitType, NormalizeImage};
use image::{DynamicImage, RgbImage};
pub fn pp_lcnet_preprocess(input_shape: (u32, u32)) -> PPLCNetPreprocessConfig {
PPLCNetPreprocessConfig {
input_shape,
..Default::default()
}
}
pub fn pp_lcnet_preprocess_with_norm(
input_shape: (u32, u32),
mean: [f32; 3],
std: [f32; 3],
) -> PPLCNetPreprocessConfig {
let mut config = pp_lcnet_preprocess(input_shape);
config.normalize_mean = mean.to_vec();
config.normalize_std = std.to_vec();
config
}
pub fn db_preprocess_with_limit_side_len(limit_side_len: u32) -> DBPreprocessConfig {
DBPreprocessConfig {
limit_side_len: Some(limit_side_len),
..Default::default()
}
}
pub fn db_preprocess_with_resize_long(resize_long: u32) -> DBPreprocessConfig {
DBPreprocessConfig {
resize_long: Some(resize_long),
..Default::default()
}
}
pub fn db_preprocess_for_text_type(text_type: Option<&str>) -> DBPreprocessConfig {
match text_type {
Some("seal") => DBPreprocessConfig {
limit_side_len: Some(736),
limit_type: Some(LimitType::Min),
max_side_limit: Some(4000),
..Default::default()
},
_ => {
DBPreprocessConfig {
limit_side_len: Some(960),
limit_type: Some(LimitType::Max),
max_side_limit: Some(4000),
..Default::default()
}
}
}
}
#[inline]
pub fn rgb_to_dynamic(images: Vec<RgbImage>) -> Vec<DynamicImage> {
images.into_iter().map(DynamicImage::ImageRgb8).collect()
}
pub fn resize_and_normalize<R>(
images: Vec<RgbImage>,
resizer: &R,
normalizer: &NormalizeImage,
) -> Result<ndarray::Array4<f32>, OCRError>
where
R: ResizeOperation,
{
let resized_images = resizer.resize(images)?;
let dynamic_images = rgb_to_dynamic(resized_images);
normalizer.normalize_batch_to(dynamic_images)
}
pub fn detection_resize_and_normalize<R>(
images: Vec<RgbImage>,
resizer: &R,
normalizer: &NormalizeImage,
) -> Result<(ndarray::Array4<f32>, Vec<ImageScaleInfo>), OCRError>
where
R: DetectionResizeOperation,
{
let dynamic_images = rgb_to_dynamic(images);
let (resized_images, scale_info) = resizer.resize_with_scale(dynamic_images)?;
let tensor = normalizer.normalize_batch_to(resized_images)?;
Ok((tensor, scale_info))
}
pub trait ResizeOperation {
fn resize(&self, images: Vec<RgbImage>) -> Result<Vec<RgbImage>, OCRError>;
}
pub trait DetectionResizeOperation {
fn resize_with_scale(
&self,
images: Vec<DynamicImage>,
) -> Result<(Vec<DynamicImage>, Vec<ImageScaleInfo>), OCRError>;
}
pub struct PreprocessPipelineBuilder {
images: Option<Vec<RgbImage>>,
dynamic_images: Option<Vec<DynamicImage>>,
}
impl PreprocessPipelineBuilder {
pub fn new() -> Self {
Self {
images: None,
dynamic_images: None,
}
}
pub fn rgb_images(mut self, images: Vec<RgbImage>) -> Self {
self.images = Some(images);
self
}
pub fn dynamic_images(mut self, images: Vec<DynamicImage>) -> Self {
self.dynamic_images = Some(images);
self
}
pub fn to_dynamic(mut self) -> Self {
if let Some(images) = self.images.take() {
self.dynamic_images = Some(rgb_to_dynamic(images));
}
self
}
pub fn resize<R>(mut self, resizer: &R) -> Result<Self, OCRError>
where
R: ResizeOperation,
{
if let Some(images) = self.images.take() {
let resized = resizer.resize(images)?;
self.images = Some(resized);
}
Ok(self)
}
pub fn normalize(self, normalizer: &NormalizeImage) -> Result<ndarray::Array4<f32>, OCRError> {
let dynamic_images = if let Some(images) = self.images {
rgb_to_dynamic(images)
} else if let Some(images) = self.dynamic_images {
images
} else {
return Err(OCRError::InvalidInput {
message: "No images provided to preprocessing pipeline".to_string(),
});
};
normalizer.normalize_batch_to(dynamic_images)
}
pub fn build(self, normalizer: &NormalizeImage) -> Result<ndarray::Array4<f32>, OCRError> {
self.normalize(normalizer)
}
}
impl Default for PreprocessPipelineBuilder {
fn default() -> Self {
Self::new()
}
}
use crate::processors::{DetResizeForTest, OCRResize};
impl ResizeOperation for OCRResize {
fn resize(&self, images: Vec<RgbImage>) -> Result<Vec<RgbImage>, OCRError> {
self.apply(&images)
}
}
pub struct DetectionResizer<'a> {
resizer: &'a DetResizeForTest,
}
impl<'a> DetectionResizer<'a> {
pub fn new(resizer: &'a DetResizeForTest) -> Self {
Self { resizer }
}
}
impl<'a> DetectionResizeOperation for DetectionResizer<'a> {
fn resize_with_scale(
&self,
images: Vec<DynamicImage>,
) -> Result<(Vec<DynamicImage>, Vec<ImageScaleInfo>), OCRError> {
let (resized, scales) = self.resizer.apply(images, None, None, None);
Ok((resized, scales))
}
}
#[inline]
pub fn wrap_detection_resizer(resizer: &DetResizeForTest) -> DetectionResizer<'_> {
DetectionResizer::new(resizer)
}