光照问题之常见算法比较(附Python代码)

时间:2023-03-09 02:13:07
光照问题之常见算法比较(附Python代码)

一、灰度世界算法

① 算法原理

灰度世界算法以灰度世界假设为基础,该假设认为:对于一幅有着大量色彩变化的图像,R,G,B三个分量的平均值趋于同一灰度值Gray。从物理意义上讲,灰色世界法假设自然界景物对于光线的平均反射的均值在总体上是个定值,这个定值近似地为“灰色”。颜色平衡算法将这一假设强制应用于待处理图像,可以从图像中消除环境光的影响,获得原始场景图像。

一般有两种方法确定Gray值

1) 使用固定值,对于8位的图像(0~255)通常取128作为灰度值

2) 计算增益系数,分别计算三通道的平均值avgR,avgG,avgB,则:

Avg=(avgR+avgG+avgB)/3

kr=Avg/avgR , kg=Avg/avgG , kb=Avg/avgB

利用计算出的增益系数,重新计算每个像素值,构成新的图片

② 算法优缺点

这种算法简单快速,但是当图像场景颜色并不丰富时,尤其出现大块单色物体时,该算法常会失效。

③ 算法展示

 def grey_world(nimg):  
nimg = nimg.transpose(2, 0, 1).astype(np.uint32)  
   avgB = np.average(nimg[0])  
   avgG = np.average(nimg[1])  
   avgR = np.average(nimg[2])  
 
   avg = (avgB + avgG + avgR) / 3  
 
   nimg[0] = np.minimum(nimg[0] * (avg / avgB), 255)  
   nimg[1] = np.minimum(nimg[1] * (avg / avgG), 255)  
   nimg[2] = np.minimum(nimg[2] * (avg / avgR), 255)  
   return  nimg.transpose(1, 2, 0).astype(np.uint8)  

① 效果图对比

光照问题之常见算法比较(附Python代码)     光照问题之常见算法比较(附Python代码)

光照问题之常见算法比较(附Python代码)    光照问题之常见算法比较(附Python代码)

第一组图片场景颜色丰富,利用灰度世界假设法校正效果明显;第二组图片中颜色相对单一,校正效果也不是很理想;这也就导致了‘灰度世界假设算法’无法通用.

二、直方图均衡化

① 算法原理

直方图均衡化的基本思想是把原始图的直方图变换为均匀分布的形式,这样就增加了象素灰度值的动态范围从而可达到增强图像整体对比度的效果

假设,一张图像的直方图如下图(左)所示,均衡化后,图像直方图如下图(右)显示

光照问题之常见算法比较(附Python代码)   光照问题之常见算法比较(附Python代码)

② 算法优缺点

直方图均衡化,一般可用于灰度图像的对比增强(如:人脸阴影部位增强);

如果直接对彩色图像R,G,B三通道分别均衡化后再合并,极容易出现颜色不均、失真等问题,所以,一般会将RGB图像转换到YCrCb空间,对Y通道进行均衡化(Y通道代表亮度成分)

③ 算法展示

在python中opencv3提供了能将灰度图直接均衡化的方法:equalizeHist(img),借助这个方法,可以实现彩色图像的均衡化

 def hisEqulColor(img):  
    ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)  
    channels = cv2.split(ycrcb)  
    cv2.equalizeHist(channels[0], channels[0]) #equalizeHist(in,out)  
    cv2.merge(channels, ycrcb)  
    img_eq=cv2.cvtColor(ycrcb, cv2.COLOR_YCR_CB2BGR)  
   return img_eq  

④ 效果图对比

光照问题之常见算法比较(附Python代码)    光照问题之常见算法比较(附Python代码)

光照问题之常见算法比较(附Python代码)   光照问题之常见算法比较(附Python代码)

光照问题之常见算法比较(附Python代码)                                                       光照问题之常见算法比较(附Python代码)

第一组、第二组彩色图像中均衡化后图片对比原图更清晰,细节突出;第三组灰度图,均衡化在光照不均调节明暗的功能上,效果更明显

三、视网膜-大脑皮层(Retinex)增强算法

① 算法原理

    视网膜-大脑皮层(Retinex)理论认为世界是无色的,人眼看到的世界是光与物质相互作用的结果,也就是说,映射到人眼中的图像和光的长波(R)、中波(G)、短波(B)以及物体的反射性质有关

光照问题之常见算法比较(附Python代码)

光照问题之常见算法比较(附Python代码)

其中I是人眼中看到的图像,R是物体的反射分量,L是环境光照射分量,(x, y)是二维图像对应的位置

它通过估算L来计算R,具体来说,L可以通过高斯模糊和I做卷积运算求得,用公式表示为:

光照问题之常见算法比较(附Python代码)

其中F是高斯模糊的滤波器,“ * ”表示卷积运算

光照问题之常见算法比较(附Python代码)

其中σ称为高斯周围空间常数(Gaussian Surround Space Constant),也就是算法中所谓的尺度,对图像处理有比较大的影响,对于二维图像,光照问题之常见算法比较(附Python代码)等于对应位置即:光照问题之常见算法比较(附Python代码)

即:一般认为光照分量是原图像经过高斯滤波后的结果

② 算法优缺点

Retinex算法,从SSR(单尺度Retinex)到MSR(多尺度Retinex)以及到最常用的MSRCR(带颜色恢复的多尺度Retinex);其中色彩恢复主要目的是来调节由于图像局部区域对比度增强而导致颜色失真的缺陷.

先看一组公式:

RMSRCR(x,y)'=G⋅RMSRCR(x,y)+b

RMSRCR (x,y)=C(x,y)RMSR(x,y)

C(x,y)=f[I'(x,y)]=f[I(x,y)/∑I(x,y)]Ci(x,y)=f[Ii′(x,y)]=f[Ii(x,y)∑j=1NIj(x,y)]

f[I'(x,y)]=βlog[αI'(x,y)]=β{log[αI'(x,y)]−log[∑I(x,y)]}

如果是灰度图像,只需要计算一次即可,如果是彩色图像,如RGB三通道,则每个通道均需要如上进行计算

G表示增益Gain(一般取值:5)

b表示偏差Offset(一般取值:25)

I (x, y)表示某个通道的图像

C表示某个通道的彩色回复因子,用来调节3个通道颜色的比例;

f(·)表示颜色空间的映射函数;

β是增益常数(一般取值:46);

α是受控制的非线性强度(一般取值:125)

MSRCR算法利用彩色恢复因子C,调节原始图像中3个颜色通道之间的比例关系,从而把相对较暗区域的信息凸显出来,达到了消除图像色彩失真的缺陷。 处理后的图像局部对比度提高,亮度与真实场景相似,在人们视觉感知下,图像显得更加逼真;但是MSRCR算法处理图像后,像素值一般会出现负值。所以从对数域r(x, y)转换为实数域R(x, y)后,需要通过改变增益Gain,偏差Offset对图像进行修正

关于Retinex算法更多的细节,可以查看https://www.cnblogs.com/wangyong/p/8665434.html

③ 算法展示

光照问题之常见算法比较(附Python代码)

④  效果图对比

光照问题之常见算法比较(附Python代码)      光照问题之常见算法比较(附Python代码)

(原图)                                                                                           (SSR)

光照问题之常见算法比较(附Python代码)     光照问题之常见算法比较(附Python代码)

(MSR)                                                                            (MSRCR)

光照问题之常见算法比较(附Python代码)      光照问题之常见算法比较(附Python代码)

(原图)                                                                                     (SSR)

光照问题之常见算法比较(附Python代码)      光照问题之常见算法比较(附Python代码)

(MSR)                                                                                    (MSRCR)

上面的两组图片,可以看到第一组的效果明显,第二组的效果很差;同时可和‘灰度世界算法’的结果进行比较;一般认为,Retinex算法比较适合航空图片的处理,‘去雾’效果显著。

四、自动白平衡(AWB)

① 算法原理

用一个简单的概念来解释什么是白平衡:假设,图像中R、G、B最高灰度值对应于图像中的白点,最低灰度值的对应于图像中最暗的点;其余像素点利用(ax+b)映射函数把彩色图像中R、G、B三个通道内的像素灰度值映射到[0.255]的范围内.

白平衡的本质是让白色的物体在任何颜色的光源下都显示为白色,这一点对人眼来说很容易办到,因为人眼有自适应的能力,只要光源的色彩不超出一定的限度,就可以自动还原白色。但相机就不同了,无论是图像传感器还是胶卷都会记录光源的颜色,白色的物体就会带上光源的颜色,白平衡所要做的就是把这个偏色去掉。

② 算法优缺点

自动白平衡是一个很复杂的问题,目前还没有一个万能的方法可以解决所有场景的白平衡问题

截止2017年,出现不少利用神经网络实现自动白平衡的算法,也会有专门的文档对这部分进行详细的介绍。

③ 算法展示

利用Lab颜色空间,对图片进行自动白平衡操作.

光照问题之常见算法比较(附Python代码)

③ 效果图对比

光照问题之常见算法比较(附Python代码)      光照问题之常见算法比较(附Python代码)

光照问题之常见算法比较(附Python代码)    光照问题之常见算法比较(附Python代码)

可以看出,这两组效果图和‘灰度世界假设’算法得出的效果图很类似,主要是因为上述的白平衡算法也是基于‘灰度世界’这个假设下的

五、自动色彩均衡(ACE)

① 算法原理

ACE算法源自retinex算法,可以调整图像的对比度,实现人眼色彩恒常性和亮度恒常性,该算法考虑了图像中颜色和亮度的空间位置关系,进行局部特性的自适应滤波,实现具有局部和非线性特征的图像亮度与色彩调整和对比度调整,同时满足灰色世界理论假设和白色斑点假设。

第一步:对图像进行色彩/空域调整,完成图像的色差校正,得到空域重构图像;

光照问题之常见算法比较(附Python代码)

式中,Rc 是中间结果,Ic(p)-Ic(j)为两个不同点的亮度差,d(p,j)表示距离度量函数,r(*)为亮度表现函数,需是奇函数;这一步可以适应局部图像对比度,r(*)能够放大较小的差异,并丰富大的差异,根据局部内容扩展或者压缩动态范围。一般得,r(*)为:

光照问题之常见算法比较(附Python代码)

第二步:对校正后的图像进行动态扩展。ACE算法是对单一色道进行的,对于彩色图片需要对每一个色道分别处理

其中存在一种简单的线性扩展:

R(x)=round[127.5+w*Rc(p)],其中,w表示线段[(0,mc),(255,Mc)]的斜率,且有:

Mc=min[Rc(p)],Mc=max[Rc(p)]

第三步:利用下面的公式将R(x)展到[0,1]之间,得到增强后的通道

光照问题之常见算法比较(附Python代码)

②算法优缺点

ACE的增强效果普遍比retinex好。需要注意的是,ACE中当前像素是与整个图像的其他像素做差分比较,计算复杂度非常非常高,这也是限制它应用的最主要原因。

所以,一般算法中,会通过指定采样数来代替与整副图像的像素点信息进行差分计算,减少运算量,提高效率。

③ 算法展示

 #饱和函数  
def calc_saturation(diff,slope,limit):  
    ret = diff * slope  
    if ret > limit:  
        ret = limit  
    elif (ret < (-limit)):  
      ret = -limit  
    return ret  
 
def automatic_color_equalization(nimg, slope=10, limit=1000, samples=500):  
 
    nimg = nimg.transpose(2, 0, 1)  
  
    #Convert input to an ndarray with column-major memory order(仅仅是地址连续,内容和结构不变)  
    nimg = np.ascontiguousarray(nimg, dtype=np.uint8)       width=nimg.shape[2]  
    height=nimg.shape[1]  
  
    cary=[]  
  
    #随机产生索引  
    for i in range(0,samples):  
        _x=random.randint(0,width)%width  
        _y=random.randint(0,height)%height  
 
       dict={"x":_x,"y":_y}  
       cary.append(dict)  
 
 
   mat=np.zeros((3,height,width),float)  
  
   r_max = sys.float_info.min  
   r_min = sys.float_info.max  
 
   g_max = sys.float_info.min  
   g_min = sys.float_info.max  
  
   b_max = sys.float_info.min  
   b_min = sys.float_info.max  
  
  for i in range(height):  
        for j in range(width):  
            r=nimg[0,i,j]  
            g=nimg[1,i,j]  
            b=nimg[2,i,j]               r_rscore_sum = 0.0  
            g_rscore_sum = 0.0  
            b_rscore_sum = 0.0  
            denominator = 0.0  
  
           for _dict in cary:  
                _x=_dict["x"] #width  
                _y=_dict["y"] #height  
  
                #计算欧氏距离  
               dist=np.sqrt(np.square(_x-j)+np.square(_y-i))  
                if (dist < height / 5):  
                    continue;  
 
               _sr=nimg[0,_y,_x]  
                _sg=nimg[1,_y,_x]  
                _sb=nimg[2,_y,_x]  
  
                r_rscore_sum +=calc_saturation(int(r) - int(_sr),slope,limit) / dist  
                g_rscore_sum +=calc_saturation(int(g) - int(_sg),slope,limit) / dist  
                b_rscore_sum +=calc_saturation(int(b) - int(_sb),slope,limit) / dist  
 
                denominator += limit / dist  
 
            r_rscore_sum = r_rscore_sum / denominator  
            g_rscore_sum = g_rscore_sum / denominator  
            b_rscore_sum = b_rscore_sum / denominator  
  
            mat[0,i,j]=r_rscore_sum  
            mat[1,i,j]=g_rscore_sum  
            mat[2,i,j]=b_rscore_sum  
 
            if r_max<r_rscore_sum:  
                r_max=r_rscore_sum  
            if r_min>r_rscore_sum:  
                r_min=r_rscore_sum  
  
            if g_max<g_rscore_sum:  
                g_max=g_rscore_sum  
            if g_min>g_rscore_sum:  
                g_min=g_rscore_sum  
  
            if b_max<b_rscore_sum:  
                b_max=b_rscore_sum  
            if b_min>b_rscore_sum:  
                b_min=b_rscore_sum  
  
   for i in range(height):  
        for j in range(width):  
           nimg[0, i, j] = (mat[0, i, j] - r_min) * 255 / (r_max - r_min)  
           nimg[1, i, j] = (mat[1, i, j] - g_min) * 255 / (g_max - g_min)  
           nimg[2, i, j] = (mat[2, i, j] - b_min) * 255 / (b_max - b_min)  
  
   return nimg.transpose(1, 2, 0).astype(np.uint8)

④ 效果图对比

光照问题之常见算法比较(附Python代码)        光照问题之常见算法比较(附Python代码)

光照问题之常见算法比较(附Python代码)      光照问题之常见算法比较(附Python代码)

总结:查看各种传统算法的效果图,ACE自动色彩均衡算法具有比较好的普遍性和效果,当然,对于一些图片ACE也不能得到很好地效果,所以,这就需要我们不断的去深入研究和学习,接下来会学习神经网络在色彩恒常性方面的应用并进行效果对比。

作为一枚技术小白,写这篇笔记的时候参考了很多博客论文,在这里表示感谢,同时,转载请注明出处......