实战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.mzph.cn/news/880046.shtml

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

相关文章

信息安全工程师(8)网络新安全目标与功能

前言 网络新安全目标与功能在当前的互联网环境中显得尤为重要&#xff0c;它们不仅反映了网络安全领域的最新发展趋势&#xff0c;也体现了对网络信息系统保护的不断加强。 一、网络新安全目标 全面防护与动态应对&#xff1a; 目标&#xff1a;建立多层次、全方位的网络安全防…

java日志框架之Log4j

文章目录 一、Log4j简介二、Log4j组件介绍1、Loggers (日志记录器)2、Appenders&#xff08;输出控制器&#xff09;3、Layout&#xff08;日志格式化器&#xff09; 三、Log4j快速入门四、Log4j自定义配置文件输出日志1、输出到控制台2、输出到文件3、输出到数据库 五、Log4j自…

WPF自定义Dialog模板,内容用不同的Page填充

因为审美的不同&#xff0c;就总有些奇奇怪怪的需求&#xff0c;使用框架自带的对话框已经无法满足了&#xff0c;这里记录一下我这边初步设计的对话框。别问为啥要用模板嵌套Page来做对话框&#xff0c;问就是不想写太多的窗体。。。。 模板窗体&#xff08;XAML&#xff09;…

植物大战僵尸【源代码分享+核心思路讲解】

植物大战僵尸已经正式完结&#xff0c;今天和大家分享一下&#xff0c;话不多说&#xff0c;直接上链接&#xff01;&#xff01;&#xff01;&#xff08;如果大家在运行这个游戏遇到了问题或者bug&#xff0c;那么请私我谢谢&#xff09; 大家写的时候可以参考一下我的代码思…

基于单片机的智能校园照明系统

由于校园用电量较大&#xff0c;本设计可以根据实际环境情况的改变&#xff0c;实现实时照明的控制。本设计以单片机芯片为控制芯片&#xff0c;热释电传感器采集教室中学生出入的信息&#xff0c;并把信息传递给单片机芯片&#xff0c;单片机芯片根据传感器传递过来的信息来控…

【STL】 set 与 multiset:基础、操作与应用

在 C 标准库中&#xff0c;set 和 multiset 是两个非常常见的关联容器&#xff0c;主要用于存储和管理具有一定规则的数据集合。本文将详细讲解如何使用这两个容器&#xff0c;并结合实例代码&#xff0c;分析其操作和特性。 0.基础操作概览 0.1.构造&#xff1a; set<T&…

【深度学习】(1)--神经网络

文章目录 深度学习神经网络1. 感知器2. 多层感知器偏置 3. 神经网络的构造4. 模型训练损失函数 总结 深度学习 深度学习(DL, Deep Learning)是机器学习(ML, Machine Learning)领域中一个新的研究方向。 从上方的内容包含结果&#xff0c;我们可以知道&#xff0c;在学习深度学…

Android 开发高频面试题之——Flutter

Android开发高频面试题之——Java基础篇 flutter高频面试题记录 Flutter1. dart中的作用域与了解吗2. dart中. .. ...分别是什么意思?3. Dart 是不是单线程模型?如何运行的?4. Dart既然是单线程模型支持多线程吗?5. Future是什么6. Stream是什么7. Flutter 如何和原生交互…

身份安全风险不断上升:企业为何必须立即采取行动

在推动安全AI 模型的过程中&#xff0c;许多组织已转向差异隐私。但这种旨在保护用户数据的工具是否阻碍了创新&#xff1f; 开发人员面临一个艰难的选择&#xff1a;平衡数据隐私或优先考虑精确结果。差分隐私可以保护数据&#xff0c;但通常以牺牲准确性为代价——对于医疗保…

基于51单片机的手环设计仿真

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;DHT11温湿度采集温湿度&#xff0c;滑动变阻器连接ADC0832数模转换器模拟水位传感器检测水位&#xff0c;通过LCD1602显示信息&#xff0c;然后在程序里设置好是否…

C++/CLI编程知识点小记

1.前言 本篇博文并非详细的C/CLI教程&#xff0c;仅是博主就学习和实践总结的部分知识点记录。 第一次接触C/CLI是2017年了&#xff0c;用C编写底层库&#xff0c;C/CLI编写wrapper层&#xff0c;在C#项目中进行调用&#xff0c;开发应用。 2.内容 C/CLI是一种混合编程&…

哈希简单介绍

1.直接定址法&#xff08;值的分布范围集中&#xff09; 比如统计字符串中字符出现的字数&#xff0c;字符范围是集中 2.除留余数法&#xff08;值的分布范围分散&#xff09; hashkey%n 哈希冲突&#xff1a;不同的值映射到相同的位置 解决哈希冲突的方案&#xff1a; 闭散…

Kafka集群扩容(新增一台kafka节点)

kafka集群扩容、kafka topic迁移 现有环境 IP组件角色192.168.17.51kafka01broker1192.168.17.52kafka02broker2192.168.17.53kafka03broker3 扩容之后环境 IP组件角色192.168.17.51kafka01broker1192.168.17.52kafka02broker2192.168.17.53kafka03broker3192.168.17.54ka…

三端全隔离压接端子485中继器磁耦隔离数据双向透传工业级2口信号放大器抗干扰防雷

美思联压接端子485中继器磁耦隔离工业级2口信号放大器抗干扰防雷https://item.taobao.com/item.htm?ftt&id736247434823 MS-H312S是一款专为工业自动化通信而生解决RS-485总线星型结构组网&#xff0c;解决复杂电磁场环境下RS-485大系统要求而设计的RS-485总线分割集线器(…

【设计模式】万字详解:深入掌握五大基础行为模式

作者&#xff1a;后端小肥肠 &#x1f347; 我写过的文章中的相关代码放到了gitee&#xff0c;地址&#xff1a;xfc-fdw-cloud: 公共解决方案 &#x1f34a; 有疑问可私信或评论区联系我。 &#x1f951; 创作不易未经允许严禁转载。 姊妹篇&#xff1a; 【设计模式】&#xf…

Linux中使用cp命令的 -f 选项,但还是提醒覆盖的问题

问题&#xff1a; linux 在执行cp的命令的时候&#xff0c;就算是执行 cp -f 也还是会提醒是否要进行替换。 问题原因&#xff1a; 查看别名&#xff0c;alias命令&#xff0c;看到cp的别名为cp -i&#xff0c;那就是说cp本身就是自带覆盖提醒&#xff0c;就算我们加上-f 的…

JavaEE初阶——初识EE(Java诞生背景,CPU详解)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能帮到你&#xff01; 目录 零&#xff1a;Java的发展背景介绍 一&#xff1a;EE的概念 二&#xff1a;计算机的构成 1&#xff1a;CU…

五、CAN总线

目录 一、基础知识 1、can介绍 2、CAN硬件电路 3、CAN电平标准 4、CAN收发器芯片介绍 5、CAN帧格式 ① CAN帧种类 ② CAN数据帧 ③ CAN遥控帧​编辑 ④ 位填充 ⑤ 波形实例 6、接收方数据采样 ① 接收方数据采样遇到的问题 ② 位时序 ③ 硬同步 ④ 再同步 ⑤ 波…

Java的IO流(二)

目录 Java的IO流&#xff08;二&#xff09; 字节缓冲流 基本使用 使用缓冲流复制文件 字符缓冲流 缓冲流读取数据原理 字符编码 字符集 转换流 序列化流与反序列化流 基本使用 禁止成员被序列化 序列号不匹配异常 打印流 基本使用 系统打印流与改变流向 Prop…

【网络安全】依赖混淆漏洞实现RCE

未经许可&#xff0c;不得转载。 文章目录 正文 依赖混淆是一种供应链攻击漏洞&#xff0c;发生在企业的内部依赖包错误地从公共库&#xff08;如npm&#xff09;下载&#xff0c;而不是从其私有注册表下载。攻击者可以在公共注册表中上传一个与公司内部包同名的恶意包&#xf…