《Adaptive Local Tone Mapping Based on Retinex for High Dynamic Range Images 》的文章提出的主要内容时这对高动态图像的显示问题,他结合传统的Retinex技术提出了全局自适应和局部自适应的HDR实现过程,我也实现了整个的代码,但感觉前面的全局适应方案特别对于低照度图像有着非常明显的调节作用,因此,我重点谈下整个。
直接应用原文的英文算了:
Global adaptation takes place like an early stage of the human visual system [4]. The human visual system senses rightness as an approximate logarithmic function according o the Weber-Fechner law [5]. To globally compress the ynamic range of a HDR scene, we use the following function n (4) presented in [5].
用中文解释下上面的公式,也是本文最重要的一个公式。
是全自适应输出的结果,我们这里就是需要得到他,表示输入图像的luminance值(亮度值),表示输入图像亮度值对的最大值,表示输入亮度对数的平均值,如下式所示:
其中N表示像素的总数,而δ一般是个很小的值,其作用主要是为了避免对纯黑色像素进行log计算时数值溢出,这个问题在图像处理时非常常见。
在log域进行计算,这个HDR算法中基本是个定律了。
直接应用原文的话,上述算式的主要作用是:
The input world luminance values and the maximum luminance values are divided by the log-average luminance of he scene. This enables (4) to adapt to each scene. As the log-verage luminance converges to the high value, the function converges from the shape of the logarithm function to the near function. Thus, scenes of the low log-average luminance reboosted more than scenes with high values. As a result, the overall scene luminance values are adequately compressed in ccordance with the log-average luminance of the scene.
特别注意的是 scenes of the low log-average luminance reboosted more than scenes with high values. 这句话,他的意思是说低照度的亮度部分比高照度的部分要能得到更大程度的提升,所以对于低照度图,上述公式能起到很好的增强作用。而算式中使用了全局的对数平均值,这就有了一定的自适应性。
我贴一段稍微修改了的作者共享的matlab代码作为本算法的参考代码:
function outval = ALTM_Retinex(I)
II = im2double(I);
Ir=double(II(:,:,1)); Ig=double(II(:,:,2)); Ib=double(II(:,:,3));
% Global Adaptation
Lw = 0.299 * Ir + 0.587 * Ig + 0.114 * Ib;% input world luminance values
Lwmax = max(max(Lw));% the maximum luminance value
[m, n] = size(Lw);
Lwaver = exp(sum(sum(log(0.001 + Lw))) / (m * n));% log-average luminance
Lg = log(Lw / Lwaver + 1) / log(Lwmax / Lwaver + 1);
gain = Lg ./ Lw;
gain(find(Lw == 0)) = 0;
outval = cat(3, gain .* Ir, gain .* Ig, gain .* Ib);
figure;
imshow(outval)
改写成python代码为:
#simple color balance
def simple_color_balance(input_img,out_img,s1,s2):
h,w = input_img.shape[:2]
sort_img = input_img.copy()
one_dim_array = sort_img.flatten()#转化为一维数组
sort_array = sorted(one_dim_array)#对一维数组按升序排序
per1 = int((h*w)*s1/100)
minvalue = sort_array[per1]
per2 = int((h*w)*s2/100)
maxvalue = sort_array[(h*w)-1-per2]
#实施简单白平衡算法
if(maxvalue<=minvalue):
for i in range(h):
for j in range(w):
out_img[i,j] = maxvalue
else:
scale = 255.0/(maxvalue-minvalue)
for m in range(h):
for n in range(w):
if(input_img[m,n] < minvalue):
out_img[m,n] = 0
elif(input_img[m,n] > maxvalue):
out_img[m, n] = 255
else:
out_img[m, n] = scale*(input_img[m,n]-minvalue)#映射中间段的图像像素
def ALTM(img):
h,w = img.shape[:2]
DouImg = array(img,dtype=float32)
Lw = zeros(img.shape[:2],dtype = float32)
log_Lw = zeros(img.shape[:2],dtype = float32)
Img_out = zeros(img.shape,dtype=uint8)
B = img[:,:,0]
G = img[:,:,1]
R = img[:,:,2]
Dou_B = array(B, dtype=float32)
Dou_G = array(G, dtype=float32)
Dou_R = array(R, dtype=float32)
Lw = 0.299*R+0.587*G+0.114*B
Lwmax = Lw.max()
log_Lw = log(0.001+Lw)
Lw_sum = log_Lw.sum()
Lwaver = exp(Lw_sum/(h*w))
Lg = log(Lw/Lwaver+1)/log(Lwmax/Lwaver+1)
#simple_color_balance(Lg, Lg, 2, 3)
gain = Lg/Lw
Dou_B = gain * Dou_B
Dou_G = gain * Dou_G
Dou_R = gain * Dou_R
##对于某些图像来说可能这个效果会好些
simple_color_balance(Dou_B,Dou_B,2,3)
simple_color_balance(Dou_G, Dou_G, 2, 3)
simple_color_balance(Dou_R, Dou_R, 2, 3)
DouImg = cv2.merge([Dou_B,Dou_G,Dou_R])
Img_out=cv2.convertScaleAbs(DouImg)
return Img_out
运行结果:
参考文献:
SSE图像算法优化系列二十:一种快速简单而又有效的低照度图像恢复算法。
Adaptive Local Tone Mapping Based on Retinex