如何在OpenCV中区分实心圆/轮廓和未实心圆/轮廓? [英] How to distinguish filled circle/contour and unfilled circle/contour in OpenCV?

查看:264
本文介绍了如何在OpenCV中区分实心圆/轮廓和未实心圆/轮廓?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法区分以下两个轮廓. cv2.contourArea两者的值相同.在Python中有什么功能可以区分它们吗?

I am unable to differentiate the below two contours. cv2.contourArea is giving the same value for both. Is there any function to distinguish them in Python?

推荐答案

要区分填充轮廓和未填充轮廓,可以在使用轮廓检索模式选择为(可选)返回包含有关图像拓扑信息的输出向量.有四种可能的模式:

To distinguish between a filled contour and unfilled contour, you can use contour hierarchy when finding contours with cv2.findContours. Specifically, you can select the contour retrieval mode to optionally return an output vector containing information about the image topology. There are the four possible modes:

  • cv2.RETR_EXTERNAL-仅检索极端的外部轮廓(无层次)
  • cv2.RETR_LIST-检索所有轮廓而无需建立任何层次关系
  • cv2.RETR_CCOMP-检索所有轮廓并将其组织为两级层次结构.在顶层,组件具有外部边界.在第二层,有孔的边界.如果所连接组件的孔内还有其他轮廓,则该轮廓仍将放置在顶层
  • cv2.RETR_TREE-检索所有轮廓并重建嵌套轮廓的完整层次结构
  • cv2.RETR_EXTERNAL - retrieves only the extreme outer contours (no hierarchy)
  • cv2.RETR_LIST - retrieves all of the contours without establishing any hierarchical relationships
  • cv2.RETR_CCOMP - retrieves all of the contours and organizes them into a two-level hierarchy. At the top level, there are external boundaries of the components. At the second level, there are boundaries of the holes. If there is another contour inside a hole of a connected component, it is still put at the top level
  • cv2.RETR_TREE - retrieves all of the contours and reconstructs a full hierarchy of nested contours

了解轮廓层次

因此有了这些信息,我们可以使用cv2.RETR_CCOMPcv2.RETR_TREE返回层次结构列表.以这张图片为例:

So with this information, we can use cv2.RETR_CCOMP or cv2.RETR_TREE to return a hierarchy list. Take for example this image:

当使用cv2.RETR_TREE参数时,轮廓按层次结构排列,每个对象的最外轮廓在顶部.在层次结构中向下移动,轮廓的每个新级别代表每个对象的下一个最内轮廓.在上面的图像中,图像中的轮廓被着色以表示返回轮廓数据的层次结构.最外面的轮廓是红色的,它们在层次结构的顶部.接下来的最里面的轮廓-在这种情况下是骰子点-是绿色的.

When we use the cv2.RETR_TREE parameter, the contours are arranged in a hierarchy, with the outermost contours for each object at the top. Moving down the hierarchy, each new level of contours represents the next innermost contour for each object. In the image above, the contours in the image are colored to represent the hierarchical structure of the returned contours data. The outermost contours are red, and they are at the top of the hierarchy. The next innermost contours -- the dice pips, in this case -- are green.

我们可以从cv2.findContours函数调用中通过层次结构数组获取有关轮廓层次结构的信息.假设我们这样调用函数:

We can get that information about the contour hierarchies via the hierarchy array from the cv2.findContours function call. Suppose we call the function like this:

(_, contours, hierarchy) = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

第三个返回值(保存在此代码的hierarchy变量中)是三维NumPy数组,具有一行,X列和深度"为4.X列对应该功能找到的轮廓数量. cv2.RETR_TREE参数使函数查找每个对象的内部轮廓和最外面的轮廓.列0对应第一个轮廓,列1对应第二个轮廓,依此类推.

The third return value, saved in the hierarchy variable in this code, is a three-dimensional NumPy array, with one row, X columns, and a "depth" of 4. The X columns correspond to the number of contours found by the function. The cv2.RETR_TREE parameter causes the function to find the internal contours as well as the outermost contours for each object. Column zero corresponds to the first contour, column one the second, and so on.

根据此方案,每列都有四元素整数数组,表示其他轮廓的索引:

Each of the columns has a four-element array of integers, representing indices of other contours, according to this scheme:

[next, previous, first child, parent]

下一个索引引用此轮廓的层次结构级别中的下一个轮廓,而上一个索引引用此轮廓的层次结构级别中的上一个轮廓. 第一个子项索引是指包含在该轮廓内部的第一个轮廓. parent 索引是指包含该轮廓的轮廓.在所有情况下,值-1表示没有下一个上一个第一个孩子父项轮廓,视情况而定.对于更具体的示例,这是一些示例hierarchy值.值在方括号中,轮廓的索引在每个条目之前. 如果您打印出层次结构数组,您将得到类似

The next index refers to the next contour in this contour's hierarchy level, while the previous index refers to the previous contour in this contour's hierarchy level. The first child index refers to the first contour that is contained inside this contour. The parent index refers to the contour containing this contour. In all cases, an value of -1 indicates that there is no next, previous, first child, or parent contour, as appropriate. For a more concrete example, here are some example hierarchy values. The values are in square brackets, and the indices of the contours precede each entry. If you printed out the hierarchy array you will get something like this

0:  [ 6 -1  1 -1]   18: [19 -1 -1 17]
1:  [ 2 -1 -1  0]   19: [20 18 -1 17]
2:  [ 3  1 -1  0]   20: [21 19 -1 17]
3:  [ 4  2 -1  0]   21: [22 20 -1 17]
4:  [ 5  3 -1  0]   22: [-1 21 -1 17]
5:  [-1  4 -1  0]   23: [27 17 24 -1]
6:  [11  0  7 -1]   24: [25 -1 -1 23]
7:  [ 8 -1 -1  6]   25: [26 24 -1 23]
8:  [ 9  7 -1  6]   26: [-1 25 -1 23]
9:  [10  8 -1  6]   27: [32 23 28 -1]
10: [-1  9 -1  6]   28: [29 -1 -1 27]
11: [17  6 12 -1]   29: [30 28 -1 27]
12: [15 -1 13 11]   30: [31 29 -1 27]
13: [14 -1 -1 12]   31: [-1 30 -1 27]
14: [-1 13 -1 12]   32: [-1 27 33 -1]
15: [16 12 -1 11]   33: [34 -1 -1 32]
16: [-1 15 -1 11]   34: [35 33 -1 32]
17: [23 11 18 -1]   35: [-1 34 -1 32]

第一个轮廓的输入是[6, -1, 1, -1].这代表最外面的轮廓中的第一个;请注意,轮廓没有特定的顺序,例如默认情况下它们不会从左到右存储.该条目告诉我们,下一个骰子轮廓是索引为6的轮廓,列表中没有先前的轮廓,该轮廓内的第一个轮廓的索引为1,并且该轮廓没有父级(不包含轮廓这个).我们可以将hierarchy数组中的信息可视化为七棵树,图像中每个骰子都一棵.

The entry for the first contour is [6, -1, 1, -1]. This represents the first of the outermost contours; note that there is no particular order for the contours, e.g., they are not stored left to right by default. The entry tells us that the next dice outline is the contour with index six, that there is no previous contour in the list, that the first contour inside this one has index one, and that there is no parent for this contour (no contour containing this one). We can visualize the information in the hierarchy array as seven trees, one for each of the dice in the image.

七个最外面的轮廓是所有没有父级的轮廓,即在hierarchy条目的第四个字段中值为-1的轮廓. 根"之一下方的每个子节点代表最外轮廓内部的轮廓.注意在图中轮廓13和14如何在轮廓12下方.这两个轮廓代表最里面的轮廓,可能是噪点或某一点的油漆丢失.一旦了解了轮廓是如何排列到层次结构中的,就可以执行更复杂的任务,例如计算形状中轮廓的数量以及图像中对象的数量.

The seven outermost contours are all those that have no parent, i.e., those with an value of -1 in the fourth field of their hierarchy entry. Each of the child nodes beneath one of the "roots" represents a contour inside the outermost contour. Note how contours 13 and 14 are beneath contour 12 in the diagram. These two contours represent the innermost contours, perhaps noise or some lost paint in one of the pips. Once we understand how contours are arranged into a hierarchy, we can perform more sophisticated tasks, such as counting the number of contours within a shape in addition to the number of objects in an image.

回到您的问题,我们可以使用层次结构来区分内部轮廓和外部轮廓,以确定轮廓是已填充还是未填充.我们可以将填充轮廓定义为没有子级的轮廓,而将未填充轮廓定义为至少一个子级的轮廓.因此,使用您的输入图像的屏幕截图(删除了该框):

Going back to your question, we can use hierarchy to distinguish between inner and outer contours to determine if a contour is filled or unfilled. We can define a filled contour as a contour with no child whereas a unfilled contour as at least one child. So with this screenshot of your input image (removed the box):

结果

代码

import cv2
import numpy as np

# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Filter using contour hierarchy
cnts, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
hierarchy = hierarchy[0]
for component in zip(cnts, hierarchy):
    currentContour = component[0]
    currentHierarchy = component[1]
    x,y,w,h = cv2.boundingRect(currentContour)
    # Has inner contours which means it is unfilled
    if currentHierarchy[3] > 0:
        cv2.putText(image, 'Unfilled', (x,y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (36,255,12), 2)
    # No child which means it is filled
    elif currentHierarchy[2] == -1:
        cv2.putText(image, 'Filled', (x,y-5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (36,255,12), 2)

cv2.imshow('image', image)
cv2.waitKey()

这篇关于如何在OpenCV中区分实心圆/轮廓和未实心圆/轮廓?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆