侯体宗的博客
  • 首页
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

OpenCV-Python实现轮廓检测实例分析

Python  /  管理员 发布于 7年前   222

相比C++而言,Python适合做原型。本系列的文章介绍如何在Python中用OpenCV图形库,以及与C++调用相应OpenCV函数的不同之处。这篇文章介绍在Python中使用OpenCV检测并绘制轮廓。

提示:

转载请详细注明原作者及出处,谢谢!

本文介绍在OpenCV-Python中检测并绘制轮廓的方法。

本文不介详细的理论知识,读者可从其他资料中获取相应的背景知识。笔者推荐清华大学出版社的《图像处理与计算机视觉算法及应用(第2版)》。

轮廓检测

轮廓检测也是图像处理中经常用到的。OpenCV-Python接口中使用cv2.findContours()函数来查找检测物体的轮廓。

实现

使用方式如下:

import cv2  img = cv2.imread('D:\\test\\contour.jpg') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)  contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img,contours,-1,(0,0,255),3)  cv2.imshow("img", img) cv2.waitKey(0) 

需要注意的是cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),所以读取的图像要先转成灰度的,再转成二值图,参见4、5两行。第六行是检测轮廓,第七行是绘制轮廓。

结果

原图如下:

检测结果如下:

注意,findcontours函数会“原地”修改输入的图像。这一点可通过下面的语句验证:

cv2.imshow("binary", binary) contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) cv2.imshow("binary2", binary) 

执行这些语句后会发现原图被修改了。

cv2.findContours()函数

函数的原型为

cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])

返回两个值:contours:hierarchy。

参数

第一个参数是寻找轮廓的图像;

第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
cv2.RETR_EXTERNAL表示只检测外轮廓
cv2.RETR_LIST检测的轮廓不建立等级关系
cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
cv2.RETR_TREE建立一个等级树结构的轮廓。

第三个参数method为轮廓的近似办法
cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

返回值

cv2.findContours()函数返回两个值,一个是轮廓本身,还有一个是每条轮廓对应的属性。

contour返回值

cv2.findContours()函数首先返回一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示。这个概念非常重要。在下面drawContours中会看见。通过

print (type(contours)) print (type(contours[0])) print (len(contours)) 

可以验证上述信息。会看到本例中有两条轮廓,一个是五角星的,一个是矩形的。每个轮廓是一个ndarray,每个ndarray是轮廓上的点的集合。

由于我们知道返回的轮廓有两个,因此可通过

cv2.drawContours(img,contours,0,(0,0,255),3) 

和

cv2.drawContours(img,contours,1,(0,255,0),3) 

分别绘制两个轮廓,关于该参数可参见下面一节的内容。同时通过

print (len(contours[0])) print (len(contours[1])) 

输出两个轮廓中存储的点的个数,可以看到,第一个轮廓中只有4个元素,这是因为轮廓中并不是存储轮廓上所有的点,而是只存储可以用直线描述轮廓的点的个数,比如一个“正立”的矩形,只需4个顶点就能描述轮廓了。

hierarchy返回值

此外,该函数还可返回一个可选的hiararchy结果,这是一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0]~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。

通过

print (type(hierarchy)) print (hierarchy.ndim) print (hierarchy[0].ndim) print (hierarchy.shape) 

得到

3 2 (1, 2, 4) 

可以看出,hierarchy本身包含两个ndarray,每个ndarray对应一个轮廓,每个轮廓有四个属性。

轮廓的绘制

OpenCV中通过cv2.drawContours在图像上绘制轮廓。

cv2.drawContours()函数

cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])

第一个参数是指明在哪幅图像上绘制轮廓;
第二个参数是轮廓本身,在Python中是一个list。
第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。后面的参数很简单。其中thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。绘制参数将在以后独立详细介绍。

补充:

写着写着发现一篇文章介绍不完,所以这里先作为入门的。更多关于轮廓的信息有机会再开一篇文章介绍。

但有朋友提出计算轮廓的极值点。可用下面的方式计算得到,如下

pentagram = contours[1] #第二条轮廓是五角星  leftmost = tuple(pentagram[:,0][pentagram[:,:,0].argmin()]) rightmost = tuple(pentagram[:,0][pentagram[:,:,0].argmin()])  cv2.circle(img, leftmost, 2, (0,255,0),3)  cv2.circle(img, rightmost, 2, (0,0,255),3)  

注意!假设轮廓有100个点,OpenCV返回的ndarray的维数是(100,1,2)!!!而不是我们认为的(100,2)。切记!!!人民邮电出版社出版了一本《NumPy攻略:Python科学计算与数据分析》,推荐去看一下。

更新:关于pentagram[:,0]的意思

在numpy的数组中,用逗号分隔的是轴的索引。举个例子,假设有如下的数组:

a = np.array([[[3,4]], [[1,2]],[[5,7]],[[3,7]],[[1,8]]]) 

其shape是(5, 1, 2)。与我们的轮廓是相同的。那么a[:,0]的结果就是:

[3,4], [1,2], [5,7], [3,7], [1,8] 

这里a[:,0]的意思就是a[0:5,0],也就是a[0:5,0:0:2],这三者是等价的。

回头看一下,a的shape是(5,1,2),表明是三个轴的。在numpy的数组中,轴的索引是通过逗号分隔的。同时冒号索引“:”表示的是该轴的所有元素。因此a[:,0]表示的是第一个轴的所有元素和第二个轴的第一个元素。在这里既等价于a[0:5,0]。

再者,若给出的索引数少于数组中总索引数,则将已给出的索引树默认按顺序指派到轴上。比如a[0:5,0]只给出了两个轴的索引,则第一个索引就是第一个轴的,第二个索引是第二个轴的,而第三个索引没有,则默认为[:],即该轴的所有内容。因此a[0:5,0]也等价于a[0:5,0:0:2]。

再详细一点,a的全体内容为:[[[3,4]],[[1,2]],[[5,7]],[[3,7]],[[1,8]]]。去掉第一层方括号,其中有五个元素,每个元素为[[3,4]]这样的,所以第一个索引的范围为[0:5]。注意OpenCV函数返回的多维数组和常见的numpy数组的不同之处!

观察[[3,4]],我们发现其中只有一个元素,即[3,4],第二个索引为[0:1]。

再去掉一层方括号,我们面对的是[3,4],有两个元素,所以第三个索引的范围为[0:2]。

再次强调一下OpenCVPython接口函数返回的NumPy数组和普通的NumPy数组在组织上的不同之处。

PS:OpenCV-Python讨论群――219962286,欢迎大家加入互相探讨学习。

得到的结果为如下:

总结

以上就是本文关于OpenCV-Python实现轮廓检测实例分析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

简单了解OpenCV是个什么东西

python通过opencv实现批量剪切图片

python+opencv实现的简单人脸识别代码示例

如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!


  • 上一条:
    python selenium UI自动化解决验证码的4种方法
    下一条:
    Python实现改变与矩形橡胶的线条的颜色代码示例
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go语言中实现字符串可逆性压缩及解压缩功能(0个评论)
    • 使用go + gin + jwt + qrcode实现网站生成登录二维码在app中扫码登录功能(0个评论)
    • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客