直方图均衡化公式推导及代码实现
1. 概述¶
1.1 直方图均衡化¶
直方图均衡化(Histogram Equalization)是一种增强图像对比度(Image Contrast)的方法,其主要思想是将一副图像的直方图分布通过累积分布函数变成近似均匀分布,从而增强图像的对比度。
- 直方图均衡化与分段变换相比,更能参数自适应
为了将原图像的亮度范围进行扩展, 需要一个映射函数, 将原图像的像素值均衡映射到新直方图中, 这个映射函数有两个条件:
①不能打乱原有的像素值大小顺序, 映射后亮、 暗的大小关系不能改变;
② 映射后必须在原有的范围内,即像素映射函数的值域应在0和255之间;
综合以上两个条件,累积分布函数是个好的选择,因为累积分布函数是单调增函数(控制大小关系),并且值域是0到1(控制越界问题),所以直方图均衡化中使用的是累积分布函数。
1.2 分布函数¶
累积分布函数(Cumulative Distribution Function),又叫分布函数,是概率密度函数的积分,能完整描述一个实随机变量X的概率分布。一般以大写CDF标记,,与概率密度函数probability density function(小写pdf)相对
因为图像由一个个像素点组成,所以图像直方图均衡化是通过离散形式的累积分布函数求解的,直方图均衡化过程中,映射方法是: $$ s_k = \sum ^k _{i=0} p_r(i) $$
其中,$s_k$是当前灰度级经过累积分布函数映射后的值,$p_r$是概率密度函数
2. 公式推导¶
设 r 为归一化后的输入图像灰度, s 为输出图像灰度,即:$r,s \in [0,1]$
若随机变量 r 的概率密度函数为 $p_r(r)$,且随机变量 s 为 r 的函数,则必有:
$$ \int_0^b p_s(s) ds = \int_0^a p_r(r)dr $$两边对 s 求导数,上式可变为:
$$ p_s(s) = \frac{p_r(r)dr}{ds} $$当输出图像的灰度均匀分布时,由于图像做了归一化,所以其概率密度$p_s(s)$恒为1,上式可变为:
$$ p_r(r)=\frac{ds}{dr} $$等式两边对 r 积分:
$$ s = \int_0^x p_r(r)dr $$其中,x 是输入输入灰度级,介于$[0, 1] $
由于图像直方图是离散的,故上式可变为:
$$ s_k = \sum ^k _{i=0} p_r(i) $$其中,$s_k \in [0, 1]$,故最终输出需要乘上255
3. 代码实现¶
计算输入图像概率密度:
# 获取图像的概率密度
def get_pdf(in_img):
total = in_img.shape[0] * in_img.shape[1] #计算图片总像素数
return [ np.sum(in_img == i)/total for i in range(256) ] #求概率密度
直方图均衡化:
# 直方图均衡化(核心代码)
def hist_equal(in_img):
# 1.求输入图像的概率密度
Pr = get_pdf(in_img)
# 2.构造输出图像(初始化成输入)
out_img = np.copy(in_img)
# 3.执行“直方图均衡化”(执行累积分布函数变换)
SUMk = 0. # 累加值存储变量
for i in range(256):
SUMk = SUMk + Pr[i]
out_img[(out_img == i)] = SUMk*255. #灰度值逆归一化
return out_img
- 这里使用了numpy的掩码矩阵特性进行计算
图像处理:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
# 读入原图
gray_img = np.asarray(Image.open('./image/bright_lena.png').convert('L'))
# 对原图执行“直方图均衡化”
out_img = hist_equal(gray_img)
# 创建1个显示主体,并分成4个显示区域
fig = plt.figure()
ax1, ax2 = fig.add_subplot(221), fig.add_subplot(222)
ax3, ax4 = fig.add_subplot(223), fig.add_subplot(224)
# 窗口显示:原图,原图灰度分布,结果图像,结果图像灰度分布
ax1.set_title('origin image', fontsize=8)
ax1.imshow(gray_img, cmap='gray', vmin=0, vmax=255)
ax1.axes.xaxis.set_visible(False)
ax1.axes.yaxis.set_visible(False)
ax2.grid(True, linestyle=':', linewidth=1)
ax2.set_title('origin histogram', fontsize=8)
ax2.set_xlim(0, 255) # 设置x轴分布范围
ax2.set_ylim(0, 0.2) # 设置y轴分布范围
ax2.hist(gray_img.flatten(),bins=50,density=True,color='r',edgecolor='k')
ax2.axes.xaxis.set_visible(False)
ax2.axes.yaxis.set_visible(False)
ax3.set_title('result image', fontsize=8)
ax3.imshow(out_img, cmap='gray', vmin=0, vmax=255)
ax4.grid(True, linestyle=':', linewidth=1)
ax4.set_title('result histogram', fontsize=8)
ax4.set_xlim(0, 255) # 设置x轴分布范围
ax4.set_ylim(0, 0.2) # 设置y轴分布范围
ax4.hist(out_img.flatten(),bins=50,density=True,color='r',edgecolor='k')
plt.show()

可以看到直方图均衡化在几乎不用设置参数的情况下有效地进行图像对比度增强

基于Python讲述直方图均衡化的推导与实现
浙公网安备 33010602011771号