OpenCV Python удалить мелкие контуры, сохранить дочерние контуры - PullRequest
0 голосов
/ 19 июня 2020

Я пытаюсь удалить все контуры, кроме самых больших, сохраняя дочерние контуры внутри самого большого контура. Фактически я хочу go отсюда: Входное изображение в: Выходное изображение Я не знаю, как go об этом (я не программист ни в какой растянуть и помочь собрать ниже). Код, который у меня есть, не сохраняет дочерние контуры. Вывод ниже.

import cv2 as cv
import numpy as np

img = cv.imread('small_contour.jpg')
image_contours = np.zeros((img.shape[1], img.shape[0], 1), np.uint8)

image_binary = np.zeros((img.shape[1], img.shape[0], 1), np.uint8)

for channel in range(img.shape[2]):
    ret, image_thresh = cv.threshold(img[:, :, channel], 127, 255, cv.THRESH_BINARY)    
    contours = cv.findContours(image_thresh, 1, 1)[0]   
    cv.drawContours(image_contours, contours, -1, (255,255,255), 3)

contours = cv.findContours(image_contours, cv.RETR_LIST,
                           cv.CHAIN_APPROX_SIMPLE)[0]

cv.drawContours(image_binary, [max(contours, key = cv.contourArea)],
                -1, (255, 255, 255), -1)

cv.imwrite('fill_contour.jpg', image_binary)
cv.imshow('Small Contour', image_binary)
cv.waitKey(0)

Ответы [ 2 ]

1 голос
/ 20 июня 2020

В этой строке cv.drawContours(image_binary, [max(contours, key = cv.contourArea)], -1, (255, 255, 255), -1) ваш код устанавливает цвет (255, 255, 255) пикселей image_binary, соответствующих границам и внутренним пикселям большего контура, найденного cv.findContours.

Создавая image_binary, вы также меняете местами ширину с высотой, и это ошибка.

Вам не нужно оставлять детей: вы должны использовать cv.RETR_TREE для этого, а затем найти индекс отец и ищите все контуры с этим отцом, рекурсивно выполняющим это для вложенных контуров (дочерние элементы детей ...). См. https://docs.opencv.org/4.1.0/d9/d8b/tutorial_py_contours_hierarchy.html Но это бесполезно для вашей цели.


Вы можете использовать текущий результат в качестве маски для исходного изображения, но код требует некоторых исправлений, начиная со связанного изображения с именем VS0L9.jpg. Обратите внимание, что я использую cv2, просто измените на cv.

Загрузите изображение

im = cv2.imread('VS0L9.jpg', cv2.IMREAD_GRAYSCALE)

Найдите контуры (я использовал RETR_TREE)

contours, hierarchy = cv2.findContours(im, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

Найдите больший контур:

bigger = max(contours, key=lambda item: cv2.contourArea(item))

Инициализируйте маску (что вы пробовали с image_binary):

the_mask = np.zeros_like(im)

Нарисуйте заливку большего контура на изображении маски, интересующая область установлена ​​в (255, 255, 255):

cv2.drawContours(the_mask, [bigger], -1, (255, 255, 255), cv2.FILLED)

На этом этапе маска выглядит как результат вашего кода, но с правильной шириной и высотой. Используйте маску с исходным изображением, чтобы показать только интересующую область:

res = cv2.bitwise_and(im, im, mask = the_mask)

Или, альтернативно:

res = im.copy()
res[the_mask == 0] = 0

Теперь res - это желаемый результат.

0 голосов
/ 20 июня 2020

Вы можете использовать морфологическую реконструкцию с размытым изображением в качестве маркера.

import cv2
img = cv2.imread('VS0L9.jpg', cv2.IMREAD_GRAYSCALE)
thresh = cv2.threshold(img, 40, 255, cv2.THRESH_BINARY)[1]
kernel=cv2.getStructuringElement(cv2.MORPH_RECT, (17,17))
kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
marker = cv2.erode(thresh,kernel,iterations = 5)
while True:
    tmp=marker.copy()
    marker=cv2.dilate(marker, kernel2)
    marker=cv2.min(thresh, marker)
    difference = cv2.subtract(marker, tmp)
    if cv2.countNonZero(difference) == 0:
        break

cv2.imwrite('out.png', marker)
cv2.imshow('result', marker )

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...