OpenCV-Python图像轮廓
简介OpenCV-Python图像轮廓
轮廓检测有什么作用:使用轮廓检测可以获得物体的边界,方便在图像中对他们进行定位。
什么是轮廓:当我们把物体边缘所有的点连接在一起可以获得轮廓。对于特定的轮廓是指那些具有相同颜色和亮度的边界点像素。
调用流程:
(1)读入图像
(2)将读入图像转化为灰度图
(3)对(2)得到的灰度图进行二值化或者Candy边缘检测处理,从而把感兴趣的物体加亮凸显出来以便于使用轮廓检测算法
(4)进行轮廓检测(使用 findContours()函数来检测图像中的所有的轮廓)
(5)在原图中显示轮廓(使用 drawContours()函数来在原图上显示轮廓)
注意:
1、对象是二值图像。所以需要预先进行阈值分割或者边缘检测处理;
2、查找轮廓需要更改原始图像。因此,通常使用原图像的一份拷贝操作;
3、在OpenCV中,是从黑色背景中查找白色对象。因此,对象必须是白色的,背景必须是黑色的。
一、进行轮廓检测
conturs,hierarchy = cv2.findContours(img,mode,method)
参数:
- contours:检测到的轮廓,每个轮廓是由一些点构成的向量组成
- hierarchy:记录轮廓之间的层级关系,四个维度分别代表:同级后一个轮廓的序号、同级上一个轮廓的序号、第一个孩子序号,父亲序号
- mode:检测轮廓的层级关系排列规则:
(1)RETR_EXTERNAL:仅仅检测外圈轮廓;
(2)RETR_LIST:检测所有轮廓,但是没有层级关系;
(3)RETR_CCOMP:仅仅两层包含关系,即只有外层和内层,假设有夹层,那么夹层也算外层,只要某个轮廓还包含有轮廓,都算外部轮廓;
(4)RETR_TREE:检测所有的轮廓,并存储非常完整的层级关系,一般都用这个 把所有轮廓都存下来以后用得到哪个就拿哪个 - method:轮廓点的存储方式:
(1)CHAIN_APPROX_NONE:将要存储的轮廓整个存储下来;
(2)HAIN_APPROX_SIMPLE:该算法对水平、垂直以及对角线方向的片段轮廓进行了省略,仅仅保存了他们的端点。这意味着所有直线上的点都会消失,只保存端点信息,比如矩形就只保存四个顶点。这种模式先处理速度要比CHAIN_APPROX_NONE更快,所需要的内存更少,因此执行时间就会被节省。
二、绘制轮廓
img = cv2.drawContours(img,contours,index,color,thickness,linetype)
参数:
- contours:是list类型的数组,里面存储了轮廓数组包含所有存储的轮廓
- contourIdx:从上面的轮廓list中取出哪一个画出来,-1代表全部
- color:绘制轮廓所用颜色
- thickness:线条粗细,-1代表填充式画轮廓,整个轮廓内部被指定颜色填充
- lineType:线条类型,虚线、实线之类的,默认实线
注意:
绘制轮廓钱要做一个原图的副本,图片传入绘制轮廓函数后,会在该图片上画出轮廓从而使得该图片无法使用
示例:
import cv2
src_img = cv2.imread("5-1.jpg", cv2.IMREAD_UNCHANGED)
cv2.imshow("src_img", src_img)
# 先对图像进行灰度处理
gray = cv2.cvtColor(src_img, cv2.COLOR_BGR2GRAY)
# 进行二值处理
rat, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 查找轮廓
contours,hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 画出轮廓
r = cv2.drawContours(src_img, contours, -1, (0, 255, 0), 6)
cv2.imshow('result', r)
cv2.waitKey(0)
cv2.destroyAllWindows()
如果有一张图片如下:
背景是白色的,我们需要找轮廓,我们需要的轮廓信息是椭圆和长方形轮廓,如果按上面的程序进行处理,效果如下:
但是效果是,轮廓多了一个最大的长方形轮廓,这是因为在OpenCV中,是从黑色背景中查找白色对象。因此,对象必须是白色的,背景必须是黑色的。所以要解决如下问题,只需要在进行二值处理时,选择反二进制阈值化。将:
rat, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
改成:
rat, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
现在就达到需要的效果了。