[OpenCV] 数字图像处理 C++ 学习——17轮廓发现详细讲解+附完整代码

文章目录

前言

轮廓发现是图像处理中一个重要的操作,可以帮助找到图像中的边界并识别物体的形状。在 OpenCV 中,findContours 函数可以用来检测图像中的轮廓,广泛应用于图像分割、形状分析、物体检测等场景。本篇文章将详细介绍如何在 OpenCV 中实现轮廓发现,并通过完整的 C++ 代码示例进行演示。

1.理论基础

1.1轮廓发现

轮廓发现是基于图像边缘提取的基础寻找对象轮廓的方法。 所以边缘提取的阈值选定会影响最终轮廓发现结果。

1.2轮廓发现步骤

  • 图像预处理cvtColor将输入的图像转为灰度图像,并使用 Canny 边缘检测算法来提取边缘。
  • 发现轮廓 :使用 findContours 函数从二值图像中发现轮廓。findContours 函数会输出一个包含轮廓的列表。
  • 绘制轮廓 :使用 drawContours 函数将发现的轮廓绘制在图像上。

1.3相关API

(1)轮廓发现(find contour)

cpp 复制代码
cv::findContours(
InputOutputArray image, // 输入图像,非0的像素被看成1,0的像素值保持不变,8-bit  
OutputArrayOfArrays contours,//  全部发现的轮廓对象
OutputArray hierachy,// 图该的拓扑结构,可选,该轮廓发现算法正是基于图像拓扑结构实现。
int mode, //  轮廓返回的模式
int method,// 发现方法
Point offset=Point()//  轮廓像素的位移,默认(0, 0)没有位移
)

(2)轮廓绘制(draw contour)

cpp 复制代码
void drawContours( 
InputOutputArray image, //输出图像 
InputArrayOfArrays contours,//全部发现的轮廓对象
int contourIdx, //轮廓索引号
const Scalar& color,//绘制时候颜色
int thickness = 1, //绘制线宽
int lineType = LINE_8,//线的类型LINE_8
InputArray hierarchy = noArray(),//拓扑结构图
int maxLevel = INT_MAX,// 最大层数, 0只绘制当前的,1表示绘制绘制当前及其内嵌的轮廓 
Point offset = Point() // 轮廓位移,可选
);

2.代码实现

2.1图像预处理

对输入图像进行预处理。将图像转为灰度图,然后使用 Canny 边缘检测算法提取图像的边缘。

cpp 复制代码
// 将图像转为灰度图
cvtColor(src, src, COLOR_BGR2GRAY);
// 使用Canny边缘检测
Canny(src, dst, threshold_value, threshold_value * 2, 3, false);

2.2轮廓发现

在二值化图像上使用 findContours 函数来发现轮廓,findContours 返回轮廓列表 contours 以及层次结构 hierarchy

cpp 复制代码
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
// 寻找轮廓
findContours(dst, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

2.3绘制轮廓

通过 drawContours 函数在图像上绘制检测到的轮廓。为了直观显示不同的轮廓,可以为每个轮廓使用不同颜色。

cpp 复制代码
Mat drawImg = Mat::zeros(dst.size(), CV_8UC3);
RNG rng(12345);
for (size_t i = 0; i < contours.size(); i++) {
    Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    drawContours(drawImg, contours, i, color, 2, LINE_8, hierarchy);
}

2.4Trackbar 调整阈值

动态调整 Canny 算法的阈值,使用 OpenCV 的 createTrackbar 函数,通过滑动条实时改变阈值并重新检测轮廓。

cpp 复制代码
createTrackbar("Threshold Value:", output_win, &threshold_value, threshold_max, Demo_Contours);
Demo_Contours(0, 0);

效果展示

3.完整代码

cpp 复制代码
#include<opencv2/opencv.hpp>
#include<highgui.hpp>
#include<iostream>
#include<math.h>

using namespace cv;
using namespace std;

Mat src, dst;
int threshold_value = 100;
int threshold_max = 255;

const char* output_win = "findcontours-demo";
void Demo_Contours(int, void*)
{
	vector<vector<Point>>contours;
	vector<Vec4i>hierarchy;
	Canny(src, dst, threshold_value, threshold_value * 2, 3, false);
	findContours(dst, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	Mat drawImg = Mat::zeros(dst.size(), CV_8UC3);
	RNG rng(12345);
	for (size_t i = 0; i < contours.size(); i++) {
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawImg, contours, i, color, 2, LINE_8, hierarchy);
	}
	imshow(output_win, drawImg);
}

void find_contour()
{
	src = imread("fish.jpg");
	if (src.empty())
	{
		cout << "ERROR: Could not load image." << endl;
		return;
	}
	namedWindow("input_image", WINDOW_AUTOSIZE);
	namedWindow(output_win, WINDOW_AUTOSIZE);
	cvtColor(src, src, COLOR_BGR2GRAY);

	const char* trackbar_title = "Threshold Value:";
	createTrackbar(trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours);
	Demo_Contours(0, 0);

	imshow("input_image", src);
	waitKey(0);
  
}
int main() 
{
  find_contour();
  return 0;
}
相关推荐
随便取个六字28 分钟前
C++学习:类和对象(二)
c++·学习
jimmy.hua1 小时前
C++刷怪笼(9)继承
开发语言·c++
OMGmyhair1 小时前
【 C++ 】C++11的初步学习
开发语言·c++·学习
LeapMay2 小时前
3D Gaussian Splatting 入门
计算机视觉·3d
秋说2 小时前
【数据结构 | PTA】懂蛇语
数据结构·c++
凯子坚持 c3 小时前
String的长度有限,而我对你的思念却无限延伸
c++
何曾参静谧3 小时前
「C/C++」C++20 之 #include<ranges> 范围
c语言·c++·c++20
挨代码4 小时前
C++ —— 常见的初始化
c++
BH042509094 小时前
VQGAN(2021-06:Taming Transformers for High-Resolution Image Synthesis)
计算机视觉·扩散模型·图像生成·cv
酒鬼猿4 小时前
C++初阶(七)--类和对象(4)
开发语言·c++