当前位置: 首页 > news >正文

图像处理基础(8):图像的灰度直方图、直方图均衡化、直方图规定化(匹配)

本文主要介绍了灰度直方图相关的处理,包括以下几个方面的内容:

•   利用OpenCV计算图像的灰度直方图,并绘制直方图曲线

•   直方图均衡化的原理及实现

•   直方图规定化(匹配)的原理及实现

图像的灰度直方图

一幅图像由不同灰度值的像素组成,图像中灰度的分布情况是该图像的一个重要特征。图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所占的多少。
图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其中,横坐标是灰度级,纵坐标是该灰度级出现的频率。

不过通常会将纵坐标归一化到

区间内,也就是将灰度级出现的频率(像素个数)除以图像中像素的总数。灰度直方图的计算公式如下:

其中,

是像素的灰度级,

是具有灰度

的像素的个数,

是图像中总的像素个数。

OpenCV灰度直方图的计算

直方图的计算是很简单的,无非是遍历图像的像素,统计每个灰度级的个数。在OpenCV中封装了直方图的计算函数calcHist,为了更为通用该函数的参数有些复杂,其声明如下:

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

该函数能够同时计算多个图像,多个通道,不同灰度范围的灰度直方图.
其参数如下:

•   images,输入图像的数组,这些图像要有相同大大小,相同的深度(CV_8U CV_16U CV_32F).

•   nimages ,输入图像的个数

•   channels,要计算直方图的通道个数。

•   mask,可选的掩码,不使用时可设为空。要和输入图像具有相同的大小,在进行直方图计算的时候,只会统计该掩码不为0的对应像素

•   hist,输出的直方图

•   dims,直方图的维度

•   histSize,直方图每个维度的大小

•   ranges,直方图每个维度要统计的灰度级的范围

•   uniform,是否进行归一化,默认为true

•   accumulate,累积标志,默认值为false。

为了计算的灵活性和通用性,OpenCV的灰度直方图提供了较多的参数,但对于只是简单的计算一幅灰度图的直方图的话,又显得较为累赘。这里对calcHist进行一次封装,能够方便的得到一幅灰度图直方图。

class Histogram1D
{
private:int histSize[1]; // 项的数量float hranges[2]; // 统计像素的最大值和最小值const float* ranges[1];int channels[1]; // 仅计算一个通道public:Histogram1D(){// 准备1D直方图的参数histSize[0] = 256;hranges[0] = 0.0f;hranges[1] = 255.0f;ranges[0] = hranges;channels[0] = 0;}MatND getHistogram(const Mat &image){MatND hist;// 计算直方图calcHist(&image ,// 要计算图像的1,                // 只计算一幅图像的直方图channels,        // 通道数量Mat(),            // 不使用掩码hist,            // 存放直方图1,                // 1D直方图histSize,        // 统计的灰度的个数ranges);        // 灰度值的范围return hist;}Mat getHistogramImage(const Mat &image){MatND hist = getHistogram(image);// 最大值,最小值double maxVal = 0.0f;double minVal = 0.0f;minMaxLoc(hist, &minVal, &maxVal);//显示直方图的图像Mat histImg(histSize[0], histSize[0], CV_8U, Scalar(255));// 设置最高点为nbins的90%int hpt = static_cast<int>(0.9 * histSize[0]);//每个条目绘制一条垂直线for (int h = 0; h < histSize[0]; h++){float binVal = hist.at<float>(h);int intensity = static_cast<int>(binVal * hpt / maxVal);// 两点之间绘制一条直线line(histImg, Point(h, histSize[0]), Point(h, histSize[0] - intensity), Scalar::all(0));}return histImg;}
};

Histogram1D提供了两个方法:getHistogram返回统计直方图的数组,默认计算的灰度范围是[0,255];getHistogramImage将图像的直方图以线条的形式画出来,并返回包含直方图的图像。测试代码如下:

    Histogram1D hist;Mat histImg;histImg = hist.getHistogramImage(image);imshow("Image", image);imshow("Histogram", histImg);

其结果如下:

直方图均衡化 Histogram Equalization

假如图像的灰度分布不均匀,其灰度分布集中在较窄的范围内,使图像的细节不够清晰,对比度较低。通常采用直方图均衡化直方图规定化两种变换,使图像的灰度范围拉开或使灰度均匀分布,从而增大反差,使图像细节清晰,以达到增强的目的。
直方图均衡化,对图像进行非线性拉伸,重新分配图像的灰度值,使一定范围内图像的灰度值大致相等。这样,原来直方图中间的峰值部分对比度得到增强,而两侧的谷底部分对比度降低,输出图像的直方图是一个较为平坦的直方图。

均衡化算法

直方图的均衡化实际也是一种灰度的变换过程,将当前的灰度分布通过一个变换函数,变换为范围更宽、灰度分布更均匀的图像。也就是将原图像的直方图修改为在整个灰度区间内大致均匀分布,因此扩大了图像的动态范围,增强图像的对比度。通常均衡化选择的变换函数是灰度的累积概率,直方图均衡化算法的步骤:

•   计算原图像的灰度直方图 

,其中

为像素总数,

为灰度级

的像素个数

•   计算原始图像的累积直方图 

•   

,其中 

是目的图像的像素,

是源图像灰度为i的累积分布,L是图像中最大灰度级(灰度图为255)

其代码实现如下:

•   在上面中封装了求灰度直方图的类,这里直接应用该方法得到图像的灰度直方图;

•   将灰度直方图进行归一化,计算灰度的累积概率;

•   创建灰度变化的查找表

•   应用查找表,将原图像变换为灰度均衡的图像

具体代码如下:

void equalization_self(const Mat &src, Mat &dst)
{Histogram1D hist1D;MatND hist = hist1D.getHistogram(src);hist /= (src.rows * src.cols); // 对得到的灰度直方图进行归一化float cdf[256] = { 0 }; // 灰度的累积概率Mat lut(1, 256, CV_8U); // 灰度变换的查找表for (int i = 0; i < 256; i++){// 计算灰度级的累积概率if (i == 0)cdf[i] = hist.at<float>(i);elsecdf[i] = cdf[i - 1] + hist.at<float>(i);lut.at(i) = static_cast(255 * cdf[i]); // 创建灰度的查找表}LUT(src, lut, dst); // 应用查找表,进行灰度变化,得到均衡化后的图像}

上面代码只是加深下对均衡化算法流程的理解,实际在OpenCV中也提供了灰度均衡化的函数equalizeHist,该函数的使用很简单,只有两个参数:输入图像,输出图像。下图为,上述代码计算得到的均衡化结果和调用equalizeHist的结果对比

最左边为原图像,中间为OpenCV封装函数的结果,右边为上面代码得到的结果。

直方图规定化

从上面可以看出,直方图的均衡化自动的确定了变换函数,可以很方便的得到变换后的图像,但是在有些应用中这种自动的增强并不是最好的方法。有时候,需要图像具有某一特定的直方图形状(也就是灰度分布),而不是均匀分布的直方图,这时候可以使用直方图规定化
直方图规定化,也叫做直方图匹配,用于将图像变换为某一特定的灰度分布,也就是其目的的灰度直方图是已知的。这其实和均衡化很类似,均衡化后的灰度直方图也是已知的,是一个均匀分布的直方图;而规定化后的直方图可以随意的指定,也就是在执行规定化操作时,首先要知道变换后的灰度直方图,这样才能确定变换函数。规定化操作能够有目的的增强某个灰度区间,相比于,均衡化操作,规定化多了一个输入,但是其变换后的结果也更灵活。

在理解了上述的均衡化过程后,直方图的规定化也较为简单。可以利用均衡化后的直方图作为一个中间过程,然后求取规定化的变换函数。具体步骤如下:

•   将原始图像的灰度直方图进行均衡化,得到一个变换函数

,其中s是均衡化后的像素,r是原始像素

•   对规定的直方图进行均衡化,得到一个变换函数

,其中v是均衡化后的像素,z是规定化的像素

•   上面都是对同一图像的均衡化,其结果应该是相等的,

,且

通过,均衡化作为中间结果,将得到原始像素

规定化后像素之间的映射关系。

详解规定化过程

对图像进行直方图规定化操作,原始图像的直方图和以及规定化后的直方图是已知的。假设

表示原始图像的灰度概率密度,

表示规定化图像的灰度概率密度(r和z分别是原始图像的灰度级,规定化后图像的灰度级)。

•   对原始图像进行均衡化操作,则有

•   对规定化的直方图进行均衡化操作,则

•   由于是对同一图像的均衡化操作,所以有

•   规定化操作的目的就是找到原始图像的像素

到规定化后图像像素的

之间的一个映射。有了上一步的等式后,可以得到

,因此要想找到

相对应的

只需要在

进行迭代,找到使式子

的绝对值最小即可。

•   上述描述只是理论的推导过程,在实际的计算过程中,不需要做两次的均衡化操作,具体的推导过程如下:$$
 

相关文章:

图像处理基础(8):图像的灰度直方图、直方图均衡化、直方图规定化(匹配)

本文主要介绍了灰度直方图相关的处理&#xff0c;包括以下几个方面的内容&#xff1a; • 利用OpenCV计算图像的灰度直方图&#xff0c;并绘制直方图曲线 • 直方图均衡化的原理及实现 • 直方图规定化&#xff08;匹配&#xff09;的原理及实现 图像的灰度直方图 一…...

探寻数组中两个不重复数字的奥秘:C 语言实战之旅

在编程的世界里&#xff0c;经常会遇到各种各样有趣的问题&#xff0c;今天我们就来探讨一个经典的题目&#xff1a;在一个整数数组中&#xff0c;除了两个数字只出现一次&#xff0c;其余数字都出现了两次&#xff0c;如何高效地找出这两个只出现一次的数字呢&#xff1f;我们…...

Mercury、LLaDA 扩散大语言模型

LLaDA 参考&#xff1a; https://github.com/ML-GSAI/LLaDA https://ml-gsai.github.io/LLaDA-demo/ 在线demo&#xff1a; https://huggingface.co/spaces/multimodalart/LLaDA Mercury 在线demo&#xff1a; https://chat.inceptionlabs.ai/ 速度很快生成...

【ESP32S3接入讯飞在线语音识别】

视频地址: 【ESP32S3接入讯飞在线语音识别】 1. 前言 使用Seeed XIAO ESP32S3 Sense开发板接入讯飞实现在线语音识别。自带麦克风模块用做语音输入,通过串口发送字符“1”来控制数据的采集和上传。 语音识别对比 平台api教程评分百度...

深入了解 SSH 及其相关协议

深入了解 SSH 及其相关协议 在网络通信的世界里&#xff0c;安全始终是至关重要的话题。SSH&#xff08;Secure Shell&#xff09;作为一种广泛应用的网络协议&#xff0c;为我们在不安全的网络环境中提供了安全的远程连接和数据传输方式。今天&#xff0c;就让我们一起来深入…...

微信小程序源码逆向 MacOS

前言 日常工作中经常会遇到对小程序的渗透测试&#xff0c;微信小程序的源码是保存在用户客户端本地&#xff0c;在渗透的过程中我们需要提取小程序的源码进行问题分析&#xff0c;本篇介绍如何在苹果电脑 MacOS 系统上提取微信小程序的源码。 0x01 微信小程序提取 在苹果电…...

【我的 PWN 学习手札】House of Husk

House of Husk House of Husk是利用格式化输出函数如printf、vprintf在打印输出时&#xff0c;会解析格式化字符如%x、%lld从而调用不同的格式化打印方法&#xff08;函数&#xff09;。同时C语言还提供了注册自定义格式化字符的方法。注册自定义格式化字符串输出方法&#xf…...

(八)趣学设计模式 之 装饰器模式!

目录 一、 啥是装饰器模式&#xff1f;二、 为什么要用装饰器模式&#xff1f;三、 装饰器模式的实现方式四、 装饰器模式的优缺点五、 装饰器模式的应用场景六、 装饰器模式 vs 代理模式七、 总结 &#x1f31f;我的其他文章也讲解的比较有趣&#x1f601;&#xff0c;如果喜欢…...

设计后端返回给前端的返回体

目录 1、为什么要设计返回体&#xff1f; 2、返回体包含哪些内容&#xff08;如何设计&#xff09;&#xff1f; 举例 3、总结 1、为什么要设计返回体&#xff1f; 在设计后端返回给前端的返回体时&#xff0c;通常需要遵循一定的规范&#xff0c;以确保前后端交互的清晰性…...

Element Plus中el-select选择器的下拉选项列表的样式设置

el-select选择器&#xff0c;默认样式效果&#xff1a; 通过 * { margin: 0; padding: 0; } 去掉内外边距后的样式效果&#xff08;样式变丑了&#xff09;&#xff1a; 通过 popper-class 自定义类名修改下拉选项列表样式 el-select 标签设置 popper-class"custom-se…...

C高级(shell)

作业 1、使用case...in实现等级判断 2、计算各个位数和 3、计算家目录下目录个数和普通文件数 4、打印图形 5、冒泡排序...

子宫腺肌症是如果引起的?

子宫腺肌症是一种常见的妇科疾病&#xff0c;它是指子宫内膜的腺体和间质侵入子宫肌层形成的一种病症。那么&#xff0c;子宫腺肌症是如何引起的呢&#xff1f; 一、病因分析 子宫腺肌症的确切病因目前尚不十分清楚&#xff0c;但经过医学研究和临床观察&#xff0c;认为其发…...

网络安全学习中,web渗透的测试流程是怎样的?

渗透测试是什么&#xff1f;网络安全学习中&#xff0c;web渗透的测试流程是怎样的&#xff1f; 渗透测试就是利用我们所掌握的渗透知识&#xff0c;对网站进行一步一步的渗透&#xff0c;发现其中存在的漏洞和隐藏的风险&#xff0c;然后撰写一篇测试报告&#xff0c;提供给我…...

【软考】【2025年系统分析师拿证之路】【啃书】第十四章 软件实现与测试(十五)

目录 程序设计方法代码重用软件测试软件测试的对象和目的软件测试方法按照被测程序是否可见分类按照是否需要执行被测试程序分类自动测试 测试类型按测试对象划分按测试阶段划分按被测试软件划分其他分类 程序设计方法 结构化程序设计&#xff1a;自顶向下&#xff0c;逐步求精…...

自然语言处理NLP深探

1. NLP 的定义、特点、具体工作、历史和流派 定义:自然语言处理(Natural Language Processing,NLP)是计算机科学与人工智能领域的一个重要分支,旨在让计算机理解、处理和生成人类自然语言,实现人与计算机之间用自然语言进行有效通信。特点 交叉性:涉及计算机科学、语言学…...

加载互联网免费地图资源并通过CesiumEarth快速浏览

免费地图资源 地理信息系统&#xff08;GIS&#xff09;的搭建主要可分为两部分&#xff1a;1、三维地球引擎&#xff1b;2、基础数据图层。 CesiumEarth提供了可直接使用的三维地球引擎&#xff0c;因此只需准备基础数据图层&#xff0c;即可搭建属于自己的地理信息系统。 …...

Android 键盘输入按确认或换行 直接触发提交

在 Android 开发中&#xff0c;若要实现键盘输入时按下确认键&#xff08;如 “完成”“发送” 等&#xff09;或者换行键直接触发提交操作&#xff0c;可以通过以下几种方式实现&#xff0c;下面为你详细介绍。 方式一&#xff1a;使用 EditText 的 setOnEditorActionListene…...

halcon三维点云数据处理(二十七)remove_bin_for_3d_object_localization

目录 一、remove_bin_for_3d_object_localization代码第一部分二、remove_bin_for_3d_object_localization代码第二部分三、效果图一、remove_bin_for_3d_object_localization代码第一部分 1、读图构建3D模型。 2、一次二值化选取区域。 3、一次和背景差值选取区域。 4、在二维…...

XFeat:轻量级的深度学习图像特征匹配

一、引言&#xff1a;图像特征匹配的挑战与XFeat的突破 在计算机视觉领域&#xff0c;图像特征匹配是视觉定位&#xff08;Visual Localization&#xff09;、三维重建&#xff08;3D Reconstruction&#xff09;、增强现实&#xff08;AR&#xff09;等任务的核心基础。传统方…...

[MD] AG stable

当然&#xff0c;以下是A-stable和G-stable的详细定义&#xff1a; A-stable (A-稳定) A-stable是数值方法稳定性的一种分类&#xff0c;主要用于分析求解常微分方程初值问题的数值方法。一个数值方法被称为A-stable&#xff0c;如果它满足以下条件&#xff1a; 对于所有的步…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...