实战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;建立多层次、全方位的网络安全防…

微服务常见面试题总结

文章目录 1 概念1.1 你对微服务是怎么理解的1.2 微服务带来了哪些挑战&#xff1f;1.3 说下微服务有哪些组件&#xff1f;&#x1f525; 2 注册中心2.1 注册中心有什么用&#xff1f;&#x1f525;2.2 SpringCloud可以选择哪些注册中心&#xff1f;2.3 说下Eureka 和 Nacos的区…

java日志框架之Log4j

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

【Docker】基于Dockerfile创建携带最新cuda版本以及与其配套的cudnn环境的ubuntu20.04镜像

基于Dockerfile创建携带最新cuda版本以及与其配套的cudnn环境的ubuntu20.04镜像 最近涉及到一个在 x86 上机器上使用英伟达GPU资源做加速计算的项目&#xff0c;包括模型推理加速和编解码加速。 为了保持两个模块开发cuda环境的一致性&#xff0c;故构建该基础镜像。 编写Docke…

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

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

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

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

如何在堆和栈上分别创建一个`QObject`子类对象

在堆上创建QObject子类对象的例子 在Qt中&#xff0c;QObject是许多Qt类和对象的基类&#xff0c;提供了对象模型的核心功能&#xff0c;如信号和槽机制、事件处理等。当一个QObject对象在堆上创建时&#xff0c;意味着这个对象是通过new操作符在堆&#xff08;heap&#xff0…

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

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

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

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

Project Online 专业版部署方案

目录 前言 1. 部署前的准备 1.1. 硬件和软件要求 1.2. 网络和安全性要求 1.3. 用户角色和权限 2. 注册和订阅 Project Online 专业版 2.1. 访问 Office 365 管理中心 2.2. 订阅 Project Online 2.3. 激活服务 3. 初始配置 3.1. 创建 Project Online 实例 3.2. 配置基…

聚簇索引和非聚簇索引的定义和区别

1.聚簇索引&#xff1a; 也叫聚集索引、主键索引&#xff0c;是将索引和数据放在一起&#xff0c;聚簇索引的 BTree 的叶子节点存放的是实际数据&#xff0c;所有完整的用户记录都存放在主键索引的 BTree 的叶子节点里&#xff1b;找到索引也就找到了数据。数据行的物理顺序与…

【深度学习】(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…