zoukankan      html  css  js  c++  java
  • OpenCV入门之寻找图像的凸包(convex hull)

    介绍

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

    凸包示意图

    在上图中,绿色线条所包围的凸集即为白色图形的凸包。
      在opencv中,通过函数convexHulll能很容易的得到一系列点的凸包,比如由点组成的轮廓,通过convexHull函数,我们就能得到轮廓的凸包。寻找图像的凸包,能够让我们做一些有意思的事情,比如手势识别等。
      下面笔者将会通过两个简单例子来展示如何用OpenCV来寻找图像的凸包。

    简单例子1 几何图形

      首先,我们用以下的Python代码来自己绘制一张简单的多边形的图片(polygon.png),代码如下:

    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)

    绘制的图片如下:

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

    总结

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

    注意:本人现已开通微信公众号: 轻松学会Python爬虫(微信号为:easy_web_scrape), 欢迎大家关注哦~

    原文:https://www.cnblogs.com/jclian91/p/9728488.html

  • 相关阅读:
    JVM学习(2):类加载器
    JVM学习(1):类加载机制
    MySQL优化(7):其他注意事项
    MySQL优化(6):分表和读写分离
    MySQL优化(5):分区
    MySQL优化(4):查询缓存
    MySQL优化(3):索引
    关于博客
    【题解】Telephone Lines
    【题解】神经网络
  • 原文地址:https://www.cnblogs.com/Ph-one/p/12080410.html
Copyright © 2011-2022 走看看