OpenCV 图像处理 轮廓检测基本原理
文章目录
- 基本原理
- 关键函数和参数
- 注意事项
- 示例代码
- 示例效果
- 代码详解
- findContours 函数原型
- findContours函数变体
基本原理
轮廓发现是图像处理中的一个重要步骤,用于检测物体的边界和形状。
-
图像预处理:
轮廓发现通常在灰度图像上进行。因此,首先将图像转换为灰度图像。接下来,应用滤波器来减少噪声。常用的滤波器有高斯模糊(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的模式和方法参数。
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())- 偏移量,用于所有轮廓点坐标的偏移。这在对图像中的ROI区域进行轮廓检测时尤其有用。
findContours函数变体
它不要求输出层次结构的层次信息。这种简化版的函数原型对于只关心检测到的轮廓而不需要它们之间的层次结构关系的情况是有用的。其具体定义如下:
CV_EXPORTS void findContours(InputArray image,OutputArrayOfArrays contours,int mode,int method,Point offset = Point()
);
参数详解
- image:
InputArray- 输入图像,通常是一个二值图像(如通过边缘检测得到的图像)。该图像会被修改,因此如果需要保留原图像,应该传递其副本。
- 类型通常为
CV_8UC1,即单通道8位无符号整数。
- contours:
OutputArrayOfArrays- 检测到的轮廓列表,每个轮廓是一个点的向量(即
std::vector<Point>)。每个点表示轮廓的一部分。 - 具体类型为
std::vector<std::vector<Point>>。
- 检测到的轮廓列表,每个轮廓是一个点的向量(即
- 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())- 偏移量,用于所有轮廓点坐标的偏移。这在对图像中的ROI(感兴趣区域)进行轮廓检测时尤其有用。
使用场景
这个版本的findContours函数适用于简单的轮廓检测任务,尤其是当不需要关心轮廓之间的层次关系时。例如,在一些形状分析或对象检测的应用中,只需要获取所有的轮廓而不关心它们的嵌套关系,此时可以使用这个简化的函数原型。
相关文章:
OpenCV 图像处理 轮廓检测基本原理
文章目录 基本原理关键函数和参数注意事项 示例代码示例效果代码详解findContours 函数原型findContours函数变体 基本原理 轮廓发现是图像处理中的一个重要步骤,用于检测物体的边界和形状。 图像预处理: 轮廓发现通常在灰度图像上进行。因此࿰…...
C 语言动态顺序表
test.h #ifndef _TEST_H #define _TEST_H #include <stdio.h> #include <stdlib.h> #include <string.h>typedef int data_type;// 定义顺序表结构体 typedef struct List{data_type *data; // 顺序表数据int size; // 顺序表当前长度int count; // 顺序表容…...
擅于辩论的人可以将黑的说成白的,但是存在无法解决的矛盾
擅于辩论的人有能力通过逻辑、证据和修辞等手段,巧妙地引导听众接受与事实相反的观点。 然而,这并不意味着擅于辩论的人就能将任何事物都颠倒黑白。辩论的基础是事实和逻辑,即使是最优秀的辩手,也必须遵循这些基本原则。如果某个…...
java的命令执行漏洞揭秘
0x01 前言 在Java中可用于执行系统命令常见的方式有两种,API为:java.lang.Runtime、java.lang.ProcessBuilder 0x02 java.lang.Runtime GetMapping("/runtime/exec")public String CommandExec(String cmd) {Runtime run Runtime.getRunti…...
爬虫中常见的加密算法Base64伪加密,MD5加密【DES/AES/RSA/SHA/HMAC】及其代码实现(一)
目录 基础常识 Base64伪加密 python代码实现 摘要算法 1. MD5 1.1 JavaScript 实现 1.2 Python 实现 2. SHA 2.1 JavaScript 实现 2.2 Python 实现 2.3 sha系列特征 3. HMAC 3.1 JavaScript 实现 3.2 Python 实现 对称加密 一. 常见算法归纳 1. 工作模式归纳 …...
C语言数据在内存中的存储超详解
文章目录 1. 整数在内存中的存储2. 大小端字节序和字节序判断2. 1 什么是大小端?2. 2 为什么会有大小端?2. 3 练习 3. 浮点数在内存中的存储3. 1 一个代码3. 2 浮点数的存储3. 2. 1 浮点数存的过程3. 2. 2 浮点数取的过程3. 3 题目解析 1. 整数在内存中的…...
【大模型】【NL2SQL】基本原理
三个输入: prompt 用户输入 数据库表格等信息 sql 语句...
RK3568平台(显示篇)DRM vop驱动程序分析
一.设备树配置 vopb: vopff900000 {compatible "rockchip,rk3399-vop-big";reg <0x0 0xff900000 0x0 0x2000>, <0x0 0xff902000 0x0 0x1000>;interrupts <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH 0>;assigned-clocks <&cru ACLK_VOP0>, &…...
vue3 动态加载组件
//模版调用 <component :is"geticon(item.icon)" />//引入 import { ref, onMounted, markRaw, defineAsyncComponent } from vue;//异步添加icon图标组建 function geticon(params) {const modules import.meta.glob(../components/icons/*.vue);const link …...
Latex on overleaf入门语法
Latex on overleaf入门语法 前言基本结构序言 简单的格式化命令添加注释:%加粗、斜体、下划线有序列表、无序列表 添加图片图片的标题、标签和引用 添加表格一个简单的表格为表格添加边框标题、标签、引用 数学表达式基本的数学命令 基本格式摘要段落、新行章节、分…...
使用Echarts来实现数据可视化
目录 一.什么是ECharts? 二.如何使用Springboot来从后端给Echarts返回响应的数据? eg:折线图: ①Controller层: ②service层: 一.什么是ECharts? ECharts是一款基于JavaScript的数据可视化图标库,提供直观&…...
一文搞懂GIT
文章目录 1. GiT概述1.1 GIT概述1.2 GIT安装 2. GIT组成3. GIT基本命令3.1 基本命令3.2 分支操作3.3 远程操作3.4 标签操作3.5 其他命令 1. GiT概述 1.1 GIT概述 Git 是一个分布式版本控制系统,被广泛应用于软件开发中。 Git 具有众多优点,比如&#…...
jQuery入门(四)案例
jQuery 操作入门案例 一、复选框案例 功能: 列表的全选,反选,全不选功能实现。 实现步骤和分析: - 全选 1. 为全选按钮绑定单击事件。 2. 获取所有的商品项复选框元素,为其添加 checked 属性,属性值为 true。 -…...
揭秘MITM攻击:原理、手法与防范措施
中间人攻击发生时,攻击者会在通讯两端之间插入自己,成为通信链路的一部分。攻击者可以拦截、查看、修改甚至重新定向受害者之间的通信数据,而不被双方察觉。这种攻击常见于未加密的Wi-Fi网络、不安全的HTTP连接或者通过社会工程学手段诱导受害…...
【YOLOv8】一文全解+亮点介绍+训练教程+独家魔改优化技巧
前言 Hello,大家好,我是cv君,最近开始在空闲之余,经常更新文章啦!除目标检测、分类、分隔、姿态估计等任务外,还会涵盖图像增强领域,如超分辨率、画质增强、降噪、夜视增强、去雾去雨、ISP、海…...
创建mvp ubo(uniform buffer object)
创建过程: 创建一个uniform buffer查找buffer memory requirements分配、绑定buffer memorymap buffer memory拷贝mvp data to buffer memoryunmap buffer memory 示例代码: glm::mat4 projection glm::perspective(glm::radians(45.0f), 1.0f, 0.1f…...
1.GPIO
理论说明 输入 上拉输入:拉高电平 下拉输入:拉低电平 浮空输入:不拉高也不拉低电平 输出 开漏输出:不能输出高电平(P-MOS不可用,则只能低电平) 推挽输出:可输出高低电平 输出速率…...
C++必修:STL之vector的了解与使用
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C学习 贝蒂的主页:Betty’s blog 1. C/C中的数组 1.1. C语言中的数组 在 C 语言中,数组是一组相同类型…...
【MySQL】索引 【上】 {没有索引的查询/磁盘/mysql与磁盘IO/初识索引}
文章目录 1.没有索引存在的问题2. 认识磁盘MySQL与存储MySQL与磁盘交互基本单位建立共识图解IO认识索引 在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物…...
GO goroutine状态流转
Gidle -> Grunnable newproc获取新的goroutine,并放置到P运行队列中 这也是go关键字之后实际编译调用的方法 func newproc(fn *funcval) {// 获取当前正在运行中的goroutinegp : getg()// 获取调用者的程序计数器地址,用于调试和跟踪pc : getcallerp…...
量子点自动调谐技术FAlCon框架解析与应用
1. 量子点自动调谐的挑战与FAlCon的诞生 量子点技术作为固态量子计算的主流平台之一,其核心优势在于能够与现代半导体制造工艺兼容,实现高密度的量子比特集成。我在实验室工作的十年间,亲眼见证了量子点设备从最初的单量子比特系统发展到如今…...
AI Workspace:统一管理AI编程工具配置,解决团队协作“上下文孤岛”
1. 项目概述:AI Workspace 如何解决团队AI协作的“孤岛”问题如果你和你的团队已经开始在日常开发中重度依赖 Cursor、Claude Code 这类AI编程工具,那你大概率已经遇到了一个令人头疼的“上下文孤岛”问题。想象一下这个场景:你的前端项目里&…...
并行计算突破:RNN序列依赖的并行化重构与优化
1. 并行计算革命:打破RNN序列依赖的固有认知循环神经网络(RNN)长期被视为序列建模的黄金标准,但其序列依赖性导致的计算瓶颈一直困扰着研究者。传统观点认为,评估长度为T的序列必须严格遵循O(T)的时间复杂度——即使拥…...
轻量级智能体框架MiniAgent:快速构建AI应用的核心原理与实践
1. 项目概述:一个轻量级智能体框架的诞生最近在GitHub上闲逛,发现了一个挺有意思的项目——ZhuLinsen/MiniAgent。光看名字,你大概能猜到,这是一个关于“智能体”的东西。没错,它是一个轻量级的智能体框架。但如果你以…...
FAQ 优雅下线与连接排空
Skeyevss FAQ:优雅下线与连接排空 试用安装包下载 | SMS | 在线演示 项目地址:https://github.com/openskeye/go-vss 1. 为什么需要优雅下线 滚动发布、节点维护、缩容时若 立刻杀进程,会导致: 进行中的 SIP 事务 中断&#x…...
ARM架构Hypervisor陷阱寄存器原理与应用
1. ARM架构Hypervisor陷阱寄存器深度解析在ARMv8/v9架构的虚拟化实现中,异常级别(EL)和系统寄存器构成了隔离机制的核心基础设施。作为虚拟化技术的实践者,我们需要深入理解Hypervisor如何通过精细陷阱寄存器(Fine-Grained Trap Registers)实现对关键系统…...
医疗AI系统安全设计:14项关键功能需求与风险缓解框架
1. 项目概述:当AI成为医疗决策的“副驾驶”医疗AI的浪潮已经席卷而来,从影像辅助诊断到临床决策支持,它正以前所未有的深度介入诊疗流程。然而,与所有颠覆性技术一样,它在带来效率革命的同时,也引入了全新的…...
OpenAI算力战略转向:Cerebras上市冲击推理市场,英伟达优势还能稳多久?
押注推理2026年5月,AI芯片制造商Cerebras Systems披露IPO发行细节,股票代码CBRS,计划发行2800万股,定价区间115 - 125美元,募资规模最高35亿美元,目标估值266亿美元。此时未上市的OpenAI,其“算…...
【2026】企业工商照面信息查询:深入了解企业的33项核心数据
企业工商照面信息查询:深入了解企业的33项核心数据在企业服务、金融风控、政务审批等场景中,全面了解企业工商信息至关重要。本文介绍一种高效的企业工商照面查询方案,帮助开发者快速获取企业的完整注册信息。一、为什么需要工商照面信息 企业…...
CANN/ops-math 3D反射填充算子
aclnnReflectionPad3d 【免费下载链接】ops-math 本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。 项目地址: https://gitcode.com/cann/ops-math 📄 查看源码 产品支持情况 产品是否支持Ascend 950PR/Ascend 950DT√Atlas …...
