Function References
General function
ImageEdgeDetection.EdgeDetectionAPI.detect_edges
— Functionout = detect_edges([T::Type,] img, f::AbstractEdgeDetectionAlgorithm, args...; kwargs...)
Detect edges of img
using algorithm f
; if left unspecified, f
is assumed to be Canny
.
Output
The return image out
is an Array{T}
. If T
is not specified, then it's inferred.
Examples
Just simply pass the input image and algorithm to detect_edges
f = Canny(spatial_scale = 1.4)
img_edges = detect_edges(img, f)
This reads as "detect_edges
of image img
using algorithm f
".
You can also explicitly specify the return type:
f = Canny(spatial_scale = 1.4)
img_edges_float32 = detect_edges(Gray{Float32}, img, f)
See also detect_edges!
for in-place edge detection.
ImageEdgeDetection.EdgeDetectionAPI.detect_edges!
— Functiondetect_edges!([out,] img, f::AbstractEdgeDetectionAlgorithm, args...; kwargs...)
Detect edges of img
using algorithm f
; if left unspecified, f
is assumed to be Canny
.
Output
If out
is specified, it will be changed in place. Otherwise img
will be changed in place.
Examples
Just simply pass an algorithm to detect_edges!
:
img_edges = similar(img)
detect_edges!(img_edges, img, f)
For cases you just want to change img
in place, you don't necessarily need to manually allocate img_edges
; just use the convenient method:
detect_edges!(img, f)
See also: detect_edges
ImageEdgeDetection.EdgeDetectionAPI.detect_subpixel_edges
— Functionout₁, out₂ = detect_subpixel_edges([T₁::Type, T₂::Type], img, f::AbstractEdgeDetectionAlgorithm, args...; kwargs...)
Detect edges of img
to subpixel precision using algorithm f
; if left unspecified, f
is assumed to be Canny
.
Output
The integer components of an edge correspond to non-zero row and column entries in out₁
which is an Array{T₁}
. The accompanying subpixel offsets are stored in a 2-D array out₂
as length-2 vectors (Array{SVector{2, T₂}}
). One can recover the subpixel coordinates by adding the subpixel offsets to the integer components.
Examples
Just simply pass the input image and algorithm to detect_subpixel_edges
f = Canny(spatial_scale = 1.4, thinning_algorithm = SubpixelNonmaximaSuppression())
img_edges, offsets = detect_subpixel_edges(img, f)
This reads as "detect_subpixel_edges
of image img
using algorithm f
".
You can also explicitly specify the return types:
f = Canny(spatial_scale = 1.4, thinning_algorithm = SubpixelNonmaximaSuppression())
img_edges, offsets = detect_subpixel_edges(Gray{Float32}, Float32, img, f)
See also detect_subpixel_edges!
for in-place edge detection.
ImageEdgeDetection.EdgeDetectionAPI.detect_subpixel_edges!
— Functiondetect_subpixel_edges!(out₁, out₂, img, f::AbstractEdgeDetectionAlgorithm, args...; kwargs...)
Detect edges of img
to subpixel precision using algorithm f
; if left unspecified, f
is assumed to be Canny
.
Output
The integer components of an edge correspond to non-zero row and column entries in out₁
. The accompanying subpixel offsets are stored in a 2-D array out₂
as length-2 vectors. One can recover the subpixel coordinates by adding the subpixel offsets to the integer components.
Examples
Just simply pass an algorithm to detect_subpixel_edges!
:
f = Canny(spatial_scale = 1.4, thinning_algorithm = SubpixelNonmaximaSuppression())
img_edges = similar(img)
offsets = zeros(SVector{2,Float64}, axes(img))
detect_edges!(img_edges, offsets, img, f)
See also: detect_subpixel_edges
ImageEdgeDetection.detect_gradient_orientation
— Functiondetect_gradient_orientation(g₁::AbstractArray, g₂::AbstractArray, orientation_convention::OrientationConvention, args...; kwargs...)
Given the gradient in the first (g₁
) and second (g₂
) spatial dimensions, returns the gradient orientation, where the orientation is interpreted according to a supplied OrientationConvention
.
Details
You can specify how you want the gradient orientation to be reported by supplying an OrientationConvention
. If left unspecified the orientation is measured counter-clockwise from the south direction. This is because in a Raster coordinate system, the first spatial dimension increases as one goes down the image (i.e. it points south), and the second spatial dimension increases as one moves to the right of the image (i.e. it points east).
If you wish to interpret the orientation in a canonical Cartesian coordinate convention you would specify east as the reference compass direction (compass_direction = 'E'
) and a counter-clockwise direction (clockwise = false
).
Output
Returns a two-dimensional array of angles. If in_radians = true
the valid angles are reported in the range of [0...2π)
, otherwise they are reported in the range [0...360)
. The values 2π
and 360
are used as sentinels to designate undefined angles (because the gradient magnitude was too close to zero). By default, an angle is undefined if (abs(g₁) < tol && abs(g₂) < tol)
where g₁
and g₂
denote the gradient in the first and second spatial dimensions, and tol = sqrt(eps(Float64))
(as defined in OrientationConvention
).
See also: detect_gradient_orientation!
ImageEdgeDetection.detect_gradient_orientation!
— Functiondetect_gradient_orientation(out::AbstractArray, g₁::AbstractArray, g₂::AbstractArray, orientation_convention::OrientationConvention, args...; kwargs...)
Given the gradient in the first (g₁
) and second (g₂
) spatial dimensions, returns the gradient orientation in out
, where the orientation is interpreted according to a supplied OrientationConvention
.
Details
You can specify how you want the gradient orientation to be reported by supplying an OrientationConvention
. If left unspecified the orientation is measured counter-clockwise in radians from the south direction. This is because in a Raster coordinate system, the first spatial dimension increases as one goes down the image (i.e. it points south), and the second spatial dimension increases as one moves to the right of the image (i.e. it points east).
If you wish to interpret the orientation in a canonical Cartesian coordinate convention you would specify east as the reference compass direction (compass_direction = 'E'
) and a counter-clockwise direction (clockwise = false
).
Output
Returns a two-dimensional array of angles. If in_radians = true
genuine angles are reported in the range of [0...2π)
, otherwise they are reported in the range [0...360)
. The values 2π
and 360
are used as sentinels to designate undefined angles (because the gradient magnitude was too close to zero). By default, an angle is undefined if (abs(g₁) < tol && abs(g₂) < tol)
where g₁
and g₂
denote the gradient in the first and second spatial dimensions, and tol = sqrt(eps(eltype(out)))
(as defined in OrientationConvention
).
See also: detect_gradient_orientation
ImageEdgeDetection.EdgeDetectionAPI.thin_edges
— Functionthin_edges([T::Type,] mag, g₁, g₂, f::AbstractEdgeThinningAlgorithm, args...; kwargs...)
Using algorithm f
, thin the edge-response based on the edge magnitude mag
, the gradient in the first spatial dimension g₁
, and the gradient in the second spatial dimension g₂
.
Output
Returns an Array{T}
representing the thinned edge response.
If T
is not specified, then it's inferred. Note that T
must represent or wrap a floating point number.
Examples
Just simply pass the input image and algorithm to thin_edges
using TestImages, ImageFiltering
img = Gray.(testimage("mandril"))
# Gradient in the first and second spatial dimension
g₁, g₂ = imgradients(img, KernelFactors.scharr)
# Gradient magnitude
mag = hypot.(g₁, g₂)
f = NonmaximaSuppression(threshold = Percentile(10))
thinned_edges = thin_edges(mag, g₁, g₂, f)
This reads as "thin_edges
based on the edge response magnitude, and spatial gradients, using algorithm f
".
You can also explicitly specify the return type:
thinned_edges_float32 = thin_edges(Gray{Float32}, mag, g₁, g₂, f)
See also thin_edges!
for in-place edge thinning.
ImageEdgeDetection.EdgeDetectionAPI.thin_edges!
— Functionthin_edges!([out,] mag, g₁, g₂, f::AbstractEdgeThinningAlgorithm, args...; kwargs...)
Isolate local maxima of gradient magnitude mag
along the local gradient direction. The arguments g₁
and g₂
represent the gradient in the first spatial dimension (y), and the second spatial dimension (x), respectively.
Output
If out
is specified, it will be changed in place. Otherwise mag
will be changed in place.
Examples
Just simply pass an algorithm to thin_edges!
:
using TestImages, ImageFiltering
img = Gray.(testimage("mandril"))
# Gradient in the first and second spatial dimension
g₁, g₂ = imgradients(img, KernelFactors.scharr)
# Gradient magnitude
mag = hypot.(g₁, g₂)
f = SubpixelNonmaximaSuppression(threshold = Percentile(10))
thinned_edges = zeros(eltype(mag), axes(mag))
thin_edges!(thinned_edges, mag, g₁, g₂, f)
For cases you just want to change mag
in place, you don't necessarily need to manually allocate thinned_edges
; just use the convenient method:
thin_edges!(mag, g₁, g₂, f)
See also: thin_edges
ImageEdgeDetection.EdgeDetectionAPI.thin_subpixel_edges
— Functionout₁, out₂ = thin_subpixel_edges(mag, g₁, g₂, f::AbstractEdgeThinningAlgorithm, args...; kwargs...)
Isolate local maxima of gradient magnitude mag
along the local gradient direction. The arguments g₁
and g₂
represent the gradient in the first spatial dimension (y), and the second spatial dimension (x), respectively.
Output
The integer components of the local maxima correspond to non-zero row and column entries in out₁
. The accompanying subpixel offsets are stored in a 2-D array out₂
as length-2 vectors. One can recover the subpixel coordinates by adding the subpixel offsets to the integer components.
Examples
Just simply pass an algorithm to thin_subpixel_edges
:
using TestImages, ImageFiltering
img = Gray.(testimage("mandril"))
# Gradient in the first and second spatial dimension
g₁, g₂ = imgradients(img, KernelFactors.scharr)
# Gradient magnitude
mag = hypot.(g₁, g₂)
f = SubpixelNonmaximaSuppression(threshold = Percentile(10))
thinned_edges, offsets = thin_subpixel_edges(mag, g₁, g₂, f)
See also: thin_subpixel_edges!
ImageEdgeDetection.EdgeDetectionAPI.thin_subpixel_edges!
— Functionthin_subpixel_edges!(out₁, out₂, mag, g₁, g₂, f::AbstractEdgeThinningAlgorithm, args...; kwargs...)
Isolate local maxima of gradient magnitude mag
along the local gradient direction. The arguments g₁
and g₂
represent the gradient in the first spatial dimension (y), and the second spatial dimension (x), respectively.
Output
The integer components of the local maxima correspond to non-zero row and column entries in out₁
. The accompanying subpixel offsets are stored in a 2-D array out₂
as length-2 vectors. One can recover the subpixel coordinates by adding the subpixel offsets to the integer components.
Examples
Just simply pass an algorithm to thin_subpixel_edges!
:
using TestImages, ImageFiltering
img = Gray.(testimage("mandril"))
# Gradient in the first and second spatial dimension
g₁, g₂ = imgradients(img, KernelFactors.scharr)
# Gradient magnitude
mag = hypot.(g₁, g₂)
f = SubpixelNonmaximaSuppression(threshold = Percentile(10))
thinned_edges = zeros(eltype(mag), axes(mag))
offsets = zeros(SVector{2,Float64}, axes(mag))
thin_subpixel_edges!(thinned_edges, offsets, mag, g₁, g₂, f)
See also: thin_subpixel_edges
Edge Detection Algorithms
ImageEdgeDetection.EdgeDetectionAPI.AbstractEdgeDetectionAlgorithm
— TypeAbstractEdgeDetectionAlgorithm <: AbstractImageFilter
The root type for ImageEdgeDetection
package.
Any concrete edge detection algorithm shall subtype it to support detect_edges
, detect_edges!
, detect_subpixel_edges
and detect_subpixel_edges!
APIs.
Examples
All edge detection algorithms in ImageEdgeDetection are called in the following pattern:
# first generate an algorithm instance
f = Canny()
# then pass the algorithm to `detect_edges`
img_edges = detect_edges(img, f)
# or use in-place version `detect_edges!`
img_edges = similar(img)
detect_edges!(img_edges, img, f)
For more examples, please check detect_edges
, detect_edges!
and concrete algorithms.
One can also detect edges to subpixel accuracy by specifying SubpixelNonmaximaSuppression
as the edge thinning algorithm and using detect_subpixel_edges
or detect_subpixel_edges!
. The function returns an edge image as well as a accompanying matrix of length-2 vectors which, when added to the edge image coordinates, specify the location of an edge to subpixel precision.
# first generate an algorithm instance
f = Canny(thinning_algorithm = SubpixelNonmaximaSuppression())
# then pass the algorithm to `detect_subpixel_edges`
img_edges, subpixel_offsets = detect_subpixel_edges(img, f)
# or use in-place version `detect_edges!`
img_edges = similar(img)
subpixel_offsets = zeros(SVector{2,Float64}, axes(img))
detect_edges!(img_edges, subpixel_offsets, img, f)
Canny
ImageEdgeDetection.Canny
— Type Canny <: AbstractEdgeDetectionAlgorithm
Canny(; spatial_scale = 1, high = Percentile(80), low = Percentile(20), thinning_algorithm = NonmaximaSuppression(threshold = low))
detect_edges([T,] img, f::Canny)
detect_edges!([out,] img, f::Canny)
detect_subpixel_edges([T₁, T₂] img, f::Canny)
detect_subpixel_edges!(out₁, out₂, img, f::Canny)
Returns a binary image depicting the edges of the input image.
Details
TODO
Options
Various options for the parameters of the detect_edges
function and Canny
type are described in more detail below.
Choices for img
The detect_edges
function can handle a variety of input types. By default the type of the returned image matches the type of the input image.
For colored images, the input is converted to grayscale.
Choices for spatial_scale
in Canny
.
The spatial_scale
determines the radius (σ) of the Gaussian filter. It must be a positive real number.
Choices for high
and low
in Canny
.
The hysteresis thresholds high
and low
(high
> low
) can be specified as positive numbers, or as Percentiles
. If left unspecified, a default value of high = Percentile(80)
and low = Percentile(20)
is assumed.
Choices for thinning_algorithm
in Canny
.
You can specify an AbstractEdgeThinningAlgorithm
. By default, the NonmaximaSuppression
algorithm is used which suppresses non-maxima up to pixel-level accuracy. For subpixel precision specify the SubpixelNonmaximaSuppression
algorithm.
Example
using TestImages, FileIO, ImageView
img = testimage("mandril_gray")
img_edges = detect_edges(img, Canny(spatial_scale = 1.4))
imshow(img)
imshow(img_edges)
References
J. Canny, "A Computational Approach to Edge Detection," in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. PAMI-8, no. 6, pp. 679-698, Nov. 1986, doi: 10.1109/TPAMI.1986.4767851.
Edge Thinning Algorithms
ImageEdgeDetection.EdgeDetectionAPI.AbstractEdgeThinningAlgorithm
— TypeAbstractEdgeThinningAlgorithm <: AbstractImageFilter
A root type for ImageEdgeDetection
package.
Any concrete edge thinning algorithm shall subtype it to support thin_edges
, thin_edges!
, thin_subpixel_edges
and thin_subpixel_edges!
APIs.
Examples
All edge thinning algorithms in ImageEdgeDetection are called in the following pattern:
# first generate an algorithm instance
f = NonmaximaSuppression()
# determine the image gradients
g₁, g₂ = imgradients(img, KernelFactors.scharr)
# determine the gradient magnitude
mag = hypot.(g₁, g₂)
# then pass the algorithm to `thin_edges`
thinned_edges = thin_edges(mag, g₁, g₂, f)
# or use in-place version `thin_edges!`
thinned_edges = zeros(eltype(mag), axes(mag))
thin_edges!(thinned_edges, mag, g₁, g₂, f)
For more examples, please check thin_edges
, thin_edges!
and concrete algorithms.
One can also perform non-maxima suppression to subpixel precision using thin_subpixel_edges
and thin_subpixel_edges!
. The function returns an edge image as well as a accompanying matrix of length-2 vectors which, when added to the edge image coordinates, specify the location of an edge to subpixel precision.
Non-maxima Suppression
ImageEdgeDetection.NonmaximaSuppression
— Type NonmaximaSuppression <: AbstractEdgeThinningAlgorithm
NonmaximaSuppression(; threshold::Union{Number, Percentile} = Percentile(20))
f = NonmaximaSuppression()
f(out::AbstractArray, mag::AbstractArray, g₁::AbstractArray, g₂::AbstractArray, f::NonmaximaSuppression)
Isolates local maxima of gradient magnitude mag
along the local gradient direction and stores the result in out
. The arguments g₁
and g₂
represent the gradient in the first spatial dimension (y), and the second spatial dimension (x), respectively.
Details
TODO
Example
using TestImages, FileIO, ImageView, ImageEdgeDetection, ImageFiltering
img = testimage("mandril_gray")
# Gradient in the first and second spatial dimension
g₁, g₂ = imgradients(img, KernelFactors.scharr)
# Gradient magnitude
mag = hypot.(g₁, g₂)
nms = zeros(eltype(mag), axes(mag))
# Instantiate the NonmaximaSuppression functor.
f = NonmaximaSuppression()
# Suppress the non-maximal gradient magnitudes and store the result in `nms`.
f(nms, mag, g₁, g₂)
imshow(img)
imshow(mag)
imshow(nms)
References
J. Canny, "A Computational Approach to Edge Detection," in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. PAMI-8, no. 6, pp. 679-698, Nov. 1986, doi: 10.1109/TPAMI.1986.4767851.
Non-maxima Suppression (Subpixel)
ImageEdgeDetection.SubpixelNonmaximaSuppression
— Type SubpixelNonmaximaSuppression <: AbstractEdgeThinningAlgorithm
SubpixelNonmaximaSuppression(; threshold::Union{Number, Percentile} = Percentile(20))
f = SubpixelNonmaximaSuppression()
f(out₁::AbstractArray, out₂::Matrix{<:AbstractArray}, mag::AbstractArray, g₁::AbstractArray, g₂::AbstractArray, f::SubpixelNonmaximaSuppression)
Isolates local maxima of gradient magnitude mag
along the local gradient direction to subpixel precision. The arguments g₁
and g₂
represent the gradient in the first spatial dimension (y), and the second spatial dimension (x), respectively.
The integer components of the local maxima correspond to non-zero row and column entries out₁
. The accompanying subpixel offsets are stored in a 2-D array out₂
as length-2 vectors. One can recover the subpixel coordinates by adding the subpixel offsets to the integer components.
Details
TODO
Example
using TestImages, FileIO, ImageView, ImageEdgeDetection, ImageFiltering
img = testimage("mandril_gray")
# Gradient in the first and second spatial dimension
g₁, g₂ = imgradients(img, KernelFactors.scharr)
# Gradient magnitude
mag = hypot.(g₁, g₂)
nms = zeros(eltype(mag), axes(mag))
subpixel_offsets = zeros(SVector{2,Float64}, axes(mag))
# Instantiate the NonmaximaSuppression functor.
f = SubpixelNonmaximaSuppression()
# Suppress the non-maximal gradient magnitudes and store the result in `nms`.
f(nms, subpixel_offsets, mag, g₁, g₂)
imshow(img)
imshow(mag)
imshow(nms)
References
- J. Canny, "A Computational Approach to Edge Detection," in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. PAMI-8, no. 6, pp. 679-698, Nov. 1986, doi: 10.1109/TPAMI.1986.4767851.
- F. Devernay, "A non-maxima suppression method for edge detection with sub-pixel accuracy", Tech. Report RR-2724, INRIA, 1995.
OrientationConvention
ImageEdgeDetection.OrientationConvention
— Type OrientationConvention(; compass_direction::AbstractChar = 'S', is_clockwise::Bool = false, in_radians = true, tol = sqrt(eps(Float64)))
Specifies the coordinate system context for detect_gradient_orientation
which determines the meaning of the angles (the gradient orientations).
Details
You can specify how you want the gradient orientation to be reported. By default, the orientation is measured counter-clockwise from the south direction. This is because in a Raster coordinate system, the first spatial dimension increases as one goes down the image (i.e. it points south), and the second spatial dimension increases as one moves to the right of the image (i.e. it points east).
If you wish to interpret the orientation in a canonical Cartesian coordinate convention you would specify east as the reference compass direction (compass_direction = 'E'
) and a counter-clockwise direction (clockwise = false
).
If in_radians = true
the valid angles are reported in the range of [0...2π)
, otherwise they are reported in the range [0...360)
. The values 2π
and 360
are used as sentinels to designate undefined angles (because the gradient magnitude was too close to zero). By default, an angle is undefined if (abs(g₁) < tol && abs(g₂) < tol)
where g₁
and g₂
denote the gradient in the first and second spatial dimensions, and tol = sqrt(eps(Float64))
.
Example
using TestImages, FileIO, ImageView, ImageEdgeDetection, ImageFiltering
img = testimage("mandril_gray")
# Gradient in the first and second spatial dimension
g₁, g₂ = imgradients(img, KernelFactors.scharr)
# Interpret the angles with respect to a canonical Cartesian coordinate system
# where the angles are measured counter-clockwise from the positive x-axis.
orientation_convention = OrientationConvention(in_radians = true,
is_clockwise = false,
compass_direction = 'E')
angles = detect_gradient_orientation(g₁, g₂, orientation_convention)
Supplementary Types
ImageEdgeDetection.Percentile
— TypePercentile(x)
Indicate that x
should be interpreted as a percentile rather than an absolute value. For example,
detect_edges(img, Canny(high = 80, low = 20))
uses absolute thresholds on the edge magnitudesdetect_edges(img, Canny(high = Percentile(80), low = Percentile(20)))
uses percentiles of the edge magnitude image as threshold
ImageEdgeDetection.Canny
ImageEdgeDetection.EdgeDetectionAPI.AbstractEdgeDetectionAlgorithm
ImageEdgeDetection.EdgeDetectionAPI.AbstractEdgeThinningAlgorithm
ImageEdgeDetection.NonmaximaSuppression
ImageEdgeDetection.OrientationConvention
ImageEdgeDetection.Percentile
ImageEdgeDetection.SubpixelNonmaximaSuppression
ImageEdgeDetection.EdgeDetectionAPI.detect_edges
ImageEdgeDetection.EdgeDetectionAPI.detect_edges!
ImageEdgeDetection.EdgeDetectionAPI.detect_subpixel_edges
ImageEdgeDetection.EdgeDetectionAPI.detect_subpixel_edges!
ImageEdgeDetection.EdgeDetectionAPI.thin_edges
ImageEdgeDetection.EdgeDetectionAPI.thin_edges!
ImageEdgeDetection.EdgeDetectionAPI.thin_subpixel_edges
ImageEdgeDetection.EdgeDetectionAPI.thin_subpixel_edges!
ImageEdgeDetection.detect_gradient_orientation
ImageEdgeDetection.detect_gradient_orientation!