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


Posted in Python onJanuary 05, 2018

相比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两行。第六行是检测轮廓,第七行是绘制轮廓。

结果

原图如下:

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

检测结果如下:

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

注意,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实现轮廓检测实例分析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

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

Python 相关文章推荐
python使用PythonMagick将jpg图片转换成ico图片的方法
Mar 26 Python
python装饰器初探(推荐)
Jul 21 Python
pandas or sql计算前后两行数据间的增值方法
Apr 20 Python
pytorch cnn 识别手写的字实现自建图片数据
May 20 Python
python 使用值来排序一个字典的方法
Nov 16 Python
利用python GDAL库读写geotiff格式的遥感影像方法
Nov 29 Python
python 多线程重启方法
Feb 18 Python
python 函数中的内置函数及用法详解
Jul 02 Python
python 哈希表实现简单python字典代码实例
Sep 27 Python
python分布式计算dispy的使用详解
Dec 22 Python
Python3列表List入门知识附实例
Feb 09 Python
Selenium自动化测试工具使用方法汇总
Jun 12 Python
django2 快速安装指南分享
Jan 05 #Python
Python实现改变与矩形橡胶的线条的颜色代码示例
Jan 05 #Python
用python制作游戏外挂
Jan 04 #Python
Python学习之Anaconda的使用与配置方法
Jan 04 #Python
Windows下Anaconda的安装和简单使用方法
Jan 04 #Python
Python+OpenCV让电脑帮你玩微信跳一跳
Jan 04 #Python
Python编程求解二叉树中和为某一值的路径代码示例
Jan 04 #Python
You might like
php 求质素(素数) 的实现代码
2011/04/12 PHP
php从memcache读取数据再批量写入mysql的方法
2014/12/29 PHP
使用PHPStorm+XDebug搭建单步调试环境
2017/11/19 PHP
详解PHP PDO简单教程
2019/05/28 PHP
PHP7 其他修改
2021/03/09 PHP
jquery 实现两Select 标签项互调示例代码
2014/09/25 Javascript
jQuery鼠标悬浮链接弹出跟随图片实例代码
2016/01/08 Javascript
在 Typescript 中使用可被复用的 Vue Mixin功能
2018/04/17 Javascript
Bootstrap模态对话框中显示动态内容的方法
2018/08/10 Javascript
新版小程序登录授权的方法
2018/12/12 Javascript
express启用https使用小记
2019/05/21 Javascript
深入浅出vue图片路径的实现
2019/09/04 Javascript
vue与iframe之间的信息交互的实现
2020/04/08 Javascript
微信小程序调用wx.getImageInfo遇到的坑解决
2020/05/31 Javascript
在Python中使用Mako模版库的简单教程
2015/04/08 Python
Python如何获取系统iops示例代码
2016/09/06 Python
详解python并发获取snmp信息及性能测试
2017/03/27 Python
Python中is与==判断的区别
2017/03/28 Python
python Socket之客户端和服务端握手详解
2017/09/18 Python
python 2.7.13 安装配置方法图文教程
2018/09/18 Python
Django给admin添加Action的步骤详解
2019/05/01 Python
numpy.random模块用法总结
2019/05/27 Python
python nohup 实现远程运行不宕机操作
2020/04/16 Python
pycharm 代码自动补全的实现方法(图文)
2020/09/18 Python
解决pycharm导入numpy包的和使用时报错:RuntimeError: The current Numpy installation (‘D:\\python3.6\\lib\\site-packa的问题
2020/12/08 Python
挪威户外活动服装和装备购物网站:Bergfreunde挪威
2016/10/20 全球购物
Vision Direct比利时:在线订购隐形眼镜
2019/08/27 全球购物
英国现代、当代和设计师家具店:Furntastic
2020/07/18 全球购物
雷朋巴西官方商店:Ray-Ban Brasil
2020/07/21 全球购物
室内设计专业个人的自我评价
2013/10/19 职场文书
大学生个人求职口试自我评价
2014/02/16 职场文书
员工试用期自我鉴定范文
2014/09/15 职场文书
谢师宴答谢词
2015/01/05 职场文书
MySQL中日期型单行函数代码详解
2021/06/21 MySQL
关于nginx 实现jira反向代理的问题
2021/09/25 Servers
Go中使用gjson来操作JSON数据的实现
2022/08/14 Golang