• 热门专题

机器视觉初级系列(9)找到图书的轮廓

作者:  发布日期:2016-08-16 20:34:09
Tag标签:轮廓  视觉  机器  
  • 图像几何轮廓特征

    虽然计算机视觉、机器视觉属于人工智能的分支之一(人工智能包括有图像识别、语音识别、语义识别等),但是对于机器视觉来说,学习图像的几何特征有着非一般的重要意义。

    为什么介么说,因为在本人实际的项目当中,很多时候处理算法都是基于图像的几何轮廓特征进行计算的,例如角点计算的几种算法HOG、SIFT、SUFT…都是基于图像的几何轮廓特征的基本理论上。

    到近年来很重要、很热门的机器视觉领域SLAM(即时定位与地图构建)绝大部分理论都是基于图像几何轮廓特征,因此在这里简单初级地对图像几何轮廓特征进行初略带过一遍,造福后人。


    举个栗子:找图书的轮廓

    看看我们要做到的效果:

    这里写图片描述

    如上图所示,我们希望能简单地不使用SVM分类,深度学习CNN、R-CNN等神经网络方法,简单粗暴地准确识别出上图所示,摆放在桌子上的书呢?这里就用到了神秘而伟大的图像几何轮廓特征。

    这里写图片描述

    在介里,我们可以很清晰地看到在图像中有4本书,但是同样有其他一些障碍物(在实验环境中是有点和谐),例如有星爸爸的咖啡杯,杯垫。我们神秘而伟大的目标就是忽略那些其他参考物,然后准确地识别出桌子上面的书籍。

    在真实情况下可能是手机app 万能扫描王里面的功能:我们用手机拍了张纸,希望高清地扫描进电脑,这时候你不用到打印店去扫描了,直接用手机吧,用我们这个程序吧。

    今天我不打算像前几个文章系列那样使用opencv C++版本,因为使用python做demo是非常方便快捷,不用写那么多括号。

    需要什么库呢?

    为了能够顺利得到图像中的轮廓,我们需要下面两个库:

    NumPy:方便数值运算。
    OpenCV:不用我介绍了吧。

    通过python和opencv在图像中找到书本

    我们通过cv2.imread读取图片,然后对图像进行灰度图处理,以后无论把图像想转什么格式都统统使用cvtColor,而后面的需要主要的是使用BGR2而不是普通的RGB2。接着,通过对图像进行高斯模糊。使用高斯模糊的作用有两:1 去除图像中的噪音,也就是自动化通信领域的低通滤波。2 增加找到图书的精确度。

    # import the necessary packages
    import numpy as np
    import cv2
    
    # load the image, convert it to grayscale, and blur it
    image = cv2.imread('example.jpg')
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (3, 3), 0)
    cv2.imshow('Gray', gray)
    cv2.waitKey(0)

    这里写图片描述

    接下来对图像所有轮廓的边缘进行检测。Opencv中Canny的第一个阈值和第二个阈值的设置一直是个很大的争议,如果想要Canny边缘提取算法自动化执行的话,应该根据什么情况进行呢?(我也在思考这问题)

    # detect edges in the image
    edged = cv2.Canny(gray, 10, 250)
    cv2.imshow('Edged', edged)
    cv2.waitKey(0)

    这里写图片描述

    现在能够看到图片当中所有物品的轮廓外观,如果不是很清晰的话可以调节一下Canny的连个阈值。另外,很明显的是可以看到有一些有一些边缘不是闭合的,不是那么滴完美。例如上面的被子的外边缘与桌子外面的轮廓连在一起了。为了解决这个问题,我们需要对图像的边缘进行闭合的操作。

    # construct and apply a closing kernel to 'close' gaps between 'white'
    # pixels
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
    closed = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, kernel)
    cv2.imshow('Closed', closed)
    cv2.waitKey(0)

    通过使用getStructuringElement建立一个7 * 7的全1矩阵,也就是一个正方形的矩形模板,然后根据这个模板作为输入到morphologyEx函数,morphologyEx函数是把高级形态学操作作用于图像。官方解释Applies an advanced morphological operation to an image。其实就是把7 * 7的矩阵当做一个正方形对图像进行腐蚀和膨胀操作。最后可以看到图像中有很多7 * 7 大小的方格子。

    这里写图片描述

    最后一个步骤就是精确地识别出我们需要的书籍的外观轮廓了。这里使用cv2.findContours函数,找图像中的角点:

    # find contours (i.e. the 'outlines') in the image and initialize the
    # total number of books found
    (cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    total = 0

    慢着,来思考一下书的几何形状。一本书或者一张纸是矩形的,矩形有四个顶点,因此我们去对角点检测的时候可以通过是否有4个角点去假设这是否一本书的外观轮廓。

    # loop over the contours
    for c in cnts:
        # approximate the contour
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    
        if len(approx) == 4:
        cv2.drawContours(image, [approx], -1, (0, 255, 0), 4)
        total += 1

    上面那段代码是核心,对于每一个角点的集合,我们通过cv2.arcLength去计算角点集合的周长,然后使用cv2.approxPolyDP去近似模拟角点的形状。为什么说近似模拟角点的形状呢?因为书籍的外观轮廓不是一个完美的矩形,例如摄像头的畸变、图片拍摄角度、书籍自身的阴影,因此通过近似模拟角点的形状,我们可以大致得到书籍的轮廓。

    然后通过使用if程序去检测是否有4个角点,如果有那么就画出来。最后效果:

    # display the output
    print 'I found {0} books in that image'.format(total)
    cv2.imshow('Output', image)
    cv2.waitKey(0)

    这里写图片描述

    所有代码:

    # import the necessary packages
    import numpy as np
    import cv2
    
    # load the image, convert it to grayscale, and blur it
    image = cv2.imread('example.jpg')
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (3, 3), 0)
    
    # detect edges in the image
    edged = cv2.Canny(gray, 10, 250)
    
    # construct and apply a closing kernel to 'close' gaps between 'white'
    # pixels
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
    closed = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, kernel)
    
    # find contours (i.e. the 'outlines') in the image and initialize the
    # total number of books found
    (cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    total = 0
    
    # loop over the contours
    for c in cnts:
        # approximate the contour
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    
        if len(approx) == 4:
        cv2.drawContours(image, [approx], -1, (0, 255, 0), 4)
        total += 1
    
    # display the output
    print 'I found {0} books in that image'.format(total)
    cv2.imshow('Output', image)
    cv2.waitKey(0)
About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规