use crate::data::{AnyDataArray, DataArray, ImageData};
pub fn image_hessian_det(input: &ImageData, scalars: &str) -> ImageData {
let arr = match input.point_data().get_array(scalars) {
Some(a) => a, None => return input.clone(),
};
let dims = input.dimensions();
let nx = dims[0] as usize;
let ny = dims[1] as usize;
let nz = dims[2] as usize;
let n = nx * ny * nz;
let sp = input.spacing();
let mut values = vec![0.0f64; n];
let mut buf = [0.0f64];
for i in 0..n { arr.tuple_as_f64(i, &mut buf); values[i] = buf[0]; }
let get = |i: i64, j: i64, k: i64| -> f64 {
let ii = i.clamp(0, nx as i64 -1) as usize;
let jj = j.clamp(0, ny as i64 -1) as usize;
let kk = k.clamp(0, nz as i64 -1) as usize;
values[kk*ny*nx + jj*nx + ii]
};
let mut det = vec![0.0f64; n];
let hx2 = sp[0]*sp[0]; let hy2 = sp[1]*sp[1];
for k in 0..nz {
for j in 0..ny {
for i in 0..nx {
let ii = i as i64; let jj = j as i64; let kk = k as i64;
let c = get(ii,jj,kk);
let fxx = (get(ii+1,jj,kk) - 2.0*c + get(ii-1,jj,kk)) / hx2;
let fyy = (get(ii,jj+1,kk) - 2.0*c + get(ii,jj-1,kk)) / hy2;
let fxy = (get(ii+1,jj+1,kk) - get(ii-1,jj+1,kk) - get(ii+1,jj-1,kk) + get(ii-1,jj-1,kk)) / (4.0*sp[0]*sp[1]);
det[k*ny*nx + j*nx + i] = fxx*fyy - fxy*fxy;
}
}
}
let mut img = input.clone();
img.point_data_mut().add_array(AnyDataArray::F64(DataArray::from_vec("HessianDet", det, 1)));
img
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn paraboloid_positive() {
let mut img = ImageData::with_dimensions(5, 5, 1);
img.set_spacing([1.0, 1.0, 1.0]);
let mut values = Vec::new();
for j in 0..5 { for i in 0..5 {
let x = i as f64 - 2.0; let y = j as f64 - 2.0;
values.push(x*x + y*y);
}}
img.point_data_mut().add_array(AnyDataArray::F64(DataArray::from_vec("f", values, 1)));
let result = image_hessian_det(&img, "f");
let arr = result.point_data().get_array("HessianDet").unwrap();
let mut buf = [0.0f64];
arr.tuple_as_f64(12, &mut buf); assert!((buf[0] - 4.0).abs() < 1e-10);
}
#[test]
fn saddle_negative() {
let mut img = ImageData::with_dimensions(5, 5, 1);
img.set_spacing([1.0, 1.0, 1.0]);
let mut values = Vec::new();
for j in 0..5 { for i in 0..5 {
let x = i as f64 - 2.0; let y = j as f64 - 2.0;
values.push(x*x - y*y);
}}
img.point_data_mut().add_array(AnyDataArray::F64(DataArray::from_vec("f", values, 1)));
let result = image_hessian_det(&img, "f");
let arr = result.point_data().get_array("HessianDet").unwrap();
let mut buf = [0.0f64];
arr.tuple_as_f64(12, &mut buf);
assert!((buf[0] + 4.0).abs() < 1e-10); }
#[test]
fn missing_array() {
let img = ImageData::with_dimensions(3, 3, 1);
let result = image_hessian_det(&img, "nope");
assert!(result.point_data().get_array("HessianDet").is_none());
}
}