use crate::core::error::{PureCvError, Result};
use crate::core::Matrix;
use num_traits::{FromPrimitive, NumCast, ToPrimitive};
#[cfg(not(feature = "parallel"))]
use crate::core::utils::ParIterFallback;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq)]
#[allow(non_camel_case_types)]
pub enum ThresholdTypes {
THRESH_BINARY = 0,
THRESH_BINARY_INV = 1,
THRESH_TRUNC = 2,
THRESH_TOZERO = 3,
THRESH_TOZERO_INV = 4,
THRESH_OTSU = 8,
THRESH_TRIANGLE = 16,
}
pub fn threshold<T>(
src: &Matrix<T>,
thresh: f64,
maxval: f64,
threshold_type: ThresholdTypes,
) -> Result<(f64, Matrix<T>)>
where
T: Default + Clone + Copy + PartialOrd + ToPrimitive + FromPrimitive + NumCast + Send + Sync,
{
let rows = src.rows;
let cols = src.cols;
let channels = src.channels;
let mut dst = Matrix::<T>::new(rows, cols, channels);
let actual_thresh = thresh;
if (threshold_type as i32 & ThresholdTypes::THRESH_OTSU as i32) != 0 {
return Err(PureCvError::InvalidInput(
"OTSU threshold is not yet implemented".to_string(),
));
}
if (threshold_type as i32 & ThresholdTypes::THRESH_TRIANGLE as i32) != 0 {
return Err(PureCvError::InvalidInput(
"TRIANGLE threshold is not yet implemented".to_string(),
));
}
let type_val = threshold_type as i32 & 0x7;
#[cfg(feature = "parallel")]
{
dst.data
.as_mut_slice()
.par_chunks_mut(cols * channels)
.enumerate()
.for_each(|(y, row_data)| {
for (x, pixel) in row_data.chunks_exact_mut(channels).enumerate() {
for (c, comp) in pixel.iter_mut().enumerate() {
if let Some(src_val) = src.at(y as i32, x as i32, c) {
let val_f64 = src_val.to_f64().unwrap_or(0.0);
let result = match type_val {
0 => {
if val_f64 > actual_thresh {
maxval
} else {
0.0
}
}
1 => {
if val_f64 > actual_thresh {
0.0
} else {
maxval
}
}
2 => {
if val_f64 > actual_thresh {
actual_thresh
} else {
val_f64
}
}
3 => {
if val_f64 > actual_thresh {
val_f64
} else {
0.0
}
}
4 => {
if val_f64 > actual_thresh {
0.0
} else {
val_f64
}
}
_ => val_f64,
};
*comp = T::from_f64(result).unwrap_or_default();
}
}
}
});
}
#[cfg(not(feature = "parallel"))]
{
for y in 0..rows {
for x in 0..cols {
for c in 0..channels {
if let Some(src_val) = src.at(y as i32, x as i32, c) {
let val_f64 = src_val.to_f64().unwrap_or(0.0);
let result = match type_val {
0 => {
if val_f64 > actual_thresh {
maxval
} else {
0.0
}
}
1 => {
if val_f64 > actual_thresh {
0.0
} else {
maxval
}
}
2 => {
if val_f64 > actual_thresh {
actual_thresh
} else {
val_f64
}
}
3 => {
if val_f64 > actual_thresh {
val_f64
} else {
0.0
}
}
4 => {
if val_f64 > actual_thresh {
0.0
} else {
val_f64
}
}
_ => val_f64,
};
*dst.at_mut(y as i32, x as i32, c).unwrap() =
T::from_f64(result).unwrap_or_default();
}
}
}
}
}
Ok((actual_thresh, dst))
}