本文分享内容来自图书《学习OpenCV 4:基于Python的算法实战》,该书内容如下:

第1章 OpenCV快速入门;
第2章 图像读写模块imgcodecs;
第3章 核心库模块core;
第4章 图像处理模块imgproc(一);
第5章 图像处理模块imgproc(二);
第6章 可视化模块highgui;
第7章 视频处理模块videoio;
第8章 视频分析模块video;
第9章 照片处理模块photo;
第10章 2D特征模块features2d;
第11章 相机标定与三维重建模块calib3d;
第12章 传统目标检测模块objdetect;
第13章 机器学习模块ml;
第14章 深度神经网络模块dnn

欢迎关注图书《深度学习计算机视觉实战》与《学习OpenCV4:基于Python的算法实战》。

Canny边缘检测算法可以很好的检测出目标的边缘,但是没有将这些边缘作为一个整体进行处理。而轮廓是一系列连续的点组成的曲线,可以表达物体的基本外形,在目标识别中有着重要作用。

案例65:轮廓查找

OpenCV中提供了轮廓查找的函数findContours,该函数处理的图像可以是Canny边缘检测的结果,也可以是使用阈值化得到的图像,函数定义如下:

contours, hierarchy = findContours(image, mode, method, contours=None, hierarchy=None, offset=None)

参数说明如下:

u image,输入图像,需传入二值图像;

u mode,轮廓查找的模式,由RetrievalModes定义(见4.1节);

u method,轮廓近似方式,由ContourApproximationModes定义(见4.1节);

u contours,检测到的轮廓的坐标点(返回值);

u hierarchy,轮廓层次(返回值);

u offset,每个轮廓点移动的偏移量。

本案例使用的源图像如图5.39所示。

图5.39

轮廓查找的案例代码如下:
import cv2
import numpy as np
#读取图像,转为灰度图像
img = cv2.imread('contour_src.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#阈值化
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# 寻找二值图像的轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#打印轮廓数量
print("Contour Numbers:", len(contours))
#打印层次关系
print("hierarchy\n", hierarchy)

执行后的打印信息如下:

Contour Numbers: 4
hierarchy
[[[-1 -1 1 -1]
[-1 -1 2 0]
[-1 -1 3 1]
[-1 -1 -1 2]]]

轮廓数量为4个,包括五边形、圆形,四边形和整个图像最外围的轮廓。

hierarchy为轮廓的层次关系,每一个轮廓中的四个元素的含义对应为:[下一个轮廓索引,上一个轮廓索引,第一个子轮廓索引,父轮廓索引],如果对应的关系不存在则对应位置的值为-1。hierarchy与参数mode有关,不同的mode对应的hierarchy不同。

案例66:轮廓绘制

对于查找到的轮廓,可以使用OpenCV中提供的轮廓绘制函数drawContours进行绘制,函数定义如下:

image = drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

参数说明如下:

u image,输入图像,在该图像上绘制轮廓(返回值);

u contours,查找到的轮廓;

u contourIdx,绘制的轮廓编号,全部绘制则编号为负数;

u color,绘制颜色;

u thickness,绘制线的粗细;

u lineType,绘制线的线型,由LineTypes定义(见4.1节);

u hierarchy,绘制轮廓的层次;

u maxLevel,轮廓绘制级别;

u offset,绘制轮廓偏移。

轮廓查找与轮廓绘制的完整案例代码如下:

import cv2
import numpy as np
#读取图像,转为灰度图像
img = cv2.imread('contour_src.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#阈值化
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# 寻找二值图像的轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#打印轮廓数量
print("Contour Numbers:", len(contours))
#打印层次关系
print("hierarchy\n", hierarchy)
#创建白底图像
contours_img = np.zeros(img.shape[:], dtype=np.uint8)
contours_img[:] = 255
#绘制轮廓
cv2.drawContours(contours_img, contours, -1, (0, 0, 255), 2)
cv2.imshow('contours_result', contours_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

本案例中绘制了所有的轮廓,绘制结果如图5.40所示。

图5.40

如果想绘制某个轮廓,则传入对应的轮廓编号即可,本案例中包括四个轮廓,从外到内的轮廓编号分别为0,1,2,3,轮廓2的绘制的结果如图5.41所示。

图5.41

OpenCV中提供了轮廓面积的计算函数contourArea,函数定义如下:

retval = contourArea(contour, oriented=None)

参数说明如下:

contour,待计算面积的轮廓。

oriented,带方向的面积标志。如果为true,函数将根据轮廓方向(顺时针或逆时针)返回带符号的面积值,这样可以通过获取某个面积的符号来确定轮廓的方向。默认情况下,参数为false,这意味着返回面积的绝对值;

u retval,计算的面积结果。

在轮廓绘制案例代码的基础上,计算面积的案例代码如下:

area = cv2.contourArea(contours_list[1])
print("Contour 1 Area is: ", area)

计算结果输出如下:

Contour 1 Area is: 219110.0