-
Notifications
You must be signed in to change notification settings - Fork 2
/
opencv笔记015:点到轮廓的距离_轮廓相似度和轮廓检索模式.py
167 lines (127 loc) · 6.77 KB
/
opencv笔记015:点到轮廓的距离_轮廓相似度和轮廓检索模式.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#http://www.cnblogs.com/Undo-self-blog/p/8438808.html
import cv2
import numpy as np
def f(contours): #求轮廓列表里点最多的轮廓
x=0
p=0
for i in range(len(contours)):
if len(contours[i])>p:
x=i
p=len(contours[i])
return x
yz=122
img1 = cv2.imread('4.jpg')
img = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
img=cv2.bitwise_not(img)
ret,thresh = cv2.threshold(img,yz,255,0)
kernel = np.ones((15,15),np.uint8)
thresh=cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
thresh=cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) #各种初始化
image,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,3) #获取轮廓列表
xx=f(contours)
cnt = contours[xx]
hull = cv2.convexHull(cnt)
img1=cv2.drawContours(img1,[hull],-1,(255,0,0),5)
cv2.imwrite('a.jpg',img1)
'''
Point Polygon Test
求解图像中的一个点到一个对象轮廓的最短距离。如果点在轮廓的外部,
返回值为负。如果在轮廓上,返回值为 0。如果在轮廓内部,返回值为正。
下面我们以点(50,50)为例:
dist = cv2.pointPolygonTest(cnt,(50,50),True)
此函数的第三个参数是 measureDist。如果设置为 True,就会计算最短距离。
如果是 False,只会判断这个点与轮廓之间的位置关系(返回值为+1,-1,0)。
注意:如果你不需要知道具体距离,建议你将第三个参数设为 False,这样速度会提高 2 到 3 倍。
'''
dist = cv2.pointPolygonTest(cnt,(50,50),False)
#求中点到轮廓的距离
a=hull[hull[:,:,0].argmax(),:,:]/2+hull[hull[:,:,0].argmin(),:,:]/2
a=np.int0(a)
dist=cv2.pointPolygonTest(cnt,tuple(a.tolist()[0]),1)
'''
形状匹配
函数 cv2.matchShape() 可以帮我们比较两个形状或轮廓的相似度。如果返回值越小,匹配越好。
它是根据 Hu 矩来计算的。文档中对不同的方法都有解释。我们试着将下面的图形进行比较
'''
ret1 = cv2.matchShapes(cnt,cnt,1,0.0) #和自己比较,返回0
ret2 = cv2.matchShapes(cnt1,cnt2,1,0.0) #这里没有cnt1和cnt2,只是做个示范
'''
21.5.3 轮廓检索模式
RETR_LIST
从解释的角度来看,这中应是最简单的。它只是提取所有的轮廓,而不去创建任何父子关系。
换句话说就是“人人平等”,它们属于同一级组织轮廓。
所以在这种情况下,组织结构数组的第三和第四个数都是 -1。但是,很明显,Next 和 Previous 要有对应的值,
你可以自己试着看看。
下面就是我得到的结果,每一行是对应轮廓的组织结构细节。例如,第一行对应的是轮廓 0。
下一个轮廓为 1,所以 Next=1。前面没有其他轮廓,所以 Previous=0。接下来的两个参数就是 -1,与刚才我们说的一样。
复制代码
>>> hierarchy
array([[[ 1, -1, -1, -1],
[ 2, 0, -1, -1],
[ 3, 1, -1, -1],
[ 4, 2, -1, -1],
[ 5, 3, -1, -1],
[ 6, 4, -1, -1],
[ 7, 5, -1, -1],
[-1, 6, -1, -1]]])
复制代码
如果你不关心轮廓之间的关系,这是一个非常好的选择。
RETR_EXTERNAL
如果你选择这种模式的话,只会返回最外边的的轮廓,所有的子轮廓都会被忽略掉。
所以在上图中使用这种模式的话只会返回最外边的轮廓(第 0 级):轮廓0,1,2。下面是我选择这种模式得到的结果:
>>> hierarchy
array([[[ 1, -1, -1, -1],
[ 2, 0, -1, -1],
[-1, 1, -1, -1]]])
当你只想得到最外边的轮廓时,你可以选择这种模式。这在有些情况下很有用。
RETR_CCOMP
在这种模式下会返回所有的轮廓并将轮廓分为两级组织结构。例如,一个对象的外轮廓为第 1 级组织结构。
而对象内部中空洞的轮廓为第 2 级组织结构,空洞中的任何对象的轮廓又是第 1 级组织结构。空洞的组织结构为第 2 级。
想象一下一副黑底白字的图像,图像中是数字 0。0 的外边界属于第一级组织结构,0 的内部属于第 2 级组织结构。
我们可以以下图为例简单介绍一下。我们已经用红色数字为这些轮廓编号,并用绿色数字代表它们的组织结构。
顺序与 OpenCV 检测轮廓的顺序一直。
CCOMP Hierarchy
现在我们考虑轮廓 0,它的组织结构为第 1 级。其中有两个空洞 1 和 2,它们属于第 2 级组织结构。
所以对于轮廓 0 来说跟他属于同一级组织结构的下一个(Next)是轮廓 3,并且没有 Previous。
它的 Fist_Child 为轮廓 1,组织结构为 2。由于它是第 1 级,所以没有父轮廓。
因此它的组织结构数组为[3,-1,1,-1]。
现在是轮廓 1,它是第 2 级。处于同一级的下一个轮廓为 2。没有 Previous,也没有 Child,
(因为是第 2 级所以有父轮廓)父轮廓是 0。所以数组是[2,-1,-1,0]。
轮廓 2:它是第 2 级。在同一级的组织结构中没有 Next。Previous 为轮廓 1。
没有子,父轮廓为 0,所以数组是 [-1,1,-1,0]
轮廓 3:它是第 1 级。在同一级的组织结构中 Next 为 5。Previous 为轮廓 0。
子为 4,没有父轮廓,所以数组是 [5,0,4,-1]轮廓 4:它是第 2 级。
在同一级的组织结构中没有 Next。没有 Previous,没有子,父轮廓为 3,所以数组是 [-1,-1,-1,3]
下面是我得到的答案:
复制代码
>>> hierarchy
array([[[ 3, -1, 1, -1],
[ 2, -1, -1, 0],
[-1, 1, -1, 0],
[ 5, 0, 4, -1],
[-1, -1, -1, 3],
[ 7, 3, 6, -1],
[-1, -1, -1, 5],
[ 8, 5, -1, -1],
[-1, 7, -1, -1]]])
复制代码
RETR_TREE
终于到最后一个了,也是最完美的一个。这种模式下会返回所有轮廓,并且创建一个完整的组织结构列表。
它甚至会告诉你谁是爷爷,爸爸,儿子,孙子等。
还是以上图为例,使用这种模式,对 OpenCV 返回的结果重新排序并分析它,红色数字是边界的序号,绿色是组织结构。
CCOMP Hierarchy
轮廓 0 的组织结构为 0,同一级中 Next 为 7,没有 Previous。子轮廓是 1,没有父轮廓。所以数组是 [7,-1,1,-1]。
轮廓 1 的组织结构为 1,同一级中没有其他,没有 Previous。子轮廓是2,父轮廓为 0。所以数组是 [-1,-1,2,0]。
剩下的自己试试计算一下吧。下面是结果:
复制代码
>>> hierarchy
array([[[ 7, -1, 1, -1],
[-1, -1, 2, 0],
[-1, -1, 3, 1],
[-1, -1, 4, 2],
[-1, -1, 5, 3],
[ 6, -1, -1, 4],
[-1, 5, -1, 4],
[ 8, 0, -1, -1],
[-1, 7, -1, -1]]])
'''