使用 openCV 从轮廓构建嵌套掩码
Building nested mask from contours with openCV
我想根据我绘制的轮廓构建一个嵌套蒙版(带孔的蒙版)。
输入轮廓图像附加到此消息 - 称为 contours.png -,这是我用来构建嵌套掩码的代码。
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]
即使它适用于此示例,我的代码似乎也不是很可靠。另外,我发现外部轮廓有两个子轮廓,这对我来说很奇怪:在我的理解中应该只有一个。
你有更好的解决办法吗?
感谢您的帮助,祝您愉快!
contours.png
desired_output
根据hierarchy设置,可以做2个mask,然后相减得到结果。第一个掩码是通过填充最外层的轮廓来完成的,第二个掩码是通过填充最内层的轮廓来完成的:
这里是抽取轮廓和填充轮廓的必要设置(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); # first mask
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); # second mask
imshow("img", img__1);
imshow("first_mask", tmp);
imshow("second_mask", tmp2);
tmp = tmp - tmp2; # subtracting the two masks to remove the holes
imshow("final image", tmp);
waitKey(0);
我想根据我绘制的轮廓构建一个嵌套蒙版(带孔的蒙版)。
输入轮廓图像附加到此消息 - 称为 contours.png -,这是我用来构建嵌套掩码的代码。
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]
即使它适用于此示例,我的代码似乎也不是很可靠。另外,我发现外部轮廓有两个子轮廓,这对我来说很奇怪:在我的理解中应该只有一个。
你有更好的解决办法吗?
感谢您的帮助,祝您愉快!
contours.png
desired_output
根据hierarchy设置,可以做2个mask,然后相减得到结果。第一个掩码是通过填充最外层的轮廓来完成的,第二个掩码是通过填充最内层的轮廓来完成的:
这里是抽取轮廓和填充轮廓的必要设置(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); # first mask
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); # second mask
imshow("img", img__1);
imshow("first_mask", tmp);
imshow("second_mask", tmp2);
tmp = tmp - tmp2; # subtracting the two masks to remove the holes
imshow("final image", tmp);
waitKey(0);