use crate::*;
use scirs2_core::ndarray::{Array2, ArrayView2, ArrayView3, ArrayViewMut1};
pub mod simd_operations {
use super::*;
pub fn simd_reconstruct_from_patches_2d(
patches: &ArrayView3<Float>,
image_size: (usize, usize),
) -> SklResult<Array2<Float>> {
let (height, width) = image_size;
if patches.is_empty() {
return Ok(Array2::zeros((height, width)));
}
let (n_patches, patch_height, patch_width) = patches.dim();
if n_patches == 0 || patch_height == 0 || patch_width == 0 {
return Ok(Array2::zeros((height, width)));
}
let mut reconstructed = Array2::zeros((height, width));
let mut overlap_counts: Array2<f64> = Array2::zeros((height, width));
let max_row = height.saturating_sub(patch_height).saturating_add(1);
let max_col = width.saturating_sub(patch_width).saturating_add(1);
if patch_height > height || patch_width > width {
return Err(SklearsError::InvalidInput(format!(
"Patch size ({}, {}) cannot be larger than image size ({}, {})",
patch_height, patch_width, height, width
)));
}
let total_positions = max_row * max_col;
let step = if n_patches < total_positions {
total_positions / n_patches
} else {
1
};
let mut patch_idx = 0;
#[allow(clippy::explicit_counter_loop)] for i in (0..total_positions).step_by(step.max(1)) {
if patch_idx >= n_patches {
break;
}
let row = i / max_col;
let col = i % max_col;
for py in 0..patch_height {
for px in 0..patch_width {
let img_y = row + py;
let img_x = col + px;
if img_y < height && img_x < width {
reconstructed[[img_y, img_x]] += patches[[patch_idx, py, px]];
overlap_counts[[img_y, img_x]] += 1.0;
}
}
}
patch_idx += 1;
}
for y in 0..height {
for x in 0..width {
if overlap_counts[[y, x]] > 0.0 {
reconstructed[[y, x]] /= overlap_counts[[y, x]];
}
}
}
Ok(reconstructed)
}
pub fn simd_array_subtraction(
a: &ArrayView2<Float>,
b: &ArrayView2<Float>,
) -> SklResult<Array2<Float>> {
if a.dim() != b.dim() {
return Err(SklearsError::InvalidInput(
"Array dimensions must match for subtraction".to_string(),
));
}
Ok(a - b)
}
pub fn simd_detect_extrema(
below: &ArrayView2<Float>,
center: &ArrayView2<Float>,
above: &ArrayView2<Float>,
threshold: Float,
) -> Vec<(usize, usize, bool)> {
let mut extrema = Vec::new();
let (height, width) = center.dim();
if height < 3 || width < 3 {
return extrema;
}
for y in 1..height - 1 {
for x in 1..width - 1 {
let center_val = center[[y, x]];
if center_val.abs() < threshold {
continue;
}
let mut is_maximum = true;
let mut is_minimum = true;
for dy in 0..3 {
for dx in 0..3 {
let ny = y + dy - 1;
let nx = x + dx - 1;
if dy == 1 && dx == 1 {
continue;
}
if center[[ny, nx]] >= center_val {
is_maximum = false;
}
if center[[ny, nx]] <= center_val {
is_minimum = false;
}
if below.dim() == center.dim() && ny < below.nrows() && nx < below.ncols() {
if below[[ny, nx]] >= center_val {
is_maximum = false;
}
if below[[ny, nx]] <= center_val {
is_minimum = false;
}
}
if above.dim() == center.dim() && ny < above.nrows() && nx < above.ncols() {
if above[[ny, nx]] >= center_val {
is_maximum = false;
}
if above[[ny, nx]] <= center_val {
is_minimum = false;
}
}
if !is_maximum && !is_minimum {
break;
}
}
if !is_maximum && !is_minimum {
break;
}
}
if is_maximum || is_minimum {
extrema.push((x, y, is_maximum));
}
}
}
extrema
}
pub fn simd_normalize_descriptor(descriptor: &mut ArrayViewMut1<Float>, threshold: Float) {
let norm: Float = descriptor.iter().map(|&x| x * x).sum::<Float>().sqrt();
if norm > Float::EPSILON {
descriptor.mapv_inplace(|x| x / norm);
}
descriptor.mapv_inplace(|x| x.min(threshold));
let norm2: Float = descriptor.iter().map(|&x| x * x).sum::<Float>().sqrt();
if norm2 > Float::EPSILON {
descriptor.mapv_inplace(|x| x / norm2);
}
}
pub fn simd_gaussian_blur(
image: &ArrayView2<Float>,
_kernel: &[Float],
sigma: Float,
) -> Array2<Float> {
let (height, width) = image.dim();
let kernel_size = (6.0 * sigma).ceil() as usize | 1; let half_size = kernel_size / 2;
let mut blurred = Array2::zeros((height, width));
for y in 0..height {
for x in 0..width {
let mut sum = 0.0;
let mut count = 0;
for ky in 0..kernel_size {
for kx in 0..kernel_size {
let img_y = y + ky;
let img_x = x + kx;
if img_y >= half_size
&& img_x >= half_size
&& img_y < height + half_size
&& img_x < width + half_size
{
let src_y = img_y - half_size;
let src_x = img_x - half_size;
if src_y < height && src_x < width {
sum += image[[src_y, src_x]];
count += 1;
}
}
}
}
blurred[[y, x]] = if count > 0 { sum / count as Float } else { 0.0 };
}
}
blurred
}
pub fn simd_compute_integral_image(image: &ArrayView2<Float>) -> Array2<Float> {
let (height, width) = image.dim();
let mut integral = Array2::zeros((height, width));
if height > 0 && width > 0 {
integral[[0, 0]] = image[[0, 0]];
for x in 1..width {
integral[[0, x]] = integral[[0, x - 1]] + image[[0, x]];
}
}
for y in 1..height {
integral[[y, 0]] = integral[[y - 1, 0]] + image[[y, 0]];
for x in 1..width {
integral[[y, x]] = image[[y, x]] + integral[[y - 1, x]] + integral[[y, x - 1]]
- integral[[y - 1, x - 1]];
}
}
integral
}
pub fn simd_haar_x_response(
integral: &ArrayView2<Float>,
x: usize,
y: usize,
size: usize,
) -> Float {
let (height, width) = integral.dim();
let half_size = size / 2;
if x < half_size || y < half_size || x + half_size >= width || y + half_size >= height {
return 0.0;
}
let left = box_filter_sum(integral, x - half_size, y - half_size, half_size, size);
let right = box_filter_sum(integral, x, y - half_size, half_size, size);
right - left
}
pub fn simd_haar_y_response(
integral: &ArrayView2<Float>,
x: usize,
y: usize,
size: usize,
) -> Float {
let (height, width) = integral.dim();
let half_size = size / 2;
if x < half_size || y < half_size || x + half_size >= width || y + half_size >= height {
return 0.0;
}
let top = box_filter_sum(integral, x - half_size, y - half_size, size, half_size);
let bottom = box_filter_sum(integral, x - half_size, y, size, half_size);
bottom - top
}
pub fn simd_compute_kurtosis(values: &[Float], mean: Float, std_dev: Float) -> Float {
super::super::compute_kurtosis_fallback(values, mean, std_dev)
}
}
pub use simd_operations::*;
fn box_filter_sum(integral: &ArrayView2<Float>, x: usize, y: usize, w: usize, h: usize) -> Float {
let (height, width) = integral.dim();
let x1 = x.saturating_sub(1);
let y1 = y.saturating_sub(1);
let x2 = (x + w).min(width - 1);
let y2 = (y + h).min(height - 1);
if x2 >= width || y2 >= height {
return 0.0;
}
integral[[y2, x2]] + integral[[y1, x1]] - integral[[y1, x2]] - integral[[y2, x1]]
}
#[allow(non_snake_case)]
#[cfg(test)]
mod tests {
use super::*;
use scirs2_core::ndarray::Array2;
#[test]
fn test_array_subtraction() {
let a = Array2::from_shape_vec((2, 2), vec![1.0, 2.0, 3.0, 4.0])
.expect("operation should succeed");
let b = Array2::from_shape_vec((2, 2), vec![0.5, 1.0, 1.5, 2.0])
.expect("operation should succeed");
let result =
simd_array_subtraction(&a.view(), &b.view()).expect("operation should succeed");
let expected = Array2::from_shape_vec((2, 2), vec![0.5, 1.0, 1.5, 2.0])
.expect("operation should succeed");
assert!((result - expected)
.map(|x| x.abs())
.iter()
.all(|&x| x < 1e-10));
}
#[test]
fn test_integral_image() {
let image =
Array2::from_shape_vec((3, 3), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])
.expect("operation should succeed");
let integral = simd_compute_integral_image(&image.view());
assert_eq!(integral[[0, 0]], 1.0);
assert_eq!(integral[[0, 2]], 6.0); assert_eq!(integral[[2, 2]], 45.0); }
#[test]
fn test_extrema_detection() {
let below =
Array2::from_shape_vec((3, 3), vec![1.0, 2.0, 1.0, 2.0, 3.0, 2.0, 1.0, 2.0, 1.0])
.expect("operation should succeed");
let center = Array2::from_shape_vec(
(3, 3),
vec![
2.0, 3.0, 2.0, 3.0, 5.0, 3.0, 2.0, 3.0, 2.0,
],
)
.expect("operation should succeed");
let above =
Array2::from_shape_vec((3, 3), vec![1.0, 2.0, 1.0, 2.0, 3.0, 2.0, 1.0, 2.0, 1.0])
.expect("operation should succeed");
let extrema = simd_detect_extrema(&below.view(), ¢er.view(), &above.view(), 1.0);
assert!(!extrema.is_empty());
assert!(extrema
.iter()
.any(|(x, y, is_max)| *x == 1 && *y == 1 && *is_max));
}
}