5.2. 直方图-2:直方图均衡化

5.2.1. 目标

在本节中,

  • 我们将学习直方图均衡化的概念,并使用它来提高图像的对比度。

5.2.2. 理论

考虑一个图像,其像素值仅限于某个特定范围的值。对于eg,较亮的图像将所有像素限制在较高的值内。但是一个好的图像会有来自图像所有区域的像素。因此,您需要将这个直方图拉伸到两端(如下图所示,来自维基百科),这就是直方图均衡化的作用(简单地说)。这通常会提高图像的对比度。

我建议你阅读维基百科的网页 Histogram Equalization 更多细节。它有一个很好的解释和已解决的例子,所以你会明白几乎所有的阅读后。相反,在这里我们将看到它的Numpy实现。之后,我们将看到OpenCV函数。

>>> %matplotlib inline
>>>
>>> import cv2
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>>
>>> img = cv2.imread('/cvdata/wiki.jpg',0)
>>>
>>> hist,bins = np.histogram(img.flatten(),256,[0,256])
>>>
>>> cdf = hist.cumsum()
>>> cdf_normalized = cdf * hist.max()/ cdf.max()
>>>
>>> plt.plot(cdf_normalized, color = 'b')
>>> plt.hist(img.flatten(),256,[0,256], color = 'r')
>>> plt.xlim([0,256])
>>> plt.legend(('cdf','histogram'), loc = 'upper left')
>>> plt.show()
../_images/sec02-histogram-equalization_1_0.png

你可以看到直方图位于较亮的区域。我们需要全谱。为此,我们需要一个转换函数,将输入像素在较亮区域映射到输出像素在整个区域。这就是直方图均衡化的作用。

现在我们找到最小直方图值(不包括0),并应用wiki页面中给出的直方图均衡化方程。但我在这里使用了,来自Numpy的蒙面数组概念数组。对于屏蔽数组,所有操作都在非屏蔽元素上执行。您可以从蒙面数组上的Numpy文档中阅读更多关于它的信息。

>>> cdf_m = np.ma.masked_equal(cdf,0)
>>> cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
>>> cdf = np.ma.filled(cdf_m,0).astype('uint8')

现在我们有了一个查找表,它提供了关于每个输入像素值的输出像素值的信息。所以我们只应用转换。

>>> img2 = cdf[img]
>>> plt.imshow(img)
<matplotlib.image.AxesImage at 0x7f0cb73a5860>
../_images/sec02-histogram-equalization_6_1.png

现在我们像以前一样计算它的直方图和cdf(您这样做),结果如下:

另一个重要的特点是,即使图像是较暗的图像(而不是我们使用的较亮的图像),经过均衡后,我们将得到几乎与我们得到的图像相同的图像。因此,这被用作“参考工具”,使所有图像具有相同的照明条件。这在很多情况下都很有用。例如,在人脸识别中,在对人脸数据进行训练之前,对人脸图像进行直方图均衡化处理,使其具有相同的光照条件。

5.2.3. OpenCV中的直方图均衡

OpenCV有这样的功能, 均衡器() . 它的输入只是灰度图像,输出是我们的直方图均衡化图像。

下面是一个简单的代码片段,显示了它对我们使用的同一图像的用法:

>>> img = cv2.imread('/cvdata/wiki.jpg',0)
>>> equ = cv2.equalizeHist(img)
>>> res = np.hstack((img,equ)) #stacking images side-by-side
>>> cv2.imwrite('res.png',res)
True

image0

所以现在你可以在不同的光照条件下拍摄不同的图像,使其均衡并检查结果。

当图像的直方图局限于某一特定区域时,直方图均衡化效果较好。如果直方图覆盖了一个很大的区域,即既有亮像素又有暗像素,那么这种方法在强度变化较大的地方就行不通了。请检查其他资源中的SOF链接。

5.2.4. 对比度受限的自适应直方图均衡化

我们刚刚看到的第一个直方图均衡化,考虑了图像的全局对比度。在许多情况下,这不是一个好主意。例如,下图显示了全局直方图均衡化后的输入图像及其结果。

直方图均衡化后,背景对比度确实有所改善。但比较两幅图像中雕像的脸。由于亮度过高,那里的大部分信息都丢失了。这是因为它的直方图并不像我们在前面的例子中看到的那样局限于一个特定的区域(试着绘制输入图像的直方图,你会得到更多的直觉)。

为了解决这个问题, 自适应直方图均衡化 使用。在这个过程中,图像被划分为称为“tiles”的小块(在OpenCV中,tileSize默认为8x8)。然后像往常一样对这些块进行直方图均衡化。所以在一个很小的区域,直方图会局限于一个很小的区域(除非有噪音)。如果有噪音,就会被放大。为了避免这种情况, 对比度限制 已应用。如果任何直方图箱高于指定的对比度限制(在OpenCV中默认为40),则在应用直方图均衡化之前,这些像素将被剪裁并均匀分布到其他箱。均衡后,采用双线性插值方法去除图像中的伪影。

下面的代码片段展示了如何在OpenCV中应用CLAHE:

>>> import numpy as np
>>> import cv2
>>>
>>> img = cv2.imread('/cvdata/tsukuba_l.png',0)
>>>
>>>
>>> # create a CLAHE object (Arguments are optional).
>>> clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
>>> cl1 = clahe.apply(img)
>>>
>>> cv2.imwrite('xx_clahe_2.jpg',cl1)
True

请参阅下面的结果并将其与上面的结果进行比较,尤其是雕像区域:

5.2.6. 练习