直方图均衡化算法和直方图规定化
对于灰度级(intensity levels)范围为[0,L−1] [0, L-1] [0,L−1]的数字图像,其直方图可以表示为一个离散函数 h(rk)=nk,其中rk是第k级灰度值(intensity value), nk 是图像中灰度值为 rk 的像素个数,也就是说,图像的灰度直方图表征的是该图像的灰度分布。在实际应用中,通常对直方图进行归一化再进行后续处理,假设灰度图像的维数是 M×N,MN 表示图像的像素总数,则归一化直方图可以表示为:
也就是说,p(rk)表示灰度级 rk 在图像中出现概率的估计,归一化直方图所有分量之和等于 1。
直方图均衡化是一种简单有效的图像增强技术,通过改变图像的直方图来改变图像中各像素的灰度,主要用于增强动态范围偏小的图像的对比度。原始图像由于其灰度分布可能集中在较窄的区间,造成图像不够清晰。例如,过曝光图像的灰度级集中在高亮度范围内,而曝光不足将使图像灰度级集中在低亮度范围内。采用直方图均衡化,可以把原始图像的直方图变换为均匀分布(均衡)的形式,这样就增加了像素之间灰度值差别的动态范围,从而达到增强图像整体对比度的效果。换言之,直方图均衡化的基本原理是:对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行归并,从而增大对比度,使图像清晰,达到增强的目的。
直方图均衡化 (Histogram Equalization) 就是把一个已知灰度概率密度分布的图像经过一种变换,使之演变为一幅具有均匀灰度概率密度分布的新图像。直方图均衡化处理的“中心思想”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。直方图均衡化就是把给定图像的直方图分布改变成“均匀”分布直方图分布。
OpenCV 库下,直方图均衡化使用 equalizeHist() 函数。
一般来说,直方图均衡能够自动地确定变换函数,且输出结果比较好,当时需要自动增强时是一种好方法。
但有的情况下,使用直方图均衡并不是最好的办法。有时候我们可以指定特定的直方图,而不是均匀分布的直方图,并让原图像的直方图变换成我们指定的形式。这个过程称为直方图匹配或者直方图规定化。
直方图规定化的步骤为:
1.求给定的函数的累积直方图 s。
2.求原图像的累积直方图 G。
3.求 s 中每一个值在 G 中距离最小的位置 index。
4.求原图像每个像素通过 index 映射到的新像素的值。
运行代码说明
1.要改变代码中的地址,我的地址说明,我是把待处理图片统一放在一个(同级)image文件夹,用os.listdir(base)读取图片名称列表,base是存放图片文件夹的相对路径,也可以是绝对路径
最后在
os.path.join(base,path)
代码中合并base和图片名称,得到完整图片地址2.如果想更改为读取同目录下图片,可以将读取图片路径的几句代码可以改为
原来
base = r'../image' paths = os.listdir(base) for path in paths: img = cv.imread(os.path.join(base,path), 1)
改为
paths = ['img1.jpg','img2.jpg','img3.png'......] for path in paths: print(path) # 读取图片 1 是加载彩色图像。任何图像的透明度都会被忽视。它是默认标志。 img = cv.imread(path, 1)
3.注意最后的
plt.savefig('1.new.jpg')
是保存plt图像,如果不使用可以注释掉
import os
import numpy as np
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def put(path):
# 读取图像
img = cv2.imread(os.path.join(base, path), 1) # 需要进行规定化的图像(原图)
ref = cv2.imread(os.path.join(base, path), 1) #直方图规定化的目标图像
# 直方图均衡化
b, g, r = cv2.split(img)
img2 = cv2.merge([r, g, b])
# 转灰度图
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ref = cv2.cvtColor(ref, cv2.COLOR_BGR2GRAY)
# 直方图均衡化,调用equalizeHist() 函数
res1 = cv2.equalizeHist(img)
# 直方图规定化
res2 = img.copy()
hist_img, _ = np.histogram(img, 256) # 直方图
hist_ref, _ = np.histogram(ref, 256)
cdf_img = np.cumsum(hist_img) # 累积直方图
cdf_ref = np.cumsum(hist_ref)
for j in range(256):
tmp = abs(cdf_img[j] - cdf_ref)
tmp = tmp.tolist()
idx = tmp.index(min(tmp))
res2[img == j] = idx
# 输出结果
plt.figure(figsize=(10,7))
plt.subplot(231), plt.imshow(img2), plt.title('原始图像')
plt.subplot(232),plt.imshow(img,plt.cm.gray),plt.title('灰度图像')
plt.subplot(233), plt.hist(img.ravel(), 16), plt.title('灰度图像直方图')
plt.subplot(234),plt.imshow(res1,plt.cm.gray),plt.title('灰度直方图均衡化')
plt.subplot(235), plt.hist(res1.ravel(), 16), plt.title('均衡化直方图')
plt.subplot(236),plt.imshow(res2,plt.cm.gray),plt.title('灰度直方图规定化')
# plt.savefig('3.new.jpg')
plt.show()
base = r'../image' # 图片根目录
paths = os.listdir(base)
for path in paths:
print(path)
put(path)