直方图均衡化

Posted 陨星落云

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了直方图均衡化相关的知识,希望对你有一定的参考价值。

直方图均衡化

想象一下,如果一副图像中的大多是像素点的像素值都集中在一个像素值范围之内会怎样呢?例如,如果一幅图片整体很亮,那所有的像素值应该都会很高。但是一副高质量的图像的像素值分布应该很广泛。所以你应该把它的直方图做一个横向拉伸(如下图),这就是直方图均衡化要做的事情。通常情况下,这种操作会改善图像的对比度。

 

这种方法通常用来增加许多图像的全局对比度,尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法,亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度,直方图均衡化通过有效地扩展常用的亮度来实现这种功能。

这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。这种方法的一个缺点是它对处理的数据不加选择,它可能会增加背景噪声的对比度并且降低有用信号的对比度。

我们先来看看相应的直方图和累积直方图,然后使用 OpenCV 进行直方图均衡化。

def img_show(name,image):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(image.shape) == 3:
        image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    plt.imshow(image,\'gray\')
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(name,fontproperties=\'FangSong\',fontsize=12)
    
if __name__=="__main__":

    img = cv2.imread("data/Unequalized.jpg",0)
    hist,bins = np.histogram(img.flatten(),256,[0,256])
    #print(hist)
    
    #查看累积直方图
    cdf = hist.cumsum()
    cdf_normalized = cdf*hist.max() / cdf.max()
    #print(cdf_normalized)
    
    #均衡化
    equ = cv2.equalizeHist(img)
    
    hist1,bins1 = np.histogram(equ.flatten(),256,[0,256])
    #print(hist)
    
    #查看均衡化后的累积直方图
    cdf1 = hist1.cumsum()
    cdf_normalized1 = cdf1*hist1.max() / cdf1.max()
    
    #显示图像结果
    plt.figure(figsize=(10,8),dpi=100)
    plt.subplot(221)
    img_show(\'原图\',img)
    plt.subplot(222)
    img_show(\'均衡化后\',equ)
    plt.subplot(223)
    plt.plot(cdf_normalized,color=\'b\')
    plt.hist(img.flatten(),256,[0,256],color=\'r\')
    plt.xlabel(\'相应的直方图(红)和累积直方图(蓝)\',fontproperties=\'FangSong\',fontsize=15)
    plt.xlim([0,256])
    plt.legend((\'cdf\',\'historgram\'),loc = \'upper left\')
    plt.subplot(224)
    plt.plot(cdf_normalized1,color=\'b\')
    plt.hist(equ.flatten(),256,[0,256],color=\'r\')
    plt.xlabel(\'均衡化相应的直方图(红)和累积直方图(蓝)\',fontproperties=\'FangSong\',fontsize=15)
    plt.xlim([0,256])
    plt.legend((\'cdf\',\'historgram\'),loc = \'upper left\')
    plt.show()

 

我们可以看出来直方图大部分在灰度值较高的部分,而且分布很集中。而我们希望直方图的分布比较分散,能够涵盖整个 x 轴。所以,我们就需要一个变换函数帮助我们把现在的直方图映射到一个广泛分布的直方图中,这就是直方图均衡化。

限制对比度自适应性直方图均衡化 CLAHE 

在上边做的直方图均衡化会改变整个图像的对比度,但是在很多情况下,这样做的效果并不好。的确在进行完直方图均衡化之后,图片背景的对比度被改变了。但是你再对比一下两幅图像中雕像的面图,由于太亮我们丢失了很多信息。

 

原理:

为了解决这个问题,我们需要使用自适应的直方图均衡化CLAHE (Contrast Limited Adaptive Histogram Equalization)。这种情况下,整幅图像会被分成很多小块,这些小块被称为“tiles”(在 OpenCV 中 tileGridSize默认是 8x8),然后再对每一个小块分别进行直方图均衡化(跟前面类似)。所以在每一个的区域中,直方图会集中在某一个小的区域中(除非有噪声干扰)。如果有噪声的话,噪声会被放大。为了避免这种情况的出现,要使用对比度限制。

CLAHE中,每一个像素邻域都要进行对比度限制,从而得到对应的变换函数,被用来降低AHE中噪声的增强,这主要是通过限制AHE中的对比度增强来实现的。像素周围邻域噪声的增强主要是由变换函数的斜率造成的,由于像素邻域的噪声与邻域的CDF成正比,因此也与邻域直方图在该中心像素位置的值成正比,CLAHE之所以能够限制对比度,是因为它在计算邻域的CDF之前在指定阈值处对直方图进行了修剪,如下图所示,这一做法不仅限制了CDF的斜率,也限制了变换函数的斜率,其中对直方图进行切割所使用的阈值,被称作修剪限制度(clip limit),这个参数不仅依赖于直方图的归一化,而且依赖于像素邻域的size大小,通常设为3到4之间。

 

对于每个小块来说,如果直方图中的 bin 超过对比度的上限的话,就把其中的像素点均匀分散到其他 bins 中,然后在进行直方图均衡化。最后,为了去除每一个小块之间“人造的”(由于算法造成)边界,再使用双线性差值,与原图做图层滤色混合操作(可选)。

实现:

def img_show(name,image):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    if len(image.shape) == 3:
        image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
    plt.imshow(image,\'gray\')
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(name,fontproperties=\'FangSong\',fontsize=12)
    
if __name__=="__main__":
    img = cv2.imread("data/tsukuba_l.jpg",0)
    hist,bins = np.histogram(img.flatten(),256,[0,256])
    #print(hist)
    
    #查看累积直方图
    cdf = hist.cumsum()
    cdf_normalized = cdf*hist.max() / cdf.max()
    #print(cdf_normalized)
    
    #均衡化
    clahe = cv2.createCLAHE(clipLimit =2.0,tileGridSize=(8,8))
    equ = clahe.apply(img)
    
    hist1,bins1 = np.histogram(equ.flatten(),256,[0,256])
    #print(hist)
    
    #查看均衡化后的累积直方图
    cdf1 = hist1.cumsum()
    cdf_normalized1 = cdf1*hist1.max() / cdf1.max()
    
    #显示图像结果
    plt.figure(figsize=(10,8),dpi=100)
    plt.subplot(221)
    img_show(\'原图\',img)
    plt.subplot(222)
    img_show(\'自适应均衡化\',equ)
    plt.subplot(223)
    plt.plot(cdf_normalized,color=\'b\')
    plt.hist(img.flatten(),256,[0,256],color=\'r\')
    plt.xlabel(\'相应的直方图(红)和累积直方图(蓝)\',fontproperties=\'FangSong\',fontsize=15)
    plt.xlim([0,256])
    plt.legend((\'cdf\',\'historgram\'),loc = \'upper left\')
    plt.subplot(224)
    plt.plot(cdf_normalized1,color=\'b\')
    plt.hist(equ.flatten(),256,[0,256],color=\'r\')
    plt.xlabel(\'自适应均衡化直方图\',fontproperties=\'FangSong\',fontsize=15)
    plt.xlim([0,256])
    plt.legend((\'cdf\',\'historgram\'),loc = \'upper left\')
    plt.show()
    

 

参考文献:
网址:直方图均衡化
Adaptive_histogram_equalization
书籍:《数字图像处理》《OpenCV-Python 中文教程》

以上是关于直方图均衡化的主要内容,如果未能解决你的问题,请参考以下文章

Opencv——直方图掩膜直方图均衡化详细介绍及代码实现

MATLAB-真彩色图像直方图均衡化及分别在RGB与HSI坐标系进行处理

图像增强总结和代码

数字图像处理直方图均衡化与规定化

数字图像处理直方图均衡化与规定化

OpenCV学习笔记13-图像直方图的介绍及代码实现