版权声明:本文为博主原创文章,未经博主允许不得转载。
数字图像处理02:直方图均衡化imhist函数的python实现
1、直方图均衡
直方图均衡就是将灰度比较集中一定范围的图像通过灰度映射/变换,使其灰度值平均分布在灰度级的范围内,以得到图像的更多细节,从而达到对比度增强的效果。
2、直方图均衡化的原理公式
1. 连续情况
其中Pr( r )和Ps(s)分别是原始图像灰度级r和变换后图像的灰度级s的概率密度函数PDF,L-1为图像的最大灰度级。上一个公式表示的是r的PDFPr( r )和s的PDFPs(s)的关系。给定一个输入,则Pr( r )已知,就可以求出s,继而求出Ps(s)。r和s的映射关系即为均衡化关系。由Pr( r )和Ps(s)可以得出输入图像的直方图和变换后的输出图像的直方图。
再经过以上两个公式的推导,可以得出结论Ps(s)=1/(L-1),可知该变换s=t( r )就是取均值。
2. 离散情况
对于图像来说,其实应该是离散情况。
其中MN为图像的像素总个数。以上两个公式是“1”中公式的离散情况,在实际对图像进行操作中也应该是离散情况下进行操作计算。
3、离散情况举例
注:该例子对应于冈萨雷斯.《数字图像处理(第三版)》中文翻译版,第76面例3.5。
上图中的数据经过‘2’中的公式计算得到经过变换的r对应的s值分别为:
对S0~S7经过四舍五入取整:
可以看原始图像数据像素集中在r0~r3 即灰度0~3,经过均衡化变换后,将0变换为1,1变换为3,2变换为5,3、4变换为6,5、6、7变换为7,这样就将灰度分散开。所谓均衡变换也就是灰度级的映射变换,即将灰度级密度大值的映射成其它原来灰度级密度小的值,以达到一种均衡化/平均的效果。从r到s的映射将集中的r分散到其他灰度,即将灰度值r变为其他灰度值,达到均衡化。
4、直方图均衡化计算步骤
其中第四步计算累积直方图是为了下一步(第五步)计算变换后对应的灰度值,而第五步中先加0.5再作INT(取整)操作即是四舍五入取整操作(此操作对于编程实现非常有用)。
对例3.5的具体步骤如下:
注:此上两张图来源于许录平.科学出版社. 《数字图像处理》. 配套教学PPT。
5、Matlab中直方图均衡化的imhist函数
h=imhist(f, b),其中f为输入图像,h为直方图,b是用来形成直方图的“统计堆栈”的数目。“统计堆栈”仅仅是灰度的一小部分。例如我们处理一幅uint8类的图像且设b=2,然后灰度范围被分成两部分:0至127和128至255。所得的直方图将有两个值:h(1)等于图像在[0,127]间隔内的像素数,h(2)等于图像在[128,255]间隔内的像素数。通过下列表达式就可以得到归一化的直方图:p=imhist(f, b)/numel(f),numel(f)函数可以给出数组f中元素的个数(即图像中的像素数)。
6、python代码实现
1. 显示图像标题所需的字体
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']
2. 需要导入的库
import numpy as np
import matplotlib.pyplot as plt
from scipy import misc
3.画条形图/直方图或者可视化所需要的包和函数创建。
由于用matplotlib自带的绘制条形图/直方图的包imhist绘图时出现了问题,所以就选择了之前用过的数据可视化的绘图包pyecharts,pyecharts函数包的是一个可以根据数据绘制条形图/折线图/饼状图的python绘图包,具体用法请见主页:pyecharts 文档。
# 画条形图/直方图 或者可视化。导入pyecharts函数包
import os
from pyecharts import Bar,Pie,Line
# 创建直方图/条形图绘制函数
def get_charts(x, y, label, type):
if type==1:
c = Pie('饼状图')
elif type==2:
c = Bar('条形图')
elif type==3:
c = Line('折线图')
c.add(label, x, y, is_more_utils=True)
c.show_config()
c.render()
os.system(r"render.html")
其中x和y分别是要绘制图形的x轴和y轴的数据,label为图形的标注/标签,type为1、2、3分别表示 ‘饼状图’ 、‘条形图’、‘折线图’,操作实现非常简单,而且绘制出来的图形非常好看。
4.imhist函数实现
# imhist函数构建,img为原始图像,L为其灰度级
def imhist(img, L):
f = misc.imread(img)
plt.figure(1)
plt.imshow(f, cmap='gray')
plt.axis('off')
plt.title('原始图像')
plt.show()
w, h = f.shape
f1 = np.zeros([w, h])
pallel = dict((i,0) for i in range(L))
# 计算原始图像灰度级像素个数ni
for x in range(0,w):
for y in range(0,h):
i = f[x, y]
if i in pallel:
pallel[i] = pallel[i] + 1
else:
pallel[i] = 1
key = [i for i in range(L)] # key为灰度级,即0~255
value1 = [pallel