use crate::core::{FPix, Pix, PixelDepth};
use crate::recog::{RecogError, RecogResult};
use super::types::Dewarp;
pub fn apply_vertical_disparity(pix: &Pix, v_disparity: &FPix, gray_in: u8) -> RecogResult<Pix> {
let w = pix.width();
let h = pix.height();
let depth = pix.depth();
let (dw, dh) = v_disparity.dimensions();
if dw < w || dh < h {
return Err(RecogError::InvalidParameter(format!(
"disparity array too small: {}x{} for image {}x{}",
dw, dh, w, h
)));
}
let result = Pix::new(w, h, depth)?;
let mut result_mut = result.try_into_mut().unwrap();
match depth {
PixelDepth::Bit1 => {
if gray_in > 127 {
} else {
for y in 0..h {
for x in 0..w {
result_mut.set_pixel_unchecked(x, y, 1);
}
}
}
}
PixelDepth::Bit8 => {
for y in 0..h {
for x in 0..w {
result_mut.set_pixel_unchecked(x, y, gray_in as u32);
}
}
}
PixelDepth::Bit32 => {
let gray_val =
((gray_in as u32) << 24) | ((gray_in as u32) << 16) | ((gray_in as u32) << 8) | 255;
for y in 0..h {
for x in 0..w {
result_mut.set_pixel_unchecked(x, y, gray_val);
}
}
}
_ => {
return Err(RecogError::UnsupportedDepth {
expected: "1, 8, or 32 bpp",
actual: depth.bits(),
});
}
}
for y in 0..h {
for x in 0..w {
let disparity = v_disparity.get_pixel(x, y).unwrap_or(0.0);
let src_y_f = y as f32 - disparity;
let src_y = (src_y_f + 0.5) as i32;
if src_y >= 0 && src_y < h as i32 {
let src_y = src_y as u32;
let val = pix.get_pixel_unchecked(x, src_y);
result_mut.set_pixel_unchecked(x, y, val);
}
}
}
Ok(result_mut.into())
}
pub fn apply_horizontal_disparity(pix: &Pix, h_disparity: &FPix, gray_in: u8) -> RecogResult<Pix> {
let w = pix.width();
let h = pix.height();
let depth = pix.depth();
let (dw, dh) = h_disparity.dimensions();
if dw < w || dh < h {
return Err(RecogError::InvalidParameter(format!(
"disparity array too small: {}x{} for image {}x{}",
dw, dh, w, h
)));
}
let result = Pix::new(w, h, depth)?;
let mut result_mut = result.try_into_mut().unwrap();
match depth {
PixelDepth::Bit1 => {
if gray_in <= 127 {
for y in 0..h {
for x in 0..w {
result_mut.set_pixel_unchecked(x, y, 1);
}
}
}
}
PixelDepth::Bit8 => {
for y in 0..h {
for x in 0..w {
result_mut.set_pixel_unchecked(x, y, gray_in as u32);
}
}
}
PixelDepth::Bit32 => {
let gray_val =
((gray_in as u32) << 24) | ((gray_in as u32) << 16) | ((gray_in as u32) << 8) | 255;
for y in 0..h {
for x in 0..w {
result_mut.set_pixel_unchecked(x, y, gray_val);
}
}
}
_ => {
return Err(RecogError::UnsupportedDepth {
expected: "1, 8, or 32 bpp",
actual: depth.bits(),
});
}
}
for y in 0..h {
for x in 0..w {
let disparity = h_disparity.get_pixel(x, y).unwrap_or(0.0);
let src_x_f = x as f32 - disparity;
let src_x = (src_x_f + 0.5) as i32;
if src_x >= 0 && src_x < w as i32 {
let src_x = src_x as u32;
let val = pix.get_pixel_unchecked(src_x, y);
result_mut.set_pixel_unchecked(x, y, val);
}
}
}
Ok(result_mut.into())
}
pub fn apply_disparity(pix: &Pix, dewarp: &Dewarp, gray_in: u8) -> RecogResult<Pix> {
let pix_v = if let Some(ref v_disp) = dewarp.full_v_disparity {
if dewarp.v_valid {
apply_vertical_disparity(pix, v_disp, gray_in)?
} else {
pix.deep_clone()
}
} else {
return Err(RecogError::InvalidParameter(
"no vertical disparity available".to_string(),
));
};
if let Some(ref h_disp) = dewarp.full_h_disparity {
if dewarp.h_valid {
apply_horizontal_disparity(&pix_v, h_disp, gray_in)
} else {
Ok(pix_v)
}
} else {
Ok(pix_v)
}
}
pub fn estimate_disparity_magnitude(lines: &[super::types::TextLine]) -> f32 {
if lines.is_empty() {
return 0.0;
}
let mut max_deviation = 0.0f32;
for line in lines {
if line.points.len() < 3 {
continue;
}
let min_y = line.points.iter().map(|(_, y)| *y).fold(f32::MAX, f32::min);
let max_y = line.points.iter().map(|(_, y)| *y).fold(f32::MIN, f32::max);
let deviation = max_y - min_y;
if deviation > max_deviation {
max_deviation = deviation;
}
}
max_deviation
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::FPix;
#[test]
fn test_apply_vertical_disparity_no_shift() {
let pix = Pix::new(10, 10, PixelDepth::Bit8).unwrap();
let mut pix_mut = pix.to_mut();
for y in 0..10 {
for x in 0..10 {
pix_mut.set_pixel_unchecked(x, y, x + y * 10);
}
}
let pix: Pix = pix_mut.into();
let v_disparity = FPix::new(10, 10).unwrap();
let result = apply_vertical_disparity(&pix, &v_disparity, 255).unwrap();
for y in 0..10 {
for x in 0..10 {
let orig = pix.get_pixel_unchecked(x, y);
let dewarped = result.get_pixel_unchecked(x, y);
assert_eq!(orig, dewarped);
}
}
}
#[test]
fn test_apply_vertical_disparity_uniform_shift() {
let pix = Pix::new(10, 10, PixelDepth::Bit8).unwrap();
let mut pix_mut = pix.to_mut();
for y in 0..10 {
for x in 0..10 {
pix_mut.set_pixel_unchecked(x, y, y * 25);
}
}
let pix: Pix = pix_mut.into();
let mut v_disparity = FPix::new(10, 10).unwrap();
v_disparity.set_all(1.0);
let result = apply_vertical_disparity(&pix, &v_disparity, 255).unwrap();
for y in 1..10 {
for x in 0..10 {
let expected = (y - 1) * 25;
let actual = result.get_pixel_unchecked(x, y);
assert_eq!(expected, actual, "Mismatch at ({}, {})", x, y);
}
}
}
#[test]
fn test_apply_horizontal_disparity_no_shift() {
let pix = Pix::new(10, 10, PixelDepth::Bit8).unwrap();
let mut pix_mut = pix.to_mut();
for y in 0..10 {
for x in 0..10 {
pix_mut.set_pixel_unchecked(x, y, x * 25);
}
}
let pix: Pix = pix_mut.into();
let h_disparity = FPix::new(10, 10).unwrap();
let result = apply_horizontal_disparity(&pix, &h_disparity, 255).unwrap();
for y in 0..10 {
for x in 0..10 {
let orig = pix.get_pixel_unchecked(x, y);
let dewarped = result.get_pixel_unchecked(x, y);
assert_eq!(orig, dewarped);
}
}
}
#[test]
fn test_apply_disparity_dimension_check() {
let pix = Pix::new(100, 100, PixelDepth::Bit8).unwrap();
let small_disparity = FPix::new(50, 50).unwrap();
let result = apply_vertical_disparity(&pix, &small_disparity, 255);
assert!(result.is_err());
}
#[test]
fn test_estimate_disparity_magnitude() {
use super::super::types::TextLine;
let straight = TextLine::new(vec![(0.0, 50.0), (50.0, 50.0), (100.0, 50.0)]);
assert_eq!(estimate_disparity_magnitude(&[straight]), 0.0);
let curved = TextLine::new(vec![(0.0, 50.0), (50.0, 55.0), (100.0, 50.0)]);
assert!((estimate_disparity_magnitude(&[curved]) - 5.0).abs() < 0.01);
}
}