直方图均衡化
1.计算过程
- 得到原始图片的灰度直方图
- 得到各个灰度级对应的概率密度函数
- 通过概率密度函数得到累积分布函数
- 累计分布函数乘以255,得到每一个灰度级对应的新的灰度
- 通过第4步的结果,将旧灰度映射得到新的灰度,即更新整张图片的灰度
(统计一幅图像中不同灰度级下的像素个数);
例如:一副64X64的8个灰度级的图像,(正常情况下一张彩色图像灰度化[R=G=B]以后,灰度级为0~255)
rk为灰度级,nk为该灰度级下的像素的数目,pk为该灰度级占整幅图的概率
计算不同灰度级的累积概率分布:
灰度级(rk) | 概率分布(pk) |
---|---|
0 | 0.19 |
1 | 0.44 |
2 | 0.65 |
3 | 0.81 |
4 | 0.89 |
5 | 0.95 |
6 | 0.98 |
7 | 1 |
灰度级映射(s = pk X (L-1))
原灰度级rk | 新灰度级NK | 四舍五入后的新灰度级nk |
---|---|---|
0 | 1.33 | 1 |
1 | 3.08 | 3 |
2 | 4.55 | 5 |
3 | 5.67 | 6 |
4 | 6.23 | 6 |
5 | 6.65 | 7 |
6 | 6.86 | 7 |
7 | 7 | 7 |
根据新的灰度级nk重新映射出像素的数目
新灰度级nk | 原灰度级 | 像素个数 |
---|---|---|
1 | 0 | 790 |
3 | 1 | 1023 |
5 | 2 | 850 |
6 | 3和4 | 985 |
7 | 5,6和7 | 448 |
再与原来进行比较:
新灰度级nk | 像素个数 |
---|---|
1 | 790 |
3 | 1023 |
5 | 850 |
6 | 985 |
7 | 448 |
2.直方图均衡化的理解
(1)为什么直方图均衡化可以使图像清晰化
一张图像的对比度可以理解为图像中细节可被肉眼分辨的程度,而图像的均衡化可以增强图像的对比度,可以通过灰度直方图来体现图像的对比度:
在直方图中,较灰暗的图像颜色直方图分布往往分布在一个比较小的像素值范围内,而较为清晰图像的颜色直方图在整个像素灰度值范围内分布的比较均匀。因此我们可以得出图像对比度越高,在由灰度/像素个数构成的直角坐标系中横向跨度越大,纵向长度越趋于一致。在横坐标上跨度越长也就说明图像中使用的灰度值越多,也就能够更加清晰的反映图像中每一个细节与它周围的细节直接的差别。
(2).概率密度函数如何均衡直方图
(3).直方图均衡化源码展示
# 1.以灰度图的形式读入
img = cv2.imread(path_02, 0)
# 2.均衡化处理
dst = cv2.equalizeHist(img)
# 3.计算原图和均衡化后的直方图
cul_img = cv2.calcHist([img], [0], None, [256], [0, 256])
cul_dis = cv2.calcHist([dst], [0], None, [256], [0, 256])
# 3.结果展示
fig, axex = plt.subplots(nrows=2, ncols=2, figsize=[10, 8], dpi=100)
axex[0][0].imshow(img, cmap=plt.cm.gray)
axex[0][0].set_title("原图")
axex[0][1].imshow(dst, cmap=plt.cm.gray)
axex[0][1].set_title("均衡化的结果")
axex[1][0].plot(cul_img)
axex[1][0].grid()
axex[1][1].plot(cul_dis)
axex[1][1].grid()
(4).限制对比度的自适应直方图均衡及化源码展示
传统的全局直方图均衡化是对整一副图像进行操作,对于像素值分布的较均匀的图像来说,效果会比较明显,如果一幅图像中有明显亮和暗的区域来说,效果就不是很明显。因此我们可以对一副图像分成多个区域,然后对多个区域分别进行直方图均衡化,此方法可以提高局部区域的对比度和细节,但同时会有一个缺点:过度放大图像中相对均匀区域的噪声。为了解决此缺点,我们在对每一个小块进行直方图均衡化之前,设置一个阈值,将直方图中超过该阈值的部分剪切掉,然后均匀的分散在直方图的其他部分,然后再进行直方图均衡化,最后,由于我们是对局部进行直方图均衡化操作,每个区域之间会有明显的界限,整幅图像看上去是方块状的,因此我们采用双线性差值的方式来拼接方块。
# 1.以灰度图的形式读入
img = cv2.imread(path_02, 0)
# 2.创建一个自适应均衡化对象,并应用于图像
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl1 = clahe.apply(img)
# 3.计算原图和均衡化后的直方图
cul_img = cv2.calcHist([img], [0], None, [256], [0, 255])
cul_cl1 = cv2.calcHist([cl1], [0], None, [256], [0, 255])
# 3.图像展示
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8), dpi=100)
axes[0][0].imshow(img, cmap=plt.cm.gray)
axes[0][0].set_title("原图")
axes[0][1].imshow(cl1, cmap=plt.cm.gray)
axes[0][1].set_title("自适应均衡化后的结果")
axes[1][0].plot(cul_img)
axes[1][0].grid()
axes[1][1].plot(cul_cl1)
axes[1][1].grid()
plt.show()
3.计算直方图函数
# 1.以灰度的方式读入图像
img = cv2.imread(path_03, 0)
# 2.统计灰度图
histr = cv2.calcHist([img], [0], None, [256], [0, 256])
# 3.绘制灰度图
plt.figure(figsize=[10, 6], dpi=100)
plt.plot(histr)
plt.grid()
plt.show()
4.掩膜
# 1.以灰度的方式读入图像
img = cv2.imread(path_03, 0)
# 2.创建模板(全黑的图像)
mask = np.zeros(img.shape[:2], np.uint8)
mask[400: 650, 200:500] = 255
# 3.掩膜 (将原图进行掩膜)
mask_img = cv2.bitwise_and(img, img, mask=mask)
# 4.计算研掩膜后的灰度图
mask_hirst = cv2.calcHist([img], [0], mask, [256], [1, 256])
# 2.统计原灰度图
histr = cv2.calcHist([img], [0], None, [256], [0, 256])
# 3.图像展示
fig, axex = plt.subplots(nrows=2, ncols=2, figsize=(10, 8))
axex[0, 0].imshow(img, cmap=plt.cm.gray)
axex[0, 0].set_title("原图")
axex[0, 1].imshow(mask, cmap=plt.cm.gray)
axex[0, 1].set_title("模板数据")
axex[1, 0].imshow(mask_img, cmap=plt.cm.gray)
axex[1, 0].set_title("掩膜后的数据")
axex[1, 1].plot(mask_hirst)
axex[1, 1].grid()
axex[1, 1].set_title("灰度直方图")
plt.show()
彩色直方图均衡化对有雾图片的效果
(1).全局直方图均衡化
path_01 = 'images/000048.jpg'
path_02 = 'images/000049.jpg'
path_03 = 'images/0058_1_0.2.jpg'
# 1.读入图像
img = cv2.imread(path_01)
# 2.通道分离
b, g, r = cv2.split(img)
# 3.分别对R, G, B均衡化图像
img_r = cv2.equalizeHist(r)
img_g = cv2.equalizeHist(g)
img_b = cv2.equalizeHist(b)
# 4.融合图像
img_heb = cv2.merge((img_b, img_g, img_r))
# 5.计算统计直方图
cul_img = cv2.calcHist([img], [0], None, [256], [0, 255])
cul_heb = cv2.calcHist([img_heb], [0], None, [256], [0, 255])
# 5.输出图像(因为plt和cvd的imread颜色次序不同,导致输出图像颜色偏差)
fig, axex = plt.subplots(nrows=2, ncols=2, figsize=[10, 8], dpi=100)
axex[0][0].imshow(img[:, :, ::-1])
axex[0][0].set_title("original_image")
axex[0][1].imshow(img_heb[:, :, ::-1])
axex[0][1].set_title("均衡化的结果")
axex[1][0].plot(cul_img)
axex[1][0].grid()
axex[1][0].set_title("original_image")
axex[1][1].plot(cul_heb)
axex[1][1].grid()
axex[1][1].set_title("cul_heb_image")
plt.show()
(2).限制对比度自适应直方图均衡化
path_01 = 'images/000048.jpg'
path_02 = 'images/000049.jpg'
path_03 = 'images/0058_1_0.2.jpg'
path_04 = 'images/000057.jpg'
path_05 = 'images/000178.jpg'
path_06 = 'images/000212.jpg'
path_07 = 'images/000058.jpg'
path_08 = 'images/000914.jpg'
path_09 = 'images/000403.jpg'
# 1.读入图像
img = cv2.imread(path_01)
# 2.通道分离
b, g, r = cv2.split(img)
# 2.创建一个自适应均衡化对象,并应用于图像
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl1_b = clahe.apply(b)
cl1_g = clahe.apply(g)
cl1_r = clahe.apply(r)
cl1 = cv2.merge((cl1_b, cl1_g, cl1_r))
# 5.计算统计直方图
cul_img = cv2.calcHist([img], [0], None, [256], [0, 255])
cul_heb = cv2.calcHist([cl1], [0], None, [256], [0, 255])
# 5.输出图像(因为plt和cvd的imread颜色次序不同,导致输出图像颜色偏差)
fig, axex = plt.subplots(nrows=2, ncols=2, figsize=[10, 8], dpi=100)
axex[0][0].imshow(img[:, :, ::-1])
axex[0][0].set_title("original_image")
axex[0][1].imshow(cl1[:, :, ::-1])
axex[0][1].set_title("new_image")
axex[1][0].plot(cul_img)
axex[1][0].grid()
axex[1][0].set_title("original_image")
axex[1][1].plot(cul_heb)
axex[1][1].grid()
axex[1][1].set_title("cul_heb_image")
plt.show()
结论:
限制性对比度直方图均衡化总体效果要优于全局直方图均衡化,对有雾图像进行全局直方图均衡化之后,对浓雾图像的边框附近来说会产生变暗的效果,但是去除浓雾的效果会更好。限制性对比度直方图均衡化没有全局直方图均衡化的缺点,但是去雾能力没有他强,总的来说直方图均衡化虽然可以达到增加图像细节,弱化了有雾的图像,但是总体上并没有改变图像有雾的情况。