BT.601/BT.709色彩空间转换原理与Verilog流水线实现
RGB基于三原色加法模型,YCbCr将亮度与色度分离。BT.601定义了标准转换公式:Y=0.299R+0.587G+0.114B, Cb=-0.169R-0.331G+0.500B+128, Cr=0.500R-0.419G-0.081B+128。选择Q1.10定点格式表示系数,最大截断误差约0.0005,对8bit像素影响小于0.5 LSB。BT.709用于高清视频,系数不同:Kr=0.2126,Kg=0.7152,Kb=0.0722。
| 系数 | 浮点值 | Q1.10定点 | 十进制 |
|---|---|---|---|
| Kr | 0.299 | 0.299*1024 | 306 |
| Kg | 0.587 | 0.587*1024 | 601 |
| Kb | 0.114 | 0.114*1024 | 117 |
最大截断误差:1/2048 约 0.0005,对8bit像素影响小于0.5 LSB。
| 标准 | Kr | Kg | Kb |
|---|---|---|---|
| BT.601(SD) | 0.299 | 0.587 | 0.114 |
| BT.709(HD) | 0.2126 | 0.7152 | 0.0722 |
// 第02课:色彩空间转换 RGB->YCbCr (BT.601)
module color_space_convert #(
parameter DATA_W = 8
)(
input wire clk, rst_n,
input wire valid_in,
input wire [DATA_W-1:0] r_in, g_in, b_in,
output reg valid_out,
output reg [DATA_W-1:0] y_out, cb_out, cr_out
);
localparam signed [11:0] KYR=12'sd306, KYG=12'sd601, KYB=12'sd117;
localparam signed [11:0] KCBR=-12'sd173, KCBG=-12'sd339, KCBB=12'sd512;
localparam signed [11:0] KCRR=12'sd512, KCRG=-12'sd429, KCRB=-12'sd083;
reg signed [20:0] yr,yg,yb,cbr,cbg,cbb,crr,crg,crb;
reg s1v;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin yr<=0;yg<=0;yb<=0;cbr<=0;cbg<=0;cbb<=0;crr<=0;crg<=0;crb<=0;s1v<=0; end
else begin
s1v<=valid_in;
yr<=$signed({1'b0,r_in})*KYR; yg<=$signed({1'b0,g_in})*KYG; yb<=$signed({1'b0,b_in})*KYB;
cbr<=$signed({1'b0,r_in})*KCBR; cbg<=$signed({1'b0,g_in})*KCBG; cbb<=$signed({1'b0,b_in})*KCBB;
crr<=$signed({1'b0,r_in})*KCRR; crg<=$signed({1'b0,g_in})*KCRG; crb<=$signed({1'b0,b_in})*KCRB;
end
end
reg signed [20:0] ys,cbs,crs; reg s2v;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin ys<=0;cbs<=0;crs<=0;s2v<=0; end
else begin s2v<=s1v; ys<=yr+yg+yb; cbs<=cbr+cbg+cbb+(128<<10); crs<=crr+crg+crb+(128<<10); end
end
function automatic [DATA_W-1:0] sat; input signed [20:0] v; logic signed [20:0] s;
begin s=v>>>10; if(s<0) sat=0; else if(s>255) sat={DATA_W{1'b1}}; else sat=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<=s2v; y_out<=sat(ys); cb_out<=sat(cbs); cr_out<=sat(crs); end
end
endmodule
✅Verilator验证通过 — 本课Verilog代码已通过 Verilator --lint-only 检查。
色彩空间转换不仅仅是数学公式,背后涉及人眼视觉生理学和色彩科学:
人眼视网膜有3种锥细胞,分别对长波(L,红)、中波(M,绿)、短波(S,蓝)最敏感。这解释了为什么RGB三色可以混合出大部分可见光颜色(三色理论)。
但人眼对亮度细节的分辨力远高于色度。这导致YCbCr空间的色度可以用更低采样率(4:2:2, 4:2:0)而几乎无感知损失。
| 格式 | 亮度采样 | 色度采样 | 压缩比 | 用途 |
|---|---|---|---|---|
| 4:4:4 | 每像素 | 每像素 | 1:1 | 专业视频 |
| 4:2:2 | 每像素 | 水平1/2 | 1.5:1 | 广播/专业 |
| 4:2:0 | 每像素 | 水平+垂直1/2 | 2:1 | 消费级/压缩 |
BT.601覆盖标准清晰度的色彩范围,BT.709覆盖高清,BT.2020覆盖超广色域。不同色域之间转换需要色域映射(Gamut Mapping)。
视频YCbCr通常使用有限范围(Limited Range):Y=16~235, Cb/Cr=16~240。计算机RGB使用完整范围(Full Range):0~255。转换时需要注意范围缩放。
Q1.10格式的精度分析:
逆转换公式需要矩阵求逆,硬件实现通常预先计算好逆矩阵系数:
| 级 | 操作 | 延迟 | 资源 |
|---|---|---|---|
| 1 | 9个乘法 | 1 cycle | 9 DSP |
| 2 | 3个加法+偏移 | 1 cycle | 3 加法器 |
| 3 | 截断+饱和 | 1 cycle | 3 比较器 |
| 总计 | 3 cycles | 9 DSP + 少量逻辑 |
9个乘法器(3个输出x3个输入)是色彩转换的主要资源消耗。优化策略:
0.299 = 0.0100110011... (二进制) ≈ 0.01010-010 (CSD)
0.299 * x = (x>>2) + (x>>4) - (x>>7) // 仅3次移位+2次加减
相比乘法器节省1个DSP切片。
4:2:2下采样:每2个水平像素共享1组Cb/Cr值
Y: Y0 Y1 Y2 Y3 Y4 Y5 ... Cb: Cb0 -- Cb2 -- Cb4 -- ... Cr: Cr0 -- Cr2 -- Cr4 -- ...
上采样(4:2:2到4:4:4):线性插值填充缺失的Cb/Cr
视频标准使用有限范围:Y=16~235(220级), Cb/Cr=16~240(225级)
硬件中用定点乘法+偏移实现,注意输入为0时Y=16(不是0)。
色彩转换的标准测试图:
| 术语 | 英文 | 说明 |
|---|---|---|
| 像素 | 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_02.v
# 带波形仿真(需要testbench)
verilator --trace --cc verilog/lesson_02.v --exe tb.cpp
make -C obj_dir -f Vlesson_02.mk
./obj_dir/Vlesson_02