为了账号安全,请及时绑定邮箱和手机立即绑定

OpenCV入门之寻找图像的凸包

标签:
Python

介绍

  凸包(Convex Hull)是一个计算几何(图形学)中的概念,它的严格的数学定义为:在一个向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。
  在图像处理过程中,我们常常需要寻找图像中包围某个物体的凸包。凸包跟多边形逼近很像,只不过它是包围物体最外层的一个凸集,这个凸集是所有能包围这个物体的凸集的交集。如下图所示:

webp

凸包示意图

在上图中,绿色线条所包围的凸集即为白色图形的凸包。
  在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)

绘制的图片如下:

webp

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]]]

这是凸包所在的轮廓的点集集合,有了它,我们就能绘制出凸包的轮廓了,如下:

webp

绘制凸包轮廓

简单例子2 手势图片

  接下来,我们将介绍一张稍微难一点的图片——手势图片(finger.jpg),如下所示:

webp

手势图片

我们将会来寻找这个手势的凸包。基本的处理思路还是和之前的一致,只是要在二值化以及凸包点集集合的大小上做一些处理,取二值化的阈值为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()

检测到的凸包如下图所示:

webp

手势图片中检测到的凸包

可以发现,一共检测到2个凸包,一个是整个手势外围的凸包,正好包围整个手,另一个是两个手指形成的内部的图形,类似于O的凸包,这符合我们的预期。

总结

  当然,我们在这里只是介绍了OpenCV检测凸包的函数convexHull以及其应用,并没有讲到如何检测凸包的算法。如有机会,笔者将会介绍该算法。欢迎大家交流,祝大家国庆快乐!



作者:但盼风雨来_jc
链接:https://www.jianshu.com/p/964179c73268


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消