数字视频基础概念、像素格式、帧缓冲架构与FPGA实现概述
数字视频基础概念、像素格式、帧缓冲架构与FPGA实现概述
// 第01课:视频处理概述 - 顶层架构示例
module video_overview #(
parameter DATA_W = 8, IMG_W = 640, IMG_H = 480
)(
input wire clk, rst_n,
input wire vid_in_valid,
input wire [DATA_W-1:0] vid_in_data,
input wire vid_in_sof, vid_in_eol,
output reg vid_out_valid,
output reg [DATA_W-1:0] vid_out_data,
output reg vid_out_sof, vid_out_eol,
input wire [7:0] cfg_brightness,
input wire [7:0] cfg_contrast,
input wire cfg_bypass
);
reg [DATA_W-1:0] s1_data; reg s1_valid, s1_sof, s1_eol;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin s1_data<=0; s1_valid<=0; s1_sof<=0; s1_eol<=0; end
else begin s1_data<=vid_in_data; s1_valid<=vid_in_valid; s1_sof<=vid_in_sof; s1_eol<=vid_in_eol; end
end
reg [DATA_W-1:0] s2_data; reg s2_valid, s2_sof, s2_eol;
wire [17:0] cmul = s1_data * {1'b0, cfg_contrast};
wire [17:0] cadd = cmul + {cfg_brightness, 9'b0};
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin s2_data<=0; s2_valid<=0; s2_sof<=0; s2_eol<=0; end
else begin
s2_valid<=s1_valid; s2_sof<=s1_sof; s2_eol<=s1_eol;
if (cadd[17]) s2_data<=0;
else if (|cadd[17:8]) s2_data<={DATA_W{1'b1}};
else s2_data<=cadd[7:0];
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin vid_out_data<=0; vid_out_valid<=0; vid_out_sof<=0; vid_out_eol<=0; end
else begin
vid_out_valid<=s2_valid; vid_out_sof<=s2_sof; vid_out_eol<=s2_eol;
vid_out_data <= cfg_bypass ? s1_data : s2_data;
end
end
endmodule
✅Verilator验证通过 — 本课Verilog代码已通过 Verilator --lint-only 检查。
现代FPGA视频处理系统通常采用深流水线架构,每个处理模块作为一个流水线级,通过valid/ready握手协议连接。这种设计确保了:
FPGA中浮点运算资源昂贵(DSP+大量逻辑),定点运算是视频处理的首选。常用Q格式:
| 格式 | 范围 | 精度 | 适用场景 |
|---|---|---|---|
| Q0.8 | 0~255/256 | 1/256 | 混合系数、增益 |
| Q1.10 | 0~2 | 1/1024 | 色彩转换系数 |
| Q4.12 | -8~8 | 1/4096 | 仿射变换系数 |
| Q16.16 | -32768~32767 | 1/65536 | 坐标映射 |
定点运算的关键问题是溢出处理。视频处理中常用的策略:
8bit像素的饱和截断实现:检查结果的高位是否非零(正溢出)或符号位为1(负溢出)。
| 资源 | 亮度+对比度模块 | 说明 |
|---|---|---|
| LUT | ~200 | 加法器+比较器+选择器 |
| FF | ~50 | 流水线寄存器 |
| DSP | 1 | 对比度乘法器 |
| BRAM | 0 | 无需行缓冲 |
| 延迟 | 3 cycles | 输入寄存+乘加+截断 |
FPGA视频模块间的数据传输通常使用以下信号:
有时还使用ready信号实现反压(back-pressure),形成完整的valid/ready握手。
Verilog视频模块的仿真验证方法:
一个完整的数字视频信号从采集到显示经历多个处理环节:
传感器(CMOS/CCD) -> ADC -> ISP -> 编码 -> 传输 -> 解码 -> 后处理 -> 显示
每个环节都可能涉及不同的色彩空间、位深、分辨率和帧率。
| 格式 | 说明 | 数据量 |
|---|---|---|
| RAW8 | 8bit Bayer原始数据 | 1 byte/pixel |
| RAW10 | 10bit Bayer | 1.25 byte/pixel |
| RAW12 | 12bit Bayer | 1.5 byte/pixel |
| YUV422 | 8bit YCbCr 4:2:2 | 2 byte/pixel |
| RGB888 | 8bit RGB全色 | 3 byte/pixel |
CMOS传感器每个像素只采集R/G/B之一,排列为Bayer模式(RGGB/GRBG/GBRG/BGGR)。去马赛克(Demosaicing)算法从单色采样恢复全色图像,常用双线性插值或边缘感知插值。
| 指标 | 定义 | 典型值 |
|---|---|---|
| 吞吐率 | 每秒处理像素数 | 18~500 Mpixels/s |
| 延迟 | 输入到输出的周期数 | 3~30 cycles |
| PSNR | 峰值信噪比(dB) | >30dB(好), >40dB(优) |
| SSIM | 结构相似性 | >0.9(好), >0.95(优) |
| 资源利用率 | FPGA资源占比 | <80%(安全) |
视频处理模块的Verilog编码应遵循以下规范:
module tb_video_module;
reg clk, rst_n;
reg valid_in;
reg [7:0] data_in;
wire valid_out;
wire [7:0] data_out;
video_module uut (
.clk(clk), .rst_n(rst_n),
.valid_in(valid_in), .data_in(data_in),
.valid_out(valid_out), .data_out(data_out)
);
always #5 clk = ~clk; // 100MHz
initial begin
clk = 0; rst_n = 0; valid_in = 0; data_in = 0;
#20 rst_n = 1;
// Test vectors here
$finish;
end
endmodule
| 术语 | 英文 | 说明 |
|---|---|---|
| 像素 | 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_01.v
# 带波形仿真(需要testbench)
verilator --trace --cc verilog/lesson_01.v --exe tb.cpp
make -C obj_dir -f Vlesson_01.mk
./obj_dir/Vlesson_01