OpenCV Python 轮廓
【目标】
- 凸性缺陷查找
- 点与多边形的关系
- 不同形状的匹配
【代码】
左图中红色点为凸性检测的缺陷点,即凹点
右图为了验证点与多边形关系而做的图,也是官网要求做的练习。
import cv2
import numpy as np
img = cv2.imread('star.png', 0)
colorimg = cv2.imread('star.png', 1)
convexHullImg = colorimg.copy()
ret, thresh = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)
# 寻找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]
# 凸包
hull = cv2.convexHull(cnt, returnPoints=False)
defects = cv2.convexityDefects(cnt, hull)
# 画出缺陷凹点
for i in range(defects.shape[0]):
startptidx, endptidx, farptidx, dis = defects[i, 0]
startpt = tuple(cnt[startptidx][0])
endpt = tuple(cnt[endptidx][0])
farpt = tuple(cnt[farptidx][0])
cv2.line(convexHullImg, startpt, endpt, (0, 255, 255))
cv2.circle(convexHullImg, farpt, 3, (0, 0, 255), 3)
# 根据点在图像中和轮廓中的位置,画出颜色图
polygonTestImg = colorimg.copy()
# cv2.circle(polygonTestImg, (280, 180), 3, (0, 0, 255), 3)
dist = cv2.pointPolygonTest(cnt, (50, 50), True)
h, w, _ = polygonTestImg.shape
# 在轮廓上,为白色
bluevalue = 255
redvalue = 255
for j in range(h):
for i in range(w):
dist = cv2.pointPolygonTest(cnt, (i, j), True)
if dist > 127:
dist = 127
if dist < -127:
dist = -127
if dist > 0:
colorshow = (255 - dist * 2, 255 - dist * 2, 0)
elif dist < 0:
colorshow = (0, 255 + dist * 2, 255 + dist * 2)
elif dist == 0:
colorshow = (255, 255, 255)
cv2.circle(polygonTestImg, (i, j), 2, colorshow, 2)
cv2.imshow('convexHullImg', convexHullImg)
cv2.imshow('polygonTestImg', polygonTestImg)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 测试形状匹配
import cv2
import numpy as np
img1 = cv2.imread('star.png', 0)
img2 = cv2.imread('box.png', 0)
img3 = cv2.imread('testfit.png', 0)
ret1, thresh1 = cv2.threshold(img1, 127, 255, cv2.THRESH_BINARY)
ret2, thresh2 = cv2.threshold(img2, 127, 255, cv2.THRESH_BINARY)
ret3, thresh3 = cv2.threshold(img3, 127, 255, cv2.THRESH_BINARY)
con1, hir1 = cv2.findContours(thresh1, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
con2, hir2 = cv2.findContours(thresh2, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
con3, hir3 = cv2.findContours(thresh3, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnt1 = con1[0]
cnt2 = con2[0]
cnt3 = con3[0]
ret12 = cv2.matchShapes(cnt1, cnt2, cv2.CONTOURS_MATCH_I2, 0.0)
ret13 = cv2.matchShapes(cnt1, cnt3, cv2.CONTOURS_MATCH_I2, 0.0)
ret23 = cv2.matchShapes(cnt2, cnt3, cv2.CONTOURS_MATCH_I2, 0.0)
print(ret12, ret13, ret23)
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('img3', img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果如下:
0.05888818307213595 0.2987404256696341 1.6190198650037022
【接口】
- convexityDefects
void cv::convexityDefects ( InputArray contour,
InputArray convexhull,
OutputArray convexityDefects
);
cv2.convexityDefects( contour, convexhull[, convexityDefects] ) -> convexityDefects
计算查找一个轮廓的凸性缺陷
- contour: 输入的轮廓
- convexhull: 轮廓的凸包,用
convexHull
- convexityDefects: 凸性缺陷输出向量, 每个缺陷是 4个整型元素的 vector。
- pointPolygonTest
double cv::pointPolygonTest ( InputArray contour,
Point2f pt,
bool measureDist
);
cv2.pointPolygonTest( contour, pt, measureDist ) -> retval
判断一个点是否在轮廓内或边缘上,计算其距离;正数在内部,负数在外部;
如果measureDist=false
则返回1, -1, 0
- contour: 输入的轮廓
- pt: 测试点
- measureDist: 如果为真,则计算距离,否则不用计算,只判断是否在内部还是外部;
- matchShapes
double cv::matchShapes ( InputArray contour1,
InputArray contour2,
int method,
double parameter
);
cv2.matchShapes( contour1, contour2, method, parameter ) -> retval
比较两个形状
- contour1: 第一个轮廓
- contour2: 第二个轮廓
- method: 比较的方法 见下 ShapeMatchModes
- parameter: 方法的特殊参数(暂时不支持)
- ShapeMatchModes
【参考】
- OpenCV官方文档