OpenCV(cv::findContours())
cv::findContours()
是 OpenCV 中用于检测图像中的轮廓的函数。
1. 函数定义
void findContours(
InputOutputArray image,
OutputArrayOfArrays contours,
OutputArray hierarchy,
int mode,
int method,
Point offset = Point()
);
参数:
-
image
:- 类型:
InputOutputArray
(通常是二值化后的图像) - 描述: 输入图像,通常是灰度图像或二值图像。该图像会被函数修改,因此如果你想保留原始图像,建议传入其副本。可以使用
cv::Canny()
或cv::threshold()
生成适合轮廓检测的二值图像。
- 类型:
-
contours
:- 类型:
OutputArrayOfArrays
- 描述: 输出的轮廓。每个轮廓是一个点的列表。例如,
contours[i]
表示第 i 个轮廓,它是图像中一系列连接的点集。
- 类型:
-
hierarchy
:- 类型:
OutputArray
- 描述: 输出的轮廓层次结构。它是一个包含四个整数的向量,分别表示同一级别的前一个轮廓、下一个轮廓、父轮廓和子轮廓。通过该层次结构可以了解轮廓之间的嵌套关系。
- 类型:
-
mode
:- 类型:
int
- 描述: 轮廓的检索模式,决定如何组织轮廓数据。取值可以是:
cv::RETR_EXTERNAL
: 只提取外部轮廓,即不考虑嵌套的轮廓。cv::RETR_LIST
: 提取所有的轮廓,但不创建层次关系。cv::RETR_CCOMP
: 提取所有的轮廓并将它们组织成两级层次。顶层是外部轮廓,第二层是内部轮廓。cv::RETR_TREE
: 提取所有轮廓并重构完整的嵌套轮廓的层次结构。
- 类型:
-
method
:- 类型:
int
- 描述: 轮廓的近似方法。取值可以是:
cv::CHAIN_APPROX_NONE
: 存储所有的轮廓点,不进行压缩。cv::CHAIN_APPROX_SIMPLE
: 仅存储拐点信息(去除冗余的中间点)。cv::CHAIN_APPROX_TC89_L1
,cv::CHAIN_APPROX_TC89_KCOS
: 使用 Teh-Chin 链逼近算法。
- 类型:
-
offset
:- 类型:
Point
- 描述: 轮廓中所有点的偏移量。这在需要对轮廓点进行平移时非常有用。
- 类型:
返回值:
该函数没有返回值。轮廓信息通过 contours
和 hierarchy
输出。
2. 示例
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main() {
Mat src = imread("image.png", IMREAD_GRAYSCALE);
Mat binarized;
threshold(src, binarized, 128, 255, THRESH_BINARY);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
// 检测轮廓
findContours(binarized, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
// 绘制轮廓
Mat output = Mat::zeros(src.size(), CV_8UC3);
for (size_t i = 0; i < contours.size(); i++) {
drawContours(output, contours, static_cast<int>(i), Scalar(0, 255, 0), 2, 8, hierarchy);
}
imshow("Contours", output);
waitKey(0);
return 0;
}
功能解析:
-
二值化图像: 为了使
cv::findContours()
正常工作,输入图像通常需要二值化(即背景和前景分离)。通过cv::threshold()
或cv::Canny()
可以生成二值图像。 -
轮廓近似: 使用
CHAIN_APPROX_SIMPLE
会显著减少存储轮廓的点数,因为它只会存储关键点,如直线段的拐点。这在处理复杂图像时,可以显著减少内存消耗。 -
层次结构:
hierarchy
数组能够提供轮廓的嵌套关系。例如,可以通过层次结构分析一个轮廓是否是另一个轮廓的子轮廓(例如洞内的对象)。这在分析复杂的图像时很有用。
3. 常见应用
- 对象检测: 检测并标记图像中的物体轮廓。
- 形状分析: 使用轮廓数据进行形状匹配和分析,例如计算轮廓的周长、面积等。
- 目标分割: 通过检测并处理轮廓,可以将图像中的对象分割出来用于后续处理。
4. 注意事项
- 输入图像:
cv::findContours()
会修改输入图像,因此如果需要保留原始图像,应该传递图像的副本。 - 轮廓检测模式: 根据应用场景选择合适的
mode
,例如在需要层次结构时选择RETR_TREE
,而只需要外部轮廓时选择RETR_EXTERNAL
。 - 图像预处理: 确保输入图像经过适当的预处理(如二值化),以获得正确的轮廓结果。