• 【opencv图像处理】-- 6.图像轮廓(面积周长)、多边形逼近、外接矩形、查找/绘制轮廓


    希望有能力的朋友还是拿C++做。

    本节讨论查找、绘制图像轮廓,轮廓的面积,周长,多边形逼近,多边形凸包,轮廓的外接矩形

    1. 图形轮廓(contours)

    具有相同颜色或灰度的连续点的曲线,轮廓是形状分析和物体的检测和识别中很有用

    • 图形分析
    • 物体的识别和检测
    • 注意:
      • 为了检测的准确性,首先要二值化或canny操作
      • 画轮廓时会修改输入的图像,如果之后想继续使用原始图像,应该先将原始图像储存到其他变量

    1.1 查找轮廓

    • cv2.findContours(image, mode, method…)
      • mode:查找轮廓模式
        • RETR_EXTERNAL=0 只检测外围轮廓
        • RETR_LIST=1 检测的轮廓不建立等级关系,检测所有轮廓
        • RETR_CCOMP=2 每层最多两级,从小到大,从里到外
        • RETR_TREE = 3 按照树形储存轮廓,从大到小,从右到左
      • method轮廓近似方法
        • CHAIN_APPROX_NONE 保存轮廓上的所有点
        • CHAIN_APPROX_SIMPLE 只保存焦点,比如四边形只存储四个角,常用
      • 返回值:contour和hierachy即轮廓和等级
    import cv2
    import numpy as np
    
    cat = cv2.imread('cat.jpeg')
    img = cv2.cvtColor(cat, cv2.COLOR_BGR2GRAY)
    
    #二值化,有两个返回值,阈值,结果
    ret, binary = cv2.threshold(img, 150, 255, cv2.THRESH_BINARY)
    
    cv2.imshow('img', img)
    # cv2.imshow('img2', binary)
    
    contours, hierarchy = cv2.findContours(binary, mode = cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)
    
    print(contours)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    1.2 绘制轮廓

    • drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
      • image 要绘制的轮廓图像
      • contours: 轮廓点
      • contouridx 要绘制的轮廓编号 -1表示绘制所有轮廓
      • color 轮廓的颜色 (0,0,255)表示红色
      • thickness 线宽 -1 表示全部填充
    import cv2
    import numpy as np
    
    cat = cv2.imread('cat.jpeg')
    img = cv2.cvtColor(cat, cv2.COLOR_BGR2GRAY)
    
    #二值化,有两个返回值,阈值,结果
    ret, binary = cv2.threshold(img, 150, 255, cv2.THRESH_BINARY)
    cat_cp = cat.copy()
    
    contours, hierarchy = cv2.findContours(binary, mode = cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)
    
    cv2.drawContours(cat_cp, contours, -1, (0, 0, 255), 2)
    
    cv2.imshow('cat', cat)
    cv2.imshow('contours', cat_cp)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    1.3 轮廓的面积和周长

    单位为像素,再找到轮廓后,会有很多细小的轮廓,可以通过轮廓面积进行过滤

    • 轮廓面积 contourArea(contour)
    • 轮廓周长 arcLengh(curve, closed)
      • curve即轮廓
      • closed是否是闭合的轮廓
    import cv2
    import numpy as np
    
    cat = cv2.imread('cat.jpeg')
    img = cv2.cvtColor(cat, cv2.COLOR_BGR2GRAY)
    
    #二值化,有两个返回值,阈值,结果
    ret, binary = cv2.threshold(img, 150, 255, cv2.THRESH_BINARY)
    cat_cp = cat.copy()
    
    contours, hierarchby = cv2.findContours(binary, mode = cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)
    
    #一个轮廓的面积
    area = cv2.contourArea(contours[0])
    print(area)
    
    #一个轮廓周长
    perimeter = cv2.arcLength(contours[1], closed=True)
    print(perimeter)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2. 多边形逼近

    findContours后的轮廓信息contours可能过于复杂不平花,可以用approxPolyDP函数对该多边形曲线近似,这就是轮廓的多边形逼近。

    • approxPolyDP就是以多边形去逼近轮廓,采用的是Douglas-Peucker算法(DP)
    • DP算法简单,就是不断找多边形最远的点加入形成新的多边形,指导最短距离小于指定精度。
      • approxPolyDP(curbe, epsilon, closed[])
        • curve就是要近似逼近的轮廓
        • epsilon 即DP算法使用的阈值,偏差值5分半开始有详解
        • closed轮廓是否闭合
    
    import cv2
    import numpy as np
    
    hand = cv2.imread('hand.jpg')
    img = cv2.cvtColor(hand, cv2.COLOR_BGR2GRAY)
    
    #二值化,有两个返回值,阈值,结果
    ret, binary = cv2.threshold(img, 150, 255, cv2.THRESH_BINARY)
    #hand_cp = img.copy()
    hand_cp2 = img.copy()
    contours, hierarchy = cv2.findContours(binary, mode = cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)
    
    #cv2.drawContours(hand_cp, contours, -1, (0, 0, 255), 2)
    
    #cv2.imshow('cat', hand)
    #cv2.imshow('contours', hand_cp)
    print(len(contours))
    #使用多边形逼近,近似模拟手的轮廓
    #阈值给20,阈值越大,逼近效果越粗糙
    approx = cv2.approxPolyDP(contours[0], 20, closed=True)
    #本质还是一个轮廓数据
    
    cv2.drawContours(hand_cp2, [approx], 0, (0, 0, 255), 2)
    cv2.imshow('moni', hand_cp)
    
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3. 多边形凸包

    多边形逼近是高度近似,凸包和多边形逼近很像,只不过它是物体最外层的凸多边形,凸包是指完全包含所有轮廓,并且仅由轮廓上的点构成的多边形。

    • 完全包含所有轮廓
    • 凸包的每一处都是凸的,在凸包内,任意三个连续点的内角小于180°
    • convexHull(points[, hull[, clockwise[r, eturnPoints[]]]])
      • points 轮廓
      • clockwise 顺时针绘制
    import cv2
    import numpy as np
    
    hand = cv2.imread('hand.jpg')
    img = cv2.cvtColor(hand, cv2.COLOR_BGR2GRAY)
    
    #二值化
    ret, binary = cv2.threshold(img, 150, 255, cv2.THRESH_BINARY)
    
    hand_cp2 = img.copy()
    contours, hierarchy = cv2.findContours(binary, mode = cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)
    
    #计算凸包
    hull = cv2.convexHull(contours[0])
    
    cv2.namedWindow('moni', cv2.WINDOW_NORMAL)
    cv2.resizeWindow('moni', 640, 480)
    cv2.drawContours(hand_cp2, [hull], 0, (0, 0, 255), 2)
    cv2.imshow('moni', hand_cp2)
    
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4. 外接矩形

    • 最小外接矩形 minAreaRect(points):有可能会有旋转
    • 最大外接矩形 boundingRect(points):没有旋转,方方正正,返回4点坐标
    import cv2
    import numpy as np
    
    cv2.namedWindow('img', cv2.WINDOW_NORMAL)
    cv2.resizeWindow('img', 640, 480)
    hand = cv2.imread('hand.jpg')
    
    img = cv2.cvtColor(hand, cv2.COLOR_BGR2GRAY)
    
    ret, binary = cv2.threshold(img, 150, 255, cv2.THRESH_BINARY)
    hand_cp2 = img.copy()
    
    contours, hierarchy = cv2.findContours(binary, mode = cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)
    
    # rect是一个rotated 的矩形,包含起始坐标(x,y),长宽,旋转角度
    # 最小外接矩形
    rect = cv2.minAreaRect(contours[540])
    print(rect)
    
    # 最大外接矩形,方方正正,返回四个点x,y  w,h
    x,y,w,h = cv2.boundingRect(contours[540])
    cv2.rectangle(hand_cp2, (x,y), (x+w, y+h), (0,0,255), 2)
    
    
    
    
    #画出矩形,画旋转矩形有用的
    #帮我们计算出旋转矩形的4个坐标点
    #坐标为整数
    box = cv2.boxPoints(rect)
    #四舍五入,再取整
    box = np.round(box).astype('int')
    
    cv2.drawContours(hand_cp2, [box], 0, (255,0,0), 2)
    
    cv2.imshow('img', hand_cp2)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
  • 相关阅读:
    世界技能大赛夺冠背后,亚马逊云科技如何培养云计算技能人才?
    设置远程服务器共享本地磁盘
    web入门---tomcat&请求响应
    从图片中识别文字的软件?这篇文章也许可以回答你的问题
    vue中设置动态路由
    线性代数学习笔记7-3:解微分方程、矩阵的指数函数(特征值的应用)
    主流消息队列RabbitMq,RocketMq,Kafka区别
    公司销售个人号如何管理?
    UDP编程
    企业云性能监控
  • 原文地址:https://blog.csdn.net/Eric_Sober/article/details/126053385