下一个教程: 轮廓特征
目标
什么是轮廓?
轮廓可以简单地解释为连接所有连续点(沿边界)的曲线,这些点具有相同的颜色或强度。轮廓是用于形状分析和对象检测与识别的有用工具。
- 为了获得更高的精度,请使用二值图像。因此,在查找轮廓之前,请应用阈值或 Canny 边缘检测。
- 从 OpenCV 3.2 开始,findContours() 不再修改源图像。
- 在 OpenCV 中,查找轮廓就像从黑色背景中查找白色物体一样。因此请记住,要查找的对象应该是白色的,背景应该是黑色的。
让我们看看如何查找二值图像的轮廓
import numpy as np
import cv2 as cv
assert im is not None, "文件无法读取,请使用 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_BGR)
从文件中加载图像。
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)
将图像从一种颜色空间转换为另一种颜色空间。
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 个点)获得的点。看看它节省了多少内存!!!
图像