Итерации против размера ядра в морфологических операциях (OpenCV)

Я использовал морф. открытие в OpenCV, чтобы уменьшить шум за пределами моей области интереса в изображениях через opencv, и до сих пор, когда мне нужна более высокая степень шумоподавления, я просто случайным образом увеличиваю размер ядра или увеличиваю количество итераций, пока не буду доволен. Но есть ли существенная разница в результатах в зависимости от того, что вы увеличиваете / как бы вы решили, что изменить в той или иной ситуации? Я пытаюсь придумать лучший подход к тому, какой параметр я изменяю (насколько), кроме угадывания и проверки.


person pyhat    schedule 13.07.2017    source источник


Ответы (1)


Это зависит от типа ядра. Для расширения или эрозии с нечетно-квадратичным ядром нет никакой разницы, увеличиваете ли вы размер или увеличиваете количество итераций (при условии, что используются значения, которые сделали бы их равными). Например:

>>> M = np.zeros((7,7), dtype=np.uint8)
>>> M[3,3] = 1

>>> k1 = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
>>> M1 = cv2.dilate(M, k1, iterations=2)

>>> k2 = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
>>> M2 = cv2.dilate(M, k2, iterations=1)

>>> M1
[[0 0 0 0 0 0 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 0 0 0 0 0 0]]

>>> M2
[[0 0 0 0 0 0 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 0 0 0 0 0 0]]

И это достаточно интуитивно. Прямоугольное ядро ​​3x3 для расширения найдет любой белый пиксель и сделает соседние пиксели белыми. Таким образом, легко увидеть, что если сделать это дважды, любой отдельный белый пиксель превратится в блок белых пикселей 5x5. Здесь мы предполагаем, что сравнивается центральный пиксель — якорь — но это можно изменить, что может повлиять на результат. Например, предположим, что вы сравнивали две итерации ядра (2, 2) с одной итерацией ядра (3, 3):

>>> M = np.zeros((5, 5), dtype=np.uint8)
>>> M[2,2] = 1

>>> k1 = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
>>> M1 = cv2.dilate(M, k1, iterations=2)

>>> k2 = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
>>> M2 = cv2.dilate(M, k2, iterations=1)

>>> M1
[[0 0 0 0 0]
 [0 0 0 0 0]
 [0 0 1 1 1]
 [0 0 1 1 1]
 [0 0 1 1 1]]

>>> M2
[[0 0 0 0 0]
 [0 1 1 1 0]
 [0 1 1 1 0]
 [0 1 1 1 0]
 [0 0 0 0 0]]

Вы можете видеть, что, хотя он создает форму (интуитивно), они не находятся в одном и том же месте (неинтуитивно). И это потому, что якорь ядра (2, 2) не может быть в центре ядра --- в этом случае мы видим, что с центрированным пикселем расширяющиеся соседи находятся только справа внизу, так как он должен выбрать направление потому что он может расширить только один пиксель, чтобы заполнить (2, 2) квадрат.

С ядрами непрямоугольной формы все становится еще сложнее. Например:

>>> M = np.zeros((5, 5), dtype=np.uint8)
>>> M[2,2] = 1

>>> k1 = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
>>> M1 = cv2.dilate(M, k1, iterations=2)

>>> k2 = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
>>> M2 = cv2.dilate(M, k2, iterations=1)

>>> M1
[[0 0 1 0 0]
 [0 1 1 1 0]
 [1 1 1 1 1]
 [0 1 1 1 0]
 [0 0 1 0 0]]

>>> M2
[[0 0 1 0 0]
 [0 0 1 0 0]
 [1 1 1 1 1]
 [0 0 1 0 0]
 [0 0 1 0 0]]

Первый проход M1 создает небольшой крест высотой 3 пикселя и шириной 3 пикселя. Но затем каждый из этих пикселей создает крест в своем месте, что фактически создает ромбовидный узор.

Таким образом, для основных морфологических операций с прямоугольными ядрами, по крайней мере, с нечетными размерами, результат тот же, но для других ядер результат другой. Вы можете применять другие морфологические операции к таким простым примерам, как этот, чтобы понять, как они ведут себя, какие из них следует использовать и как усилить их эффекты.

person alkasm    schedule 13.07.2017