【数字图像处理】小白也能懂,最浅显方式手撕直方图均衡化(附python实现)

news2024/12/25 13:37:50

文章目录

  • 1 概念
  • 2 原理
    • 2.1 数学原理
  • 3 python代码实现
  • 4 测试效果
  • 5 结论

1 概念

直方图均衡化,同伽马变换一样,也是增强图像对比度的一种工具。区别在于,直方图均衡化是一种自适应的工具,即自动工具。也就是说,我们只需要将一张待处理的图片丢给这个工具,就可以实现对比度的增强,而无需像伽马变换一样需要手动调整一个输入参数。

什么是直方图呢?这里以很简单的方式来解释。我们可以将直方图视为图形或绘图,它可以用来从而可以总体了解图像的强度分布。其x轴是像素的等级(根据图像的类型判断,大部分情况是0到255),而y轴是相应像素值的数量。换言之,其实就是一个统计图,用于统计图片中像素值为x的像素点有多少个。

如下是一个直方图的例子,这个图片是彩色的,但实际上是先将该图转化为对应的灰度图像再绘制的直方图。其实想要对彩色图像做直方图均衡化也很简单,只要分别对三个通道单独做一次,再将三个结果组合在一起即可。

![[Pasted image 20240930173713.png]]

2 原理

2.1 数学原理

直方图均衡化其实会用到一些简单的概率论知识。我尽量以比较通俗的方法来叙述,所以其中的一些表述可能不是很严谨,不过仅用于理解本例是足够了。(如果你对概率论比较了解可以直接看公式掠过废话)

ps:以下仅为理论部分的叙述,实际代码实现时还会有一些不同的地方,但其实本质是一样的,只不过先熟悉原理会更好理解。

首先第一步,肯定就是要统计出所有像素值分别有多少个,这个其实就是一个图像遍历的过程。

做完上一步后,我们需要求取每一个像素值的概率密度函数(PDF),什么是概率密度函数呢?其实很好理解,就是图像中像素值为x的点的个数对于图像像素点总数的比重。因为这里是离散的情况,所以非常好求。假设像素值为k的点在图像(假设图像总共有MN个像素)中有r个,那么该点的概率密度函数,或者说这些点所占据的个数比重就是 P D F = r M N PDF={r\over{MN}} PDF=MNr
之后还需要介绍一下累积分布函数(CDF)的概念,这个概念刚开始理解可能会不知所云,其实,跟PDF对照起来就很好理解。

PDF是针对一个特定的点计算的,也就是说是一对一的关系。
而CDF是指(在本例中),假如针对一个像素值x,求它的CDF,就是所有像素值≤x的点的PDF之和。
举一个例子,假设我现在要求像素值为5的PDF,即 P D F 5 PDF_5 PDF5 ,那么结果就是像素值为5的点在所有点中占据的比重。
而如果现在我要求 C D F 5 CDF_5 CDF5 ,根据上面的定义,结果就是所有像素值≤5的PDF之和。由于这里是离散的情况,且像素值的最低边界是0,所以这里计算起来并没有很复杂,无非就是
C D F 5 = P D F 0 + P D F 1 + P D F 2 + P D F 3 + P D F 4 + P D F 5 CDF_5=PDF_0+PDF_1+PDF_2+PDF_3+PDF_4+PDF_5 CDF5=PDF0+PDF1+PDF2+PDF3+PDF4+PDF5
不难知道,CDF是非递减的,也就是说, C D F x + 1 ≥ C D F X CDF_{x+1}≥CDF_X CDFx+1CDFX

得到CDF以后,就可以引出最核心的步骤了,也就是直方图均衡化的核心公式:
S x = ( L − 1 ) C D F x   ,      x ∈ [ 0 , L − 1 ] S_x=(L-1)CDF_x\ ,\ \ \ \ x\in[0, L-1] Sx=(L1)CDFx ,    x[0,L1]
其中,L表示图像的像素等级数,对于256级的灰度图L就是256。 S x S_x Sx是映射的值,表示的是原图中像素值为x的点需要映射到这个值,其实就是一种变化关系。这个公式其实也跟概率论有关,如果不理解的话直接记忆即可,或者可以学习一下概率论相关的知识。

利用这个公式,将原图中的每个像素点进行映射输出以后,就得到了直方图均衡化的结果。可以发现,直方图均衡化其实是一种线性变化,所以这种方法也被叫做直方图线性变化。

3 python代码实现

上面说到,代码实现跟理论是由一些差别的。至于差别在哪,先上代码再说结论

def equalize_self(src_img):  
    """  
    :param src_img: 待处理图像  
    :return: 直方图均衡化后的新图像  
    """    height, width = src_img.shape[:2]  
    # 统计r_k  
    r_dict = [0 for i in range(256)]  
    for r in range(height):  
        for c in range(width):  
            r_dict[src_img[r, c]] += 1  
  
    # 计算累积分布函数(使用前缀和算法优化)  
    cdf = [0 for i in range(256)]  
    cdf[0] = r_dict[0]  
    for i in range(1, 256):  
        cdf[i] = cdf[i - 1] + r_dict[i]  
  
    # 计算映射关系,建立查找表  
    s = []  
    for i in range(256):  
        # 累积分布函数的最小值不一定是0,直接采取书上的公式会导致图片偏灰  
        # 对于每一个cdf,计算时将其减去cdf_min使最小的像素映射到0,得到的图片效果更接近库方法  
        s.append((cdf[i] - cdf[0]) * 255.0 / (height * width - cdf[0]))  
  
    # 查表修改原像素值  
    dst_img = np.zeros((height, width), dtype=np.uint8)  
    for r in range(height):  
        for c in range(width):  
            dst_img[r, c] = round(s[src_img[r, c]])  
    return dst_img

首先关注到s.append这一行,append内的参数其实就是上面所给的直方图均衡化的映射公式。

有趣的是,会发现这里的cdf[i]在参与运算时,还减去了cdf[0],这是为什么呢?其实,这是为了正确调整归一化的比例范围,确保映射结果的动态范围合理。

实际图像中的像素值并不总是从 0 开始,图像的最小像素值可能不是 0。因此,累积分布函数的最小值 C D F m i n CDF_{min} CDFmin也不一定是 0。

如果不减去 C D F m i n CDF_min CDFmin​,则累积分布函数 CDF 中的最小值不会映射为 0,而是映射为一个正值,导致图像中没有真正的黑色区域,会让图像看起来灰蒙蒙的,缺少足够的对比度。因此,通过减去 C D F m i n CDF_{min} CDFmin​,我们可以将图像中的最小灰度值映射为 0,从而增强对比度,最大化使用图像的动态范围。

注意到为什么这一项还除上了一串东西,其实这是一个运算简化的过程。在前面计算CDF时,我并没有先计算PDF,这是因为PDF都会除以一个公共项,那就是图像的像素总数。因此我们可以先算分子的部分,最后只进行一次除法就可以了。不过由于上述我们减去 C D F m i n CDF_{min} CDFmin,累积分布函数的起点变成 0,但其终点也相应地缩小了。因此,整个映射范围也需要缩小,以确保新的 CDF 被正确地归一化到 0 和 255 之间,即像素总数也要减去 C D F m i n CDF_{min} CDFmin

还有一个值得提的点,计算CDF时,可以使用前缀和算法优化,这样可以帮我们省去很多的重复计算,关于前缀和算法可以自行查阅相关资料了解。

4 测试效果

下面给出几组测试案例。每一组图像第一行是原图,第二行是上述实现的直方图均衡化处理,第三行是使用OpenCV提供的直方图均衡化方法处理,右侧绘制出了对应的直方图。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5 结论

可以看到,直方图均衡化适用于处理一些灰度分布较集中的图像。通过直方图均衡化可以动态拉伸图像的灰度范围,并通过这种方式增强图像的对比度。如果待处理图像的灰度比较集中,或者是看上去对比度很低,不妨可以试试用直方图均衡化处理。

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

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

相关文章

使用RestTemplate调用EMQX API查询MQTT客户端列表信息

项目中集成mqtt客户端查询功能,使用到了EMQX api-v5,具体步骤: 一、准备工作 首先在EMQX dashboard中添加API 密钥 填写密钥名称,点击确定,会生成API Key和Secret Key,保存起来备用。 二、配置文件 在…

SUP-NeRF-ECCV2024数据集: 单目3D对象重建的新突破

2024-09-25,由Bosch Research North America和Michigan State University联合发布的SUP-NeRF,是一个基于单目图像进行3D对象重建的新型方法。一个无缝集成姿态估计和物体重建的统一网格。 ECCV:欧洲计算机视觉会议的缩写,它是计算…

如何使用ssm实现科技银行业务管理系统+vue

TOC ssm743科技银行业务管理系统vue 第一章 绪论 1.1 研究背景 在现在社会,对于信息处理方面,是有很高的要求的,因为信息的产生是无时无刻的,并且信息产生的数量是呈几何形式的增加,而增加的信息如何存储以及短时间…

移除元素

移除元素 题目链接:移除元素 示例 1: 输入:nums [3,2,2,3], val 3 输出:2, nums [2,2,_,_] 解释:你的函数函数应该返回 k 2, 并且 nums 中的前两个元素均为 2。 你在返回的 k 个元素之外留下了什么并不重要&…

URL从输入到⻚面显示的过程(详细版)

URL从输入到⻚面显示的过程(详细版) 浏览器中输入网址 DNS 解析域名得到 IP 地址 DNS 解析首先会从你的浏览器的缓存中去寻找是否有这个网址对应的 IP 地址,如果没有就向OS系统的 DNS 缓存中寻找,如果没有就是路由器的 DNS 缓存&…

C++之 友元重载 以及最常用的几种友元函数

在之前的友元中就曾经讲过,我们为了去访问修改私有成员中的数据时,只能通过公有的办法去进行访问操作,非常的局限。所以C引用了友元函数,只要加上friend关键字,C的这个类,会自动把这个函数的权限拉到类内&a…

无水印短视频素材下载网站有哪些?十个高清无水印视频素材网站分享

你知道怎么下载无水印视频素材吗?今天小编就给大家推荐十个高清无水印视频素材下载的网站,如果你也是苦于下载高清无水印的短视频素材,赶紧来看看吧~ 1. 稻虎网 首推的是稻虎网。这个网站简直就是短视频创作者的宝库。无论你需要…

编程魔法:基于LLM的AI function开发,如何实现高效数据生成?

基于大语言模型(LLM)的AI function开发,简直就是现代编程界的“魔法棒”! 你好,我是三桥君 最近三桥君有个任务,需要造一些测试数据,比如姓名、手机号、银行卡号、邮箱啥的,用来做测…

每日OJ题_牛客_添加逗号_模拟_C++_Java

目录 牛客_添加逗号_模拟 题目解析 C代码1 C代码2 Java代码 牛客_添加逗号_模拟 添加逗号_牛客题霸_牛客网 题目解析 读取输入:读取一行字符串。分割字符串:使用空格将字符串分割成单词数组。拼接字符串:将单词数组中的每个单词用逗号…

群晖安装Gitea(代码托管工具)

一、Gitea介绍 Gitea 是一款开源的轻量级代码托管平台,可以为团队和开发者提供了一个易于部署、运行快速、使用体验良好的自建 Git 服务。相比于其它自部署代码托管平台,Gitea 的设计更加轻量,对系统资源的占用相对较少,能够在较低配置的服务器上流畅运行。相比于其他代码…

嘉楠科技AI芯片K230-初探

勘智K230 介绍入门购买开发板 安装开机开发学习点亮第1个LED点亮屏幕预览摄像头代码离线运行 在线训练平台 参考 介绍 K230芯片是嘉楠科技 Kendryte系列AIoT芯片中的最新一代SoC产品。该芯片采用全新的多异构单元加速计算架构,集成了2个RISC-V高能效计算核心&#x…

Spring系列 BeanPostProcessor

文章目录 BeanPostProcessor注册时机执行时机 InstantiationAwareBeanPostProcessorSmartInstantiationAwareBeanPostProcessor 本文源码基于spring-beans-5.3.31 参考:https://docs.spring.io/spring-framework/reference/core/beans/factory-extension.html#beans…

【ASE】第四课_高亮显示效果(手动切换)

今天我们一起来学习ASE插件,希望各位点个关注,一起跟随我的步伐 今天我们来学习高亮的效果。 思路: 1.添加纹理贴图和法线贴图,环境光遮挡贴图 2.添加高亮的参数,并设置 3.手搓一个边缘光,通过高亮参数调节 4.将模…

微信小程序——音乐播放器

目的 掌握swiper组件、scroll-view组件的使用掌握image组件的使用掌握音频API的使用掌握slider组件的使用 内容 了音乐小程序项目的完整开发流程,其开发步骤包括页面结构的分析、样式的设计、组件的运用等。通过本章的学习,读者能够掌握小程序的基本交…

聚星文社——绘唐科技有什么区别!

聚星文社和绘唐科技是两个不同的公司,有一些区别。下面是它们的一些区别: 绘唐科技——聚星文社https://iimenvrieak.feishu.cn/docx/ZhRNdEWT6oGdCwxdhOPcdds7nof 行业领域:聚星文社主要从事文化娱乐行业,包括出版、影视制作等&…

点餐小程序实战教程14点餐功能

目录 1 功能分析2 初始化菜品的数量3 加入购物车4 显示购物车5 最终的效果总结 上一篇我们讲解了如果通过扫码实现餐桌信息显示,本篇我们介绍一下点餐的功能。 1 功能分析 点餐的话一般我们是在菜品点击号或者-号来加入购物车,加入购物车之后还可以修改…

APP 安全测试项总结

一、安装包测试 1.1、关于反编译 目的是为了保护公司的知识产权和安全方面的考虑等,一些程序开发人员会在源码中硬编码一些敏感信息,如密码。而且若程序内部一些设计欠佳的逻辑,也可能隐含漏洞,一旦源码泄漏,安全隐患…

Temporal Dynamic Quantization for Diffusion Models阅读

文章目录 AbstractIntroductionBackgrounds and Related Works2.1 扩散模型2.2 量化2.3 量化感知训练和训练后量化 TemporalDynamic Quantization3.1 量化方法3.2 扩散模型量化的挑战3.3 TDQ模块的实现3.4 工程细节时间步的频率编码TDQ模块的初始化 Experimental SetupResults5…

#git 问题failed to resolve head as a valid ref

问题如下: 解决方法: 1、运行 git fsck --full 可以查看具体error信息,一般都是head索引问题 2、.git\refs\heads\xxx(当前分支)txt编辑器打开显示乱码,而不是hash编码 3、在.git\logs\refs\heads\xxx&a…

如何评价 Python 语言的运行速度

Python 作为一门编程语言,其运行速度一直是业界讨论的焦点。它的简洁语法和广泛的应用使得它在开发过程中非常高效,然而,运行速度与一些更底层的编程语言相比存在一定的劣势。这是否是由于 Python 语法的简洁性所带来的代价?我们可…