亮度/对比度/饱和度调整的硬件实现与系数定点化
亮度调整对所有像素值加减偏移量;对比度调整以中灰(128)为中心缩放像素值差异;饱和度调整缩放色度分量相对于中性灰的距离。使用Q0.8格式(128=1.0x)表示系数。注意:对比度和饱和度调整都可能产生超出[0,255]范围的值,必须做饱和截断!
// 第03课:色彩校正 - 亮度/对比度/饱和度
module color_correction #(
parameter DATA_W = 8, COEF_W = 8
)(
input wire clk, rst_n,
input wire valid_in,
input wire [DATA_W-1:0] y_in, cb_in, cr_in,
input wire [COEF_W-1:0] brightness, contrast, saturation,
output reg valid_out,
output reg [DATA_W-1:0] y_out, cb_out, cr_out
);
reg signed [DATA_W:0] y_adj;
wire signed [DATA_W:0] boff = $signed({1'b0,brightness}) - 128;
always @(*) begin y_adj=$signed({1'b0,y_in})+boff; if(y_adj<0) y_adj=0; else if(y_adj>255) y_adj=255; end
reg signed [17:0] yc, cbs, crs;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin yc<=0; cbs<=0; crs<=0; end
else if (valid_in) begin
yc<=(y_adj-128)*$signed({1'b0,contrast});
cbs<=($signed({1'b0,cb_in})-128)*$signed({1'b0,saturation});
crs<=($signed({1'b0,cr_in})-128)*$signed({1'b0,saturation});
end
end
function automatic [DATA_W-1:0] clip8; input signed [17:0] v; logic signed [17:0] s;
begin s=(v>>>7)+128; if(s<0) clip8=0; else if(s>255) clip8={DATA_W{1'b1}}; else clip8=s[DATA_W-1:0]; end
endfunction
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin valid_out<=0; y_out<=0; cb_out<=0; cr_out<=0; end
else begin valid_out<=valid_in; y_out<=clip8(yc); cb_out<=clip8(cbs); cr_out<=clip8(crs); end
end
endmodule
✅Verilator验证通过 — 本课Verilog代码已通过 Verilator --lint-only 检查。
本节深入探讨色彩校正在FPGA实现中的关键设计决策和优化策略。
视频处理模块的时序设计需要考虑以下因素:
FPGA资源有限,视频处理模块需要精心优化:
| 策略 | 适用场景 | 节省资源 |
|---|---|---|
| 时分复用乘法器 | 像素时钟远低于系统时钟 | DSP 4~8x |
| 移位替代乘法 | 系数为2的幂次 | DSP 1个/次 |
| CSD编码 | 固定系数乘法 | DSP全部 |
| 查表替代计算 | 非线性函数(sin,exp) | 逻辑大量 |
| 对称性利用 | FIR系数对称 | 乘法器减半 |
视频处理中定点运算的精度直接影响图像质量。分析方法:
8bit视频处理的经验法则:中间结果至少保留12bit,最终输出截断到8bit。
好的视频处理模块应该是参数化的:
视频模块的完整验证包括:
标准视频模块接口信号:
input wire clk, rst_n, // 时钟复位 input wire valid_in, // 输入有效 input wire [DATA_W-1:0] data_in, // 输入数据 input wire sof_in, eol_in, // 帧起始/行结束 output reg valid_out, // 输出有效 output reg [DATA_W-1:0] data_out, // 输出数据 output reg sof_out, eol_out // 帧起始/行结束
这种接口设计使模块可以自由级联,形成处理流水线。
视频处理是持续运行的,功耗优化很重要:
专业视频处理使用3D查找表(3D LUT)进行色彩校正。3D LUT将(R,G,B)映射到(R',G',B'),可以表示任意非线性色彩变换。
典型3D LUT大小:17x17x17 = 4913个条目,每个条目3x12bit = ~18KB。硬件实现需要三线性插值(8个顶点加权平均)。
色温(Color Temperature)用开尔文(K)表示光源的颜色。常见色温:
| 色温 | 光源 | 偏色 |
|---|---|---|
| 2700K | 白炽灯 | 暖黄 |
| 4000K | 荧光灯 | 中性白 |
| 5500K | 日光 | 标准白 |
| 6500K | 阴天 | 冷蓝 |
| 10000K | 蓝天 | 明显蓝 |
硬件实现:等量偏移Cb和Cr。暖色调+Cr, 冷色调+Cb。
AWB算法流程:
通过亮度直方图统计,可以实现自动曝光控制:
| 术语 | 英文 | 说明 |
|---|---|---|
| 像素 | Pixel | 图像最小单元 |
| 帧 | Frame | 一帧完整图像 |
| 场 | Field | 隔行扫描的半帧 |
| 消隐 | Blanking | 非有效视频区域 |
| 流水线 | Pipeline | 多级并行处理架构 |
| 定点数 | Fixed-point | 有限精度数值表示 |
| 饱和截断 | Saturation | 超出范围钳位到边界 |
| 行缓冲 | Line Buffer | 缓存一行像素的存储器 |
| 帧缓冲 | Frame Buffer | 缓存一帧图像的存储器 |
| 时序 | Timing | 视频同步信号参数 |
| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
| 输出全零 | 复位未释放或valid未传播 | 检查rst_n和valid链 |
| 色彩偏移 | 系数位宽不足或溢出 | 增加中间结果位宽 |
| 行间错位 | 行缓冲地址不对齐 | 检查写地址和读地址 |
| 画面闪烁 | 时序违例或跨时钟域 | 添加同步器或约束 |
| 边缘伪影 | 边界处理不正确 | 添加边界检测和钳位 |
| 资源 | 估计使用量 | 说明 |
|---|---|---|
| LUT | 100~500 | 加法器、比较器、选择器 |
| FF | 50~200 | 流水线寄存器、状态机 |
| DSP | 0~9 | 乘法器(色彩转换9个) |
| BRAM(18K) | 0~6 | 行缓冲(2~4行)、帧缓冲、LUT |
| 延迟 | 2~5 cycles | 流水线级数 |
# 语法检查
verilator --lint-only verilog/lesson_03.v
# 带波形仿真(需要testbench)
verilator --trace --cc verilog/lesson_03.v --exe tb.cpp
make -C obj_dir -f Vlesson_03.mk
./obj_dir/Vlesson_03