内容来自OpenCV-Python Tutorials 自己翻译整理
目标
如何找到凸缺陷
某一点到多边形的最短距离
不同形状匹配
凸缺陷
在目标图形上的任何凹陷都可以被看作凸缺陷,在Opencv中有cv2.convexityDefects()函数可以找到凸缺陷。
import cv2
import numpy as np
img = cv2.imread('11.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
im,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()
查找凸缺陷时的hull要用参数returnPoints = False
defects 为一个数组,每行包含[起点,终点,最远点,到最远点的近似距离]
起点和终点用绿线连接,最远点画个红圈。
返回值的值是轮廓的索引
点与多边形测试
求解图像一个点到一个目标轮廓的最短距离,点在轮廓外部返回负值,在轮廓上返回0,轮廓内部返回正值。
import cv2
import numpy as np
img = cv2.imread('11.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
im,contours,hierarchy = cv2.findContours(thresh,2,1)
cnt = contours[0]
dist = cv2.pointPolygonTest(cnt,(50,50),True)
print(dist)
pointPolygonTest函数的第三个参数是measureDist设置为 True会计算最
短距离,如果是 False,只会判断这个点与轮廓之间的位置关系(返回值为
+1,-1,0)。
如果不知道具体距离,建议将第三个参数设置为False,速度回提升2至3倍
形状匹配
cv2.matchShape可以比较两个轮廓的相似程度,返回值越小,越匹配。
计算方法根据Hu矩计算
(此处比较同一个图片中的两个轮廓)
import cv2
import numpy as np
img = cv2.imread('11.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
im,contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
cnt2 = contours[1]
ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print(ret)
图形发生旋转以后,对匹配结果影响不大,这里涉及到Hu矩的原理。
练习:
在图片上绘制不同颜色的点,根据点到轮廓的距离来决定。
import cv2
import numpy as np
def draw_circle(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
dist = cv2.pointPolygonTest(cnt,(x,y),True)
if dist > 0:
cv2.circle(img,(x,y),4,(255,0,0),-1)
elif dist==0:
cv2.circle(img,(x,y),4,(0,255,0),-1)
elif dist < 0:
cv2.circle(img,(x,y),4,(0,0,255),-1)
img = cv2.imread('11.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
im,contours,hierarchy = cv2.findContours(thresh,2,1)
cnt = contours[0]
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
cv2.imshow('image',img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()