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

Обнаружение краев методом Кэнни

Фильтр Кэнни по-прежнему является эффективным детектором краев, хотя он был изобретен в 1986 году [1]. В этой демонстрации показано использование недавно разработанного пакета ImageEdgeDetection на примере фильтра Кэнни.

using Images, ImageEdgeDetection, Noise
using ImageEdgeDetection: Percentile
using TestImages

В ImageEdgeDetection.jl переписаны многие функции, которые ранее имелись в Images.jl и будут повторно экспортированы в Images в будущем, после чего использовать директиву using ImageEdgeDetection явным образом будет не нужно.

В JuliaImages любой объект AbstractArray можно рассматривать как изображение. В этой демонстрации в качестве иллюстрации мы используем сгенерированное изображение.

Сначала создадим тестовое изображение.

function make_simple_image(sz)
    img_gray = zeros(Gray{Float64}, sz...)
    fill_region = map(x->x÷4:3x÷4, sz)
    img_gray[fill_region...] .= 1
    img_rot = imrotate(img_gray, pi/4)

    # Исказим изображение размытостью и шумом, чтобы немного затруднить работу нашей функции
    # обнаружения краев методом Кэнни, так как фильтр Кэнни основан на принципе
    # нахождения градиентов.
    img_gauss = imfilter(img_rot, Kernel.gaussian(2))

    # Используем фильтр `salt_pepper` из `Noise.jl`. Шум соли и перца — это в общем случае
    # шум, который изменяет пиксель двумя различными значениями шума.
    # Здесь мы случайным образом присваиваем пикселям только белый цвет.
    img_noise = salt_pepper(img_gauss, 0.05, salt_prob = 0, pepper = 0.9)
end
img = make_simple_image((200, 200))
hlfjgzm

ImageEdgeDetection предлагает унифицированный API detect_edges(img, alg) с различными алгоритмами. В этой демонстрации мы покажем, как использовать оператор Canny [1]. Сначала нужно создать экземпляр алгоритма Canny:

alg = Canny(spatial_scale=1, high=Percentile(80), low=Percentile(20))
ImageEdgeDetection.Canny{Int64, ImageEdgeDetection.Percentile{Int64}, ImageEdgeDetection.Percentile{Int64}, ImageEdgeDetection.NonmaximaSuppression{ImageEdgeDetection.Percentile{Int64}}}
  spatial_scale: Int64 1
  high: ImageEdgeDetection.Percentile{Int64}
  low: ImageEdgeDetection.Percentile{Int64}
  thinning_algorithm: ImageEdgeDetection.NonmaximaSuppression{ImageEdgeDetection.Percentile{Int64}}

а затем применить его в качестве параметров detect_edges. Благодаря механизму множественной диспетчеризации в Julia detect_edges определяет, какую реализацию алгоритма следует вызвать с информацией alg.

edges = detect_edges(img, alg)
mosaicview(img, edges; nrow=1)
murwfcf

Теперь посмотрим, как различные параметры Кэнни изменяют результат, а также как алгоритм работает с реальными изображениями:

cameraman = testimage("cameraman")
canny(σ) = Canny(spatial_scale=σ, high=Percentile(80), low=Percentile(20))
simple_results = map(σ->detect_edges(img, canny(σ)), 1:5)
cameraman_results = map(σ->detect_edges(cameraman, canny(σ)), 1:5)

mosaicview(
    mosaicview(img, cameraman),
    map(mosaicview, simple_results, cameraman_results)...;
    nrow=1
)
eyhmkpu

Как видите, чем больше значение spatial_scale, тем более мелкие детали будет игнорировать оператор Кэнни, что дает «чистый» результат по краю. Нужен ли такой результат, зависит от интерпретации.

Справочные материалы

[1] J. Canny. A Computational Approach to Edge Detection. IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. PAMI-8, no. 6, pp. 679—​698, Nov. 1986, doi: 10.1109/TPAMI.1986.4767851.


Эта страница была создана с помощью DemoCards.jl и Literate.jl.