如何在OpenCV中区分实心圆/轮廓和未实心圆/轮廓?

时间:2020-02-06 12:55:16

标签: python image opencv image-processing computer-vision

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

Fig: example circle/contour

1 个答案:

答案 0 :(得分:6)

要区分填充轮廓和未填充轮廓,可以在使用cv2.findContours查找轮廓时使用轮廓层次。具体来说,您可以选择contour retrieval mode,以选择返回包含有关图像拓扑信息的输出向量。有四种可能的模式:

  • cv2.RETR_EXTERNAL-仅检索极端的外部轮廓(无层次)
  • cv2.RETR_LIST-在不建立任何层次关系的情况下检索所有轮廓
  • cv2.RETR_CCOMP-检索所有轮廓并将其组织为两级层次结构。在顶层,组件具有外部边界。在第二层,有孔的边界。如果所连接组件的孔内还有其他轮廓,则该轮廓仍将放置在顶层
  • cv2.RETR_TREE-检索所有轮廓并重建嵌套轮廓的完整层次结构

了解轮廓层次

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

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

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

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

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

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

cv2.RETR_TREE

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

的内容
hierarchy

第一个轮廓的输入为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,并且该轮廓没有父级(不包含轮廓这个)。我们可以将[6, -1, 1, -1]数组中的信息可视化为七棵树,图像中每个骰子都一棵。

enter image description here

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


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

enter image description here

结果

enter image description here

代码

hierarchy