use crate::filters::{sobel, BorderMode};
use scirs2_core::ndarray::{Array, ArrayD, Dimension, Ix2};
use scirs2_core::numeric::{Float, NumAssign};
#[allow(dead_code)]
pub fn harris_corners(
image: &Array<f32, Ix2>,
block_size: usize,
k: f32,
threshold: f32,
) -> Array<bool, Ix2> {
let image_dim = image.raw_dim();
let mut image_d = ArrayD::from_elem(image_dim.into_dyn(), 0.0f32);
for (idx, &val) in image.indexed_iter() {
let idx_d = [idx.0, idx.1];
image_d[idx_d] = val;
}
let gradient_y = sobel(&image_d, 0, Some(BorderMode::Reflect)).expect("Operation failed");
let gradient_x = sobel(&image_d, 1, Some(BorderMode::Reflect)).expect("Operation failed");
let mut ix2: ArrayD<f32> = gradient_x.clone().mapv(|x| x * x);
let mut iy2: ArrayD<f32> = gradient_y.clone().mapv(|y| y * y);
let mut ixy: ArrayD<f32> = gradient_x.clone();
for (idx, &y) in gradient_y.indexed_iter() {
ixy[idx.slice()] *= y;
}
let sigma = 0.5 * (block_size as f32 - 1.0) / 3.0; ix2 = crate::filters::gaussian_filter_f32(&ix2, sigma, Some(BorderMode::Reflect), None)
.expect("Operation failed");
iy2 = crate::filters::gaussian_filter_f32(&iy2, sigma, Some(BorderMode::Reflect), None)
.expect("Operation failed");
ixy = crate::filters::gaussian_filter_f32(&ixy, sigma, Some(BorderMode::Reflect), None)
.expect("Operation failed");
let shape = image.raw_dim();
let mut ix2_2d = Array::zeros(shape);
let mut iy2_2d = Array::zeros(shape);
let mut ixy_2d = Array::zeros(shape);
for idx in image.indexed_iter() {
let pos = idx.0;
let idx_d = [pos.0, pos.1];
ix2_2d[pos] = ix2[idx_d.as_ref()];
iy2_2d[pos] = iy2[idx_d.as_ref()];
ixy_2d[pos] = ixy[idx_d.as_ref()];
}
let mut response = Array::zeros(shape);
for idx in response.indexed_iter_mut() {
let pos = idx.0;
let det = ix2_2d[pos] * iy2_2d[pos] - ixy_2d[pos] * ixy_2d[pos];
let trace = ix2_2d[pos] + iy2_2d[pos];
*idx.1 = det - k * trace * trace;
}
let mut corners = Array::from_elem(shape, false);
let (rows, cols) = (shape[0], shape[1]);
let window_radius = block_size / 2;
for row in window_radius..(rows - window_radius) {
for col in window_radius..(cols - window_radius) {
let r = response[(row, col)];
if r > threshold {
let mut is_local_max = true;
'window: for i in (row - window_radius)..=(row + window_radius) {
for j in (col - window_radius)..=(col + window_radius) {
if i < rows && j < cols && !(i == row && j == col) && response[(i, j)] > r {
is_local_max = false;
break 'window;
}
}
}
if is_local_max {
corners[(row, col)] = true;
}
}
}
}
corners
}
#[allow(dead_code)]
pub fn fast_corners<T>(image: &Array<T, Ix2>, threshold: T, n: usize) -> Array<bool, Ix2>
where
T: Float + NumAssign + scirs2_core::numeric::FromPrimitive,
{
let shape = image.raw_dim();
let (rows, cols) = (shape[0], shape[1]);
let mut corners = Array::from_elem(shape, false);
if rows < 7 || cols < 7 {
return corners;
}
let circle_points = [
(0, 3),
(1, 3),
(2, 2),
(3, 1),
(3, 0),
(3, -1),
(2, -2),
(1, -3),
(0, -3),
(-1, -3),
(-2, -2),
(-3, -1),
(-3, 0),
(-3, 1),
(-2, 2),
(-1, 3),
]
.map(|(y, x)| (y as isize, x as isize));
for row in 3..(rows - 3) {
for col in 3..(cols - 3) {
let center_value = image[(row, col)];
let high_threshold = center_value + threshold;
let low_threshold = center_value - threshold;
let mut is_corner = false;
let num_points = circle_points.len();
for start in 0..num_points {
let mut _count_brighter = 0;
let mut _count_darker = 0;
let mut consecutive_brighter = 0;
let mut consecutive_darker = 0;
for offset in 0..num_points {
let idx = (start + offset) % num_points;
let (dy, dx) = circle_points[idx];
let r = (row as isize + dy) as usize;
let c = (col as isize + dx) as usize;
let pixel_value = image[(r, c)];
if pixel_value > high_threshold {
consecutive_brighter += 1;
consecutive_darker = 0;
} else if pixel_value < low_threshold {
consecutive_darker += 1;
consecutive_brighter = 0;
} else {
consecutive_brighter = 0;
consecutive_darker = 0;
}
if consecutive_brighter >= n || consecutive_darker >= n {
is_corner = true;
break;
}
}
if !is_corner {
for offset in 0..n - 1 {
let idx = (start + offset) % num_points;
let (dy, dx) = circle_points[idx];
let r = (row as isize + dy) as usize;
let c = (col as isize + dx) as usize;
let pixel_value = image[(r, c)];
if pixel_value > high_threshold {
consecutive_brighter += 1;
} else {
consecutive_brighter = 0;
}
if pixel_value < low_threshold {
consecutive_darker += 1;
} else {
consecutive_darker = 0;
}
}
if consecutive_brighter >= n || consecutive_darker >= n {
is_corner = true;
}
}
if is_corner {
break;
}
}
if is_corner {
corners[(row, col)] = true;
}
}
}
corners
}