python--opencv之convex hull

凸包(Convex Hull)

数学定义:在一个向量空间中,对于给定几何X, 所有包含X的凸集的交集S被称为X的凸包

场景:
图像处理过程中,常常需要寻找图像中,包围某个物体的凸包。凸包跟多边形逼近很像,只不过它是包围
物体外层的一个凸集,这个凸集是所有能包围这个物体的凸集的交集。

图中,绿色线条所包围的凸集,集为白色图案的凸包。

opencv中,convexhull()能够得到一系列点的凸包,比如由点组成的轮廓,通过ConvexHull函数,得到凸包。
可以用来做手势的识别。

几何图形

我们用以下的Python代码来自己绘制一张简单的多边形的图片

import cv2
import 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)

接着我们需要寻找这个多边形的凸包,利用OpenCV的convexHull函数,然后再将这个凸包绘制出来,得到直观的展示结果。

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

手势识别

我们将介绍一张稍微难一点的图片——手势图片

我们将会来寻找这个手势的凸包。基本的处理思路还是和之前的一致,只是要在二值化以及凸包点集集合的大小上做一些处理,
取二值化的阈值为235,凸包点集中的点个数大于5


import cv2

# 读取图片并转至灰度模式
imagepath = 'F://finger.jpg'
img = cv2.imread(imagepath, 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值化,取阈值为235
ret, 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的凸包,这符合我们的预期

posted @ 2022-03-29 10:56  酷酷的排球  阅读(3262)  评论(0编辑  收藏  举报