Skip to content

Commit

Permalink
Update docs for Norm::L2 and uses (#578)
Browse files Browse the repository at this point in the history
  • Loading branch information
theotherphil authored Apr 28, 2024
1 parent fc4b6fa commit 965684c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 59 deletions.
37 changes: 19 additions & 18 deletions src/distance_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,24 @@ use image::{GenericImage, GenericImageView, GrayImage, ImageBuffer, Luma};
use std::cmp::min;

/// How to measure distance between coordinates.
/// See the [`distance_transform`](fn.distance_transform.html) documentation for examples.
///
/// Note that this enum doesn't currently include the `L2` norm. As `Norm`
/// is used by the [`morphology`](../morphology/index.html) functions, this means that we
/// don't support using the `L2` norm for any of those functions.
///
/// This module does support calculating the `L2` distance function, via the
/// [`euclidean_squared_distance_transform`](fn.euclidean_squared_distance_transform.html)
/// function, but the signature of this function is not currently compatible with those for
/// computing `L1` and `LInf` distance transforms. It would be nice to unify these functions
/// in future.
/// See [`distance_transform`] for examples.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Norm {
/// Defines d((x1, y1), (x2, y2)) to be abs(x1 - x2) + abs(y1 - y2).
/// `d((x1, y1), (x2, y2)) = abs(x1 - x2) + abs(y1 - y2)`
///
/// Also known as the Manhattan or city block norm.
L1,
/// Defines d((x1, y1), (x2, y2)) to be sqrt((x1 - x2)^2 + (y1 - y2)^2).
/// `d((x1, y1), (x2, y2)) = sqrt((x1 - x2)^2 + (y1 - y2)^2)`
///
/// Also known as the Euclidean norm.
/// when working with integer distances, we take the smallest
/// greater integer value, also know as 'ceiling'
/// example : d((0,0),(1,2)) = ceil(sqrt(1+2^2)) = ceil(2.236...) = 3
///
/// Note that both [`distance_transform`] and the functions in the [`morphology`](crate::morphology)
/// module represent distances as integer values, so cannot accurately represent `L2` norms. Instead,
/// these functions approximate the `L2` norm by taking the ceiling of the true value. If you want accurate
/// distances then use [`euclidean_squared_distance_transform`] instead, which returns floating point values.
L2,
/// Defines d((x1, y1), (x2, y2)) to be max(abs(x1 - x2), abs(y1 - y2)).
/// `d((x1, y1), (x2, y2)) = max(abs(x1 - x2), abs(y1 - y2))`
///
/// Also known as the chessboard norm.
LInf,
}
Expand All @@ -38,6 +33,9 @@ pub enum Norm {
/// A pixel belongs to the foreground if it has non-zero intensity. As the image
/// has a bit-depth of 8, distances saturate at 255.
///
/// When using `Norm::L2` this function returns the ceiling of the true distances.
/// Use [`euclidean_squared_distance_transform`] if you need floating point distances.
///
/// # Examples
/// ```
/// # extern crate image;
Expand Down Expand Up @@ -101,7 +99,10 @@ pub fn distance_transform(image: &GrayImage, norm: Norm) -> GrayImage {
/// A pixel belongs to the foreground if it has non-zero intensity. As the image has a bit-depth of 8,
/// distances saturate at 255.
///
/// See the [`distance_transform`](fn.distance_transform.html) documentation for examples.
/// When using `Norm::L2` this function returns the ceiling of the true distances.
/// Use [`euclidean_squared_distance_transform`] if you need floating point distances.
///
/// See [`distance_transform`] for examples.
pub fn distance_transform_mut(image: &mut GrayImage, norm: Norm) {
distance_transform_impl(image, norm, DistanceFrom::Foreground);
}
Expand Down
54 changes: 13 additions & 41 deletions src/morphology.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ use image::GrayImage;
/// assert_pixels_eq!(dilate(&image, Norm::L1, 1), l1_dilated);
///
/// // L2 norm
/// // (note that L2 behaves identically to L1 for distances of 2 or less)
/// //
/// // When computing distances using the L2 norm we take the ceiling of the true values.
/// // This means that using the L2 norm gives the same results as the L1 norm for `k <= 2`.
/// let l2_dilated = gray_image!(
/// 0, 0, 0, 0, 0;
/// 0, 0, 255, 0, 0;
Expand Down Expand Up @@ -125,9 +127,10 @@ pub fn dilate_mut(image: &mut GrayImage, norm: Norm, k: u8) {
///
/// assert_pixels_eq!(erode(&image, Norm::L1, 1), l1_eroded);
///
/// // L2 norm - all foreground pixels within a distance of n or less
/// // of a background pixel are eroded.
/// // (note that L2 behaves identically to L1 for distances of 2 or less)
/// // L2 norm
/// //
/// // When computing distances using the L2 norm we take the ceiling of the true values.
/// // This means that using the L2 norm gives the same results as the L1 norm for `k <= 2`.
/// let l2_eroded = gray_image!(
/// 0, 0, 0, 0, 0, 0, 0, 0, 0;
/// 0, 0, 0, 0, 0, 0, 0, 0, 0;
Expand Down Expand Up @@ -366,10 +369,7 @@ mod tests {
0, 0, 0, 0, 0
);
let dilated = dilate(&image, Norm::L1, 0);

let expected = image;

assert_pixels_eq!(dilated, expected);
assert_pixels_eq!(dilated, image);
}

#[test]
Expand All @@ -390,7 +390,6 @@ mod tests {
0, 0, 255, 0, 0;
0, 0, 0, 0, 0
);

assert_pixels_eq!(dilated, expected);
}

Expand All @@ -412,7 +411,6 @@ mod tests {
0, 255, 255, 255, 0;
0, 0, 255, 0, 0
);

assert_pixels_eq!(dilated, expected);
}

Expand Down Expand Up @@ -456,10 +454,7 @@ mod tests {
0, 0, 0, 0, 0
);
let dilated = dilate(&image, Norm::L2, 0);

let expected = image;

assert_pixels_eq!(dilated, expected);
assert_pixels_eq!(dilated, image);
}

#[test]
Expand All @@ -480,7 +475,6 @@ mod tests {
0, 0, 255, 0, 0;
0, 0, 0, 0, 0
);

assert_pixels_eq!(dilated, expected);
}

Expand All @@ -502,7 +496,6 @@ mod tests {
0, 255, 255, 255, 0;
0, 0, 255, 0, 0
);

assert_pixels_eq!(dilated, expected);
}

Expand Down Expand Up @@ -532,7 +525,6 @@ mod tests {
0, 0, 255, 255, 255, 255, 255, 0, 0;
0, 0, 0, 0, 255, 0, 0, 0, 0
);

assert_pixels_eq!(dilated, expected);
}

Expand All @@ -546,10 +538,7 @@ mod tests {
0, 0, 0, 0, 0
);
let dilated = dilate(&image, Norm::LInf, 0);

let expected = image;

assert_pixels_eq!(dilated, expected);
assert_pixels_eq!(dilated, image);
}

#[test]
Expand All @@ -570,7 +559,6 @@ mod tests {
0, 255, 255, 255, 0;
0, 0, 0, 0, 0
);

assert_pixels_eq!(dilated, expected);
}

Expand All @@ -592,7 +580,6 @@ mod tests {
255, 255, 255, 255, 255;
255, 255, 255, 255, 255
);

assert_pixels_eq!(dilated, expected);
}

Expand Down Expand Up @@ -622,7 +609,6 @@ mod tests {
255, 255, 255, 255, 255, 255, 255, 255, 255;
255, 255, 255, 255, 255, 255, 255, 255, 255
);

assert_pixels_eq!(dilated, expected);
}

Expand All @@ -636,10 +622,7 @@ mod tests {
0, 0, 0, 0, 0
);
let eroded = erode(&image, Norm::L1, 0);

let expected = image;

assert_pixels_eq!(eroded, expected);
assert_pixels_eq!(eroded, image);
}

#[test]
Expand All @@ -660,7 +643,6 @@ mod tests {
0, 0, 0, 0, 0;
0, 0, 0, 0, 0
);

assert_pixels_eq!(eroded, expected);
}

Expand Down Expand Up @@ -690,7 +672,6 @@ mod tests {
255, 255, 255, 255, 0, 0, 0, 0, 0;
255, 255, 255, 255, 0, 0, 0, 0, 0
);

assert_pixels_eq!(dilated, expected);
}

Expand All @@ -704,10 +685,7 @@ mod tests {
0, 0, 0, 0, 0
);
let eroded = erode(&image, Norm::L2, 0);

let expected = image;

assert_pixels_eq!(eroded, expected);
assert_pixels_eq!(eroded, image);
}

#[test]
Expand All @@ -728,7 +706,6 @@ mod tests {
0, 0, 0, 0, 0;
0, 0, 0, 0, 0
);

assert_pixels_eq!(eroded, expected);
}

Expand Down Expand Up @@ -758,7 +735,6 @@ mod tests {
255, 255, 255, 255, 0, 0, 0, 0, 0;
255, 255, 255, 255, 0, 0, 0, 0, 0
);

assert_pixels_eq!(dilated, expected);
}

Expand All @@ -772,10 +748,7 @@ mod tests {
0, 0, 0, 0, 0
);
let eroded = erode(&image, Norm::LInf, 0);

let expected = image;

assert_pixels_eq!(eroded, expected);
assert_pixels_eq!(eroded, image);
}

#[test]
Expand All @@ -796,7 +769,6 @@ mod tests {
0, 0, 0, 0, 0;
0, 0, 0, 0, 0
);

assert_pixels_eq!(eroded, expected);
}

Expand Down

0 comments on commit 965684c

Please sign in to comment.