FPGA图像处理之自动白平衡(附源码)
概要
白平衡(White Balance)是图像处理中的一种基本技术,用于调整图像的颜色表现,使其在不同光照条件下能够呈现出真实的色彩。白平衡的核心目标是校正图像中的色偏,使图像中的白色物体在各种光源下都能显现为真实的白色,同时保证其他颜色的准确性。
在FPGA(现场可编程门阵列)上实现白平衡处理是一种高效的硬件加速方法,特别适用于需要实时处理的场景,例如数字相机、监控摄像头和工业视觉系统。FPGA通过并行处理的能力,可以以极高的速度完成白平衡算法的计算。
FPGA图像处理白平衡实现方法详解
这个白平衡模块是基于灰度世界法实现自动白平衡(AWB),通过AXI-Stream接口接收像素数据,实时调整RGB通道增益,输出校正后的图像。
1.输入流水线与数据同步
流水线延迟:输入数据通过多级寄存器(I_tdata_d0、I_tdata_d1、I_tdata_d2)延迟3个周期,确保后续处理时序对齐。
信号同步:I_tvalid和I_tuser等控制信号同步延迟,避免时序冲突。
2. RGB通道累加
累加器复位:帧开始信号I_tuser有效时,复位累加器sum_r、sum_g、sum_b,开始新一帧的累加。
实时累加:在I_tvalid_r0有效时,将每个像素的RGB值分别累加,统计整帧的总和。
3. 增益计算(存在问题)
除法器调用:通过IP核div_gen_awb计算G/R和G/B的比值,将sum_g左移16位作为被除数,提高计算精度。
增益截断:检查除法结果高位,防止溢出,保留20位定点数(Q16.4格式)表示增益。
问题点:除法器在I_tvalid_r1(即每像素有效)时触发,导致基于部分累加值的错误增益,正确做法应在帧结束时触发。
4. 增益应用与数据校正
乘法操作:延迟后的像素数据与增益相乘,R和B通道分别调整,G通道保持原值。
溢出处理:若乘法结果超出8位范围,截断为0xFF,保留最大值。
5. 输出同步
信号对齐:通过多级寄存器延迟tlast和tuser信号,确保输出信号与校正数据同步。
AXI-Stream接口:输出数据拼接为24位像素,O_tvalid和O_tready控制流传输。
源码
module awb #(
parameter IMG_HEIGHT = 1080, // 图像高度参数,默认值为1080
parameter IMG_WIDTH = 1920 // 图像宽度参数,默认值为1920
)
(
input I_clk , // 输入时钟信号
input I_rst_n, // 输入复位信号,低电平有效
input I_tlast , // 行结束信号
input I_tuser , // 帧开始信号
input [23:0] I_tdata , // 输入数据,总共包含4个像素的RGB值,每个像素24位,4*24=96位
input I_tvalid , // 输入数据有效信号
output I_tready , // 输入数据准备好信号
output O_tlast , // 输出行结束信号
output O_tuser , // 输出帧开始信号
output [23:0] O_tdata , // 输出数据
output O_tvalid , // 输出数据有效信号
input O_tready // 输出数据准备好信号
);
reg I_tvalid_r0,I_tvalid_r1,I_tvalid_r2; // 输入有效信号的寄存
reg [23:0] I_tdata_d0,I_tdata_d1,I_tdata_d2; // 输入数据的寄存
// 累加RGB通道的数值,用于计算平均值
reg [31:0] sum_r;
reg [31:0] sum_g;
reg [31:0] sum_b;
wire [23:0] data_d0 ; // 延时后的数据
wire valid_d0; // 延时后的有效信号
reg [23:0] data_d1 ; // 再次延时后的数据
reg valid_d1; // 再次延时后的有效信号
wire [7:0] rgb888_r_d0;
wire [7:0] rgb888_g_d0;
wire [7:0] rgb888_b_d0;
// 对输入数据和有效信号进行寄存,形成流水线
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
I_tdata_d0 <= 0;
I_tdata_d1 <= 0;
I_tdata_d2 <= 0;
{I_tvalid_r0,I_tvalid_r1} <= 0;
end else begin
I_tdata_d0 <= I_tdata ;
I_tdata_d1 <= I_tdata_d0;
I_tdata_d2 <= I_tdata_d1;
I_tvalid_r0 <= I_tvalid;
I_tvalid_r1 <= I_tvalid_r0;
end
end
assign rgb888_r_d0 = I_tdata_d0[16+:8];
assign rgb888_g_d0 = I_tdata_d0[8+:8];
assign rgb888_b_d0 = I_tdata_d0[0+:8];
// 对每个通道的值进行累加,用于计算平均值
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n || I_tuser) begin
// 复位或行开始信号有效时,清零累加器
sum_r <= 0;
sum_g <= 0;
sum_b <= 0;
end else if (I_tvalid_r0) begin
// 当输入有效时,累加RGB分量的值
sum_r <= sum_r + rgb888_r_d0;
sum_g <= sum_g + rgb888_g_d0;
sum_b <= sum_b + rgb888_b_d0;
end
end
// 定义除法器的输出信号
wire [79:0] dout_R ;
wire [79:0] dout_B ;
wire done ;
// 为了保证合理的延迟,这里使用了除法器IP核
// 调用除法器IP核,计算G/R的比值
div_gen_awb div_gen_G_R_r1 (
.aclk(I_clk), // input wire aclk
.s_axis_divisor_tvalid(I_tvalid_r1), // 输入除数有效信号
.s_axis_divisor_tdata(sum_r), // 输入除数数据,R通道的累加值
.s_axis_dividend_tvalid(I_tvalid_r1), // 输入被除数有效信号
.s_axis_dividend_tdata({s