OpenCV 图像处理 轮廓检测基本原理

文章目录

    • 基本原理
      • 关键函数和参数
      • 注意事项
    • 示例代码
      • 示例效果
      • 代码详解
      • findContours 函数原型
      • findContours函数变体

基本原理

轮廓发现是图像处理中的一个重要步骤,用于检测物体的边界和形状。

  1. 图像预处理
    轮廓发现通常在灰度图像上进行。因此,首先将图像转换为灰度图像。接下来,应用滤波器来减少噪声。常用的滤波器有高斯模糊(Gaussian Blur),它有助于平滑图像并减少噪声。

  2. 边缘检测
    在预处理后的图像上应用边缘检测算法。常用的边缘检测算法是Canny边缘检测器,它能有效地检测出图像中的边缘。Canny边缘检测器使用梯度的方向和幅度来找到图像中的边缘。

  3. 轮廓提取
    一旦得到二值化的边缘图像,就可以使用OpenCV的findContours函数来提取轮廓。findContours函数将图像中的每一个边缘视为一个轮廓,并返回一个轮廓列表。每个轮廓都由一系列点组成,这些点定义了轮廓的形状。

  4. 轮廓的层次结构
    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)
    用于在图像上绘制轮廓。

注意事项

  1. 图像的预处理
    轮廓发现对输入图像的质量非常敏感。良好的预处理(如去噪、对比度增强等)可以显著提高轮廓检测的效果。

  2. 边缘检测器的选择
    边缘检测器的参数(如Canny边缘检测器的阈值)需要根据图像的特征进行调整。

  3. 轮廓的近似和表示
    对于复杂的形状,可以使用多边形逼近(如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;
}

示例效果

在这里插入图片描述

代码详解

  1. 读取图像

    Mat src = imread("image.jpg");
    

    使用imread函数加载图像。

  2. 灰度化

    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    

    使用cvtColor函数将彩色图像转换为灰度图像。

  3. 高斯模糊

    Mat blurred;
    GaussianBlur(gray, blurred, Size(5, 5), 1.5);
    

    使用GaussianBlur函数对灰度图像进行平滑处理,以减少噪声。

  4. Canny边缘检测

    Mat edges;
    Canny(blurred, edges, 100, 200);
    

    使用Canny函数进行边缘检测。这里100200是低和高阈值,用于控制边缘的检测。

  5. 发现轮廓

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(edges, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
    

    使用findContours函数提取图像中的轮廓。RETR_TREE参数用于获取轮廓的层次结构,CHAIN_APPROX_SIMPLE用于压缩水平、垂直和对角直线段,只保留它们的终点。

  6. 绘制轮廓

    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函数在图像上绘制检测到的轮廓。

  7. 显示结果

    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()
);

参数详解

  1. image: InputOutputArray

    • 输入图像,通常为二值化图像(如通过边缘检测得到的图像)。该图像会被修改,因此如果需要保留原图像,应该传递其副本。
    • 类型通常为 CV_8UC1,即单通道8位无符号整数。
  2. contours: OutputArrayOfArrays

    • 检测到的轮廓列表,每个轮廓是一个点的向量(即 std::vector<Point>)。每个点表示轮廓的一部分。
    • 具体类型为 std::vector<std::vector<Point>>
  3. hierarchy: OutputArray

    • 可选的层次结构输出向量。对于每个轮廓,hierarchy[i][0] 表示下一个轮廓的索引,hierarchy[i][1] 表示前一个轮廓的索引,hierarchy[i][2] 表示第一个子轮廓的索引,hierarchy[i][3] 表示父轮廓的索引。
    • 如果不需要层次结构,可以传递 noArray() 或一个空的 Mat
  4. mode: int

    • 轮廓检索模式,决定如何提取轮廓以及如何处理它们之间的关系。可选值有:
      • RETR_EXTERNAL: 只检索最外层的轮廓。
      • RETR_LIST: 检索所有轮廓,不建立层次关系。
      • RETR_CCOMP: 检索所有轮廓,组织为两级结构:顶层是连通分量的外边界,次层是孔的边界。
      • RETR_TREE: 检索所有轮廓,并重建完整的嵌套轮廓。
  5. method: int

    • 轮廓逼近方法,指定如何对轮廓点进行存储。可选值有:
      • CHAIN_APPROX_NONE: 存储所有的轮廓点。
      • CHAIN_APPROX_SIMPLE: 压缩水平、垂直和对角线段,只保留这些线段的终点。
      • CHAIN_APPROX_TC89_L1CHAIN_APPROX_TC89_KCOS: 使用 Teh-Chin 链逼近算法。
  6. offset: Point (默认值为 Point())

    • 偏移量,用于所有轮廓点坐标的偏移。这在对图像中的ROI区域进行轮廓检测时尤其有用。

findContours函数变体

它不要求输出层次结构的层次信息。这种简化版的函数原型对于只关心检测到的轮廓而不需要它们之间的层次结构关系的情况是有用的。其具体定义如下:

CV_EXPORTS void findContours(InputArray image,OutputArrayOfArrays contours,int mode,int method,Point offset = Point()
);

参数详解

  1. image: InputArray
    • 输入图像,通常是一个二值图像(如通过边缘检测得到的图像)。该图像会被修改,因此如果需要保留原图像,应该传递其副本。
    • 类型通常为 CV_8UC1,即单通道8位无符号整数。
  2. contours: OutputArrayOfArrays
    • 检测到的轮廓列表,每个轮廓是一个点的向量(即 std::vector<Point>)。每个点表示轮廓的一部分。
    • 具体类型为 std::vector<std::vector<Point>>
  3. mode: int
    • 轮廓检索模式,决定如何提取轮廓以及如何处理它们之间的关系。可选值包括:
      • RETR_EXTERNAL: 只检索最外层的轮廓。
      • RETR_LIST: 检索所有轮廓,不建立层次关系。
      • RETR_CCOMP: 检索所有轮廓,组织为两级结构:顶层是连通分量的外边界,次层是孔的边界。
      • RETR_TREE: 检索所有轮廓,并重建完整的嵌套轮廓。
  4. method: int
    • 轮廓逼近方法,指定如何对轮廓点进行存储。可选值包括:
      • CHAIN_APPROX_NONE: 存储所有的轮廓点。
      • CHAIN_APPROX_SIMPLE: 压缩水平、垂直和对角线段,只保留这些线段的终点。
      • CHAIN_APPROX_TC89_L1CHAIN_APPROX_TC89_KCOS: 使用 Teh-Chin 链逼近算法。
  5. offset: Point (默认值为 Point())
    • 偏移量,用于所有轮廓点坐标的偏移。这在对图像中的ROI(感兴趣区域)进行轮廓检测时尤其有用。

使用场景

这个版本的findContours函数适用于简单的轮廓检测任务,尤其是当不需要关心轮廓之间的层次关系时。例如,在一些形状分析或对象检测的应用中,只需要获取所有的轮廓而不关心它们的嵌套关系,此时可以使用这个简化的函数原型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/388621.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

程序员转型AI大模型好转吗?成功率高吗?

前言 在程序员圈子中&#xff0c;技术转型近年来一直是热门话题。随着AI技术的迅猛发展&#xff0c;优秀人才短缺&#xff0c;程序员向AI大模型转型似乎成为了一条通往职场先机的路径。但是&#xff0c;这条转型之路是否容易走&#xff0c;成功率又如何呢&#xff1f; 一、程…

SSM大学生体质管理系统-计算机毕业设计源码75960

摘要 基于SSM的大学生体质管理系统是一款综合性平台&#xff0c;融合了在线课程、健康知识、体测报告等多项功能&#xff0c;旨在为广大大学生提供全方位的健康管理服务。通过在线课程和健康知识模块&#xff0c;用户可以随时学习健康知识&#xff0c;掌握科学的健康管理方法&a…

大屏自适应方案

1.npm下载 npm i autofit.js2.在项目中引入 import autofit from autofit.js3.init(&#xff09;初始化&#xff0c;注意&#xff1a;要在mounted&#xff08;&#xff09;里

通过阿里云OOS“快速设置”快速配置多地域运维任务

1. 介绍 什么是系统运维管理OOS? 系统运维管理OOS&#xff08;CloudOps Orchestration Service&#xff09;是阿里云提供的一项云上自动化运维服务&#xff0c;旨在帮助用户实现运维任务的自动化管理和执行。通过OOS&#xff0c;用户可以设计模板来详细定义执行任务的内容、…

微型丝杆弯曲:工件精度下降的隐形杀手!

微型丝杆作为精密机械部件&#xff0c;‌其弯曲或变形会对使用它进行加工的工件产生直接影响。在机械加工中&#xff0c;微型丝杆弯曲是一个不容忽视的问题&#xff0c;它会对工件造成多方面的损害。 1、加工精度受损&#xff1a;弯曲会直接导致工具的实际运动轨迹与程序设计的…

【软件建模与设计】-07-静态建模

目录 1、类之间关系 1.1、关联 1.1.1、关联的多重性 1.1.2、三元关联 1.1.3、一元关联 1.1.4、关联类 2、组合与聚合层次 2.1、组合 2.2、聚合 3、泛化/特化层次 4、约束 5、静态建模和UML 5.1、问题域的静态建模 6、系统上下文的静态建模 7、使用UML构造型对类…

【Python学习手册(第四版)】学习笔记12-if语句(and、or、三元表达式)详解

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文较简单&#xff0c;对if语句的格式、示例、多路做了示例&#xff0c;以及真值测试&#xff08;and、or等&#xff09;介绍&#xff0c;最后介绍了三三元表达式…

8G内存的Mac够用吗 ?苹果电脑内存满了怎么清理?可以有效地管理和优化你的Mac电脑内存,确保设备运行流畅

嘿&#xff0c;朋友们&#xff0c;让咱们聊聊怎么让我们的Mac小伙伴时刻保持巅峰状态吧&#xff01;想象一下&#xff0c;每一次点击、每一次滑动&#xff0c;都如同初见时那般丝滑顺畅&#xff0c;是不是超级心动&#xff1f;为了这份持久的畅快体验&#xff0c;我强烈推荐大家…

注册中心--Eureka

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;Spring Cloud实战&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 1.项目问题 2.解决URL问题 2.1解决思路 2.2注册中心 2.3 CAP理…

2024.8.1 作业

使用两个线程完成两个文件的拷贝&#xff0c;分支线程1拷贝前一半&#xff0c;分支线程2拷贝后一半&#xff0c;主线程回收两个分支线程的资源 代码&#xff1a; /*******************************************/ 文件名&#xff1a;threadwork.c /************************…

06.java集合

1.集合框架体系 集合主要分为两组&#xff1a;单列集合(collection)&#xff0c;双列集合(map) 单列集合(collection接口) 双列集合(map接口) 2.Collection接口 (1).常见的方法 */ public class arraylist_ {public static void main(String[] args) {//常用方法&#xff0…

Day81 代码随想录打卡|贪心算法篇---跳跃游戏 II

题目&#xff08;leecode T45&#xff09;&#xff1a;给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j…

【Linux】(26) 详解磁盘与文件系统:从物理结构到inode机制

目录 1.认识磁盘、 1.1 理论 1.2 磁盘的物理结构 CHS 寻址 1.3 磁盘的逻辑抽象结构 2. inode 结构 1.Boot Block 启动块 2.Super Block&#xff08;超级块&#xff09; 3.Group Descriptor Block&#xff08;块组描述符&#xff09; 4.Data Blocks (数据块) 5.Inode…

【C++】巧用缺省参数与函数重载:提升编程效率的秘密武器

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间 本章将分享缺省参数与函数重载相关知识&#xff0c;为了更加深入学习C打下了坚实的基础。本章重点在于缺省参数与函数重载使用前提与注意事项 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1…

[C++]多态与虚函数

一、多态的概念 顾名思义&#xff0c;多态的意思就是一个事物有多种形态&#xff0c;在完成某个行为的时候&#xff0c;当不同的对象去完成时会产生不同的状态。在面向对象方法中一般是这样表示多态的&#xff1a;向不同的对象发送同一条消息&#xff0c;不同的对象在接收时会产…

jetbrain插件市场无法下载插件/idea插件install无效

最近把电脑重装了一次系统&#xff0c;发现idea插件市场可以搜到插件&#xff0c;但是不显示overview之类的信息&#xff0c;点install也没反应。 于是打算直接到插件市场的官网plugins.jetbrains.com下载插件安装。 结果发现同样可以搜索到插件&#xff0c;但是无法下载。 在…

中国工商银行长春分行开展“工驿幸福 健康财富”长辈客群康养活动

中国工商银行长春分行作为国有大行&#xff0c;持续完善有温度、专业化、安全稳健的养老场景服务&#xff0c;以工行驿站为依托、以长辈客群养老需求为中心&#xff0c;积极对接社区构建敬老、康养的“金融泛金融”工行驿站服务生态&#xff0c;进一步提升长辈客群的到店体验。…

第十九天培训笔记

上午 1 、构建 vue 发行版本 [rootserver eleme_web]# nohup npm run serve& // 运行 vue 项目 [rootserver eleme_web]# mkdir /eleme [rootserver eleme_web]# cp -r /root/eleme_web/dist/* /eleme/ // 将项目整体 移动到 /eleme 目录下 [rootserver eleme_web]# …

Opencv threshold函数、adaptiveThreshold函数详解和示例

1.threshold函数 double cv::threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type ) src&#xff1a;待二值化的图像&#xff0c;图像只能是 CV_8U 和 CV_32F 两种数据类型。对于图像通道数目的要求与选择的二值化方法相关。dst&#xff1a;…

TypeScript 定义不同的类型(详细示例)

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…