AWB算法

david 2022-02-03 09:00:20 3891

1 白平衡介绍

白平衡算法主要的作用是将偏暖或者偏冷的色调自动恢复到正常色调,是图像看起来更加色彩饱满正常。

如上图所示,左一色温偏冷,中间色温正常,右一色温偏暖。上图比较直观的展示了色温的概念。偏冷的色温会给人一种还冷的感觉,偏暖的色温会给人一种温暖的感觉。

2 白平衡算法以及matlab实现

1)原始的灰度世界算法

灰度世界算法(Gray World)是以灰度世界假设为基础的,该假设认为对于一幅有着大量色彩变化的图像, R、 G、 B 三个分量的平均值趋于同一个灰度K。一般有两种方法来确定该灰度。

(1)直接给定为固定值, 取其各通道最大值的一半,即取为127或128;

(2)令 K = (Raver+Gaver+Baver)/3,其中Raver,Gaver,Baver分别表示红、 绿、 蓝三个通道的平均值。

算法的第二步是分别计算各通道的增益:

Kr=K/Raver;

Kg=K/Gaver;

Kb=K/Baver;

算法第三步为根据Von Kries 对角模型,对于图像中的每个像素R、G、B,计算其结果值:

Rnew = R * Kr;

Gnew = G * Kg;

Bnew = B * Kb;

对于上式,计算中可能会存在溢出(>255,不会出现小于0的)现象,处理方式有两种。

a、 直接将像素设置为255,这可能会造成图像整体偏白。

b、 计算所有Rnew、Gnew、Bnew的最大值,然后利用该最大值将将计算后数据重新线性映射到[0,255]内。实践证明这种方式将会使图像整体偏暗,建议采用第一种方案。

2)完美反射算法

原理:完美全反射理论perfect Reflector假设图像上最亮点就是白点,并以此白点为参考对图像进行自动白平衡,最亮点定义为R+G+B的最大值,具体编码步骤如下:

(1)计算每个像素的R\G\B之和,并保存到一临时内存块中。

(2)按R+G+B值的大小计算出其前10%或其他Ratio的白色参考点的的阈值T。

(3)遍历图像中的每个点,计算其中R+G+B值大于T的所有点的R\G\B分量的累积和的平均值。

(4)对每个点将像素量化到[0,255]之间。

3)动态阈值法

(1). 把图像w*h从RGB空间转换到YCrCb空间。

(2). 选择参考白色点:

a. 把图像分成宽高比为4:3个块(块数可选)。

b. 对每个块,分别计算Cr,Cb的平均值Mr,Mb。

c. 对每个块,根据Mr,Mb,用下面公式分别计算Cr,Cb的方差Dr,Db。

d. 判定每个块的近白区域(near-white region)。

判别表达式为:

设一个“参考白色点”的亮度矩阵RL,大小为w*h。

若符合判别式,则作为“参考白色点”,并把该点(i,j)的亮度(Y分量)值赋给RL(i,j);

若不符合,则该点的RL(i,j)值为0。

(3). 选取参考“参考白色点”中最大的10%的亮度(Y分量)值,并选取其中的最小值Lu_min.

(4). 调整RL,若RL(i,j)

(5). 分别把R,G,B与RL相乘,得到R2,G2,B2。 分别计算R2,G2,B2的平均值,Rav,Gav,Bav;

(6). 得到调整增益:

Ymax=double(max(max(Y)))/5;

Rgain=Ymax/Rav;

Ggain=Ymax/Gav;

Bgain=Ymax/Bav;

(7). 调整原图像:

Ro= R*Rgain;

Go= G*Ggain;

Bo= B*Bgain;

FPGA的实现采用灰度世界算法。

Matlab代码:

<pre class="code-snippet__js" data-lang="makefile">```
<span class="code-snippet_outer">close all</span>

clear all

<span class="code-snippet_outer">clc</span>

I=imread('test1.jpg');

<span class="code-snippet_outer">[H,W,L]=size(I);%得到图像长宽高</span>

Rsum = 0;

<span class="code-snippet_outer">Gsum = 0;</span>

Bsum = 0;

<span class="code-snippet_outer">Rsum = double(Rsum);</span>

Gsum = double(Gsum);

<span class="code-snippet_outer">Bsum = double(Bsum);</span>

for i = 1 : H

<span class="code-snippet_outer">    for j = 1 :W</span>

Rsum = Rsum + double(I(i,j,1));

<span class="code-snippet_outer">        Gsum = Gsum + double(I(i,j,2));</span>

Bsum = Bsum + double(I(i,j,3));

<span class="code-snippet_outer">    end</span>

end

<span class="code-snippet_outer">Raver = Rsum / (H*W);</span>

Gaver = Gsum / (H*W);

<span class="code-snippet_outer">Baver = Bsum / (H*W);</span>

%K=128;%第一种K取值方法

<span class="code-snippet_outer">K = (Raver+Gaver+Baver)/3;%第二种方法</span>

Rgain = K / Raver;

<span class="code-snippet_outer">Ggain = K / Gaver;</span>

Bgain = K / Baver;

<span class="code-snippet_outer"><span class="code-snippet__section">Iwb(:,:,1) = I(:,:,1) * Rgain;</span></span>

Iwb(:,:,2) = I(:,:,2) * Ggain;

<span class="code-snippet_outer"><span class="code-snippet__section">Iwb(:,:,3) = I(:,:,3) * Bgain;</span></span>

imwrite(Iwb,'Result1.jpg');

<span class="code-snippet_outer">figure(1),</span>

subplot(121),imshow(I),title('原始图像');

<span class="code-snippet_outer">subplot(122),imshow(Iwb),title('自动白平衡图像');</span>

效果展示:

![](https://ebaina.oss-cn-hangzhou.aliyuncs.com/wechat-official-crawl/2022-02/164385001143168.jpg)

**3 FPGA实现自动白平衡灰度世界法**

灰度世界法Verilog代码:

- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
- 
```
/**********************************
``````
copyright@FPGA OPEN SOURCE STUDIO
``````
微信公众号:FPGA开源工作室
``````
Algorithm:Auto White balance
``````
      Gray World
``````
  800X600X255=480000
``````
***********************************/
``````
`define XLEN   32
``````
`define N(n)                       [(n)-1:0]
``````
module White_balance#(
``````
     parameter DW                             = 24
``````
      )(
``````
    input                             pixelclk,
``````
    input                             reset_n,
``````
    input [DW-1:0]                                din,       //rgb in
``````
    input                             i_hsync,
``````
    input                             i_vsync,
``````
    input                             i_de,
``````
    
``````


``````

`````` output [DW-1:0] dout, //gray out `````` output o_hsync, `````` output o_vsync, `````` output o_de `````` ); `````` `````` localparam STAGE_LIST = 32'h0101_0101;//32'b00000000_00000000_00000000_00000000; `````` localparam divisor = 32'h0007_5300;//800*600 `````` localparam divisorK = 32'h0000_0003;//800*600 `````` `````` wire [7:0] R,G,B; `````` reg [27:0] sumr,sumg,sumb; `````` reg [27:0] sumr_r,sumg_r,sumb_r; `````` wire [9:0] Kave; `````` wire [7:0] K; ``````

``````

`````` wire Rack; `````` wire `N(`XLEN) Rquo,Rrem; ``````

``````

`````` wire Gack; `````` wire `N(`XLEN) Gquo,Grem; ``````

``````

`````` wire Back; `````` wire `N(`XLEN) Bquo,Brem; ``````

``````

`````` wire Kack; `````` wire `N(`XLEN) Kquo,Krem; ``````

``````

`````` wire GRack; `````` wire `N(`XLEN) GRquo,GRrem; ``````

``````

`````` wire GGack; `````` wire `N(`XLEN) GGquo,GGrem; ``````

``````

`````` wire GBack; `````` wire `N(`XLEN) GBquo,GBrem; ``````

``````

`````` reg [39:0] R_r,G_r,B_r; `````` wire [7:0] RO,GO,BO; ``````

``````

`````` reg hsync_r1; `````` reg vsync_r1; `````` reg de_r1; ``````

``````

`````` reg i_vsync_r; `````` reg vsync_neg_r; ``````

``````

`````` wire vsync_neg=(i_vsync_r&(~i_vsync)); ``````

``````

`````` assign Kave=(Rquo+Gquo+Bquo); `````` assign K=Kquo[7:0]; ``````

``````

`````` assign R=din[23:16]; `````` assign G=din[15:8]; `````` assign B=din[7:0]; ``````

``````

`````` assign o_hsync = hsync_r1; `````` assign o_vsync = vsync_r1; `````` assign o_de = de_r1; ``````

``````

`````` assign RO=(R_r[18:10]>255)?255:R_r[17:10]; `````` assign GO=(G_r[18:10]>255)?255:G_r[17:10]; `````` assign BO=(B_r[18:10]>255)?255:B_r[17:10]; `````` assign dout={RO,GO,BO}; ``````

``````

``````

``````

`````` //synchronization `````` always @(posedge pixelclk) begin `````` hsync_r1 `````` vsync_r1 `````` de_r1 `````` end ``````

``````

``````

``````

`````` always @(posedge pixelclk or negedge reset_n)begin `````` if(!reset_n)begin `````` sumr=28'd0; `````` sumg=28'd0; `````` sumb=28'd0; `````` sumr_r=28'd0; `````` sumg_r=28'd0; `````` sumb_r=28'd0; `````` i_vsync_r=1'b0; `````` vsync_neg_r=1'b0; `````` R_r=40'b0; `````` G_r=40'b0; `````` B_r=40'b0; `````` end `````` else begin `````` i_vsync_r=i_vsync; `````` vsync_neg_r=vsync_neg; `````` `````` R_r=r*grquo; `````` G_r=g*ggquo; `````` B_r=b*gbquo; `````` `````` if(vsync_neg==1'b1) begin `````` sumr_r=sumr; `````` sumg_r=sumg; `````` sumb_r=sumb; `````` end `````` `````` if(i_vsync==1'b1) begin `````` if(i_de==1'b1) begin `````` sumr=sumr+r; `````` sumg=sumg+g; `````` sumb=sumb+b; `````` end `````` else begin `````` sumr=sumr; `````` sumg=sumg; `````` sumb=sumb; `````` end `````` end `````` else begin `````` sumr=28'd0; `````` sumg=28'd0; `````` sumb=28'd0; `````` end `````` end `````` end ``````

``````

``````

``````

`````` //Rave `````` divfunc `````` #( `````` .XLEN ( `XLEN ), `````` .STAGE_LIST ( STAGE_LIST ) ``````

``````

`````` ) i_divR ( `````` .clk ( pixelclk ), `````` .rst ( ~reset_n ), `````` `````` .a ( {4'b0,sumr_r} ), `````` .b ( divisor ), `````` .vld ( vsync_neg_r ), `````` `````` .quo ( Rquo ), `````` .rem ( Rrem ), `````` .ack ( Rack ) ``````

``````

`````` ); ``````

``````

``````

``````

`````` //Gave `````` divfunc `````` #( `````` .XLEN ( `XLEN ), `````` .STAGE_LIST ( STAGE_LIST ) ``````

``````

`````` ) i_divG ( `````` .clk ( pixelclk ), `````` .rst ( ~reset_n ), `````` `````` .a ( {4'b0,sumg_r} ), `````` .b ( divisor ), `````` .vld ( vsync_neg_r ), `````` `````` .quo ( Gquo ), `````` .rem ( Grem ), `````` .ack ( Gack ) ``````

``````

`````` ); ``````

``````

``````

``````

`````` //Bave `````` divfunc `````` #( `````` .XLEN ( `XLEN ), `````` .STAGE_LIST ( STAGE_LIST ) ``````

``````

`````` ) i_divB ( `````` .clk ( pixelclk ), `````` .rst ( ~reset_n ), `````` `````` .a ( {4'b0,sumb_r} ), `````` .b ( divisor ), `````` .vld ( vsync_neg_r ), `````` `````` .quo ( Bquo ), `````` .rem ( Brem ), `````` .ack ( Back ) ``````

``````

`````` ); ``````

``````

`````` //K `````` divfunc `````` #( `````` .XLEN ( `XLEN ), `````` .STAGE_LIST ( STAGE_LIST ) ``````

``````

`````` ) i_divK ( `````` .clk ( pixelclk ), `````` .rst ( ~reset_n ), `````` `````` .a ( {22'b0,Kave} ), `````` .b ( divisorK ), `````` .vld ( Back ), `````` `````` .quo ( Kquo ), `````` .rem ( Krem ), `````` .ack ( Kack ) ``````

``````

`````` ); ``````

``````

`````` //RGain `````` divfunc `````` #( `````` .XLEN ( `XLEN ), `````` .STAGE_LIST ( STAGE_LIST ) ``````

``````

`````` ) i_divGR ( `````` .clk ( pixelclk ), `````` .rst ( ~reset_n ), `````` `````` .a ( {14'b0,K,10'b0} ), `````` .b ( Rquo ), `````` .vld ( Kack ), `````` `````` .quo ( GRquo ), `````` .rem ( GRrem ), `````` .ack ( GRack ) ``````

``````

`````` ); ``````

``````

`````` //GGain `````` divfunc `````` #( `````` .XLEN ( `XLEN ), `````` .STAGE_LIST ( STAGE_LIST ) ``````

``````

`````` ) i_divGG ( `````` .clk ( pixelclk ), `````` .rst ( ~reset_n ), `````` `````` .a ( {14'b0,K,10'b0} ), `````` .b ( Gquo ), `````` .vld ( Kack ), `````` `````` .quo ( GGquo ), `````` .rem ( GGrem ), `````` .ack ( GGack ) ``````

``````

`````` ); ``````

``````

`````` //BGAIN `````` divfunc `````` #( `````` .XLEN ( `XLEN ), `````` .STAGE_LIST ( STAGE_LIST ) ``````

``````

`````` ) i_divGB ( `````` .clk ( pixelclk ), `````` .rst ( ~reset_n ), `````` `````` .a ( {14'b0,K,10'b0} ), `````` .b ( Bquo ), `````` .vld ( Kack ), `````` `````` .quo ( GBquo ), `````` .rem ( GBrem ), `````` .ack ( GBack ) ``````

``````

`````` ); ``````

`````` `````` endmodule ``` ``` **1)仿真效果** ![](https://ebaina.oss-cn-hangzhou.aliyuncs.com/wechat-official-crawl/2022-02/164385001156435.jpg) 原始图像 ![](https://ebaina.oss-cn-hangzhou.aliyuncs.com/wechat-official-crawl/2022-02/164385001374400.jpg) 经过灰度世界法的白平衡仿真效果 **2)下板验证模型以及实现效果** ![](https://ebaina.oss-cn-hangzhou.aliyuncs.com/wechat-official-crawl/2022-02/164385001446175.jpg) 下板验证图像由笔记本电脑通过HDMI输入到FPGA芯片,经过FPGA算法处理后在通过HDMI将图像送到显示屏展示处理效果。 ![](https://ebaina.oss-cn-hangzhou.aliyuncs.com/wechat-official-crawl/2022-02/164385001538931.jpg) 笔记本电脑显示图片 ![](https://ebaina.oss-cn-hangzhou.aliyuncs.com/wechat-official-crawl/2022-02/164385001860975.jpg) 经过FPGA处理后的显示效果 - - - - - - 视频效果 转载:全栈芯片工程师
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
david
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
david
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区