OpenCV直方图-2:直方图均衡

目标

在本节中,

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

理论

考虑其像素值仅限于某一特定值范围的图像。例如,更亮的图像将所有像素限制在高值。但是一个好的图像会有来自图像所有区域的像素。因此,您需要将这个直方图扩展到两端,而这就是直方图均衡化所做的事情(用简单的话来说)。这通常会改善图像的对比度。

Histograms Equalization

这里我们将看到它的Numpy实现。之后,我们将看到OpenCV函数。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('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()

Histograms Equalization

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

现在,我们找到了最小直方图值(不包括0),并应用了在wiki页面中给出的直方图均衡方程。但是我在这里使用了来自Numpy的蒙面数组概念数组。对于mask数组,所有操作都是对非mask元素执行的。

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]

现在,我们像以前一样计算它的直方图和cdf,结果如下所示:

Histograms Equalization

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

OpenCV中的直方图均衡

OpenCV有这样的功能,cv2.equalizeHist()。其输入为灰度图像,输出为直方图均衡化图像。

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

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

Histograms Equalization

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

当图像直方图被限制在特定区域时,直方图均衡是很好的。在直方图覆盖一个大区域(即亮像素和暗像素都存在)的情况下,在灰度变化较大的地方,它将不能很好地工作。

对比度有限自适应直方图均衡

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

Problem of Global HE

经过直方图均衡化后,背景对比度确实有所改善。但是比较一下这两幅图像中雕像的脸。由于亮度过高,我们失去了大部分信息。这是因为它的直方图并不像我们以前看到的那样局限于特定的区域。

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

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

import numpy as np
import cv2

img = cv2.imread('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('clahe_2.jpg',cl1)

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

Result of CLAHE

猜你喜欢

转载自blog.csdn.net/rongpeisheng666/article/details/81633103