介绍
凸包(Convex Hull)是一个计算几何(图形学)中的概念,它的严格的数学定义为:在一个向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。
在图像处理过程中,我们常常需要寻找图像中包围某个物体的凸包。凸包跟多边形逼近很像,只不过它是包围物体最外层的一个凸集,这个凸集是所有能包围这个物体的凸集的交集。如下图所示:
凸包示意图
在上图中,绿色线条所包围的凸集即为白色图形的凸包。
在opencv中,通过函数convexHulll能很容易的得到一系列点的凸包,比如由点组成的轮廓,通过convexHull函数,我们就能得到轮廓的凸包。寻找图像的凸包,能够让我们做一些有意思的事情,比如手势识别等。
下面笔者将会通过两个简单例子来展示如何用OpenCV来寻找图像的凸包。
简单例子1 几何图形
首先,我们用以下的Python代码来自己绘制一张简单的多边形的图片(polygon.png),代码如下:
import cv2import numpy as np# 新建512*512的空白图片img = np.zeros((512,512,3), np.uint8)# 平面点集pts = np.array([[200,250], [250,300], [300, 270], [270,200], [120, 240]], np.int32) pts = pts.reshape((-1,1,2))# 绘制填充的多边形cv2.fillPoly(img, [pts], (255,255,255))# 保存图片cv2.imwrite('F://polygon.png', img)
绘制的图片如下:
polygon.png
接着我们需要寻找这个多边形的凸包,利用OpenCV的convexHull函数,然后再将这个凸包绘制出来,得到直观的展示结果。处理的Python代码如下:
import cv2# 读取图片并转至灰度模式imagepath = 'F://convex.png'img = cv2.imread(imagepath, 1) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 二值化ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)# 图片轮廓image, contours, hierarchy = cv2.findContours(thresh, 2, 1) cnt = contours[0]# 寻找凸包并绘制凸包(轮廓)hull = cv2.convexHull(cnt) print(hull) length = len(hull)for i in range(len(hull)): cv2.line(img, tuple(hull[i][0]), tuple(hull[(i+1)%length][0]), (0,255,0), 2)# 显示图片cv2.imshow('line', img) cv2.waitKey()
输出的结果如下:
[[[300 270]] [[299 271]] [[254 298]] [[250 300]] [[120 240]] [[122 239]] [[257 203]] [[269 200]] [[270 200]] [[273 206]] [[300 269]]]
这是凸包所在的轮廓的点集集合,有了它,我们就能绘制出凸包的轮廓了,如下:
绘制凸包轮廓
简单例子2 手势图片
接下来,我们将介绍一张稍微难一点的图片——手势图片(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检测凸包的函数convexHull以及其应用,并没有讲到如何检测凸包的算法。如有机会,笔者将会介绍该算法。欢迎大家交流,祝大家国庆快乐!
作者:但盼风雨来_jc
链接:https://www.jianshu.com/p/964179c73268
共同学习,写下你的评论
评论加载中...
作者其他优质文章