1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use crate::core::*;
use crate::processing::*;
use core::ops::Neg;
use ndarray::prelude::*;
use num_traits::{cast::FromPrimitive, real::Real, Num, NumAssignOps};
use std::marker::Sized;
pub trait SobelExt
where
Self: Sized,
{
type Output;
fn apply_sobel(&self) -> Result<Self, Error>;
fn full_sobel(&self) -> Result<(Self::Output, Self::Output), Error>;
}
fn get_edge_images<T>(mat: &Array3<T>) -> Result<(Array3<T>, Array3<T>), Error>
where
T: Copy + Clone + Num + NumAssignOps + Neg<Output = T> + FromPrimitive + Real,
{
let v_temp: Array3<T> = SobelFilter::build_with_params(Orientation::Vertical).unwrap();
let h_temp: Array3<T> = SobelFilter::build_with_params(Orientation::Horizontal).unwrap();
let shape = (v_temp.shape()[0], v_temp.shape()[1], mat.shape()[2]);
let h_kernel = Array3::<T>::from_shape_fn(shape, |(i, j, _)| h_temp[[i, j, 0]]);
let v_kernel = Array3::<T>::from_shape_fn(shape, |(i, j, _)| v_temp[[i, j, 0]]);
let h_deriv = mat.conv2d(h_kernel.view())?;
let v_deriv = mat.conv2d(v_kernel.view())?;
Ok((h_deriv, v_deriv))
}
impl<T> SobelExt for Array3<T>
where
T: Copy + Clone + Num + NumAssignOps + Neg<Output = T> + FromPrimitive + Real,
{
type Output = Self;
fn apply_sobel(&self) -> Result<Self, Error> {
let (h_deriv, v_deriv) = get_edge_images(self)?;
let h_deriv = h_deriv.mapv(|x| x.powi(2));
let v_deriv = v_deriv.mapv(|x| x.powi(2));
let mut result = h_deriv + v_deriv;
result.mapv_inplace(|x| x.sqrt());
result.mapv_inplace(|x| if x > T::one() { T::one() } else { x });
Ok(result)
}
fn full_sobel(&self) -> Result<(Self::Output, Self::Output), Error> {
let (h_deriv, v_deriv) = get_edge_images(self)?;
let mut magnitude = h_deriv.mapv(|x| x.powi(2)) + v_deriv.mapv(|x| x.powi(2));
magnitude.mapv_inplace(|x| x.sqrt());
magnitude.mapv_inplace(|x| if x > T::one() { T::one() } else { x });
let mut rotation = v_deriv / h_deriv;
rotation.mapv_inplace(|x| x.atan());
Ok((magnitude, rotation))
}
}
impl<T, C> SobelExt for Image<T, C>
where
T: Copy + Clone + Num + NumAssignOps + Neg<Output = T> + FromPrimitive + Real,
C: ColourModel,
{
type Output = Array3<T>;
fn apply_sobel(&self) -> Result<Self, Error> {
let data = self.data.apply_sobel()?;
Ok(Image::from_data(data))
}
fn full_sobel(&self) -> Result<(Self::Output, Self::Output), Error> {
self.data.full_sobel()
}
}