mreconstruct
Оператор морфологической реконструкции служит для многократного применения определенного оператора до достижения устойчивости, то есть неизменности результата. Чаще всего применяются реконструкция по расширению и реконструкция по эрозии.
using ImageMorphology
using TestImages
using ImageBase
using ImageShow
using IndirectArrays #hide
img = Gray.(testimage("blob"))
nothing #hide
В отличие от других морфологических операторов, таких как erode, mreconstruct требует двух входных изображений. Одно из них — маркерное изображение, а другое — масочное. Обычно на основе изображения mask производится обучение, а на основе изображения marker — реконструкция. Основой для построения маркерного изображения могут быть следующие данные [1]:
-
знания об ожидаемом результате;
-
известные факты об изображении или физике объекта, который представлен на нем;
-
определенные преобразования масочного изображения;
-
другие графические данные, если они имеются (например, многоспектральные и многовременные изображения);
-
взаимодействие с пользователем (маркеры определяются вручную).
Возьмем в качестве примера реконструкцию по расширению: мы строим маркерное изображение на основе масочного, а затем многократно применяем marker = min.(dilate(marker), mask).
mask = img
marker = mask .- 0.3
mosaic(marker, mask; nrow=1)
Следующая функция представляет собой примитивную реализацию этой идеи:
# Только для иллюстрации; на практике следует использовать `mreconstruct`
function my_reconstruct(marker, mask)
# реконструкция по расширению
# Для реконструкции по эрозии можно заменить `min` на `max`, а `dilate` на `erode`
out = min.(mask, marker)
has_changed = true
while has_changed
old = out
out = min.(dilate(out), mask)
has_changed = !(old == out)
end
return out
end
На следующей GIF-анимации показаны промежуточные результаты out каждой итерации. Слева показано фактическое значение оттенка серого, а справа — цветное значение для большей наглядности.
function my_reconstruct_outs(marker, mask) #hide
out = min.(mask, marker) #hide
outs = [out] #hide
has_changed = true #hide
n = 1 #hide
while has_changed #hide
old = out #hide
out = min.(dilate(out), mask) #hide
n % 4 == 1 && push!(outs, out) #hide
has_changed = !(old == out) #hide
n = n + 1 #hide
end #hide
return outs #hide
end #hide
function with_color(img, orders, colormap) #hide
return IndirectArray([orders[img[i]] for i in CartesianIndices(img)], colormap) #hide
end #hide
outs = my_reconstruct_outs(marker, mask) #hide
orders = Dict(x => i for (i, x) in enumerate(sort(mapreduce(unique, union, outs)))) #hide
colormap = ImageCore.Colors.distinguishable_colors(length(orders)) #hide
gif = ImageShow.gif([mosaic(frame, with_color(frame, orders, colormap); nrow=1) for frame in outs]; fps=5) #hide
Вот как происходит реконструкция и почему она так называется — изображение marker реконструируется с помощью опорного изображения mask, что помогает исследовать определенные свойства изображения mask. Например, если мы хотим исследовать только пятна (темные участки), следует применить реконструкцию по расширению.
Функция mreconstruct(op, marker, mask) в настоящее время поддерживает только dilate и erode в качестве op, то есть соответственно реконструкцию по расширению и по эрозии. Есть также псевдонимы underbuild и overbuild.
# реконструкция по расширению -- `underbuild`
out1 = mreconstruct(dilate, img .- 0.3, img)
# реконструкция по эрозии -- `overbuild`
out2 = mreconstruct(erode, img .+ 0.3, img)
mosaic(mask, out1, out2; nrow=1)
По умолчанию используется структурирующий элемент прямоугольной формы. Как и в другие операторы, в mreconstruct можно передать именованный аргумент dims или позиционный аргумент se. Например:
mreconstruct(dilate, img .- 0.3, img; dims=1) # реконструкция по столбцу
mreconstruct(dilate, img .- 0.3, img, strel_diamond(img)) # СЭ ромбовидной формы
nothing #hide
Однако для универсального структурирующего элемента половинный размер (или радиус) должен быть не более 1 для каждого измерения. Это связано с тем, что алгоритм производит наращение до достижения устойчивости, поэтому СЭ с половинным размером больше 1 на практике не имеет значения.
Эта страница была создана с помощью DemoCards.jl и Literate.jl.