自动白平衡算法比较

我们的眼睛非常擅长在不同的光照条件下判断什么是白色。然而,数码相机不需要进行任何调整,就可以很容易地用强烈的色彩投射捕捉到不切实际的图像。自动白平衡(AWB)算法试图在用户输入最少的情况下对环境光进行校正,以使生成的图像看起来像我们的眼睛所看到的。但哪种AWB算法是最好的?在本例中,我们解释了自动白平衡背后的过程,并展示了如何比较和选择最佳算法。

自动白色平衡分两步完成:

  • 步骤1:估计场景照明。

  • 第2步:纠正图像的颜色平衡。

最难的步骤,我们将专注于优化的步骤是步骤1 - 环境光的估计。一旦知道环境光,然后校正图像中的颜色(步骤2)是一种简单且固定的过程。

在下文中,我们通过与地面真实场景照明进行比较,来判断三种照明估计算法的质量:

  • 白斑视网膜[1]

  • 灰色世界[2]

  • 程的主成分分析(PCA)方法[3]

读取16位图像的线性RGB值

在将图像压缩并保存到存储卡之前,通常在原始图像数据上应用自动白平衡算法。foosballraw.tiff是一个图像文件,它在纠正黑级并将强度缩放到每像素的16位之后,是这样的原始传感器数据。此图像不含摄像机完成的白色平衡,以及去脱模,去噪,色差补偿,音调调整,伽马校正和在图像保存到存储卡之前完成的处理。

一个= imread (“foosballraw.tiff”);

图片A.包含线性RGB值。大多数发光体估计算法假设成像传感器和像素强度的响应之间的线性关系。但是,由于显示设备的非线性性质,意味着诸如JPEG文件的图像文件包含伽马校正。没有伽玛校正图像看起来非常暗淡在电脑屏幕上。如果您正在使用伽玛校正的图像,请确保将它们线性化rgb2lin功能。这不是这种情况foosballraw.tiff,所以跳过这一步。

插值以恢复缺少颜色信息

数码相机使用叠加在成像传感器上的彩色滤光片阵列来模拟彩色视觉,因此每个像素对红色、绿色或蓝色都很敏感。要恢复每个像素上丢失的颜色信息,必须进行插值。拍摄照片的相机(佳能EOS 30D)使用的拜耳模式为RGGB。

一个= demosaic (,'rggb');

伽玛校正图像显示

如果您尝试显示线性图像,则由于显示设备的非线性特性,它将出现非常暗淡。因此,出于显示目的,伽马校正图像以使用SRGB颜色空间。

a_srgb = lin2rgb(a);

在Gamma校正之前和之后显示原始的,最小处理的图像

警告('离开',“图片:initSize: adjustingMag”)蒙太奇({a,a_srgb})标题(在伽玛校正之前和之后的原始,最小处理的图像')

找到ColorChecker图表

一个ColorChecker图表已经包含在场景中。这张图由24个已知光谱反射率的中性色和色斑组成。我们将使用底部一行的6个中性(消色差)补丁来估计场景中的地面真实光照,并与算法进行比较。然而,当测试算法时,图表必须被排除,以防止算法不公平地利用它-在现实生活中没有ColorChecker图。

指定ColorChecker图表的位置。默认情况下,该示例提供了边界四边形的CoOroinate。如果要交互方式选择多边形坐标,请更改值选择_Polygon.真正的.

select_polygon = false;如果选择_Polygon.%使用roidoly从手动绘制的多边形创建掩码。%单击以添加顶点,然后右键单击并选择“创建遮罩”返回。imshow(a_srgb)标题('在图表周围绘制一个多边形')mask_chart = ropoly;别的%使用边界矩形的提供的坐标。c = [930 1280 1316 953];r = [1877 1890 1382 1370];mask_chart = roidoly(a_srgb,r,c);结尾

稍微向掩模扩展以确保我们不包括属于图表的任何像素。

mask_chart = imdilate(mask_chart,ofon(7));

使用ColorChecker图表测量地面真相照明

出于白平衡的目的,我们只会在图表的底行上使用6个中性贴片。这些中性贴片在可见光谱上同样反射光。他们反映了场景的照明。地面真理光源被计算为中性斑块的平均颜色,不包括底层和过度暴露的像素。

指定每个中立补丁的中心。默认情况下,本例提供了每个补丁的中心坐标的估计。如果您希望交互式地选择ROI中心,请更改的值estisms_roi_centers.真正的.

estisms_roi_centers = false;如果estisms_roi_centers.%放大并单击6个中性面片的中心。XLIM([1350 1930])ylim([900 1350])标题(“点击6个中立区域的中心”)[x,y] = ginput(6);别的%使用ROI中心坐标提供的估计。x = [1424 1514 1598 1676 1757 1835];Y = [1268 1250 1247 1250 1235 1229];结尾

我们通过将正方形的一侧视为分离两个连续斑块的中心的距离的80%,从每个贴片的中心的坐标中得出一个平方区域。

x = round(x);y =圆形(y);r =平均值(差异(x))/ 2 * 0.80;r =楼层(r);

创建一个覆盖中性面片的二元遮罩。

mask = false(size(A,1), size(A,2));对于k = 1:6掩码(y(k)-r:y(k)+ r,x(k)-r:x(k)+ r)= true;结尾

侵蚀掩模以避免包括贴片之外的像素,或者在边框上,易于俯视色差,其颜色可以偏斜地面真理的测量。

mask_eroded = imerode(掩码,strel('盘',5));

识别输入图像中的饱和RGB值。这些值应排除在基础真值的计算之外,因为它们也会使测量结果产生偏差。

掩码截取=(A==intmax(class(A)));(A==intmin(class(A));掩码截取=掩码截取(:,:,1)|掩码截取(:,:,2)|掩码截取(:,:,3);

从对应于中性斑块的掩模中排除这些剪切像素。

Mask_patches = mask_etching & ~mask_clip;

可视化所选像素。高亮的像素应该都在中性的斑块内。如果没有,尝试再次单击补丁的中心,并重复上述步骤。

A_patches=imoverlay(A_sRGB,mask_patches);imshow(A_补丁)标题(“所选的像素以黄色”突出显示)

获取中性补丁的红、绿、红值。

patches_r = a(:,:,1);patches_g = a(:,:,2);patches_b = a(:,:3);patches_r = patches_r(mask_patches);patches_g = patches_g(mask_patches);patches_b = patches_b(mask_patches);

为简单起见,由于大多数光照估计算法都是浮点运算,我们将patch的RGB值转换为[0 1]中的值的两倍和比例,然后计算平均值。

patches_R = im2double (patches_R);patches_G = im2double (patches_G);patches_B = im2double (patches_B);

计算地面真实RGB光源作为横跨中性斑块的平均RGB值。

Illuminant_groundtruth = [均值(patches_r)均值(patches_g)均值(patches_b)];

角度错误

比较估计的发光体与地面真相进行计算,计算角误差在两种颜色之间。为了更好地理解角误差的概念,考虑以下任意光源的可视化和我们刚刚测量的地面真相。每个光源代表RGB空间中的一个向量。

光源=[0.066 0.1262 0.0691];图3([01],[01],[0,1],'linestyle',':','颜色','K')举行Plot3(......[0 Illuminant_groundtruth(1)/常规(Illuminant_groundtruth)],......% 红色的[0 Illuminant_groundtruth(2)/ rang(Illuminant_groundtruth)],......%绿色的[0 Illuminant_groundtruth(3)/常规(Illuminant_groundtruth)],......% 蓝色'标记','.',“MarkerSize”,10)持有Plot3(......[0发光体(1)/常规(发光体)],......% 红色的[0发光体(2)/常规(发光体)],......%绿色的[0光源(3)/标准(光源)],......% 蓝色'标记','.',“MarkerSize”,10)xlabel(“R”) ylabel ('G')Zlabel('B') 标题('RGB Space中的发光体')xlim([01])ylim([01])zlim([01])视图(28,36)图例('消极线','地面真理发光','估计发光体') 网格平等的

估计的光源的确切值与其方向一样多无相关,因为发光体的方向是用于白平衡图像的习惯。理想情况下,估计的光源应与地面真理光亮对齐。估计的发光体和地面事实之间的角误差是由两个向量形成的角度(以度)。角度误差越小,估计越好。我们将根据对角真理的角度误差评估估计的质量。

白色补丁Retinex.

用于光源估计的白色面片Retinex方法[1]假设场景包含一个明亮的面片。该面片反射每个色带可能的最大光,即场景照明的颜色。

这个illumwhite.函数实现了White Patch Retinex方法,同时还提供了从计算中排除部分最亮像素的能力,以避免将曝光像素考虑在内。

首先,使用图像中的所有像素估计场景的光照,减去ColorChecker Chart。这是通过指定要排除的前百分位数为0来实现的。这个“面具”名称 - 值对用于指定用于计算的哪些像素,这在我们的情况下是不属于ColorChecker图表的像素。

illuminant_wp1 = illumwhite(A, 0,)“面具”,~u图);

计算使用白色贴片视网膜估计的光源的角度误差。

err_wp1 = colorangle(Illuminant_wp1,Illiminant_groundtruth);DISP(['白色补丁与百分位数的角度错误= 0:'num2str (err_wp1)))
百分位为0的白色贴片的角度误差:16.5163

要使用此估计光源对图像进行白平衡(AWB的步骤2),请使用chromadapt.函数,默认值在Bradford锥形响应模型中缩放颜色。确保指定我们正在使用线性RGB颜色值。

B_wp1 = (A, illuminant_wp1,'色彩空间',“线性rgb”);

显示伽玛校正的白色平衡图像

B_wp1_sRGB = lin2rgb (B_wp1);图imshow (B_wp1_sRGB)标题(“使用百分位数=0的White Patch Retinex进行白色平衡图像”)

其次,由于选择最大RGB值对过度暴露的像素敏感,因此通过从计算中排除一定比例的最亮像素,可以更加稳健地进行白色跳线算法。这是通过illumwhite函数的百分位参数实现的。选择百分位值为1.(默认为1.)

Illuminant_wp2 = Illumwhite(A,1,“面具”,~u图);

计算使用更强大的白色补丁Retinex估计的光源的角度误差。

err_wp2=色角(发光体_wp2,发光体_地面真相);显示(['白色补丁的角度错误,百分位数= 1:'num2str(err_wp2)])
白色补丁的角度误差百分位数= 1:5.0323

用新的发光显示伽马校正的白色平衡图像

b_wp2 = chromadapt(a,Illiminant_wp2,'色彩空间',“线性rgb”);b_wp2_srgb = lin2rgb(b_wp2);imshow(b_wp2_srgb)标题(“使用百分位数=1的White Patch Retinex进行白色平衡图像”)

灰色世界

灰色世界[2]最肯定是最着名的发光体估计方法。它假设世界的平均颜色是灰色,即消化不良。因此,它计算现场光源作为平均的图像中的RGB值。

这个Illumgray.函数实现了Gray World算法,只增加了一个功能:它提供了从计算中排除最暗和最亮像素的能力,这可能会扭曲光源的估计,使算法更健壮。

首先,估计使用图像的所有像素的场景照明,不包括与ColorChecker图表相对应的那些。这个Illumgray.函数提供一个参数,用于指定要排除的底部和顶部值(按亮度排序)的百分位数。这里,我们将百分位数指定为[0]。

Illuminant_gw1 = Illumgray(A,0,“面具”,~u图);

通过计算两者之间的角度误差,将估计的光源与地面真实值进行比较,类似于我们对White Patch Retinex所做的。

err_gw1 = colorangle(Illuminant_gw1,Illiminant_groundtruth);DISP(['百分比为[0]的灰色世界的角度误差:'num2str(err_gw1)])
灰色世界的角度误差百分比=[0 0]:5.063

使用估计的发光物应用色彩适应白色平衡图像。

b_gw1 = chromadapt(a,Illiminant_gw1,'色彩空间',“线性rgb”);

显示伽玛校正的白色平衡图像

B_gw1_sRGB=lin2rgb(B_gw1);imshow(B_gw1_sRGB)标题('使用灰色世界的白色平衡图像与百分位数= [0 0]')

其次,由于曝光不足和过度的像素会对作为图像中平均RGB值的光源的估计产生负面影响,让我们排除底部和顶部1%的像素。(默认值为百分位数是[1 1]。)

Illuminant_Gw2 = Illumgray(A,1,“面具”,~u图);

计算使用灰色世界估计的第二个光源的角度误差。

err_gw2 = colorangle(Illuminant_gw2,Illiminant_groundtruth);DISP(['灰色世界的角度误差与百分比=[1 1]:'num2str(err_gw2)])
灰色世界的角度误差与百分比=[1 1]:5.1314

用新的发光显示伽马校正的白色平衡图像。

b_gw2 = Chromadapt(A,Illifumant_gw2,'色彩空间',“线性rgb”);B_gw2_sRGB = lin2rgb (B_gw2);imshow (B_gw2_sRGB)标题('使用灰色世界的白色平衡图像百分比= [1 1]')

程的主成分分析(PCA)方法

Cheng的光源估计方法[3]的灵感来自于空间域方法,如Grey Edge[4],它假设图像的梯度是消色差的。结果表明,灰度边缘可以通过变换图像块人工引入强梯度来改善,最强的梯度跟随光源的方向。他们的方法是根据像素沿图像平均颜色方向的投影范数对像素进行排序,并保留底部和顶部的p%。这两组对应于图像中的强梯度。最后,他们表演主成分分析(PCA)在保留像素上,并将第一组件返回为估计的照明。

Cheng的方法由illumpca作用我们使用Cheng的方法,使用沿平均颜色方向的底部和顶部5%的像素来估计场景中的光源。(默认值为3.5。)

Illuminant_ch1 = Illumpca(A,5,“面具”,~u图);

将此估计与地面真相进行比较。

err_ch1 = colorangle(Illuminant_ch1,Illiminant_groundtruth);DISP(['Cheng的角度误差百分比= 5:'num2str(err_ch1)])
Cheng的角度误差百分比= 5:4.7595

显示伽玛校正的白色平衡图像

b_ch1 = chromadapt(a,illiminant_ch1,'色彩空间',“线性rgb”); B_ch1_sRGB=lin2rgb(B_ch1);imshow(B_ch1_sRGB)标题('白色平衡图像使用cheng百分比= 5')

现在让我们使用默认的百分比值,看看它是如何比较的。

Illuminant_ch2 = Illumpca(A,“面具”,~u图);err_ch2 = colorangle(Illiminant_ch2,Illiminant_groundtruth);DISP(['Cheng的角度误差百分比= 3.5:'num2str(err_ch2)])
Cheng的角度误差百分比=3.5:5.0283

在SRGB中显示校正的图像。

b_ch2 = Chromadapt(A,Illiminant_ch2,'色彩空间',“线性rgb”);b_ch2_srgb = lin2rgb(b_ch2);imshow(b_ch2_srgb)标题(“白平衡的图像使用Cheng百分位数= 3.5')

参数扫描

要找到为每种方法使用的最佳参数,我们可以扫描到范围并计算每个方法并计算每个方法。三种算法的参数具有不同的含义,但是这些参数的类似范围使得可以易于以编程方式地搜索每个算法的最佳。

param_range = 0:0.25:5;err = zeros(numel(param_range),3);对于k=1:numel(参数范围)%白色补丁Illuminant_wp = IllumWhite(A,Param_Range(k),“面具”,~u图);err(k,1)= icoryangle(Illiminant_wp,Illiminant_groundtruth);%灰色世界illuminant_gw = illumgray(A, param_range(k)),“面具”,~u图);err(k,2)= icorarangle(Illuminant_gw,Illiminant_groundtruth);%程如果(参数范围(k)~=0)光源(ch=illumpca)(A,参数范围(k),“面具”,~遮罩图);误差(k,3)=色角(发光体,发光体);别的%Cheng的算法未定义百分比=0。err(k,3)=NaN;结尾结尾

创建角度误差的可视化作为热图。

err_normalized = mat2gray(日志(err));block_size_x = 120;block_size_y = 50;Err_image = ones(size(err,1) * block_size_y, size(err,2) * block_size_x);对于i = 0:大小(err,1)-1对于j=0:size(err,2)-1个err_图像(block_size_y*i+1:block_size_y*(i+1),block_size_x*j+1:block_size_x*(j+1))=err_归一化(i+1,j+1);结尾结尾

显示角度误差的热图。浅蓝色表示角度误差较小(良好),而红色表示角度误差较大(不良)。

old_pref = iptgetpref ('imshowaxesvisible');iptsetpref('imshowaxesvisible',“开”)imshow(err_image,'colormap',酷)iptsetpref('imshowaxesvisible',旧(优先)对于i = 0:大小(err,1)-1对于j = 0:大小(err,2)-1 y = block_size_y * i + 1 + block_size_y / 2;x = block_size_x * j + 1 + block_size_x / 3;文字(x,y,sprintf(' % 1.2 f ',err(i + 1,j + 1)))))结尾结尾盒子离开标题(“角度误差”) ylabel (“参数”)yticks(linspace(block_size_y / 2,size(err_image,1) -  block_size_y / 2,numel(param_range)))yticklabels(arrayfun(@(x){num2str(x),param_range))xticks(block_size_x / 2 +[0 block_size_x 2 * block_size_x])xticklabels({'白色补丁','灰色世界',“程”})

为每个算法找到最佳参数。

[〜,idx_best] = min(错误);best_param_wp = param_range(idx_best(1));best_param_gw = param_range(idx_best(2));best_param_ch = param_range(idx_best(3));fprintf(“白色贴片的最佳参数是%1.2f,角度误差%1.2f \ n',......best_param_wp,err(idx_best(1),1));
白色贴片的最佳参数为0.25,角度误差3.33度
fprintf('灰色世界的最佳参数是%1.2f,角度误差%1.2f \ n',......最佳参数gw,err(idx_最佳(2),2));
灰色世界的最佳参数为0.00,角度误差5.06度
fprintf('Cheng的最佳参数为%1.2f,角度误差%1.2f \ n',......best_param_ch,err(idx_best(3),3));
Cheng的最佳参数为0.50,角误差1.72度

计算并显示RGB空间中每种算法的最佳估计光源。

best_illum_wp = illumwhite(a,best_param_wp,“面具”,~u图);best_illum_gw = illumgray(a,best_param_gw,“面具”,~u图);best_illum_ch = illumpca(a,best_param_chch,“面具”,~u图);Plot3([01],[01],[0,1],'linestyle',':','颜色','K')举行Plot3(......[0 Illuminant_groundtruth(1)/常规(Illuminant_groundtruth)],......% 红色的[0 Illuminant_groundtruth(2)/ rang(Illuminant_groundtruth)],......%绿色的[0 Illuminant_groundtruth(3)/常规(Illuminant_groundtruth)],......% 蓝色'标记','.',“MarkerSize”,10)图3(......[0 best_illum_wp(1)/ rang(best_illum_wp)],......% 红色的[0 best_illum_wp(2)/ rang(best_illum_wp)],......%绿色的[0 best_illum_wp(3)/ norm(best_illum_wp)],......% 蓝色'标记','.',“MarkerSize”,10)图3(......[0 best_illum_gw(1)/ rang(best_illum_gw)],......% 红色的[0 best_illum_gw(2)/ norm(best_illum_gw)],......%绿色的[0最佳照明量(3)/标准(最佳照明量)],......% 蓝色'标记','.',“MarkerSize”,10)图3(......[0 best_illum_ch(1)/ rang(best_illum_ch)],......% 红色的[0 best_illum_ch(2)/ rang(best_illum_chch)],......%绿色的[0最佳照明(3)/标准(最佳照明)],......% 蓝色'标记','.',“MarkerSize”,10)xlabel(“R”) ylabel ('G')Zlabel('B') 标题(“RGB空间中最好的光源”)xlim([01])ylim([01])zlim([01])视图(28,36)图例('消极线','真相','白色补丁','灰色世界',“程”) 网格平等的

使用最佳光源并排显示每种方法的白色平衡图像。

b_wp_best = chromadapt(a,best_illum_wp,'色彩空间',“线性rgb”);b_wp_best_srgb = lin2rgb(b_wp_best);b_gw_best = chromadapt(a,best_illum_gw,'色彩空间',“线性rgb”);b_gw_best_srgb = lin2rgb(b_gw_best);b_ch_best = chromadapt(a,best_illum_ch,'色彩空间',“线性rgb”);b_ch_best_srgb = lin2rgb(b_ch_best);m =零(尺寸(a,1),3 *尺寸(a,2),尺寸(a,3),'喜欢', 一种);m(:,1:size(a,2),:) = b_wp_best_srgb;m(:,大小(a,2)+1:2 *大小(a,2),:) = b_gw_best_srgb;m(:,2 *大小(a,2)+1:结束,:) = b_ch_best_srgb;图imshow(m)标题('蒙太奇最好的白色平衡图像:白点,灰色世界,程')

结论

在两个经典的光源估计方法和更近一个的快速枪战显示Cheng的方法,使用顶部和底部的0.75%最黑暗和最亮像素,为该特定图像获胜。然而,这种结果应用一粒盐进行。

首先,使用ColorChecker图表测量地面真理光源,对射击和传感器噪声敏感。可以使用分光光度计更好地估计场景的地面真理光源。

其次,我们估计地面真光源作为中性斑块的平均颜色。使用中位数而不是平均值也是很常见的。这样做可以在很大程度上改变事实。例如,在本研究的图像中,使用相同的像素,中性块的中值颜色和平均颜色之间的距离为0.5度,在某些情况下可能会超过不同方法估计光源的角度误差。

第三,光源估计方法的完整比较应该使用在不同条件下拍摄的各种图像。一种方法可能比其他图像更好地工作,但可能在整个数据集上执行差。

参考

[1] Marc Ebner。白色贴片视网膜,颜色恒定。约翰瓦里&Sons,2007. ISBN 978-0-470-05829-9。

[2]埃布纳,马克。灰色世界假设,色彩恒定。约翰瓦里&Sons,2007. ISBN 978-0-470-05829-9。

[3]程,东凉,Dilip K.Prasad,和迈克尔S. Brown。“颜色恒定的发光体估计:为什么空间域方法工作和颜色分布的作用。”josa a 31.5(2014):1049-1058。

[4] Van de Weijer,Joost,Theo Gevers和Arjan Gijsenij。“边缘的色彩恒定。”IEEE在图像处理上的交易16.9(2007):2207-2214。

另见

|||||||||

相关的话题