使用OpenCV从轮廓构建嵌套掩码

huangapple go评论72阅读模式
英文:

Building nested mask from contours with openCV

问题

以下是翻译好的代码部分:

import cv2
import numpy as np
import matplotlib.pyplot as plt

test_im = cv2.imread("contours.png")
im_gray = cv2.cvtColor(test_im, cv2.COLOR_RGB2GRAY)

# 使用OpenCV查找轮廓和层次关系
cnts, hierarchy = cv2.findContours(im_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = np.array(cnts)

mask = np.zeros_like(test_im)

# 使用cv2.fillPoly从轮廓绘制嵌套掩码
for i, cnt in enumerate(cnts):

    # 寻找外部轮廓
    if hierarchy[0][i][3] == -1:
        cnt = cnt.reshape((cnt.shape[0], 2))
        # 填充外部轮廓
        cv2.fillPoly(mask, [cnt], 255)
        
        # 寻找孙子轮廓并用零填充它们(得到嵌套掩码作为输出)
        child_ix = hierarchy[0][i][2]
        same_level_ix = hierarchy[0][child_ix][0]
        
        # 由于某种原因,外部轮廓有两个子轮廓
        # (根据我的理解,应该只有一个)
        if same_level_ix == -1:
            grandchild_ix = hierarchy[0][child_ix][2]
        else:
            child_ix = hierarchy[0][child_ix][2]
            grandchild_ix = hierarchy[0][same_level_ix][2]

        if grandchild_ix != -1:
            cnt = cnts[grandchild_ix]
            cnt = cnt.reshape((cnt.shape[0], 2))
            cv2.fillPoly(mask, [cnt], 0)
            same_level_ix = hierarchy[0][grandchild_ix][0]
            
            while same_level_ix != -1:
                cnt = cnts[same_level_ix]
                cnt = cnt.reshape((cnt.shape[0], 2))
                cv2.fillPoly(mask, [cnt], 0)
                same_level_ix = hierarchy[0][same_level_ix][0]

希望对您有所帮助。如果您有任何其他问题,请随时提出。

英文:

I'd like to build a nested mask (mask with holes) from contours that I've drawn.

The input contour image is attached to this message - called contours.png -, and here is the code I used to build my nested mask.

import cv2
import numpy as np
import matplotlib.pyplot as plt

test_im = cv2.imread("contours.png")
im_gray = cv2.cvtColor(test_im, cv2.COLOR_RGB2GRAY)

# find contours and hierarchy with OpenCV 
cnts, hierachy = cv2.findContours(im_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = np.array(cnts)

mask = np.zeros_like(test_im)

# draw nested mask from contours using cv2.fillPoly
for i, cnt in enumerate(cnts):

    # look for external contours
    if hierachy[0][i][3] == -1:
        cnt = cnt.reshape((cnt.shape[0], 2))
        # fill the external contour entirely
        cv2.fillPoly(mask, [cnt], 255)
        
        # look for grandchild contours to fill them with zeros (and have a nested mask as output)
        child_ix = hierachy[0][i][2]
        same_level_ix = hierachy[0][child_ix][0]
        
        # for an akward reason, the extrenal contour has two child contours
        # (should get only one in my understanding)
        if same_level_ix == -1:
            grandchild_ix = hierachy[0][child_ix][2]
        else:
            child_ix = hierachy[0][child_ix][2]
            grandchild_ix = hierachy[0][same_level_ix][2]

        if grandchild_ix != -1:
            cnt = cnts[grandchild_ix]
            cnt = cnt.reshape((cnt.shape[0], 2))
            cv2.fillPoly(mask, [cnt], 0)
            same_level_ix = hierachy[0][grandchild_ix][0]
            
            while same_level_ix != -1:
                cnt = cnts[same_level_ix]
                cnt = cnt.reshape((cnt.shape[0], 2))
                cv2.fillPoly(mask, [cnt], 0)
                same_level_ix = hierachy[0][same_level_ix][0]

Even if it works on this example, my code doesn't seem really robust. Additionaly, I found that the external contour has two child contours which is weird to me: should get only one in my understanding.

Do you have any better solution ?

Thanks for your help, have a nice day !

contours.png

desired_output

答案1

得分: 0

基于层次结构设置,您可以通过制作2个蒙版并相减来获得结果。第一个蒙版是通过填充最外层的轮廓而完成的,第二个蒙版是通过填充最内层的轮廓而完成的:

使用OpenCV从轮廓构建嵌套掩码

这是提取轮廓并填充它们所需的设置(代码是C ++,但设置与Python等效):

Mat img__1, img__2, img__ = imread("E:/img.jpg", 0);

threshold(img__, img__1, 0, 255, THRESH_BINARY);

vector<vector<Point>> contours;
vector<Vec4i> hierarchy;

findContours(img__1, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);

Mat tmp = Mat::zeros(img__1.size(), CV_8U);
Mat tmp2 = Mat::zeros(img__1.size(), CV_8U);

for (size_t i = 0; i < contours.size(); i++)
    if (hierarchy[i][3] < 0)
        drawContours(tmp, contours, i, Scalar(255, 255, 255), -1); # 第一个蒙版

for (size_t i = 0; i < contours.size(); i++)
    if (hierarchy[i][2] < 0 && hierarchy[i][3] > -1)
        drawContours(tmp2, contours, i, Scalar(255, 255, 255), -1); # 第二个蒙版

imshow("img", img__1);
imshow("first_mask", tmp);
imshow("second_mask", tmp2);

tmp = tmp - tmp2;  # 相减两个蒙版以去除空洞

imshow("final image", tmp);
waitKey(0);
英文:

Based on the hierarchy settings, you can get the result by making 2 mask, and subtracting them. First mask is done by filling the outermost contour, and the second mask is done by filling the innermost contours:

使用OpenCV从轮廓构建嵌套掩码

Here is the necessary setting for extracting contours and filling them (the code in c++ but the settings are equivalent with python):

Mat img__1, img__2,img__ = imread(&quot;E:/img.jpg&quot;, 0);

threshold(img__, img__1, 0, 255, THRESH_BINARY);

vector&lt;vector&lt;Point&gt;&gt; contours;
vector&lt; Vec4i &gt; hierarchy;

findContours(img__1, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);

Mat tmp = Mat::zeros(img__1.size(), CV_8U);
Mat tmp2 = Mat::zeros(img__1.size(), CV_8U);

for (size_t i = 0; i &lt; contours.size(); i++)
	if (hierarchy[i][3]&lt;0)
		drawContours(tmp, contours, i, Scalar(255, 255, 255), -1); # first mask

for (size_t i = 0; i &lt; contours.size(); i++)
	if (hierarchy[i][2]&lt;0 &amp;&amp; hierarchy[i][3]&gt;-1)
		drawContours(tmp2, contours, i, Scalar(255, 255, 255), -1); # second mask

imshow(&quot;img&quot;, img__1);
imshow(&quot;first_mask&quot;, tmp);
imshow(&quot;second_mask&quot;, tmp2);

tmp = tmp - tmp2;  # subtracting the two masks to remove the holes

imshow(&quot;final image&quot;, tmp);
waitKey(0);

huangapple
  • 本文由 发表于 2020年1月3日 19:05:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/59577466.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定