[Day 04] 眼前的黑不是黑,你说的白是什麽白?(直方图均衡化)

前言

「眼前的黑不是黑,你说的白是什麽白」-- 你是我的眼(萧煌奇)
没错,并非所有图片都是在理想的环境下拍摄的,
光线不足(太黑)或是过曝(太白)问题都会让图片中的讯息丢失,
造成人们看不清楚照片中的物品。
好在我们可以统计各个像素值的数量,得知这张图片灰度的分布。
然後使用数学来解决它!


  • 什麽是灰度直方图(Histogram):
    X轴为像素值(0 ~ 255),Y轴为该值的数量。

  • 灰度直方图的特性:
    若图片全黑(像素为0),则直方会集中在图的左侧,代表图片太暗了。

  • 观察照片(angry):
    因为下图(MDFK)较上图暗,所以直方图的bin偏向左边。
    0

  • 观察照片(neutral):
    因为上图(女人)各个灰度值发生较平均,所以直方图的bin呈现平均分散的状态,
    而下图(婴儿)黑白分明,少有中间灰色,所以直方图的bin集中在两侧,中间只有零星几个bin。
    6


1. 原始图片

我们挑选一张可爱的婴儿表情图片进行解说,
由於原图片太小,我将它放大至(600,600)。

idx = 12
gray_img = X_train[idx][:, :, 0].astype("uint8")
gray_img = cv2.resize(gray_img, (600, 600))
plt.figure(figsize=(5, 5))
plt.imshow(gray_img, cmap='gray')

之所以挑选这张照片,
是因为它黑白分明,有利於说明。
baby_origin


2. 直方图均衡化(Histogram Equalization)

在opencv中,有提供equalizeHist函数,将图片进行均衡化(Equalization)。
均衡化:透过拉伸的像素值(对比度拉伸),使得像素分布较均匀,提高对比度。
原理:透过调整累积分布函数(CDF),把像素值高的区域分散给周围区域,使CDF呈现斜直线。

equalized_img = cv2.equalizeHist(gray_img)
cv2.imshow("equal_image", equalized_img)

来看看调整後的图片:
baby_equalized

好像有点恐怖.../images/emoticon/emoticon21.gif/images/emoticon/emoticon21.gif/images/emoticon/emoticon21.gif

这时,我们就可以透过灰度直方图的比较来看看发生什麽事:
compare_0
看起来是因为原本超级白的脸蛋在边缘位置上被黑色污染了,
如果这张图是彩色的,那我可以合理推测婴儿是掉进泥巴坑了。
不~~~~~~~把我可爱的宝宝还来!


3. 自适应直方图均衡化(Adaptive Histogram Equalization)

有没有更好的均衡化方法呢?有的!
那就是自适应直方图均衡化
它的改良处在於将图片分成多个区域(如8x8),
每个区域各自做直方图均衡化,所以AHE比HE更适合增强局部对比度。

但直方图均衡化的缺点「放大暗处的杂讯」在AHE中并没有获得改善。
好在有人提出限制对比度自适应直方图均衡化(Contrast Limited Adaptive Histogram Equalization),
限制对比度的核心概念是控制CDF斜率,将突然长太高(超过某阈值)的bin砍掉头,拿去补低的像素值。

clahe = cv2.createCLAHE(clipLimit=2)
clahe_img = clahe.apply(gray_img)
cv2.imshow("clahe_img", clahe_img)

经由CLAHE处理过後图片的对比增加了,
连婴儿的眼睛鼻子嘴巴都看得非常清楚呢!
baby_clahe

再来比较CLAHE处理前後的直方图,
灰度分布比只用HE还要更均匀了。
compare_1


结语

这篇讲到影像处理中常用的图像增强技巧,

  1. 用数值方法将图片的size变大(实际上就是cv2.resize,要用GAN也可以)
  2. 增加图片对比度(CLAHE)

目的是让大家认识这个技巧,
我没有深入到讲解演算法的部分,
如果有兴趣知道背後数学的话,
网路上有许多资源可以学习。


<<:  [Day 04] 深度学习与神经网路

>>:  Spring boot 配置 Fluent bit 传递 Log

Day 28 - 强化学习 Reinforcement Learning(2)

时差学习 Temporal difference learning link 时差学习是通过boot...

Day13:终於要进去新手村了-Javascript-判断式基本结构-if…else

今天要来提到的是判断式的部分,在JS中判断式有两种语法:if...else和 switch。 这篇我...

Day 24. Hashicorp Vault: PKI issue limit

Hashicorp Vault: PKI issue limit Vault Forum 有篇文章询...

Day06:Swift 基础语法—Class

前言 前面学习了 Structure, 今天就来介绍 Class, Structure 与 Clas...

Spring 初探 (二)

Spring 初探 (二) Spring初探(二) ...