实战OpenCV之直方图

基础入门

        直方图是对数据分布情况的图形表示,特别适用于图像处理领域。在图像处理中,直方图通常用于表示图像中像素值的分布情况。直方图由一系列矩形条(也被称为bin)组成,每个矩形条的高度表示某个像素值(或像素值范围)在图像中出现的频次。直方图的横轴(X轴)表示像素值的范围,通常对于8位灰度图像,其范围为0-255。直方图的纵轴(Y轴)表示在图像中每个像素值(或像素值范围)出现的频次。

        在OpenCV中,计算直方图使用cv::calcHist函数,其函数原型如下。

void cv::calcHist(const Mat* images, int nimages, const int* channels, const Mat& mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool accumulate=false);

        各个参数的含义如下。

        images:输入图像或图像集合的指针数组。images指向一个图像矩阵数组,nimages指定数组的长度,即要处理的图像数量。通常,当处理单个图像时,会传递一个包含单个图像地址的指针。

        nimages:输入图像的数量,表示images数组中图像的个数。

        channels:一个整数数组,指定了要从每个图像中使用的通道的索引。比如:如果处理的是一个三通道的BGR图像,并且只想计算蓝色通道的直方图,则应传递{0}。如果想计算所有通道的联合直方图,则可以传递{0, 1, 2}。

        mask: 可选的掩码图像,它定义了一个感兴趣的区域,只有这个区域内的像素才会被用于计算直方图。如果不需要掩码,可以传递一个空的cv::Mat()。

        hist:输出的直方图,它是一个多维数据的数组,其维度取决于dims和histSize参数。这个输出直方图需要事先创建好,或使用智能指自动管理内存。

        dims:直方图的维度。对于单通道图像,通常是1;对于多通道联合直方图,这个值会更高。

        histSize:指定每一维直方图的bin(桶)数量的数组。对于单通道8位图像,通常使用{256}来表示从0到255的每个灰度级都有一个bin。

        ranges:指定每个维度的值范围的数组的指针。通常情况下,对于单通道8位图像,每个维度的范围是{0, 256},意味着从0到255的像素值范围。数组中的每个元素都是一个包含两个元素(起始值和结束值)的数组。

        accumulate:如果设置为true,则当前计算的直方图会被累积到hist中已有的值上。默认值为false,意味着每次调用都会重新计算直方图,而不保留之前的结果。

实战解析

        在下面的实战代码中,我们首先读取一张图像,并转换为灰度图像img。然后,计算该图像的灰度直方图hist。其中histSize设为256,意味着将灰度级分为256个区间。接下来,我们使用cv::normalize函数对其进行归一化处理,以确保直方图的高度总和为1,便于可视化展示。

        最后,我们创建一个新的图像histImage,用于绘制直方图。通过循环遍历每个bin,根据每个bin的高度在histImage上绘制相应的矩形条,形成可视化的直方图。直方图的背景色为白色,矩形条的颜色为蓝色。

#include <opencv2/opencv.hpp>
using namespace cv;#include <iostream>
using namespace std;int main()
{Mat img = imread("OpenCV.png", IMREAD_GRAYSCALE);if(img.empty()){cout << "Can not open or find the image" << endl;return -1;}// 计算灰度直方图int channels[] = {0};int histSize = 256;float range[] = {0, 256};const float* histRange = {range};bool uniform = true;bool accumulate = false;Mat hist;calcHist(&img, 1, channels, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate);// 对直方图进行归一化normalize(hist, hist, 0, 1, NORM_MINMAX, -1, Mat());// 绘制直方图int hist_w = 512;int hist_h = 400;int bin_w = cvRound((double)hist_w / histSize);Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(255, 255, 255));for(int i = 1; i < histSize; i++){rectangle(histImage, Point(bin_w*(i-1), hist_h - cvRound(hist.at<float>(i-1)*hist_h)),Point(bin_w*(i), hist_h), Scalar(255, 0, 0), -1);}// 显示原图和直方图imshow("Original Image", img);imshow("Histogram", histImage);waitKey(0);destroyAllWindows();return 0;
}

        执行上面的代码,运行效果可参考下图。

直方图比较

        比较两个直方图的相似度是通过cv::compareHist函数实现的,常用于图像检索、对象识别等场景,该函数的原型如下。

double cv::compareHist(InputArray H1, InputArray H2, int method);

        各个参数的含义如下。

        H1:第一个直方图。

        H2:第二个直方图,需要与H1有相同的尺寸和类型。

        method:指定用于比较直方图的方法,被定义为枚举类型cv::HistCompMethods,常用的比较方法如下。

          (1)cv::HISTCMP_CORREL:相关性方法,计算两个直方图之间的皮尔逊相关系数。此时,函数返回值表示两个直方图之间的皮尔逊相关系数,范围从[-1, 1]。值接近1表示两个直方图非常相似(高度相关),值接近-1表示两者几乎完全负相关,而接近0则表示没有线性关系。

          (2)cv::HISTCMP_INTERSECT:交集方法,计算两直方图的重叠部分。此时,函数返回值的范围是[0, 1]。值越接近1表示直方图越相似,值越接近0表示差异越大。

          (3)cv::HISTCMP_BHATTACHARYYA:巴氏距离,计算两直方图的巴塔查里亚距离。此时,函数返回值用于衡量两个直方图的相似度。这是一种基于概率密度函数的测度,值越小表示直方图越相似。最大值为1,表示完全不相似。

        在下面的实战代码中,我们首先读取两张灰度图像img1和img2。然后,分别计算每张图像的灰度直方图,并使用cv::normalize函数对直方图进行了归一化处理。接下来,我们使用cv::compareHist函数比较这两个直方图。最后,我们输出了比较结果,展示了两幅图像直方图的相似度。

#include <opencv2/opencv.hpp>
using namespace cv;#include <iostream>
using namespace std;int main()
{Mat img1 = imread("OpenCV.png", IMREAD_GRAYSCALE);Mat img2 = imread("C++.png", IMREAD_GRAYSCALE);if(img1.empty() || img2.empty()){cout << "Can not open or find the image" << endl;return -1;}// 计算两幅图像的直方图int histSize = 256;float range[] = {0, 256};const float* histRange = {range};bool uniform = true;bool accumulate = false;Mat hist1;Mat hist2;calcHist(&img1, 1, 0, Mat(), hist1, 1, &histSize, &histRange, uniform, accumulate);calcHist(&img2, 1, 0, Mat(), hist2, 1, &histSize, &histRange, uniform, accumulate);// 归一化直方图normalize(hist1, hist1, 0, 1, NORM_MINMAX, -1, Mat());normalize(hist2, hist2, 0, 1, NORM_MINMAX, -1, Mat());// 比较直方图double result = compareHist(hist1, hist2, HISTCMP_CORREL);// 输出:0.953461cout << result << endl;waitKey(0);destroyAllWindows();return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙设置,修改APP图标和名称

1、先看默认的图标和名称 2、打开项目开始设置自己需要的图标和名称 2.1找到 路径src\main\module.json5&#xff0c; 找到 abilities&#xff0c;下的&#xff0c;图标icon、名称label&#xff0c;label可以按住ctrl鼠标左键点击跳转 2.2先修改APP名称 1、ctrl鼠标左键点击…

华为OD机试 - 选修课(Python/JS/C/C++ 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

【C语言零基础入门篇 - 15】:单链表

文章目录 单链表链表的基本概念单链表功能的实现单链表的初始化单链表新结点的创建单链表头插法单链表的输出单链表的查找单链表修改单链表的删除单链表所有数据结点释放源代码 单链表 链表的基本概念 一、什么是链表&#xff1f; 链表是数据结构中线性表的一种&#xff0c;其…

华为OD机试 - 需要打开多少监控器(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

软考高级:数据库保持函数依赖和有损无损分解 AI 解读

讲解 生活化例子 想象你经营着一家快餐店&#xff0c;店里有各种商品&#xff0c;你也记录了每天的销量。你有一个表格&#xff0c;记录了「商品名称」、「价格」、「库存数量」、「供应商信息」等数据。最开始&#xff0c;你可能把所有数据都写在一张表上&#xff0c;但时间…

2024年9月22日---关于MyBatis框架(1)

一 Mybatis概述 1.1 简介 MyBatis&#xff08;官网&#xff1a;mybatis – MyBatis 3 | 简介 &#xff09;是一款优秀的开源的 持久层 框架&#xff0c;用于简化JDBC的开发。是 Apache的一个开源项目iBatis&#xff0c;2010年这个项目由apache迁移到了google code&#xff0c…

PCL 随机下采样

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff08;长期更新&#xff09; 一、概述 随机下采样 是一种常用的点…

类和对象(2)(重点)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 类的默认成员函数 概念概述 默认成员函数就是用户没有显式实现&#xff0c;编译器会自…

项目扩展一:信道池的实现

项目扩展一&#xff1a;信道池的实现 一、为何要设计信道池1.引入信道的好处2.为何要设计信道池 二、信道池的设计1.服务器需要设计信道池吗&#xff1f;2.设计&#xff1a;动态变化的信道池1.为什么&#xff1f;2.怎么办&#xff1f;1.动态扩容和缩容2.LRU风格的信道置换3.小总…

0基础学习HTML(十三)布局

HTML 布局 网页布局对改善网站的外观非常重要。 请慎重设计您的网页布局。 如何使用 <table> 元素添加布局。 网站布局 大多数网站会把内容安排到多个列中&#xff08;就像杂志或报纸那样&#xff09;。 大多数网站可以使用 <div> 或者 <table> 元素来创建…

软件测试分类篇(下)

目录 一、按照测试阶段分类 1. 单元测试 2. 集成测试 3. 系统测试 3.1 冒烟测试 3.2 回归测试 4. 验收测试 二、按照是否手工测试分类 1. 手工测试 2. 自动化测试 3. 手工测试和自动化测试的优缺点 三、按照实施组织分类 1. α测试(Alpha Testing) 2. β测试(Beta…

【LTW】Domain General Face Forgery Detection by Learning to Weight

文章目录 Domain General Face Forgery Detection by Learning to Weightkey points方法LTW元分割策略学习过程损失函数实验评价结果消融实验总结Domain General Face Forgery Detection by Learning to Weight 会议:AAAI-21 作者: code: https://github.com/skJack/LTW 上…

理解JVM中的死锁:原因及解决方案

死锁是并发应用程序中的常见问题。在此类应用程序中&#xff0c;我们使用锁定机制来确保线程安全。此外&#xff0c;我们使用线程池和信号量来管理资源消耗。然而&#xff0c;在某些情况下&#xff0c;这些技术可能会导致死锁。 在本文中&#xff0c;我们将探讨死锁、死锁出现…

旋转机械故障诊断 震动故障分析与诊断

旋转机械故障诊断 机理资料整理 电气故障&#xff0c;机械故障(不平衡&#xff0c;不对中&#xff0c;松动&#xff0c;轴承&#xff0c;共振&#xff0c;流体振动&#xff0c;皮带松动)&#xff0c;低速与高速机器故障诊断等 旋转机械故障诊断&#xff1a;机理资料整理 目录…

河钢数字PMO牛红卫受邀为第四届中国项目经理大会演讲嘉宾

全国项目经理专业人士年度盛会 河钢数字技术股份有限公司项目管理部PMO牛红卫受邀为PMO评论主办的全国项目经理专业人士年度盛会——2024第四届中国项目经理大会演讲嘉宾&#xff0c;演讲议题为“从技术到领导力——项目经理成长进阶之道”。大会将于10月26-27日在北京举办&…

数据结构——串的模式匹配算法(BF算法和KMP算法)

算法目的&#xff1a; 确定主串中所含子串&#xff08;模式串&#xff09;第一次出现的位置&#xff08;定位&#xff09; 算法应用&#xff1a; 搜索引擎、拼写检查、语言翻译、数据压缩 算法种类&#xff1a; BF算法&#xff08;Brute-Force&#xff0c;又称古典的…

NASA:ATLAS/ICESat-2 L3 B每周网格大气数据集V005

目录 简介 摘要 代码 引用 网址推荐 0代码在线构建地图应用 机器学习 ATLAS/ICESat-2 L3B Weekly Gridded Atmosphere V005 简介 该产品报告每周全球云覆盖率、海洋上总列光学深度、极地云覆盖率、风吹雪频率、视表面反照率以及地面探测频率。 参数&#xff1a;云光学…

Java 每日一刊(第15期):内部类

文章目录 前言内部类成员内部类&#xff08;Member Inner Class&#xff09;静态内部类&#xff08;Static Nested Class&#xff09;局部内部类&#xff08;Local Inner Class&#xff09;匿名内部类&#xff08;Anonymous Inner Class&#xff09; 内部类的详细对比内部类字节…

新增用户 开发

原型分析 接口设计 数据库设计 代码开发 controller /*** 新增员工** param employeeDTO* return*/ApiOperation("新增员工")PostMappingpublic Result<String> save(RequestBody EmployeeDTO employeeDTO) {log.info("新增员工&#xff1a;{}", emp…

C++离线查询

前言 C算法与数据结构 打开打包代码的方法兼述单元测试 概念及原理 离线算法( offline algorithms)&#xff0c;离线计算就是在计算开始前已知所有输入数据&#xff0c;输入数据不会产生变化&#xff0c;且在解决一个问题后就要立即得出结果的前提下进行的计算。 通俗的说&a…