ACE算法源自retinex算法,可以調整圖像的對比度,實現人眼色彩恆常性和亮度恆常性,通過差分來計算目標點與周圍像素點的相對明暗關系來校正最終像素值,有很好的增強效果。但是計算復雜度非常高,本文提出一種有效的快速實現方法。
為敘述方便,這里假設后面的圖像都是歸一化到[0,1]之間的浮點數圖像。
ACE算法的計算公式為:
Y = ∑(g(I(x0)-I(x))w(x0,x)) / ∑(w(x0,x)) x屬於I (1)
其中,w是權重參數,離中心點像素越遠w值越小,可以直接取值歐氏距離的倒數。g()是相對對比度調節參數,非線性的,簡單取如下計算方法:
g(x) = max(min(ax, 1.0), -1.0) (2)
這里a是控制參數,值越大,細節增強越明顯。計算完后,還要對Y進行一次歸一化即可得到最終的增強圖像。
ACE的增強效果普遍與retinex好。需要注意的是,ACE中當前像素是與整個圖像的其他像素做差分比較,計算復雜度非常非常高,這也是限制它應用的最主要原因,本文主要基於兩個假設:(1)對一副圖像ACE增強后得到輸出Y,如果對Y再進行一次ACE增強,輸出仍然是Y本身;(2)對一副圖像的ACE增強結果進行尺寸縮放得到Y,對Y進行ACE增強,輸出仍然是Y本身。這兩個假設我沒法證實,呵呵,就算臆想的吧。
如果上面假設成立,我們就可以對圖像進行縮放得到I1,對I1的ACE增強結果進行尺度放大(與I尺寸一樣)得到Y1,那么Y和Y1是非常接近的,我們只需要在Y1基礎上進一步處理即可。這里就又引申了兩個細節問題:1)如何快速的求I1的ACE增強結果? 其實很簡單,對它再次縮放得到I2,求I2的增強結果,依次類推,就是金字塔結構思想。2)如何在Y1基礎上進一步處理得到Y? 因為是在整個圖像域進行差分比較運算,與近處鄰域像素的比較構成了Y的細節信息,與遠處像素的比較構成了Y的全局背景信息,那么我們合理假設,Y和Y1的全局背景信息相同,只更新細節信息即可,也就是,我們需要在Y1基礎上加上I中鄰近像素的差分結果,並減去Y1中鄰近像素的差分結果就是最終的輸出Y。
上面說的有點繞,慢慢看吧。
下面是python代碼
import cv2 import numpy as np import math def stretchImage(data, s=0.005, bins = 2000): #線性拉伸,去掉最大最小0.5%的像素值,然后線性拉伸至[0,1] ht = np.histogram(data, bins); d = np.cumsum(ht[0])/float(data.size) lmin = 0; lmax=bins-1 while lmin<bins: if d[lmin]>=s: break lmin+=1 while lmax>=0: if d[lmax]<=1-s: break lmax-=1 return np.clip((data-ht[1][lmin])/(ht[1][lmax]-ht[1][lmin]), 0,1) g_para = {} def getPara(radius = 5): #根據半徑計算權重參數矩陣 global g_para m = g_para.get(radius, None) if m is not None: return m size = radius*2+1 m = np.zeros((size, size)) for h in range(-radius, radius+1): for w in range(-radius, radius+1): if h==0 and w==0: continue m[radius+h, radius+w] = 1.0/math.sqrt(h**2+w**2) m /= m.sum() g_para[radius] = m return m def zmIce(I, ratio=4, radius=300): #常規的ACE實現 para = getPara(radius) height,width = I.shape zh,zw = [0]*radius + range(height) + [height-1]*radius, [0]*radius + range(width) + [width -1]*radius Z = I[np.ix_(zh, zw)] res = np.zeros(I.shape) for h in range(radius*2+1): for w in range(radius*2+1): if para[h][w] == 0: continue res += (para[h][w] * np.clip((I-Z[h:h+height, w:w+width])*ratio, -1, 1)) return res def zmIceFast(I, ratio, radius): #單通道ACE快速增強實現 height, width = I.shape[:2] if min(height, width) <=2: return np.zeros(I.shape)+0.5 Rs = cv2.resize(I, ((width+1)/2, (height+1)/2)) Rf = zmIceFast(Rs, ratio, radius) #遞歸調用 Rf = cv2.resize(Rf, (width, height)) Rs = cv2.resize(Rs, (width, height)) return Rf+zmIce(I,ratio, radius)-zmIce(Rs,ratio,radius) def zmIceColor(I, ratio=4, radius=3): #rgb三通道分別增強,ratio是對比度增強因子,radius是卷積模板半徑 res = np.zeros(I.shape) for k in range(3): res[:,:,k] = stretchImage(zmIceFast(I[:,:,k], ratio, radius)) return res if __name__ == '__main__': m = zmIceColor(cv2.imread('p4.bmp')/255.0)*255 cv2.imwrite('zmIce.jpg', m)
下面是實驗結果,上邊是原圖,下邊是增強結果。