2. 基于Verilog的RGB图像灰度化实时处理
任务与实现边界
本案例实现一个 Verilog 流水线模块,将摄像头输入的 RGB888 像素实时转换为灰度值,并输出到 HDMI 显示通路。灰度公式采用整数近似:Y = (77*R + 150*G + 29*B) >> 8,对应 ITU-R BT.601 的定点实现。模块按像素时钟逐拍处理,3 级流水线保证每个时钟输出一个灰度像素,无阻塞。
模块接口与流水线结构
输入为 clk、rst_n、像素有效信号 de_in 及 RGB 分量;输出为 de_out 与 8 位灰度 y_out。流水线分三级:乘法、加法、移位截断。HDMI 输出端将 y_out 同时接到 R/G/B 三个通道即可显示灰度图。
完整代码
module rgb2gray_pipeline (
input wire clk,
input wire rst_n,
input wire de_in,
input wire [7:0] r_in,
input wire [7:0] g_in,
input wire [7:0] b_in,
output reg de_out,
output reg [7:0] y_out
);
// Stage1: 乘法
reg [15:0] r_mul, g_mul, b_mul;
reg de_s1;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
r_mul <= 16'd0;
g_mul <= 16'd0;
b_mul <= 16'd0;
de_s1 <= 1'b0;
end else begin
r_mul <= r_in * 8'd77;
g_mul <= g_in * 8'd150;
b_mul <= b_in * 8'd29;
de_s1 <= de_in;
end
end
// Stage2: 加法
reg [17:0] sum;
reg de_s2;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
sum <= 18'd0;
de_s2 <= 1'b0;
end else begin
sum <= r_mul + g_mul + b_mul;
de_s2 <= de_s1;
end
end
// Stage3: 移位截断
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
y_out <= 8'd0;
de_out <= 1'b0;
end else begin
y_out <= sum[15:8];
de_out <= de_s2;
end
end
endmodule
HDMI 输出接入
在顶层模块中,将 y_out 同时赋给 HDMI 编码器的 R、G、B 输入,并保持 de_out 与行场同步信号对齐。例如:
assign hdmi_r = y_out;
assign hdmi_g = y_out;
assign hdmi_b = y_out;
assign hdmi_de = de_out;
运行与验证
- 综合工具:Vivado / Quartus 均可,目标器件任意含足够 DSP 的 FPGA。
- 仿真验证:编写 testbench,在
de_in=1时依次输入已知像素,例如R=255,G=255,B=255,3 拍后检查y_out是否为 255;输入R=0,G=0,B=0时输出应为 0。 - 上板验证:摄像头输出彩色条纹或彩条测试图,HDMI 显示器应显示对应灰度图像,无彩色残留。
- 通过条件:每个有效像素在 3 个时钟周期后输出对应灰度值,
de_out与de_in延迟一致,图像无撕裂或错位。
常见问题
- 若图像偏暗或偏亮,检查乘法系数是否被综合工具截断,确认位宽足够(16 位乘法结果)。
- 若 HDMI 无显示,确认
de_out与像素时钟同步,且行场时序未因流水线延迟而错位。 - 若资源紧张,可将乘法改为移位加法近似,但会损失精度。