下一篇教程: 轮廓特征
目标
什么是轮廓?
轮廓可以简单地解释为连接所有连续点(沿边界)的曲线,这些点具有相同的颜色或强度。轮廓是形状分析和物体检测及识别的有用工具。
- 为了获得更高的准确度,请使用二值图像。因此在查找轮廓之前,请应用阈值或 Canny 边缘检测。
- 从 OpenCV 3.2 开始,findContours() 不再修改源图像。
- 在 OpenCV 中,查找轮廓就像从黑色背景中查找白色物体。因此请记住,要查找的物体应为白色,而背景应为黑色。
我们来看看如何查找二值图像的轮廓
import numpy as np
import cv2 as cv
assert im is not None, "file could not be read, check with os.path.exists()"
contours, hierarchy =
cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR)
从文件中加载图像。
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0)
将图像从一个颜色空间转换成另一个颜色空间。
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
对每个数组元素应用固定级别阈值。
void findContours(InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
在二值图像中查找轮廓。
看到了吧,cv.findContours() 函数有三个参数,第一个是源图像,第二个是轮廓检索模式,第三个是轮廓近似方法。并且它会输出轮廓层次结构。轮廓是图像中所有轮廓的 Python 列表。每个单独的轮廓是一个 Numpy 数组,其中包含对象边界点的 (x,y) 坐标。
- 注意
- 我们将在后面详细讨论第二个和第三个参数以及层次结构。在那之前,代码样本中给它们的这些值对所有图像来说都是合适的。
如何绘制轮廓?
为了绘制轮廓,使用 cv.drawContours 函数。当所提供的边界点时,它也可以用来绘制任何形状。它的第一个参数是源图像,第二个参数是被当做 Python 列表传递的轮廓,第三个参数是轮廓的索引(在绘制单个轮廓时很有用。要绘制所有轮廓,传递 -1),剩余的参数是颜色、厚度等。
- 要绘制图像中的所有轮廓
void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar &color, int thickness=1, int lineType=LINE_8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point())
绘制轮廓线或填充轮廓。
- 要绘制单个轮廓,比如第 4 个轮廓
- 但是大多数时候,下面这个方法会很有用
- 注意
- 最后两种方法是一样的,但是当你深入研究之后,你会发现最后一个更有用。
轮廓近似方法
这是 cv.findContours 函数中的第三个参数。它到底表示什么?
上面我们说过轮廓具有相同强度的形状的边界。它存储形状边界的 (x,y) 坐标。但是它是否存储所有坐标?这由轮廓近似方法指定。
如果你传递 cv.CHAIN_APPROX_NONE,那么存储所有的边界点。但实际上我们是否需要所有的点?例如,你找到了一个直线的轮廓。你需要直线上的所有点来表示这条直线吗?不需要,我们只需要这条直线的两个端点。这就是 cv.CHAIN_APPROX_SIMPLE 所做的。它删除所有冗余点并压缩轮廓,从而节省内存。
下方的矩形图像演示了此技术。只需在轮廓数组(以蓝色绘制)中的所有坐标上绘制圆。第一幅图像显示了使用 cv.CHAIN_APPROX_NONE(734 个点)获得的点,第二幅图像显示了使用 cv.CHAIN_APPROX_SIMPLE(仅有 4 个点)获得的点。看看这节省了多少内存!!!
图像
其他资源
练习