21.OpenCV获取图像轮廓信息

OpenCV获取图像轮廓信息

在计算机视觉领域,识别和分析图像中的对象形状是一项基本任务。OpenCV 库提供了一个强大的工具——轮廓检测(Contour Detection),它能够帮助我们精确地定位对象的边界。这篇博文将带你入门 OpenCV 的轮廓检测,理解其原理,并学会如何在 C++ 中使用它。

1.什么是轮廓?

简单来说,轮廓可以看作是一条连接所有具有相同颜色或灰度值的连续点(沿着边界)的曲线。

更准确地说,轮廓是图像中强度或颜色发生显著变化的区域的边界。在 OpenCV 中,轮廓检测通常作用于二值图像(只有黑色和白色像素的图像)。算法会寻找白色(或非零)区域的边界,并将这些边界表示为一系列点的坐标。

通过检测轮廓,我们可以实现目标分割、形状分析、物体计数、特征提取及对象检测和识别等任务。

轮廓介绍

如上图1,2,3 轮廓还有层次,有最外的轮廓1依次往里包括2,3轮廓。

2. OpenCV 轮廓检测函数

2.1 findContours 函数

findContours 是 OpenCV 中最常用的轮廓检测函数,其函数原型如下:

void findContours(InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy,int mode, int method, Point offset = Point());
  • image:输入的二值图像(非零值表示前景)。
  • contours:输出轮廓,存储为 std::vector<std::vector<Point>>
  • hierarchy:输出轮廓的层级信息,描述轮廓之间的嵌套关系。
  • mode:轮廓检索模式,如 RETR_EXTERNAL(只检测最外层轮廓)、RETR_LIST(检测所有轮廓但不建立层级关系)、RETR_TREE(检测所有轮廓并重构完整的层级结构)。
  • method:轮廓近似方法,如 CHAIN_APPROX_SIMPLE(压缩水平、垂直和对角冗余点)和 CHAIN_APPROX_NONE(存储所有点)。
  • offset:可选参数,用于给输出轮廓的所有点加上偏移值。

2.3 drawContours 函数

drawContours 函数用于在图像上绘制检测到的轮廓。它可以帮助直观展示轮廓检测和形状分析的结果。函数原型如下:

void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx,const Scalar& color, int thickness = 1, int lineType = LINE_8,InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point());
  • image:输入输出图像,即在该图像上绘制轮廓。
  • contours:轮廓集合,通常由 findContours 得到,类型为 std::vector<std::vector<Point>>
  • contourIdx:指定绘制哪一个轮廓;若设为 -1,则绘制所有轮廓。
  • color:绘制轮廓的颜色,如 Scalar(0,255,0) 表示绿色。
  • thickness:轮廓线的粗细;若为负值,则填充轮廓内部。
  • lineType:线型,默认 LINE_8
  • hierarchy:轮廓的层级信息,可选。
  • maxLevel:绘制轮廓的最大层级,默认 INT_MAX
  • offset:绘制时添加的偏移量。

drawContours 常用于可视化轮廓检测结果,结合 findContours 使用可以将检测到的目标区域在图像上直观标记出来。

2.3 轮廓检测的基本步骤

使用 OpenCV C++ 进行轮廓检测通常遵循以下步骤:

  1. 读取图像 (Read Image): 使用 cv::imread 加载你想要处理的源图像到 cv::Mat 对象。
  2. 转换为灰度图 (Convert to Grayscale): 使用 cv::cvtColor 将彩色图像转换为灰度图,以简化图像信息。
  3. 二值化 (Thresholding): 使用 cv::threshold 将灰度图像转换为二值图像。这是轮廓检测的关键步骤,因为 findContours 函数通常需要二值图像作为输入。
  4. 查找轮廓 (Find Contours): 使用 cv::findContours() 函数来检测图像中的所有轮廓。
  5. 绘制轮廓 (Draw Contours): (可选)使用 cv::drawContours() 函数将检测到的轮廓绘制在原始图像或新的画布上,以便可视化。

2.4 参考代码

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;int main() {// 读取灰度图像Mat src = imread("E:/image/test.png");if (src.empty()) {cerr << "图像加载失败!" << endl;return -1;}Mat gray;cvtColor(src, gray, COLOR_BGR2GRAY);GaussianBlur(gray, gray, Size(5, 5), 0);Mat binary;double otsu_thresh_val = threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);cout << "Otsu 自动选择的阈值为:" << otsu_thresh_val << endl;imshow("原始灰度图像", gray);imshow("otsu 二值化", binary);//查找轮廓vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);cout << hierarchy.size();//绘制所有轮廓Mat contourImage = src.clone();drawContours(contourImage, contours, -1, Scalar(0, 0, 255), 1);imshow("contour", contourImage);waitKey(0);destroyAllWindows();return 0;
}

轮廓检测结果

如果只想要最外面的轮廓只需要把参数RETR_TREE改为**RETR_EXTERNAL**

3. 计算并绘制轮廓几何特征

在检测到轮廓后,我们可以计算并绘制轮廓的几何特征,例如:

  • 面积 (contourArea)
  • 周长 (arcLength)
  • 重心
  • 最小外接矩形 (boundingRect)
  • 最小外接圆 (minEnclosingCircle)

3.1 参考代码

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像并转换为灰度图Mat src = imread("E:/image/test1.png");if (src.empty()) {cerr << "图像加载失败!" << endl;return -1;}Mat gray;cvtColor(src, gray, COLOR_BGR2GRAY);// 应用阈值处理得到二值图像Mat binary;threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);// 检测轮廓vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);// 创建用于显示轮廓的图像Mat contourImage = src.clone();for (size_t i = 0; i < contours.size(); i++) {// 绘制轮廓drawContours(contourImage, contours, static_cast<int>(i), Scalar(0, 255, 0), 2);// 计算轮廓面积和周长double area = contourArea(contours[i]);double perimeter = arcLength(contours[i], true);if (area < 500) continue;// 计算重心Moments M = moments(contours[i]);int cx = static_cast<int>(M.m10 / M.m00);int cy = static_cast<int>(M.m01 / M.m00);circle(contourImage, Point(cx, cy), 5, Scalar(255, 0, 0), -1);// 计算外接矩形Rect boundingBox = boundingRect(contours[i]);rectangle(contourImage, boundingBox, Scalar(0, 0, 255), 2);//最小外接矩形RotatedRect box2 = minAreaRect(contours[i]);Point2f vertices[4];box2.points(vertices);for (int j = 0; j < 4; j++) {line(contourImage, vertices[j], vertices[(j + 1) % 4], Scalar(0, 255, 255), 1);}// 计算最小外接圆Point2f center;float radius;minEnclosingCircle(contours[i], center, radius);circle(contourImage, center, static_cast<int>(radius), Scalar(255, 255, 0), 2);// 在图像上标注几何特征putText(contourImage, "Area: " + to_string(static_cast<int>(area)),Point(boundingBox.x, boundingBox.y - 10), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 1);putText(contourImage, "Perimeter: " + to_string(static_cast<int>(perimeter)),Point(boundingBox.x, boundingBox.y + boundingBox.height + 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 1);}// 显示结果imshow("轮廓检测与几何特征", contourImage);waitKey(0);return 0;
}

代码简介

  1. 轮廓检测:使用 findContours 提取二值图像中的所有轮廓。
  2. 绘制轮廓:使用 drawContours 绘制检测到的轮廓。
  3. 计算几何特征
    • 面积和周长:使用 contourAreaarcLength 计算。
    • 重心:通过 moments 计算轮廓的中心点,并用 circle 绘制。
    • 最小外接矩形:使用 boundingRect 计算,并用 rectangle 绘制。
    • 最小外接圆:使用 minEnclosingCircle 计算,并用 circle 绘制。
  4. 标注特征信息:使用 putText 在图像上显示面积和周长。
  5. 面积筛选:代码中过滤不显示面积小于500的轮廓
    获取轮廓信息

4. 应用场景

轮廓检测技术在多个领域都有广泛应用,包括但不限于:

  • 目标分割和计数

    利用轮廓检测可以分割图像中的独立目标,并统计数量,如细胞计数、车牌识别等。

  • 形状分析

    分析轮廓的几何特征(如周长、面积、凸包、旋转角度等),用于目标识别和匹配。

  • 运动跟踪

    在视频处理中,通过检测运动目标的轮廓,进一步实现对象跟踪和行为分析。

  • OCR 前处理

    对文档图像进行轮廓检测,提取文字区域,为光学字符识别(OCR)提供准备工作。

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

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

相关文章

LETTERS(DFS)

【题目描述】 给出一个rowcolrowcol的大写字母矩阵&#xff0c;一开始的位置为左上角&#xff0c;你可以向上下左右四个方向移动&#xff0c;并且不能移向曾经经过的字母。问最多可以经过几个字母。 【输入】 第一行&#xff0c;输入字母矩阵行数RR和列数SS&#xff0c;1≤R,S≤…

Day2-2:前端项目uniapp壁纸实战

再在wallpaper新建一个目录components 在components下新建组件common-title 记得点击创建同名目录 在index加 <view class"select"><common-title></common-title></view> 图片换了下&#xff0c;原来的有点丑&#xff0c;图片可按自己喜欢…

其他 vector 操作详解(四十)

介绍 除去向 vector 添加元素&#xff08;如 push_back&#xff09;之外&#xff0c;vector 还提供了许多其他操作&#xff0c;这些操作大多与 string 的操作类似。通过掌握这些操作&#xff0c;我们可以方便地查询、修改和比较 vector 中的元素&#xff0c;从而构建灵活、高效…

【Leetcode 每日一题】368. 最大整除子集

问题背景 给你一个由 无重复 正整数组成的集合 n u m s nums nums&#xff0c;请你找出并返回其中最大的整除子集 a n s w e r answer answer&#xff0c;子集中每一元素对 ( a n s w e r [ i ] , a n s w e r [ j ] ) (answer[i], answer[j]) (answer[i],answer[j]) 都应当…

python基础-13-处理excel电子表格

文章目录 【README】【13】处理Excel电子表格【13.1】Excel文档【13.2】安装openpyxl模块【13.3】读取Excel文档【13.3.1】使用openpyxl模块打开excel文档【13.3.2】从工作簿取得工作表【13.3.3】从工作表sheet获取单元格cell【13.3.5】从表中获取行和列【13.3.6】工作簿、工作…

ABS函数c++

简介&#xff1a; abs 函数用于计算一个数的绝对值&#xff0c;在 C 中它继承自 C 语言的标准库&#xff0c;其历史可以追溯到早期的 C 语言发展历程&#xff0c;以下是详细介绍&#xff1a; 早期编程语言的需求 在计算机编程的早期阶段&#xff0c;处理数学运算就是一项基本…

闭环SOTA!北航DiffAD:基于扩散模型实现端到端自动驾驶「多任务闭环统一」

端到端自动驾驶目前是有望实现完全自动驾驶的一条有前景的途径。然而&#xff0c;现有的端到端自动驾驶系统通常采用主干网络与多任务头结合的方式&#xff0c;但是它们存在任务协调和系统复杂度高的问题。为此&#xff0c;本文提出了DiffAD&#xff0c;它统一了各种驾驶目标并…

整车CAN网络和CANoe

车载网络中主要包含有Can网络,Lin网络,FlexRay,Most,以太网。 500kbps:500波特率,表示的数据传输的速度。表示的是最大的网速传输速度。也就是每秒 500kb BodyCan车身Can InfoCan娱乐信息Can 车身CAN主要连接的是ESB电动安全带 ADB自适应远光灯等 PTCan动力Can 底盘Can

实战设计模式之迭代器模式

概述 与上一篇介绍的解释器模式一样&#xff0c;迭代器模式也是一种行为设计模式。它提供了一种方法来顺序访问一个聚合对象中的各个元素&#xff0c;而无需暴露该对象的内部表示。简而言之&#xff0c;迭代器模式允许我们遍历集合数据结构中的元素&#xff0c;而不必了解这些集…

JVM 垃圾回收器是如何判断一个对象是否要回收?

JVM 垃圾回收器&#xff08;Garbage Collector&#xff09;需要判断哪些对象是“垃圾”&#xff0c;即不再被程序使用的对象&#xff0c;以便回收它们占用的内存。JVM 主要使用以下两种方法来判断对象是否是垃圾&#xff1a; 1. 引用计数算法 (Reference Counting): 原理&…

kali——httrack

目录 前言 使用教程 前言 HTTrack 是一款运行于 Kali Linux 系统中的开源网站镜像工具&#xff0c;它能将网站的页面、图片、链接等资源完整地下载到本地&#xff0c;构建出一个和原网站结构相似的离线副本。 使用教程 apt install httrack //安装httrack工具 httrac…

kotlin函数类型

一 函数类型定义 1 定义 函数类型就是 (Int, Int) -> Int 函数类型其实就是将函数的 “参数类型” 和 “返回值类型” 抽象出来 2 示例 &#xff1a; (Int, Int) -> Int 表示接收两个 Int 参数并返回 Int 的函数类型&#xff1b; (String) -> Unit 表示接收 Strin…

C# Winform 入门(9)之如何封装并调用dll

封装dll 首先创建 .Net平台 类库 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace _09.Encapsulation_dll {public class Program{/// <summary>/// 求两个double类型的数值的和/// &l…

前后端分离下,Spring Boot 请求从发起到响应的完整执行流程

以下是前后端分离架构下&#xff0c;Spring Boot 请求从发起到响应的完整执行流程&#xff0c;结合你提出的所有问题&#xff0c;按真实执行顺序和职责链条重新整理所有核心概念、结构、关键类、数据转换点和典型代码示例&#xff1a; 一、前端发起请求&#xff08;步骤1-2&…

基于sklearn实现文本摘要思考

和各位小伙伴分享一下使用sklearn进行文本摘要的思考。 第一版本 原理 提取式文本摘要的基本原理是&#xff1a; 将文本分割成句子 计算每个句子的重要性(权重) 选择权重最高的几个句子组成摘要 常用的句子权重计算方法&#xff1a; TF-IDF&#xff1a;基于词频-逆文档频…

OpenHarmony子系统开发 - DFX(三)

OpenHarmony子系统开发 - DFX&#xff08;三&#xff09; 五、HiTraceMeter开发指导 HiTraceMeter概述 简介 HiTraceMeter在OpenHarmony中&#xff0c;为开发者提供业务流程调用链跟踪的维测接口。通过使用该接口所提供的功能&#xff0c;可以帮助开发者迅速获取指定业务流…

2025年 能够有效提升AI的生成质量和逻辑严谨性 的通用型系统提示

以下是三个经过精心设计的通用型系统提示&#xff08;System Prompt&#xff09;&#xff0c;能够有效提升AI的生成质量和逻辑严谨性&#xff0c;适用于各类对话、分析和创作场景&#xff1a; Prompt 1 - 专家级分步验证模式 你是一个具备跨领域知识整合能力的超级AI&#xff…

python爬虫:小程序逆向实战教程

根据我之前发表的文章&#xff0c;我们进行延伸实战https://blog.csdn.net/weixin_64809364/article/details/146981598?spm1001.2014.3001.5501 1. 想要爬取什么小程序&#xff0c;我们进行搜索 2. 找到我们vx小程序的文件地址&#xff0c;我们就可以进行破解 破解步骤强看…

C语言变长数组(VLA)详解:灵活处理动态数据的利器

引言 在C语言中&#xff0c;传统的数组大小必须在编译时确定&#xff0c;这限制了程序处理动态数据的灵活性。C99标准引入的变长数组&#xff08;Variable-Length Array, VLA&#xff09; 打破了这一限制&#xff0c;允许数组长度在运行时动态确定。本文将深入解析VLA的语法、…

串口数据转换为IP数据

串口数据转换为IP数据是一种常见的通信技术,用于将传统的串行设备(如传感器、控制器等)接入现代的IP网络。以下是详细介绍: 1. 转换原理 串口数据转换为IP数据的过程涉及硬件和软件的结合,核心是将串行数据封装为TCP/IP或UDP/IP数据包,通过网络传输。具体步骤如下: 硬…