OpenCV—python 自适应对比度增强(ACE)

一、算法原理

在图像处理的方法中,自适应方法是与图像本身信息相关,根据图像对图特征对图像进行处理的一系列方法,这些方法往往具有更好的鲁棒性、普适性。而本文中提到的这种ACE方法由NarendraPM Narendra P MNarendraPM等人在《Real-Time Adaptive Contrast Enhancement》 提到。不同于全局图像增强方法,使用局部标准差实现图像的局部对比度增强比全局的图像增强方法有更好的效果。它充分的考虑到图片图片区域对比度。不过计算量更大。

在经典图像算法中,涉及到局部区域的算法,效果大多好于全局性的,但是计算量也几乎呈指数级增长,例如NLM降噪算法。

对于图像中的每一个点,分别计算其局部均值与局部标准差;
M ( i , j ) = 1 ( 2 n + 1 ) ( 2 m + 1 ) ∑ s = i − n i + n ∑ k = j − m j + m f ( s , k ) M(i,j) = \frac{1}{(2n+1)(2m+1)}\sum_{s=i-n}^{i+n}\sum_{k=j-m}^{j+m}f(s,k) M(i,j)=(2n+1)(2m+1)1s=ini+nk=jmj+mf(s,k)

σ ( i , j ) = 1 ( 2 n + 1 ) ( 2 m + 1 ) ∑ s = i − n i + n ∑ k = j − m j + m ( f ( s , k ) − M ( i , j ) ) \sigma (i,j) = \frac{1}{(2n+1)(2m+1)}\sum_{s=i-n}^{i+n}\sum_{k=j-m}^{j+m}(f(s,k)-M(i,j)) σ(i,j)=(2n+1)(2m+1)1s=ini+nk=jmj+m(f(s,k)M(i,j))

其中:
f ( s , k ) f(s,k) f(s,k) 代表坐标 ( s , k ) (s,k) (s,k) 的点像素值。
M ( i , j ) M(i,j) M(i,j) 为以点 ( i , j ) (i,j) (i,j)为中心,窗口大小为 ( 2 n + 1 ) , ( 2 m + 1 ) (2n+1),(2m+1) (2n+1)(2m+1) 的区域的局部均值
σ 2 ( i , j ) σ^2 (i,j) σ2(i,j)为局部的方差,即 σ ( i , j ) σ(i,j) σ(i,j) 为局部图像的标准差。

求得局部均值与标准差后,就可以对图像进行增强了,公式如下;
I ( i . j ) = M ( i . j ) + G ( f ( i . j ) − M ( i . j ) ) I(i.j) = M(i.j) +G ( f(i.j) -M(i.j) ) I(i.j)=M(i.j)+G(f(i.j)M(i.j))

G = α M σ ( i . j )        0 < α < 1 G = \alpha \frac{M}{\sigma (i.j)} ~~~~~~ 0<\alpha <1 G=ασ(i.j)M      0<α<1

上式中:
I ( i , j ) I(i,j) I(i,j) 为增强后的像素值,
M M M 为全局均值(你也可以把它设为某一合理数值),
α α α 是一个系数参数,一般取小于1大于0的小数。

如果将每个点的局部均值 M ( i , j ) M(i,j) M(i,j)构成一张图,《数字图像傅里叶变换的物理意义及简单应用》
提到,均值滤波是一种低通滤波,获得的是图像的低频部分,也就是背景部分, f ( i , j ) − M ( i , j ) f(i,j)−M(i,j) f(i,j)M(i,j)就可以用来量化图像中的一个点是高频还是低频。而在一般情况下,G 都是大于1的,所以通过 G ( f ( i , j ) − M ( i , j ) ) G(f(i,j)−M(i,j)) G(f(i,j)M(i,j))可以实现对图像的高频部分的放大,进而对图像进行增强。
在这里插入图片描述
经过上面的过程可以看出,如果G 是一个固定参数,通过式子中的局部均值,我们已经能够将图像实现一定程度上的自适应增强了。那么为什么还要在参数G中引入标准差呢?

我们回忆一下对比度增强的初衷,对比度增强是为了让本身对比度不强的图像的对比度变得明显,而对本身对比度很强的图像,是没必要做增强的。那么在同一图像中,我们尤其需要增强对比度不强的部分。而方差表示的是图像的像素值的均匀性,我们可以认为方差越大的局部区域,其像素值越不均匀,对比度越强;反之,方差越小的局部区域,其像素值越均匀,对比度越弱。因此,在参数GG中除以了局部标准差,可以让图像中对比度较弱的部分的增强效果更加明显。

其次,如果对整张图像中所有点进行等比例增强,图像中本身就是高频的部分出现过增强的现象,图像看起来十分奇怪。

彩色图像的ACE
在网上看到有人说,对彩色图像增强可以分别对RGB三通道进行增强后进行合并。这个观点是错误的,因为分别对各个通道进行增强,会引起图像色相的变化,图像会变的不是其原来的颜色了。

所以需要将图像转到HSI色彩空间,或者是YCrCb颜色空间。前者只需要对I亮度通道进行增强,而H、S分别代表的色调和饱和度通道不需要变化。后者用Y通道表示亮度,只需要对Y通道进行增强即可。增强之后再合并通道,转换回RGB空间便完成了对彩色图像的增强。

二、代码与各方法效果对比

使用PIL图像处理包:(全局性的)图像对比度增强。【关于更多请点击】

from PIL import Image
from PIL import ImageEnhance
 
img = Image.open('./001.png')
 
#对比度增强  
enh_con = ImageEnhance.Contrast(img)  
contrast = 1.5
img_contrasted = enh_con.enhance(contrast)  
img_contrasted.save("./001_1.png")

局部自适应图片增强

# -*- coding: utf-8 -*-
import numpy as np
import cv2

def getVarianceMean(scr, winSize):
    if scr is None or winSize is None:
        print("The input parameters of getVarianceMean Function error")
        return -1
    
    if winSize % 2 == 0:
        print("The window size should be singular")
        return -1 
    
    copyBorder_map=cv2.copyMakeBorder(scr,winSize//2,winSize//2,winSize//2,winSize//2,cv2.BORDER_REPLICATE)
    shape=np.shape(scr)
    
    local_mean=np.zeros_like(scr)
    local_std=np.zeros_like(scr)
    
    for i in range(shape[0]):
        for j in range(shape[1]):   
            temp=copyBorder_map[i:i+winSize,j:j+winSize]
            local_mean[i,j],local_std[i,j]=cv2.meanStdDev(temp)
            if local_std[i,j]<=0:
                local_std[i,j]=1e-8
            
    return local_mean,local_std
    
def adaptContrastEnhancement(scr, winSize, maxCg):
    if scr is None or winSize is None or maxCg is None:
        print("The input parameters of ACE Function error")
        return -1
    
    YUV_img=cv2.cvtColor(scr,cv2.COLOR_BGR2YUV)    ##转换通道
    Y_Channel = YUV_img[:,:,0]
    shape=np.shape(Y_Channel)
    
    meansGlobal=cv2.mean(Y_Channel)[0]
    
   ##这里提供使用boxfilter 计算局部均质和方差的方法
#    localMean_map=cv2.boxFilter(Y_Channel,-1,(winSize,winSize),normalize=True)
#    localVar_map=cv2.boxFilter(np.multiply(Y_Channel,Y_Channel),-1,(winSize,winSize),normalize=True)-np.multiply(localMean_map,localMean_map)
#    greater_Zero=localVar_map>0
#    localVar_map=localVar_map*greater_Zero+1e-8
#    localStd_map = np.sqrt(localVar_map)
   
    localMean_map, localStd_map=getVarianceMean(Y_Channel,winSize)

    for i in range(shape[0]):
        for j in range(shape[1]):
            
            cg = 0.2*meansGlobal/ localStd_map[i,j];
            if cg >maxCg:
                cg=maxCg
            elif cg<1:
                cg=1
            
            temp = Y_Channel[i,j].astype(float)
            temp=max(0,min(localMean_map[i,j]+cg*(temp-localMean_map[i,j]),255))
            
#            Y_Channel[i,j]=max(0,min(localMean_map[i,j]+cg*(Y_Channel[i,j]-localMean_map[i,j]),255))
            Y_Channel[i,j]=temp
                
            
    YUV_img[:,:,0]=Y_Channel
    
    dst=cv2.cvtColor(YUV_img,cv2.COLOR_YUV2BGR)
    
    return dst

def main():
    img=cv2.imread(input_fn)
    
    if img is None:
        print("The file name error,please check it")
        return -1
    
    print(np.shape(img))
    dstimg=adaptContrastEnhancement(img,15,10)
    
    cv2.imwrite('output.jpg',dstimg)
    cv2.waitKey(0)
    
    return 0
 
    
input_fn='temp1.jpg'
if __name__ == '__main__':
    main()

在这里插入图片描述

参考
https://www.cnblogs.com/Imageshop/p/3324282.html
https://blog.csdn.net/u013921430/article/details/83865427
https://blog.csdn.net/piaoxuezhong/article/details/78385517

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值