python 填充等高线但保留未填充的包含区域

vof42yt1  于 2023-03-28  发布在  Python
关注(0)|答案(1)|浏览(194)

我有这样一段python代码,它可以填充图像的轮廓,但保留其中包含的未填充的洞。这就是我想要的:

但这是我得到的:

我已经尝试指定轮廓层次填充cv 2,但我不能得到我想要的结果。
这是我尝试过的方法:

import numpy as np
import cv2

# Load the PNG image
img = cv2.imread('slice.png')

# Convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Threshold the image to create a binary image
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)

# Find the contours in the binary image
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Create a blank image with the same dimensions as the original image
filled_img = np.zeros(img.shape[:2], dtype=np.uint8)

# Iterate over the contours and their hierarchies
for i, contour in enumerate(contours):
    # Check if the contour has a parent
    if hierarchy[0][i][3] == -1:
        # If the contour doesn't have a parent, fill it with pixel value 255
        cv2.drawContours(filled_img, [contour], -1, 255, cv2.FILLED)

# Display the result
cv2.imshow('Original Image', img)
cv2.imshow('Filled Regions', filled_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

我试过修改“if hierarchy[0][i][3] == -1:'"部分的-1,0,1值,但它要么填充了较小的洞,要么像我发布的第一张图片一样填充了整个较大的轮廓。

w1jd8yoj

w1jd8yoj1#

问题是cv2.drawContours填充闭合轮廓的整个内部,而不管是否存在内部轮廓。
代替用白色填充没有父轮廓的轮廓,我们可以从白色轮廓开始,并且用黑色填充没有子轮廓的轮廓。
假设我们知道内部部分应该是黑色的,我们可以应用以下阶段:

  • 使用cv2.RETR_EXTERNAL查找轮廓,并用白色填充外部轮廓。
  • 使用cv2.RETR_TREE查找等高线。
  • 迭代轮廓层次,并仅用黑色填充没有子轮廓的轮廓(用黑色填充最内部的轮廓)。

代码示例:

import numpy as np
import cv2

# Load the PNG image
img = cv2.imread('slice.png')

# Convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Threshold the image to create a binary image
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)

# Find the outer contours in the binary image (using cv2.RETR_EXTERNAL)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Create a blank image with the same dimensions as the original image
filled_img = np.zeros(img.shape[:2], dtype=np.uint8)

# Fill the outer contour with white color
cv2.drawContours(filled_img, contours, -1, 255, cv2.FILLED)

# Find contours with hierarchy, this time use cv2.RETR_TREE
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Iterate over the contours and their hierarchies
for i, contour in enumerate(contours):
    # Check if the contour has no child
    if hierarchy[0][i][2] < 0:
        # If contour has no child, fill the contour with black color
        cv2.drawContours(filled_img, [contour], -1, 0, cv2.FILLED)

# Display the result
cv2.imshow('Original Image', img)
cv2.imshow('Filled Regions', filled_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果filled_img

注:
在我们不知道最内部轮廓的颜色的情况下,我们可以在黑色背景上绘制白色轮廓,并且使用结果作为掩模-使用掩模来复制输入图像的原始内容。

更新:

支持没有子对象的轮廓:
为了同时支持有子元素的轮廓和没有子元素的轮廓,我们可以用黑色填充,只填充匹配这两个条件的轮廓:

  • 轮廓没有子轮廓。
  • 轮廓具有祖轮廓(查找祖轮廓而不是父轮廓,因为空轮廓具有内部轮廓,其父轮廓是外部轮廓)。

代码示例:

import numpy as np
import cv2

# Load the PNG image
img = cv2.imread('slice.png')

# Convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Threshold the image to create a binary image
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)

# Find the outer contours in the binary image (using cv2.RETR_EXTERNAL)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Create a blank image with the same dimensions as the original image
filled_img = np.zeros(img.shape[:2], dtype=np.uint8)

# Fill the outer contour with white color
cv2.drawContours(filled_img, contours, -1, 255, cv2.FILLED)

# Find contours with hierarchy, this time use cv2.RETR_TREE
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Iterate over the contours and their hierarchies
for i, contour in enumerate(contours):
    has_grandparent = False
    has_parent = hierarchy[0][i][3] >= 0
    if has_parent:
        # Check if contour has a grandparent
        parent_idx = hierarchy[0][i][3]
        has_grandparent = hierarchy[0][parent_idx][3] >= 0

    # Check if the contour has no child
    if hierarchy[0][i][2] < 0 and has_grandparent:
        # If contour has no child, fill the contour with black color
        cv2.drawContours(filled_img, [contour], -1, 0, cv2.FILLED)

# Display the result
cv2.imshow('Original Image', img)
cv2.imshow('Filled Regions', filled_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

相关问题