CV14 轮廓检测:入门

1.前言

轮廓检测是计算机检测图像和视频主体轮廓的重要步骤,常用于人脸检测和物体追踪等方向

本节我们将学习:边界、最小矩形及最小外接圆轮廓检测、凸轮廓Douglas-Peucker算法

2.边界、最小矩形及最小外接圆

在Opencv中确定主体的边框、最小外接矩形和圆非常简单

我们只需要使用cv2.findContours()函数即可完成

2.1程序流程

  • 首先,从文件中读取一幅图像,并转换成灰度图
  • 对灰度图像阈值化,使之转换为黑白图

​ 为什么?因为cv2.findContours()函数只能读黑白图,所以需要调用cv2.threshold()函数,而 阈值函数只能读灰度图

  • 针对每一个轮廓寻找并画出边框,最小外接矩形和最小外接圆
  • 最后,绘制轮廓并在窗口中显示

代码如下:

import cv2
import numpy as np

img = cv2.imread('hammer.jpg',cv2.IMREAD_UNCHANGED)
img = cv2.pyrDown(img)
img2 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img2,127, 255, cv2.THRESH_BINARY)
contours,hier = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

for c in contours:
    # 画出边框
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

    # 找到最小外接矩形
    rect = cv2.minAreaRect(c)
    # 计算最小外接矩形的坐标
    box = cv2.boxPoints(rect)
    # 将坐标归一化为整数
    box = np.int0(box)
    # 画图
    cv2.drawContours(img,[box],0,(0,0,255),3)

    # 计算最小外接圆的半径和圆心
    (x,y),radius = cv2.minEnclosingCircle(c)
    # 转化为整数
    center = (int(x),int(y))
    radius = int(radius)
    # 画圆
    cv2.circle(img,center,radius,(255,0,255),5)

# 画轮廓
cv2.drawContours(img,contours,-1,(255,0,0),3)
cv2.imshow("contour",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

注意:轮廓检测是在黑白图像上进行的,因此该阶段颜色信息已经丢失了。但我们是在原始彩色图像上绘制的,所以显示的是彩色结果

contour1

2.2cv2.findContours()函数

cv2.findContours()函数

功能:查找检测物体的轮廓

输入参数

  1. 黑白图(thresh),不是灰度图
  2. 指定函数返回的层次结构树类型
  3. 轮廓的近似办法

返回值

  1. 轮廓本身
  2. 每条轮廓对应的属性

2.3cv2.drawContours()函数

cv2drawContours()函数

功能:根据cv2.findContours()返回的contours,绘制轮廓

输入参数

  1. 输入图像(img)
  2. 轮廓(contours)
  3. 绘制轮廓的范围(-1是绘制所有的轮廓线;否则,绘制数组索引的轮廓线)
  4. 颜色(B,G,R)
  5. 线宽

2.4bug的发现与解决

在写代码的过程中,发现一个小bug

我将源图片转成黑白图并在这张图上绘制轮廓(而不是在彩色图片上绘制)

zczxc

如下图,第79行cv2.circle(img,center,radius,(255,0,255),5),假设B=0,G、R>0,那么无法绘制圆形轮廓

tyy 1354354

然而,若B>0时,则会出现想要的轮廓

gray_B255

为什么?

# 画圆,输入参数依次为:1.图片,2.圆心,3.半径,4.颜色,5.线宽(-1表示填充整个圆形)
cv2.circle(img,(300,300),50,(0,0,255),-1)

cv2.circle()函数中,第4个参数,若img是彩色图,那么可以用(0,0,255)表示颜色,若img是灰度图,那么只能由一个数(0~255),表示绘制线的亮度

所以,当我在灰度图中,放了一个(0,0,255)/(0,255,0),由于灰度图只读第一个参数(这里读到的是第一个参数—— 0),所以不会绘制任何轮廓

如果我放了(255,0,0),第一个参数不是0,那么就可以绘制出轮廓

3.凸轮廓和Douglas-Peucker算法

处理轮廓时,会遇到各种奇形怪状的图形,这时我们可用下面三条函数绘制轮廓

3.1相关程序

import cv2
import numpy as np

img = cv2.imread('hammer.jpg', cv2.IMREAD_UNCHANGED)
img = cv2.pyrDown(img)
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img2, 127, 255, cv2.THRESH_BINARY)
contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (255, 0, 0), 3)

for c in contours:
   epsilon = 0.01*cv2.arcLength(c,True)
   approx = cv2.approxPolyDP(c,epsilon,True)
    
   # 绘制凸形
   hull = cv2.convexHull(c)

   cv2.drawContours(img,[c],-1,(0,255,0),2)
   cv2.drawContours(img,[approx],-1,(255,0,255),2)
   cv2.drawContours(img,[hull],-1,(0,0,255),2)

cv2.imshow("contour", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

先看效果

contour

3.2cv2.approxPolyDP()函数

cv2.approxPolyDP()函数

功能:描绘近似多边形轮廓

输入参数

  1. 轮廓
  2. 原始轮廓和近似多边形之间的最大误差δ值
  3. 布尔标志,如果是True,表示多边形是闭合的

δ值:δ是近似多边形周长和原始轮廓线周长之差的最大值,δ值越低,近似值越接近原始轮廓

一般我们可以用轮廓的周长作为参考值:
δ = epsilon =0.01*cv2.arcLength(c,True)

epsilon = 0.01*cv2.arcLength(c,True)
approx = cv2.approxPolyDP(c,epsilon,True)

此时,δ 是原弧度的1%

4.结语

本来还想讲一下霍夫变换的,无奈本人才疏学浅,天性愚钝🤔而且霍夫变换的理论部分又晦涩难懂,便留到下一节再讲吧

讲完霍夫变换,入门篇也差不多学完了,接下来打算实战一下,把15篇博客统一整理一下。毕竟蓦然回首当初写的文章,不能说拉跨吧,只能说完全看不下去😅😅😅

或许可以整理成一本书?让我们看看接下来会发生什么哈哈哈哈哈哈🤣🤣🤣

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落叶随峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值