• OpenCVPython系列之轮廓特征中阶


    本次我们将讨论OpenCV中图像轮廓的另一些特征,它们将非常有用。

    边界矩形

    有两类边界矩形

    直边界矩形—boundingRect()

    一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。所以边界矩形的面积不是最小的。可以使用函数 cv2.boundingRect() 查找得到,我们来看函数原型:

    x,y,w,h = cv2.boundingRect(cnt)

    (x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高,通常情况下,cnt代表识别的轮廓。

    之后我们利用cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)画出矩形、

    参数解释

    第一个参数:img是原图

    第二个参数:(x,y)是矩阵的左上点坐标

    第三个参数:(x+w,y+h)是矩阵的右下点坐标

    第四个参数:(0,255,0)是画线对应的rgb颜色

    第五个参数:2是所画的线的宽度

    我们来看代码:

    import cv2
    
    # 读取图片并转至灰度模式
    img = cv2.imread("tubao.png", 1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 二值化,取阈值为235
    ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)
    
    # 寻找图像中的轮廓
    contours, hierarchy = cv2.findContours(thresh, 2, 1)
    
    cnt = contours[0]
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
    
    cv2.imshow('finger', img)
    cv2.waitKey()

    image.png

    可以看到一个外接矩形,但是它不是最小的外接矩形,接下来我们讨论最小外接矩形。

    旋转的边界矩形

    这个边界矩形是面积最小的,因为它考虑了对象的旋转。

    用到的函数为 :

    cv2.minAreaRect(cnt)

    在这里的cnt仍然跟上面的相同,该函数返回的是一个 Box2D 结构:

    Box2D结构 rect:(最小外接矩形的中心(x,y),(宽度,高度),旋转角度),但是要绘制此矩形,我们需要矩形的4个角。 它是通过函cv2.boxPoints()获得的。

    我们来看代码:

    import cv2
    import numpy as np
    
    # 读取图片并转至灰度模式
    img = cv2.imread("tubao.png", 1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 二值化,取阈值为235
    ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)
    
    # 寻找图像中的轮廓
    contours, hierarchy = cv2.findContours(thresh, 2, 1)
    
    cnt = contours[0]
    
    rect = cv2.minAreaRect(cnt)
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    cv2.drawContours(img,[box],0,(0,0,255),2)
    
    cv2.imshow('finger', img)
    cv2.waitKey()

    image.png

    可以看到,这里得出的结果是最小外接矩形。

    最小外接圆

    跟之前一样,轮廓可以外接矩形,同时也可以外接圆形。接下来,我们使用函数cv.minEnclosingCircle()找到对象的外接圆。 它是一个以最小面积完全覆盖对象的圆圈。

    函数原型:

          center, radius     =     cv.minEnclosingCircle(   points    )

    image.png

    直接来看代码:

    import cv2
    import numpy as np
    
    # 读取图片并转至灰度模式
    img = cv2.imread("tubao.png", 1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 二值化,取阈值为235
    ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)
    
    # 寻找图像中的轮廓
    contours, hierarchy = cv2.findContours(thresh, 2, 1)
    
    cnt = contours[0]
    
    (x, y), radius = cv2.minEnclosingCircle(cnt)
    center = (int(x), int(y))
    radius = int(radius)
    cv2.circle(img, center, radius, (0, 255, 0), 2)
    
    cv2.imshow('finger', img)
    cv2.waitKey()

    image.png

    椭圆拟合

    轮廓同样也可以进行椭圆拟合,函数原型:

    retval=cv.fitEllipse(points)

    输入参数跟之前的外界矩形是一样的,就不一一详述了。代码:

    import cv2
    import numpy as np
    
    # 读取图片并转至灰度模式
    img = cv2.imread("tubao.png", 1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 二值化,取阈值为235
    ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)
    
    # 寻找图像中的轮廓
    contours, hierarchy = cv2.findContours(thresh, 2, 1)
    
    cnt = contours[0]
    
    ellipse = cv2.fitEllipse(cnt)
    cv2.ellipse(img,ellipse,(0,255,0),2)
    
    cv2.imshow('finger', img)
    cv2.waitKey()

    image.png

    直线拟合

    同样,我们可以将一条直线拟合到一组点。下图包含一组白点,我们可以近似一条直线。函数原型:

    output = cv2.fitLine(InputArray  points, distType, param, reps, aeps)

    InputArray Points: 待拟合的直线的集合,必须是矩阵形式;

    distType: 距离类型。fitline为距离最小化函数,拟合直线时,要使输入点到拟合直线的距离和最小化。这里的距离的类型有以下几种:

    cv2.DIST_USER : User defined distance

    cv2.DIST_L1: distance = |x1-x2| + |y1-y2|

    cv2.DIST_L2: 欧式距离,此时与最小二乘法相同

    cv2.DIST_C:distance = max(|x1-x2|,|y1-y2|)

    cv2.DIST_L12:L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1))

    cv2.DIST_FAIR:distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998

    cv2.DIST_WELSCH: distance = c2/2(1-exp(-(x/c)2)), c = 2.9846

    cv2.DIST_HUBER:distance = |x|<c |x^2/2 : c(|x|-c/2), c=1.345

    param: 距离参数,跟所选的距离类型有关,值可以设置为0。

    reps, aeps: 第5/6个参数用于表示拟合直线所需要的径向和角度精度,通常情况下两个值均被设定为1e-2。

    output : 对于二维直线,输出output为4维,前两维代表拟合出的直线的方向,后两位代表直线上的一点。(即通常说的点斜式直线)。

    代码:

    import cv2
    import numpy as np
    
    # 读取图片并转至灰度模式
    img = cv2.imread("tubao.png", 1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 二值化,取阈值为235
    ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)
    
    # 寻找图像中的轮廓
    contours, hierarchy = cv2.findContours(thresh, 2, 1)
    
    cnt = contours[0]
    rows,cols = img.shape[:2]
    
    [vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
    lefty = int((-x*vy/vx) + y)
    righty = int(((cols-x)*vy/vx)+y)
    cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
    
    cv2.imshow('finger', img)
    cv2.waitKey()

    image.png

    现在我们可以来一个实战部分,用椭圆拟合来进行人眼识别之后标注出来,首先我们需要安装dlib库,这种一个人脸特征检测库,接下来我们设置特征检测器,dlib有已经训练的好的需要下载,也可以自己根据需要训练:

    下载链接:http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2

    下载完之后解压,将路径放到根目录里面,当然了,下载是需要科 学上网的,否则下载速度非常慢。

    我们使用图片:

    image.png

    代码:

    import cv2
     import dlib
     import numpy as np
     
     detector = dlib.get_frontal_face_detector()
     landmark_predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
     
     img = cv2.imread("min.jpg")
     faces = detector(img,1)
     left_eye = []
     right_eye = []
     if ( len(faces) > 0):
         for k,d in enumerate(faces):
             shape = landmark_predictor(img,d)
             for i in range(36,42):
                 right_eye.append([shape.part(i).x,shape.part(i).y])
             for i in range(42,48):
                 left_eye.append([shape.part(i).x,shape.part(i).y])
     
     
     
     
     
     ellipse_left = cv2.fitEllipse(np.array(left_eye))
     ellipse_right = cv2.fitEllipse(np.array(right_eye))
     cv2.ellipse(img, ellipse_left, (0,255,0), 1)
     cv2.ellipse(img, ellipse_right, (0,255,0), 1)
     
     ellipse_left
     ((275.1310119628906, 197.24081420898438),
      (13.491097450256348, 47.203433990478516),
      84.19256591796875)
     
     
     center = ellipse_left[0]
     size = ellipse_left[1]
     angle = ellipse_left[2]
     
     
     
     cv2.imshow('PIC',img)
     cv2.waitKey(0)

    image.png

    可以看到,人眼已经识别出来,并用椭圆进行了拟合,是不是很有趣。

    本次我们主要讨论轮廓的外界图形,事实上它们都是非常有用的,下次我们将讨论轮廓特征的一些高阶方法。

  • 相关阅读:
    [转]jQuery 1.4的十五大新功能实例精讲
    数据库优化使用索引优化存储过程
    SQL语句练习实例之一——找出最近的两次晋升日期与工资额
    Sql Server中三种字符串合并方法的性能比较
    在IIS7下配置ASP.NET v1.1(Visual Studio .NET 2003)环境
    数据库优化方法 (一)
    WEB版一次选择多个文件进行批量上传(swfupload)的解决方案
    [转]根据性能监视器,分析性能瓶颈
    数据库优化方法(三)
    英文SilverLight 4 tools for vs 2010 安装于vs 2010中文版,无法拖拽数据源问题解决方法
  • 原文地址:https://www.cnblogs.com/wuyuan2011woaini/p/15656479.html
Copyright © 2020-2023  润新知