Заполнение контуров / линий
У меня есть следующее изображение:
и я хотел бы заполнить его контуры (то есть, я бы хотел, чтобы зазор был заполнен линиями на этом изображении).
Я пробовал морфологическое закрытие, но с использованием прямоугольного ядра размером 3x3
с 10
итерации не заполняют всю границу. Я также попробовал 21x21
ядро с 1
итерации тоже не повезло.
ОБНОВИТЬ:
Я пробовал это в OpenCV (Python), используя:
cv2.morphologyEx(img, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_RECT, (21,21)))
а также
cv2.morphologyEx(img, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)), iterations=10)
closing(img, square(21))
Моя конечная цель состоит в том, чтобы иметь заполненную версию всего изображения без искажения покрытой области.
2 ответа
В следующем фрагменте я вычисляю карту расстояний обратного изображения. Я порождаю его, чтобы получить большой контур текущего объекта, который я затем скелетирую, чтобы получить центральную линию. Это может быть уже достаточно для ваших целей. Но чтобы привести его в соответствие с заданной толщиной линии, я расширяю скелет и добавляю его к оригиналу, тем самым закрывая все пробелы. Я также удаляю оставшийся объект, касающийся границы.
from skimage import io, morphology, img_as_bool, segmentation
from scipy import ndimage as ndi
import matplotlib.pyplot as plt
image = img_as_bool(io.imread('/tmp/gaps.png'))
out = ndi.distance_transform_edt(~image)
out = out < 0.05 * out.max()
out = morphology.skeletonize(out)
out = morphology.binary_dilation(out, morphology.selem.disk(1))
out = segmentation.clear_border(out)
out = out | image
plt.imshow(out, cmap='gray')
plt.imsave('/tmp/gaps_filled.png', out, cmap='gray')
plt.show()
Предполагая, что на втором этапе вы хотите использовать эти контуры для обнаружения контуров, у меня есть более простое решение. Использование Dilation увеличит белые области, закрыв таким образом пробелы:
import cv2
import numpy as np
image = cv2.imread('lineswithgaps.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# apply dilation on src image
kernel = np.ones((3,3),np.uint8)
dilated_img = cv2.dilate(gray, kernel, iterations = 2)
cv2.imshow("filled gaps for contour detection", dilated_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Как недостаток, края становятся толще, однако это может не быть проблемой, если вам не нужна высокая точность... Если вы хотите определить контуры сейчас, просто добавьте эти строки в первый отрезанный код:
canvas = dilated_img.copy() # Canvas for plotting contours on
canvas = cv2.cvtColor(canvas, cv2.COLOR_GRAY2RGB) # create 3 channel image so we can plot contours in color
contours, hierarchy = cv2.findContours(dilated_img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
# loop through the contours and check through their hierarchy, if they are inner contours
# more here: https://docs.opencv.org/master/d9/d8b/tutorial_py_contours_hierarchy.html
for i,cont in enumerate(contours):
# look for hierarchy[i][3]!=-1, ie hole boundaries
if ( hierarchy[0][i][3] != -1 ):
#cv2.drawContours(canvas, cont, -1, (0, 180, 0), 1) # plot inner contours GREEN
cv2.fillPoly(canvas, pts =[cont], color=(0, 180, 0)) # fill inner contours GREEN
else:
cv2.drawContours(canvas, cont, -1, (255, 0, 0), 1) # plot all others BLUE, for completeness
cv2.imshow("Contours detected", canvas)
cv2.waitKey(0)
cv2.destroyAllWindows()