这篇教程OpenCV-Python实现凸包的获取写得很实用,希望能帮到您。
前言
逼近多边形是某个图像轮廓的高度近似,而凸包的提出是为了简化逼近多边形的。其实,凸包跟逼近多边形很像,只不过它是物体最外层的“凸”多边形。 简单的概括,凸包是指完全包含原有轮廓,并且仅由轮廓上的点所构成的多边形。凸包的特点是每一处都是凸的,即在凸包内连接任意两点的直线都在凸包的内部,并且任意连续3个点的内角小于180度。 在OpenCV中,它给我们提供cv2.convexHull()来获取轮廓的凸包。其完整定义如下: def convexHull(points, hull=None, clockwise=None, returnPoints=None): points:轮廓 hull:返回值,为凸包角点。可以理解为多边形的点坐标,或索引。 clockwise:布尔类型,为True时,凸包角点将按顺时针方向排列;为False时,为逆时针。 returnPoints:布尔类型,默认值True,函数返回凸包角点的x/y坐标;为False时,函数返回轮廓中凸包角点的索引。
获取凸包角点既然,我们已经了解了凸包的作用,并且理解了OpenCV提供的函数。下面,我们随便选取一张图,获取凸包角点。具体代码如下所示: import cv2img = cv2.imread("24.jpg")cv2.imshow("img", img)# 转换为灰度图像gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)hull=cv2.convexHull(contours[0])print(hull) 这里,我们随便获取了一张图像,并获取其凸包的角点。运行之后,角点坐标如下: 
如果修改参数returnPoints为False,会返回对应的6个索引值。
这里我们再添加一行代码就可以绘制凸包多边形了,具体添加的代码如下: #获取hull之后cv2.polylines(img, [hull], True, (0, 255, 0), 2)cv2.imshow("img1", img) 运行之后,效果如下所示:

凸缺陷凸包与轮廓之间的部分我们称之为凸缺陷。在OpenCV中使用函数cv2.convexityDefects()获取凸缺陷,其完整定义如下: def convexityDefects(contour, convexhull, convexityDefects=None): contour:轮廓 convexhull:凸包 convexityDefects:返回值,为凸缺陷点集。它是一个数组,返回的指包括[起点,终点,轮廓上的距离凸包最远点,最远点到凸包的近似距离] 特别注意,用该函数计算凸缺陷之前,我们需要使用函数cv2.convexHull()获取凸包,但其参数returnPoints必须为False。
下面,我们来使用该函数计算上图的凸缺陷。代码如下: import cv2img = cv2.imread("24.jpg")cv2.imshow("img", img)# 转换为灰度图像gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)hull = cv2.convexHull(contours[0], returnPoints=False)defects = cv2.convexityDefects(contours[0], hull)print(defects)for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = tuple(contours[0][s][0]) end = tuple(contours[0][e][0]) far = tuple(contours[0][f][0]) cv2.line(img, start, end, [0, 255, 0], 2) cv2.circle(img, far, 5, [0, 0, 255], -1)cv2.imshow("img1", img)cv2.waitKey()cv2.destroyAllWindows() 运行之后,效果如下: 
如上图所示,我们用点标记出来的凸缺陷,可以看到五角星的每个凹肩都是凸缺陷。 最后可以扩展以下,其中OpenCV提供函数cv2.isContourConvex()来判断轮廓是否是凸形的。同时,也提供了cv2.pointPolygonTest()函数来计算点到多边形(轮廓)的最短距离,也就是垂线距离,这个计算由称为点和多边形的关系测试。感兴趣的读者可以自己实验这两个方函数。
简单例子 手势图片接下来,我们将介绍一张稍微难一点的图片——手势图片(finger.jpg),如下所示: 
我们将会来寻找这个手势的凸包。基本的处理思路还是和之前的一致,只是要在二值化以及凸包点集集合的大小上做一些处理,取二值化的阈值为235,凸包点集中的点个数大于5,完整的Python代码如下: import cv2# 读取图片并转至灰度模式imagepath = 'F://finger.jpg'img = cv2.imread(imagepath, 1)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 二值化,取阈值为235ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)# 寻找图像中的轮廓image, contours, hierarchy = cv2.findContours(thresh, 2, 1)# 寻找物体的凸包并绘制凸包的轮廓for cnt in contours: hull = cv2.convexHull(cnt) length = len(hull) # 如果凸包点集中的点个数大于5 if length > 5: # 绘制图像凸包的轮廓 for i in range(length): cv2.line(img, tuple(hull[i][0]), tuple(hull[(i+1)%length][0]), (0,0,255), 2)cv2.imshow('finger', img)cv2.waitKey() 检测到的凸包如下图所示: 
可以发现,一共检测到2个凸包,一个是整个手势外围的凸包,正好包围整个手,另一个是两个手指形成的内部的图形,类似于O的凸包,这符合我们的预期。 到此这篇关于OpenCV-Python实现凸包的获取的文章就介绍到这了,更多相关OpenCV-Python 凸包内容请搜索51zixue.net以前的文章或继续浏览下面的相关文章希望大家以后多多支持51zixue.net! OpenCV-Python实现多模板匹配 OpenCV-Python实现轮廓拟合 |