不调用python函数实现直方图均衡化_直方图均衡化(HE)
前面我们已经讲过图像的直方图,那图像的直方图均衡化又是干嘛的呢?
顾名思义:其实对直方图进行均衡化,哈哈感觉自己说的就是废话...
举个例子:
import cv2
from matplotlib import pyplot as pltimg = cv2.imread("src.jpg", 0)plt.hist(img.ravel(), 256, [0, 256])plt.savefig("histogram.jpg", dpi = 300, bbox_inches = "tight", pad_inches = 0)# dpi : dot per inch
# bbox_inches: if 'tight', try to figure out the tight bbox of the figure.
# pad_inches: amount of padding[填充] around the figure when bbox_inches is 'tight'.plt.show()
观察图1:原图的亮暗对比不明显,感性上,感觉整幅图像就是灰蒙蒙的.
通过绘制原图的灰度直方图,可以看到,像素基本集中在100~200之间,其它的几乎没有,因此可理性判断,该图像不能够很好的突出细节信息.
Q1: 怎么才能让图像看起来层次比较分明呢?(包含细节信息)
A1: 需要对灰度值进行相关的处理(各种均衡化算法),使图像的像素分布尽可能广泛,改善图像的对比度.
1.直方图均衡化
首先需要明白一个概念:累积分布函数(CDF : Cumulative Distribution Function)
可参考:
0704:概率分布函数、概率密度函数zhuanlan.zhihu.com
假设你明白了,累积分布函数的相关概念.
现在我们开始直接举例:
下图是一个8 x 8 的 灰度图像的灰度值.
对灰度值的出现次数进行统计:
更进一步:计算累积分布函数值,为简化,累积分布函数值为0的灰度值被省略.
直方图均衡化的公式如下:
注:式(1) 中的round()是一个函数
a: 为整数,round(a)不变;
a: 为浮点数,round(a)圆整到离它最近的整数
a: 为浮点数,且距离两个整数一样近时,圆整到偶数.
比如:a = 1.5, 则round(a) = 2
本例中,
注:L为图像的灰度级数,图像为灰度图,所以位深度为8,故灰度级数共有2^8 = 256 级数.
均衡化后的灰度是多少呢?
用灰度78进行实验:
依次类推:可计算出原图中每个灰度均衡化后的灰度,如图4所示:
注:最小值52变为了0,最大值154变为了255.
代码实现:
① 原始图像的直方图及累积函数图像:
from cv2 import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread("src.jpg", 0)hist, bins = np.histogram(img.ravel(), 256, [0, 256])cdf = np.cumsum(hist) #计算累积函数值
cdf_normalized = cdf * max(hist) / max(cdf)plt.plot(cdf_normalized, color = "r")
plt.hist(img.ravel(), 256, [0, 256])plt.legend(("cdf", "histogram"), loc = "upper left")plt.show()
我们可以看出来直方图大部分在灰度值较高的部分,而且分布很集中。而 我们希望直方图的分布比较分散,能够涵盖整个 x 轴。所以,我们就需要一个 变换函数帮助我们把现在的直方图映射到一个广泛分布的直方图中。这就是直方图均衡化要做的事情。
② 原始图像均衡化后的直方图与累积函数分布图
为便于与直方图均衡化算法原理相结合,我们分为以下几步来实验.
第一步:看一下原图像直方图纵坐标值
我们用程序跑一下,显示原图像直方图纵坐标值(也就是上面代码中hist数组里的值),如下图7所示:
hist数组:序号表示的是灰度,数值表示灰度的个数.
同样:我们可以看原图像累积函数cdf的值,如下图8所示:
Q1:cdf中含有大量的0值,我们上述的算法是要忽略0,那怎么办呢?
A1:使用numpy
# 构建 Numpy 掩膜数组,cdf 为原数组,当数组元素为 0 时,掩盖(计算时被忽略).
cdf_m = np.ma.masked_equal(cdf,0)
使用这个函数,效果如何呢?如图9所示:
注:计算时,0会被忽略.
第二步:算法公式
其实比较容易实现,如下:
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
可以得到映射完后的灰度值,如图10所示:
第三步:对掩盖的元素重新赋值0
图10所显示映射后的灰度值,需对被掩盖的元素重新赋值0
Q1:该怎么做?
# 对被掩盖的元素赋值,这里赋值为 0
cdf = np.ma.filled(cdf_m, 0).astype('uint8') # 数据类型为:uint8
使用这个函数后,效果如图11所示:
现在就获得了一个表(里面的值为映射后的灰度值),我们可以通过查表得知与输入像素对应的输出像素 的值。我们只需要把这种变换应用到图像上就可以了。
img2 = cdf[img] # img为原图像
这个不知道大家理不理解,其实img的灰度值 成了cdf的索引,然后重新生成一幅新的图像(也就是均衡化后的图像).
最后写一个代码:
import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread("src.jpg", 0)hist, bins = np.histogram(img.ravel(), 256, [0, 256])cdf = np.cumsum(hist)# 构建 Numpy 掩模数组,cdf 为原数组,当数组元素为 0 时,掩盖(计算时被忽略)。
cdf_m = np.ma.masked_equal(cdf,0)# 均衡化公式
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())# 对被掩盖的元素赋值,这里赋值为 0
cdf = np.ma.filled(cdf_m,0).astype('uint8')img2 = cdf[img]hist2, bins2 = np.histogram(img2.ravel(), 256, [0, 256])cdf2 = np.cumsum(hist2)
cdf_equal_normalized = cdf2 * max(hist2) / max(cdf2)plt.hist(img2.ravel(), 256, [0, 256])
plt.plot(cdf_equal_normalized, "r")cv2.imwrite("equal.jpg", img2)
plt.savefig("histogram.jpg", dpi = 300, bbox_inches = "tight")plt.show()
参考:
https://bk.tw.lvfukeji.com/wiki/%E7%9B%B4%E6%96%B9%E5%9B%BE%E5%9D%87%E8%A1%A1%E5%8C%96bk.tw.lvfukeji.com
是不是感觉上面的直方图均衡化算法有点难,其实OpenCV提供了直方图均衡化算法.
equ = cv2.equalizeHist(img)
一个函数就搞定了,哈哈,说这么多,其实就是在说一个函数,相关的代码如下:
import cv2
import numpy as npimg = cv2.imread("Origianl.jpg", 0)equ = cv2.equalizeHist(img)
res = cv2.hstack((img, equ)) #stacking images side-by-sidecv2.imshow("demo", res)cv2.waitKey()
cv2.destroyAllWindows()
效果如下:
Q2: 大家有没有想过,为什么变换函数是形如CDF的形式,难道是凭空想出来的 ?
A2: 显然不是,下面我们一起来分析一下.
假设我们有一张图像
整个过程可按下图13的图示说明:图中右下方是
于是可以理解
上面公式可以理解为对应的区间内像素点总数不变. 为实现直方图均衡化,特殊地有:
其实在这里,我自己有一个疑问:区间
与区间内的像素点总数是相等的,这点确实如此,但是,这跟积分求和,好像没有多大的关系啊,在数学中,积分就是求面积(无穷个小矩形的面积相加,这是比较好理解的),在物理中,拿速度与时间进行举例,积分就是路程(无穷个小区间的路程相加,就是整个区间的路程),而本题中,
,这个我不清楚它代表的是什么?好像没有实际的意义.不知道有没有人清楚,这个该怎么解释?
经查资料,其实这个积分可以理解为概率,我们可以把灰度与灰度出现的次数(要进行相应的归一化处理),看成概率密度函数,某一灰度出现的次数越多,代表它的概率密度越大(注意并不是概率越大,连续型随机变量,概率是要区间的,单说某一变量的概率并没有意义).
因为我们的目标是直方图均匀化,那么理想的有
便可以解得:
离散形式得:
通过上面推导过程可以看出,映射函数
参考:
李新春:直方图均衡化zhuanlan.zhihu.com
ybai62868:说说直方图均衡化zhuanlan.zhihu.com
不调用python函数实现直方图均衡化_直方图均衡化(HE)相关推荐
- python中execute函数_在excel中调用python函数
效果: 通过excel引用在py文件中写好的load_settle()函数,可以快捷的获取对应的历史结算价. 使用方法: 1.首先安装office,我用的是2016版本. 2.安装python,推荐使 ...
- VS2017 QT/C++ 调用python函数传图像
原文:VS2019 C++ 调用python函数/类对象的方法_ 蜗牛在听雨的博客-CSDN博客_c++调用python函数 1.c++调用python类(传图像参数) ,编译出错,解决方法: 因为需 ...
- c调用python脚本如何获取结果_使用C++调用Python代码的方法详解
一.配置python环境问题 1.首先安装Python(版本无所谓),安装的时候选的添加python路径到环境变量中 安装之后的文件夹如下所示: 2.在VS中配置环境和库 右击项目->属性-&g ...
- C++调用Python函数
From: http://www.flatws.cn/article/program/c/2010-08-24/9677.html Python代码在实现某些功能的时候非常方便,如果能够将Python ...
- C++和Python混合编程:C++调用Python函数
文章目录 一.C++直接运行python代码的控制台Demo 二.环境配置 三.C++调用Python函数 C++传入Python的参数格式转换 C++调用Python[有参有返回值]函数 C++运行 ...
- Excel单元格使用xlwings包调用python函数的公式,截取子网页(标题)的试验 问题求助CSDN
Excel单元格使用xlwings包调用python函数的公式,截取子网页(标题)的试验 问题求助CSDN Python 环境:python3.7 的conda上的py3环境 Excel 2010 E ...
- C++回调函数中调用Python函数出现的死锁问题调试及解决
一.查找死锁原因: 1.使用gdb exe指令进入gdb命令行,再输入r运行可执行文件 gdb /home/sdhm/catkin_ws/devel/lib/gpd_ros/gpd_server GN ...
- python函数默认参数位置_二十二、Python函数参数类型(位置、关键字、默认、不定长参数)...
调用函数时可使用的参数类型 在调用Python函数时可使用的参数类型主要有以下几种: 必要参数(位置参数) 关键字参数 默认参数 不定长参数 必要参数(位置参数) 在Python中, 必要参数必须以正 ...
- html怎么调用python,使用HTML调用python函数
我在python中有一个显示名称列表的函数.使用HTML调用python函数 def search(): with open('business_ten.json') as f: data=f.rea ...
- 实践在C++中调用Python函数
目标 目标是在C++中调用Python函数,给定输入,得到输出. 主要参考: 如何实现 C/C++ 与 Python 的通信? - 知乎 C++调用Python脚本中的函数 - Achimesir - ...
最新文章
- js中的装饰器执行顺序
- Atitit. Async await 优缺点 异步编程的原理and实现 java c# php
- django链接mysql网页显示数据_使用Django连接mysql数据库并显示在网页上
- Android之Unexpected error while executing: am start -n “***.Activity“-a android.intent.action.MAIN
- 腾讯再发股票吸引人才,受益2.57万名员工,人均超8万港元
- PHP5与MySQL数据库操作
- 微服务架构的 10个 最佳实践 !
- python的datetime模块用法_Python3.5内置模块之time与datetime模块用法实例分析
- sql server 2008安装的时候选NT AUTHORITY\NEWORK SERVICE 还是选 NT AUTHORITY\SYSTEM ?
- Learn OpenGL(三)——顶点着色器(Vertext Shader)
- 2016北京集训测试赛(十三) Problem B: 网络战争
- [zz]世界第一只计算机bug和Debug
- 人工智能、机器学习、神经网络、深度学习之间的关系
- 计算机网络试题及答案(史上最全)
- java做一个客房管理系统定制_基于JAVA的酒店客房管理系统的设计与实现
- 协同级CRM能帮助企业带来哪些管理提升?
- 为什么会有这么多中间表?
- 【VMware vSphere】Veeam备份
- 淘宝客微信机器人搭建教程分享
- 零基础入门学习HTML(下)
热门文章
- 深入浅出Spring Boot,你和大神的差距,就只有这份文档的距离
- Ansible script模块使用示例
- 安装Putty远程终端连接工具
- docker-compose执行报错(selinux所致):write /proc/self/attr/keycreate: permission denied
- 【视频】vue指令之@click及其stop修饰符
- python3 import导入模块
- python编程少儿游戏编程_少儿编程课堂|python – 用游戏学编程
- android os于8.1区别,Android-x86 8.1-rc2发布 运行于x86 PC上的安卓OS
- Qt三种方式实现FTP上传功能
- go读取excel_Excelize 2.3.0 发布,Go 语言 Excel 文档基础库