FPGA图像预处理加速:用硬件逻辑实时完成720P画面边缘检测
720P即1280×720,按60fps算像素率约55.3M像素/秒,1像素/时钟用60~75MHz即可跑满;做预处理不存整帧,采用“灰度化—行缓冲—3×3 Sobel—阈值输出”流式管线最省资源。 先转灰度再进算法,避免RGB三通道各建行缓冲,BRAM和带宽都能降三分之一。
一、行缓冲建3×3窗口
3×3卷积需同时取当前行、上1行、上2行。用两块BRAM存历史行、当前行直接移位,宽度1280、像素8bit;小分辨率可用XPM_SHIFT_RAM,大分辨率用Block RAM更省LUT。
module line3 #(parameter W=1280, BW=8)(
input clk, rst_n, input vld, input [BW-1:0] din,
output reg [BW-1:0] p0,p1,p2,p3,p4,p5,p6,p7,p8, output reg win_vld);
reg [BW-1:0] ram0[0:W-1], ram1[0:W-1];
reg [11:0] wa, ra;
reg [BW-1:0] r0,r1,cur;
reg [1:0] fill;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin wa<=0;ra<=0;fill<=0;win_vld<=0; end
else if(vld) begin
ram0[wa]<=r0; ram1[wa]<=r1; // 存上两行
r0<=ram0[ra]; r1<=ram1[ra]; cur<=din; // 读历史、锁当前
// 3x3:p0..p8按行排列,边界外做镜像复制
p0<=ra==0?r0:ram0[ra-1]; p1<=r0; p2<=ra==W-1?r0:ram0[ra+1];
p3<=ra==0?r1:ram1[ra-1]; p4<=r1; p5<=ra==W-1?r1:ram1[ra+1];
p6<=ra==0?cur:din; p7<=cur; p8<=ra==W-1?cur:din;
wa<=wa+1; ra<=ra+1;
if(fill<2) fill<=fill+1;
win_vld<=(fill==2);
end
end
endmodule
镜像填充比补零更稳,边缘不会被压暗;若输出允许裁2行2列,可省镜像逻辑、降低比较次数。
二、Sobel梯度与流水
Gx用[-1,0,1;-2,0,2;-1,0,1],Gy用[-1,-2,-1;0,0,0;1,2,1]。乘2用移位,不加乘法器;幅值用|Gx|+|Gy|近似,避免开方,硬件代价低、工业检测足够。
module sobel_core(input clk,rst_n,input vld,
input [7:0] p0,p1,p2,p3,p4,p5,p6,p7,p8,
input [7:0] th, output reg out_vld, output reg [7:0] edge);
reg signed [10:0] gx,gy; reg [11:0] mag;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin out_vld<=0; edge<=0; end
else begin
gx<=(p2+p8+{p5[7:0],1'b0})-(p0+p6+{p3[7:0],1'b0});
gy<=(p6+p8+{p7[7:0],1'b0})-(p0+p2+{p1[7:0],1'b0});
mag<= (gx[10]?-gx:gx)+(gy[10]?-gy:gy);
out_vld<=vld;
edge<= (mag[11:8]>th)?8'hFF:8'h00; // 超阈值输出白边,否则黑
end
end
endmodule
三级打拍:取窗→算Gx/Gy→取绝对值求和并阈值,1像素/周期稳定出数。720P行消隐期间可插入帧复位,避免跨行窗口错位。
三、AXI-Stream与背压
摄像头、VDMA、HDMI都走AXI4-Stream,模块按tvalid/tready握手;下游慢就在前端放同步FIFO,行缓冲不因tready拉低而丢窗。
module sobel_axis(input clk,rst_n,
input [7:0] s_tdata, input s_tvalid, output s_tready,
output reg [7:0] m_tdata, output reg m_tvalid, input m_tready);
reg [7:0] p0,p1,p2,p3,p4,p5,p6,p7,p8; reg win;
line3 #(1280,8) L(clk,rst_n,s_tvalid,s_tdata,p0,p1,p2,p3,p4,p5,p6,p7,p8,win);
sobel_core C(clk,rst_n,win,p0,p1,p2,p3,p4,p5,p6,p7,p8,8'd40,m_tvalid,m_tdata);
assign s_tready = m_tready; // 简单透传;高吞吐改FIFO解耦
endmodule
阈值th走AXI-Lite由CPU/寄存器配置,按光照自适应;弱光调低、强光调高,减少误边。
四、资源与调试
先灰度后缓存:RGB888转Y=77R+150G+29B再>>8,只缓存8bit单通道,720P两行历史约1280×2=2560字节,小块BRAM即可。
行缓冲用Block RAM,别用分布式RAM;纯移位可用XPM_SHIFT_RAM,深度1280不占很多逻辑。
关键路径在Gx/Gy加法,拆三级寄存;目标Artix-7 100~150MHz、Kintex/Zynq可上更高。
跨时钟:传感器PCLK与处理时钟不同时,入口异步FIFO,避免亚稳态;输出到HDMI再按像素时钟出。
验证:ModelSim喂单竖线/单横线/灰度图,看p0~p8窗口、gx/gy符号、edge二值;ILA抓s_tvalid/s_tready/m_tdata,对比Matlab/OpenCV参考图,PSNR一般可





