本文是对论文“Auto White Balance Using the Coincidence of Chromaticity Histograms”中自动白平衡算法的matlab实现。论文思想也很简单,就是颜色直方图反映了色温信息,良好照明(合适色温)下的图像各颜色通道直方图通常具有较大的重叠面积,否则则图像中的颜色直方图的重叠面积通常较小(示例见fig1),于是可以根据颜色直方图重叠面积最大化原则来设计自动白平衡算法。其中,转换到rgb色域是为了消除亮度变化的影响。计算直方图重叠面积时则只计算50~120之间的重叠面积以增强鲁棒性和减少计算量。(先前的程序中有一处错误,现已订正)
废话不多说,还是直接上代码吧。
function cimg=AWBbasedHistOverlap3(img,wid,minGain,maxGain,minGainG,maxGainG,interval)
% 基于rgb空间(对R/G/B归一化)直方图重叠面积最大化的自动白平衡算法
% img为8bit图像
% wid为统计直方图时的区间宽度
% minGain/maxGain分别是R、B通道的最小与最大增益
% minGainG/maxGainG分别是G通道的最小与最大增益
% G通道增益取值一般在0.8~1.2
% minGainG=maxGainG=1意味着不改变G分量,论文中也推荐这样操作
dimg=double(img);
R=dimg(:,:,1);
G=dimg(:,:,2);
B=dimg(:,:,3);
gainNum=floor((maxGain-minGain)/interval)+1;
gainNumG=floor((maxGainG-minGainG)/interval)+1;
overlapNum=zeros(gainNum,gainNum,gainNumG);
countsBox=zeros(floor(256/wid),floor(256/wid),floor(256/wid)); %RGB三维直方图
for i=1:size(img,1)
for j=1:size(img,2)
idxR=floor(R(i,j)/wid)+1;
idxG=floor(G(i,j)/wid)+1;
idxB=floor(B(i,j)/wid)+1;
countsBox(idxR,idxG,idxB)=countsBox(idxR,idxG,idxB)+1;
end
end
for i=1:gainNum
for j=1:gainNum
for k=1:gainNumG
gainR=minGain+interval*(i-1);
gainG=minGainG+interval*(k-1);
gainB=minGain+interval*(j-1);
rc=zeros(1,floor(256/wid)); %r分量在各区间的像素点个数,下同
gc=zeros(1,floor(256/wid));
bc=zeros(1,floor(256/wid));
for m=0:floor(256/wid)-1
for n=0:floor(256/wid)-1
for p=0:floor(256/wid)-1
mnpNum=countsBox(m+1,n+1,p+1);
midR=min(255,wid*(2*m+1)/2);
midG=min(255,wid*(2*n+1)/2);
midB=min(255,wid*(2*p+1)/2);
gainedSum=gainR*midR+gainG*midG+gainB*midB;
r=round(255*gainR*midR/gainedSum);
r=min(255,max(r,0));
g=round(255*gainG*midG/gainedSum);
g=min(255,max(g,0));
b=255-r-g;
idxR=floor(r/wid)+1;
idxG=floor(g/wid)+1;
idxB=floor(b/wid)+1;
rc(idxR)=rc(idxR)+mnpNum;
gc(idxG)=gc(idxG)+mnpNum;
bc(idxB)=bc(idxB)+mnpNum;
end
end
end
minHist=min([rc;gc;bc]);
overlapNum(i,j,k)=sum(minHist(floor(50/wid)+1:floor(120/wid)+1)); %只选取r,g,b取值在50~120的部分
end
end
end
%对3D/2D重叠数图像滤波,可选操作
f_overlapNum=overlapNum;
r=0;
for i=1:gainNum
for j=1:gainNum
for k=1:gainNumG
ilow=max(1,i-r);
ihigh=min(gainNum,i+r);
jlow=max(1,j-r);
jhigh=min(gainNum,j+r);
klow=max(1,k-r);
khigh=min(gainNumG,k+r);
block=overlapNum(ilow:ihigh,jlow:jhigh,klow:khigh);
f_overlapNum(i,j,k)=sum(block(:))/((ihigh-ilow+1)*(jhigh-jlow+1)*(khigh-klow+1));
end
end
end
maxOverlapIdx=find(f_overlapNum(:)==max(f_overlapNum(:)))-1; %可设置一定阈值选取多个点取平均
gainR=minGain+interval*mod(maxOverlapIdx(1),gainNum);
gainB=minGain+interval*floor(mod(maxOverlapIdx(1),gainNum^2)/gainNum);
gainG=minGainG+interval*floor(maxOverlapIdx(1)/gainNum^2);
%执行映射
cR=gainR*R;
cG=gainG*G;
cB=gainB*B;
cimg=cat(3,cR,cG,cB);
cimg=uint8(cimg);
function [rhist,ghist,bhist]=rgbhist(img)
% 求rgb色域空间各分量的直方图
img=double(img);
sumRGB=sum(img,3);
R=img(:,:,1);
G=img(:,:,2);
B=img(:,:,3);
r=R./(sumRGB+0.001);
g=G./(sumRGB+0.001);
b=1-r-g;
rr=round(255*r);
gg=round(255*g);
bb=255-rr-gg;
rhist=histcounts(rr(:),0:256);
ghist=histcounts(gg(:),0:256);
bhist=histcounts(bb(:),0:256);
脚本文件:
clear all;close all;clc;
img=imread('3.jpg');
figure,imshow(img);
[rhist,ghist,bhist]=rgbhist(img);
figure,plot(0:255,rhist,'r',0:255,ghist,'g',0:255,bhist,'b');
saveas(gcf,'orgHist.png');
wbimg=AWBbasedHistOverlap(img,8,0.76,1.36,1,1,0.02);
figure,imshow(wbimg);
imwrite(wbimg,'res.jpg');
[rhist,ghist,bhist]=rgbhist(wbimg);
figure,plot(0:255,rhist,'r',0:255,ghist,'g',0:255,bhist,'b');
saveas(gcf,'wbHist.png');
处理结果示例:
可以看出,除了最后一张蓝天图像外,该白平衡算法处理得都还不错。最后一张图处理效果不太好,这是由于蓝天占据了过多的比例,白平衡时为了重叠面积最大化给蓝色通道分配了过低的权重,而事实上蓝天图像中本来就应该保留较多的蓝色分量。
另外,本文中所示结果与论文中所给出结果有一定出入,这有几方面原因引起:一是由于本文中进行测试时图像都是从论文PDF中截取的,与原始图像会存在一定出入;二是本文实现中直方图统计采取了更宽的区间以加速运算;三是论文中提到有高斯去噪操作,但没有给出具体的参数,笔者测试中调试了几组高斯滤波参数却发现都无法达到文中效果(主要是最后的蓝天图像);四是作者的算法实现或与笔者实现略有不同。
该算法的主要优点是计算量不随图像尺寸与表观而改变,且对图像中是否存在白色块或灰色块没有要求,整体处理效果不错。缺点是类似蓝天这样的本身某一颜色分量应该比较突出的情况可能处理结果不会太好。