赞
踩
轮廓发现是图像处理中的一个重要步骤,用于检测物体的边界和形状。
图像预处理:
轮廓发现通常在灰度图像上进行。因此,首先将图像转换为灰度图像。接下来,应用滤波器来减少噪声。常用的滤波器有高斯模糊(Gaussian Blur),它有助于平滑图像并减少噪声。
边缘检测:
在预处理后的图像上应用边缘检测算法。常用的边缘检测算法是Canny边缘检测器,它能有效地检测出图像中的边缘。Canny边缘检测器使用梯度的方向和幅度来找到图像中的边缘。
轮廓提取:
一旦得到二值化的边缘图像,就可以使用OpenCV的findContours
函数来提取轮廓。findContours
函数将图像中的每一个边缘视为一个轮廓,并返回一个轮廓列表。每个轮廓都由一系列点组成,这些点定义了轮廓的形状。
轮廓的层次结构:
findContours
函数不仅可以返回轮廓,还可以返回轮廓的层次结构。这对于包含内嵌轮廓(如嵌套在其他轮廓中的孔洞)的图像非常有用。层次结构信息存储了每个轮廓的父子关系。
cv2.findContours(image, mode, method)
:
image
: 输入的二值图像(通常是边缘检测的结果)。mode
: 轮廓检索模式,如cv2.RETR_EXTERNAL
(只检测外轮廓)、cv2.RETR_TREE
(检测所有轮廓并构建层次结构)。method
: 轮廓逼近方法,如cv2.CHAIN_APPROX_SIMPLE
(只保存轮廓的必要点)、cv2.CHAIN_APPROX_NONE
(保存所有轮廓点)。cv2.drawContours(image, contours, contourIdx, color, thickness)
:
用于在图像上绘制轮廓。
图像的预处理:
轮廓发现对输入图像的质量非常敏感。良好的预处理(如去噪、对比度增强等)可以显著提高轮廓检测的效果。
边缘检测器的选择:
边缘检测器的参数(如Canny边缘检测器的阈值)需要根据图像的特征进行调整。
轮廓的近似和表示:
对于复杂的形状,可以使用多边形逼近(如Douglas-Peucker算法)来简化轮廓。
轮廓发现技术广泛应用于对象检测、形状分析、图像分割等领域。在这些应用中,轮廓的精确提取和表示对于后续处理和分析至关重要。
在OpenCV中,使用C++进行轮廓发现通常包括以下主要步骤:读取图像、灰度化、边缘检测、轮廓发现和绘制轮廓。以下是一个基本的C++代码示例,展示如何使用OpenCV进行这些操作:
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { // 读取图像 Mat src = imread("image.jpg"); if (src.empty()) { cout << "无法加载图像!" << endl; return -1; } // 转换为灰度图像 Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); // 应用高斯模糊以去除噪声 Mat blurred; GaussianBlur(gray, blurred, Size(5, 5), 1.5); // 进行Canny边缘检测 Mat edges; Canny(blurred, edges, 100, 200); // 发现轮廓 vector<vector<Point>> contours; vector<Vec4i> hierarchy; findContours(edges, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); // 在原图上绘制轮廓 Mat drawing = Mat::zeros(edges.size(), CV_8UC3); for (size_t i = 0; i < contours.size(); i++) { Scalar color = Scalar(255, 0, 0); // 轮廓的颜色 drawContours(drawing, contours, (int)i, color, 2, 8, hierarchy, 0); } // 显示结果 imshow("轮廓", drawing); waitKey(0); return 0; }
读取图像:
Mat src = imread("image.jpg");
使用imread
函数加载图像。
灰度化:
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
使用cvtColor
函数将彩色图像转换为灰度图像。
高斯模糊:
Mat blurred;
GaussianBlur(gray, blurred, Size(5, 5), 1.5);
使用GaussianBlur
函数对灰度图像进行平滑处理,以减少噪声。
Canny边缘检测:
Mat edges;
Canny(blurred, edges, 100, 200);
使用Canny
函数进行边缘检测。这里100
和200
是低和高阈值,用于控制边缘的检测。
发现轮廓:
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(edges, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
使用findContours
函数提取图像中的轮廓。RETR_TREE
参数用于获取轮廓的层次结构,CHAIN_APPROX_SIMPLE
用于压缩水平、垂直和对角直线段,只保留它们的终点。
绘制轮廓:
Mat drawing = Mat::zeros(edges.size(), CV_8UC3);
for (size_t i = 0; i < contours.size(); i++) {
Scalar color = Scalar(255, 0, 0); // 轮廓的颜色
drawContours(drawing, contours, (int)i, color, 2, 8, hierarchy, 0);
}
使用drawContours
函数在图像上绘制检测到的轮廓。
显示结果:
imshow("轮廓", drawing);
waitKey(0);
使用imshow
函数显示绘制好的图像,并使用waitKey
等待用户按键。
在实际应用中,可以根据具体需求调整模糊参数、Canny边缘检测的阈值,以及findContours
的模式和方法参数。
OpenCV 中的 findContours
函数用于检测图像中的轮廓。其函数原型如下:
void findContours(
InputOutputArray image,
OutputArrayOfArrays contours,
OutputArray hierarchy,
int mode,
int method,
Point offset = Point()
);
参数详解
image: InputOutputArray
CV_8UC1
,即单通道8位无符号整数。contours: OutputArrayOfArrays
std::vector<Point>
)。每个点表示轮廓的一部分。std::vector<std::vector<Point>>
。hierarchy: OutputArray
hierarchy[i][0]
表示下一个轮廓的索引,hierarchy[i][1]
表示前一个轮廓的索引,hierarchy[i][2]
表示第一个子轮廓的索引,hierarchy[i][3]
表示父轮廓的索引。noArray()
或一个空的 Mat
。mode: int
RETR_EXTERNAL
: 只检索最外层的轮廓。RETR_LIST
: 检索所有轮廓,不建立层次关系。RETR_CCOMP
: 检索所有轮廓,组织为两级结构:顶层是连通分量的外边界,次层是孔的边界。RETR_TREE
: 检索所有轮廓,并重建完整的嵌套轮廓。method: int
CHAIN_APPROX_NONE
: 存储所有的轮廓点。CHAIN_APPROX_SIMPLE
: 压缩水平、垂直和对角线段,只保留这些线段的终点。CHAIN_APPROX_TC89_L1
和 CHAIN_APPROX_TC89_KCOS
: 使用 Teh-Chin 链逼近算法。offset: Point
(默认值为 Point()
)
它不要求输出层次结构的层次信息。这种简化版的函数原型对于只关心检测到的轮廓而不需要它们之间的层次结构关系的情况是有用的。其具体定义如下:
CV_EXPORTS void findContours(
InputArray image,
OutputArrayOfArrays contours,
int mode,
int method,
Point offset = Point()
);
参数详解
InputArray
CV_8UC1
,即单通道8位无符号整数。OutputArrayOfArrays
std::vector<Point>
)。每个点表示轮廓的一部分。std::vector<std::vector<Point>>
。int
RETR_EXTERNAL
: 只检索最外层的轮廓。RETR_LIST
: 检索所有轮廓,不建立层次关系。RETR_CCOMP
: 检索所有轮廓,组织为两级结构:顶层是连通分量的外边界,次层是孔的边界。RETR_TREE
: 检索所有轮廓,并重建完整的嵌套轮廓。int
CHAIN_APPROX_NONE
: 存储所有的轮廓点。CHAIN_APPROX_SIMPLE
: 压缩水平、垂直和对角线段,只保留这些线段的终点。CHAIN_APPROX_TC89_L1
和 CHAIN_APPROX_TC89_KCOS
: 使用 Teh-Chin 链逼近算法。Point
(默认值为 Point()
)
使用场景
这个版本的findContours
函数适用于简单的轮廓检测任务,尤其是当不需要关心轮廓之间的层次关系时。例如,在一些形状分析或对象检测的应用中,只需要获取所有的轮廓而不关心它们的嵌套关系,此时可以使用这个简化的函数原型。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。