Документация Engee

Function References

General function

# ImageEdgeDetection.EdgeDetectionAPI.detect_edgesFunction

out = 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!Function

detect_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_edgesFunction

out₁, 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!Function

detect_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)

# ImageEdgeDetection.detect_gradient_orientationFunction

detect_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 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).

# ImageEdgeDetection.detect_gradient_orientation!Function

detect_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 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).

# ImageEdgeDetection.EdgeDetectionAPI.thin_edgesFunction

thin_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!Function

thin_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_edgesFunction

out₁, 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)

# ImageEdgeDetection.EdgeDetectionAPI.thin_subpixel_edges!Function

thin_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)

Edge Detection Algorithms

# ImageEdgeDetection.EdgeDetectionAPI.AbstractEdgeDetectionAlgorithmType

AbstractEdgeDetectionAlgorithm <: 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.CannyType

    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.AbstractEdgeThinningAlgorithmType

AbstractEdgeThinningAlgorithm <: 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.NonmaximaSuppressionType

    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.SubpixelNonmaximaSuppressionType

    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

  1. 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.

  2. F. Devernay, "A non-maxima suppression method for edge detection with sub-pixel accuracy", Tech. Report RR-2724, INRIA, 1995.

OrientationConvention

# ImageEdgeDetection.OrientationConventionType

    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 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)