官网参见https://docs.opencv.org/3.4.1/d5/d45/tutorial_py_contours_more_functions.html
我们已经了解过凸包概念https://blog.csdn.net/weixin_42555985/article/details/97115338。
物体和凸包之间的任何偏差就称为凸缺陷。
opencv提供cv.convexityDefects()函数找到凸缺陷。
调用方式如下:
hull = cv.convexHull(cnt,returnPoints = False)
defects = cv.convexityDefects(cnt,hull)
cv.convexHull()函数获取凸包,其中cnt是利用cv2.findContours()函数获取的轮廓。
cv.convexityDefects()函数就是把cnt轮廓和hull凸包进行比较,获得凸缺陷。
为了找到凸缺陷,convexHull()函数必须传入returnPoints = False
函数返回一个数组,每一行包含的值是:起始点,终点,最远的点,最远点的近似距离。我们可以在图像中显示它。起点和终点画一根直线,然后在最远的点画个圆。
注意:返回值是轮廓的索引点,可以在cnt中找到对应的值。
例,找到凸缺陷
# -*- coding: cp936 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('defects.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(img_gray, 127, 255,0)
im2,contours,hierarchy = cv2.findContours(thresh,2,1)
cnt = contours[0]
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)
for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
cv2.line(img,start,end,[0,255,0],2)
cv2.circle(img,far,5,[0,0,255],-1)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
这个函数用于找到图像中的点到轮廓的最短距离。
如果返回负值,表示点在轮廓外部;如果是正值,表示点在轮廓内部;0,表示在轮廓上。
假设我们要检查点(50,50)的距离
dist = cv.pointPolygonTest(cnt,(50,50),True)
函数的第三个参数measureDist,如果是True,表示计算最短距离;如果是False,表示判断点和轮廓的位置关系,返回1,-1,0。
如果不需要知道距离,可以把这个参数设置为False。这样可以解决计算速度,大约可以提高2-3倍。
3.形状匹配
opencv提供 cv.matchShapes() 函数来对比2个图形或者轮廓,并返回相似度。返回值越小,表示越相似。它是基于**hu矩(hu-moment)**值来计算的。
例1,测试形状匹配-自己匹配自己
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('defects.jpg',0)
img2 = cv2.imread('defects.jpg',0)
ret, thresh = cv2.threshold(img, 127, 255,0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
im,contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
im2,contours2,hierarchy = cv2.findContours(thresh2,2,1)
cnt2 = contours2[0]
ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print ret
我们导入上面图像,然后自己和自己匹配,结果为0.0,显然是完全匹配的。
例2,测试形状匹配–近似图形
这次我们尝试把下面心形和上面那个图匹配。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('defects.jpg',0)
img2 = cv2.imread('7.jpg',0)
ret, thresh = cv2.threshold(img, 127, 255,0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
im,contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
im2,contours2,hierarchy = cv2.findContours(thresh2,2,1)
cnt2 = contours2[0]
ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print ret
结果为0.00726087928139
例3,测试形状匹配–差别很大图形
这次我们尝试把下面矩形和例1的那个图心形匹配。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('defects.jpg',0)
img2 = cv2.imread('8.jpg',0)
ret, thresh = cv2.threshold(img, 127, 255,0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
im,contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
im2,contours2,hierarchy = cv2.findContours(thresh2,2,1)
cnt2 = contours2[0]
ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print ret
结果0.330222004794,明显比2个心形之间比较差多了。
同时还可以发现,例1和例2的2个心形之间匹配,没有因为例2的图形发生的旋转而降低。
对于形状匹配来说,我们希望计算出来的矩具有平移不变性,旋转不变性,尺度不变性,hu矩就可以满足这一要求。
hu矩是7个数字的组合,每个数字都是利用central moments计算得来,前6个被证明包含平移不变性,旋转不变性,尺度不变性和翻转不变性,第7个的符号与图像翻转有关(如果一个形状是另一个的镜像图像,那么他们的hu矩中第七个数字相同,符号是相反的)。
opencv中提供cv.HuMoments()函数来获得hu矩。