Newer
Older
fn gaussian_smoothing<n, m, gs : usize>(
input: f32[n, m],
filter: f32[gs, gs],
) -> f32[n, m] {
// Define the gaussian radius as half the gaussian size
const gr = gs / 2;
for j = 0 to gs {
let val = input[if row + i < gr then 0
else if row + i - gr > n - 1 then n - 1
else row + i - gr,
if col + j < gr then 0
else if col + j - gr > m - 1 then m - 1
else col + j - gr];
smoothed += val * filter[i, j];
}
}
result[row, col] = smoothed;
}
}
return result;
}
const MIN_BR : f32 = 0;
const MAX_BR : f32 = 1;
fn laplacian_estimate<n, m, sz: usize>(
input: f32[n, m],
structure: f32[sz, sz],
) -> f32[n, m] {
const r = sz / 2;
for col = 0 to m {
// Compute pixel of dilated image
let dilated = MIN_BR;
let filter = if row + i < r
|| row + i - r > n - 1
|| col + j < r
|| col + j - r > m - 1 then MIN_BR
else input[row + i - r, col + j - r];
dilated = max!(dilated, filter * structure[i, j]);
}
}
// Compute pixel of eroded image
let eroded = MAX_BR;
let filter = if row + i < r
|| row + i - r > n - 1
|| col + j < r
|| col + j - r > m - 1 then MAX_BR
else input[row + i - r, col + j - r];
eroded = min!(eroded, filter * structure[i, j]);
}
}
let laplacian = dilated + eroded - 2 * input[row, col];
result[row, col] = laplacian;
}
}
return result;
}
fn zero_crossings<n, m, sz: usize>(
input: f32[n, m],
structure: f32[sz, sz],
) -> f32[n, m] {
const r = sz / 2;
for col = 0 to m {
// Compute the pixel of dilated image
let dilated = MIN_BR;
let filter = if row + i < r
|| row + i - r > n - 1
|| col + j < r
|| col + j - r > m - 1 then MIN_BR
else if input[row + i - r, col + j - r] > MIN_BR then MAX_BR
else MIN_BR;
dilated = max!(dilated, filter * structure[i, j]);
}
}
// Compute the pixel of eroded image
let eroded = MAX_BR;
let filter = if row + i < r
|| row + i - r > n - 1
|| col + j < r
|| col + j - r > m - 1 then MAX_BR
else if input[row + i - r, col + j - r] > MIN_BR then MAX_BR
else MIN_BR;
eroded = min!(eroded, filter * structure[i, j]);
}
}
let sign = dilated - eroded;
result[row, col] = sign;
}
}
return result;
}
fn gradient<n, m, sb: usize>(
input: f32[n, m],
sx: f32[sb, sb],
sy: f32[sb, sb],
) -> f32[n, m] {
const sbr = sb / 2;
for row = 0 to n {
for col = 0 to m {
let gx = 0;
let gy = 0;
for j = 0 to sb {
let val = input[if row + i < sbr then 0
else if row + i - sbr > n - 1 then n - 1
else row + i - sbr,
if col + j < sbr then 0
else if col + j - sbr > m - 1 then m - 1
else col + j - sbr];
gx += val * sx[i, j];
gy += val * sy[i, j];
}
}
result[row, col] = sqrt!(gx * gx + gy * gy);
}
}
return result;
}
fn max_gradient<n, m: usize>(gradient: f32[n, m]) -> f32 {
for i = 0 to n {
for j = 0 to m {
max = max!(max, gradient[i, j]);
}
}
return max;
}
fn reject_zero_crossings<n, m: usize>(
crossings: f32[n, m],
gradient: f32[n, m],
max_gradient: f32,
theta: f32,
) -> f32[n, m] {
for row = 0 to n {
for col = 0 to m {
result[row, col] =
if crossings[row, col] > 0 && gradient[row, col] > theta * max_gradient
then 1.0
else 0.0;
}
}
return result;
}
#[entry]
fn edge_detection<n, m, gs, sz, sb: usize>(
input: f32[n, m],
gaussian_filter: f32[gs, gs],
structure: f32[sz, sz],
sx: f32[sb, sb],
sy: f32[sb, sb],
theta: f32,
) -> f32[n, m] {
let smoothed = gaussian_smoothing::<n, m, gs>(input, gaussian_filter);
@le let laplacian = laplacian_estimate::<n, m, sz>(smoothed, structure);
@zc let zcs = zero_crossings::<n, m, sz>(laplacian, structure);
let gradient = gradient::<n, m, sb>(smoothed, sx, sy);
let maxgrad = max_gradient::<n, m>(gradient);
return reject_zero_crossings::<n, m>(zcs, gradient, maxgrad, theta);
}