opencv基础篇 ——(十二)轮廓提取与绘制
findContours轮廓提取
void void findContours( InputArray image, OutputArrayOfArrays contours,OutputArray hierarchy, int mode,int method, Point offset = Point());
功能介绍
cv::findContours 是 OpenCV 中用于在图像中查找轮廓的函数之一。它可以帮助你找到图像中所有的轮廓,并且可以选择性地进行轮廓的过滤和处理。主要用于在二值图像中查找对象的边界轮廓。这些轮廓通常是对象之间的分界线,可以通过它们进行形状分析、对象检测等操作。
-
image: 输入图像,必须是单通道的二值图像,即像素值为0或255(或0或1)
-
contours: 输出轮廓的容器。函数会将检测到的轮廓信息存储在这个数据结构中。具体而言,contours应当是一个 std::vector<std::vectorcv::Point> 类型的容器,其中每个内部向量代表一个轮廓,由构成该轮廓的连续边界点(cv::Point)组成。
-
hierarchy: 参数是一个可选输出参数,用于存储轮廓之间的层级关系信息。如果用户不关心轮廓间的嵌套或层次结构,可以将其设置为 noArray() 或者忽略此参数。但若希望获取轮廓间的父子关系、内部轮廓与外部轮廓的关联等信息,应提供一个合适的输出容器(如 std::vector)来接收这些数据。
每个轮廓在 hierarchy 中对应一个四元组 (h_next, v_next, h_prev, v_prev),其中:- h_next:指向同一级别下下一个轮廓的索引。
- v_next:指向当前轮廓的直接内嵌子轮廓的索引。
- h_prev:指向同一级别下前一个轮廓的索引。
- v_prev:指向当前轮廓的直接父轮廓的索引。
当某个值为 -1 时,表示没有对应的邻居或父/子轮廓。这种层次信息有助于分析图像中轮廓之间的包含关系,例如用于识别内部孔洞、独立对象以及构建多级轮廓树。
-
mode: 轮廓检索模式,指定如何组织和返回检测到的轮廓。常用的模式包括:
- cv::RETR_EXTERNAL: 只返回最外层轮廓,忽略任何嵌套的轮廓(即内部空洞或子轮廓)。
- cv::RETR_LIST: 返回所有轮廓,不建立任何层次关系,轮廓按检测顺序排列。
- cv::RETR_CCOMP: 返回所有轮廓,并按照两个级别构建层次结构:外部轮廓(级别1)和它们的内嵌孔洞(级别2)。
- cv::RETR_TREE: 返回所有轮廓,并以完整的嵌套层次结构形式组织,即每个轮廓可以有任意数量的直接子轮廓。
-
method: 轮廓逼近方法,用于决定如何将实际轮廓点集近似为更紧凑的点集,以减少轮廓点的数量。常用的逼近方法包括:
- cv::CHAIN_APPROX_SIMPLE: 仅保留轮廓端点和拐点,将轮廓压缩为一系列直线段。
- cv::CHAIN_APPROX_TC89_L1, cv::CHAIN_APPROX_TC89_KCOS: 使用 Teh-Chin 链码算法的变种进行更复杂的逼近。
- cv::CHAIN_APPROX_NONE: 不进行任何压缩,保留轮廓上的所有原始点。
-
offset: 可选的偏移量,表示在检测轮廓前将输入图像平移的像素值。这对于从原图像中裁剪出的部分进行轮廓检测时特别有用,可以确保返回的轮廓坐标与原图像坐标系统保持一致。
功能与用途
cv::findContours 函数的主要功能如下:
-
轮廓检测:在二值图像中识别并分离出各个连通的白色像素区域,即独立的物体或形状。
-
轮廓提取:将每个检测到的物体或形状的边界点序列化为一个点集(cv::Point 向量),这些点集构成了轮廓。
-
轮廓组织:根据指定的 mode 参数,可以将轮廓按不同的层次结构进行组织和返回,如仅返回最外层轮廓、返回所有轮廓的列表,或者构建完整的嵌套轮廓树。
-
轮廓近似:根据指定的 method 参数,可以选择是否对原始轮廓点集进行近似处理,以减小存储和后续处理的复杂性。
综上所述,cv::findContours 函数提供了一种通用且强大的工具,用于从二值图像中自动提取并结构化表示各种形状的轮廓信息。
drawContours 轮廓绘制
功能介绍
cv::drawContours 是 OpenCV 库中用于在图像上绘制轮廓的函数,常用于可视化检测到的轮廓或创建轮廓相关的图形输出。以下是该函数的功能介绍:
cv::drawContours(inputImage, // InputOutputArray imagecontours, // InputArrayOfArrays contourscontourIdx, // int contourIdxcolor, // const Scalar& colorthickness, // int thicknesslineType, // int lineTypehierarchy, // InputArray hierarchymaxLevel, // int maxLeveloffset // Point offset
);
参数解释:
-
inputImage: 输入/输出图像(cv::Mat 类型),轮廓将在该图像上绘制。图像可以是任意通道数和深度的,但通常为单通道或三通道(彩色)的 8-bit 或 16-bit 图像。
-
contours: 输入的轮廓数组(std::vector<std::vectorcv::Point> 类型)。这是从 cv::findContours 函数或其他方式获取的一系列轮廓,每个轮廓由一组连续的边界点(cv::Point)组成。
-
contourIdx: 要绘制的轮廓索引。可以是单个整数,表示要绘制指定索引的单个轮廓;也可以是负数,此时绘制所有轮廓:
- -1:绘制所有轮廓。
- -2:绘制除了最大(面积最大)轮廓以外的所有轮廓。
- -3:绘制除了最小(面积最小)轮廓以外的所有轮廓。
-
color: 绘制轮廓使用的颜色。对于单通道灰度图像,通常是一个标量值;对于彩色图像,通常是 cv::Scalar 类型的 BGR 或 BGRA 值。
-
thickness: 轮廓线的粗细。可以是正数(表示像素宽度)、负数(表示填充轮廓)或 CV_FILLED(完全填充轮廓,等同于负数的最大值)。
-
lineType: 线型。常见的选项包括:
- cv::LINE_8:8-connected 直线(默认)。
- cv::LINE_AA:抗锯齿线条,适用于高质量输出。
-
hierarchy: (可选)轮廓的层级信息。通常是从 cv::findContours 函数返回的,用于遵循轮廓之间的嵌套关系。如果未提供或为空,所有轮廓被视为无层级关系。
-
maxLevel: (仅当提供了 hierarchy 时有效)绘制轮廓的最大嵌套级别。例如,设置为 0 表示只绘制最外层轮廓;设置为 1 表示绘制最外层轮廓及其直接子轮廓,依此类推。
-
offset: (可选)绘制轮廓时应用的偏移量。如果提供了这个参数,所有轮廓将在原位置基础上加上这个偏移量。
功能与用途
cv::drawContours 函数的主要功能如下:
-
轮廓绘制:在指定的输入图像上绘制给定的轮廓集合,可以是单个轮廓或多组轮廓。
-
样式定制:允许用户控制轮廓的颜色、线宽(或填充方式)、线型等视觉属性,以满足不同应用场景的需求。
-
层级支持:结合轮廓的层级信息(hierarchy),可以按照轮廓间的嵌套关系有选择地绘制部分轮廓,如仅绘制最外层轮廓、特定层级的轮廓或整个轮廓树。
-
坐标变换:通过提供 offset 参数,可以在绘制轮廓时对轮廓坐标进行平移,适应图像裁剪、视窗调整等场景。
综上所述,cv::drawContours 函数为用户提供了一个灵活的工具,用于在图像上可视化表示轮廓数据,便于观察、分析和展示检测到的形状边界。该函数接受轮廓数据、绘制参数及可选的附加信息作为输入,将轮廓绘制到指定的输入图像上,生成包含轮廓图形的输出图像。
示例
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat image = imread("image.jpg", IMREAD_GRAYSCALE);if (image.empty()) {cout << "无法读取图像文件!" << endl;return -1;}Mat binary;threshold(image, binary, 128, 255, THRESH_BINARY);vector<vector<Point>> contours;vector<Vec4i> hierarchy;// 查找轮廓findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);// 绘制轮廓Mat result = Mat::zeros(image.size(), CV_8UC3);drawContours(result, contours, -1, Scalar(0, 255, 0), 2);// 显示结果imshow("Contours", result);waitKey(0);return 0;
}
效果展示
- RETR_EXTERNAL与RETR_CCOMP的区别
设置RETR_CCOMP参数,会返回内部轮廓和内部轮廓,至于上图中thickness=-1的情况下,没有输出填充图,尚未找到缘由。
-
调整参数,输出想要的格式
-
下图绘制某一图形的内外轮廓: