简体   繁体   English

如何在 Python OpenCV 中删除轮廓内的轮廓?

[英]How to remove a contour inside contour in Python OpenCV?

OpenCV in Python provides the following code: Python 中的 OpenCV 提供以下代码:

regions, hierarchy = cv2.findContours(binary_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)


for region in regions:
    x, y, w, h = cv2.boundingRect(region)

    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 1)

This gives some contours within contour.这给出了轮廓内的一些轮廓。 How to remove them in Python?如何在 Python 中删除它们?

For that, you should take a look at this tutorial on how to use the hierarchy object returned by the method findContours .为此,您应该查看本教程,了解如何使用findContours方法返回的hierarchy对象。

The main point is that you should use cv2.RETR_TREE instead of cv2.RETR_LIST to get parent/child relationships between your clusters:要点是您应该使用cv2.RETR_TREE而不是cv2.RETR_LIST来获取集群之间的父/子关系:

regions, hierarchy = cv2.findContours(binary_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

Then you can check whether a contour with index i is inside another by checking if hierarchy[0,i,3] equals -1 or not.然后,您可以通过检查hierarchy[0,i,3]是否等于 -1 来检查索引为i的轮廓是否在另一个轮廓内。 If it is different from -1, then your contour is inside another.如果它不同于-1,那么你的轮廓在另一个里面。

In order to remove the contours inside a contour:为了删除轮廓内的轮廓:

shapes, hierarchy = cv2.findContours(image=image, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE)

However, in some cases you may observe that a big contour is formed on the whole image, and applying the above returns you that one big contour.但是,在某些情况下,您可能会观察到整个图像上形成了一个大轮廓,并且应用上述内容会返回一个大轮廓。

In order to avoid this, try inverting the image:为了避免这种情况,请尝试反转图像:

image = cv2.imread("Image Path")
image = 255 - image
shapes, hierarchy = cv2.findContours(image=image, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE)

This will give you the desired result.这将为您提供所需的结果。

UPDATE:更新:

The reason why hierarchy does not work if a big bounding box is approximated on the whole image is that the output of hierarchy[0,iteration,3] is -1 only for the one bounding box drawn on the whole image, as all other bounding boxes are inside this big bounding box, and hierarchy[0,iteration,3] is not equal to -1 for any of them.如果在整个图像上近似一个大边界框,层次结构不起作用的原因是, hierarchy[0,iteration,3]的输出仅对于绘制在整个图像上的一个边界框为-1 ,与所有其他边界一样框在这个大边界框内,其中任何一个的hierarchy[0,iteration,3]都不等于-1 Thus, inverting the image will be required in order to comply with the following:因此,将需要反转图像以符合以下要求:

In OpenCV, finding contours is like finding white object from black background.在 OpenCV 中,寻找轮廓就像从黑色背景中寻找白色物体。 So remember, object to be found should be white and background should be black.所以请记住,要找到的对象应该是白色的,背景应该是黑色的。

However, as pointed out by @Jeru, this is not a generalized solution and one must visualize the image before inverting it.但是,正如@Jeru 所指出的,这不是一个通用的解决方案,必须在反转图像之前将其可视化。 Consider this image:考虑这张图片: 在此处输入图像描述

Running跑步

shapes, hierarchy = cv2.findContours(image=image, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)

results in结果是

在此处输入图像描述

Now, only displaying the contour with hierarchy[0,iteration,3] = -1 results in现在,仅显示具有hierarchy[0,iteration,3] = -1的轮廓会导致

在此处输入图像描述

which is not correct.这是不正确的。 If we want to obtain the rectangle containing the shapes and the text shapes , we can do如果我们想获得包含形状和文本形状的矩形,我们可以这样做

image = 255 - image
shapes, hierarchy = cv2.findContours(image=thresh, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE)

In this case we get:在这种情况下,我们得到:

在此处输入图像描述

Code:代码:

import cv2
from easyocr import Reader
import math


shape_number = 2

image = cv2.imread("Image Path")
deep_copy = image.copy()

image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(image_gray, 210, 255, cv2.THRESH_BINARY)
thresh = 255 - thresh

shapes, hierarchy = cv2.findContours(image=thresh, mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(image=deep_copy, contours=shapes, contourIdx=-1, color=(0, 255, 0), thickness=2, lineType=cv2.LINE_AA)

for iteration, shape in enumerate(shapes):

        if hierarchy[0,iteration,3] == -1:
                print(hierarchy[0,iteration,3])
                print(iteration)

cv2.imshow('Shapes', deep_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
img_output, contours, hierarchy = cv2.findContours(blank_image_firstImage, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

这将删除子轮廓

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM