目录
[三、FIFO IP核调用](#三、FIFO IP核调用)
一、任务
将下面这幅图片进行Sobel算子。

二、Sobel算子
Sobel算子是一种基于 离散微分算子 的边缘检测方法,通过计算图像中像素点的 梯度幅值 来增强边缘信息。当用于图像锐化时,其核心思想是突出边缘细节 ,使图像看起来更清晰。
I(x,y):原始图像像素值
G(x,y):Sobel梯度幅值
k:锐化强度系数(通常 0.2 ≤ k ≤ 1.5)
思路:
Sobel 算子通过两个 3×3 卷积核 (水平方向 Gx 和垂直方向 Gy )计算图像的梯度:
Gx **:**检测 垂直边缘 (水平方向变化)
Gy **:**检测 水平边缘 (垂直方向变化)
欧几里得距离:
通常采用以下近似计算:
G 代表该点亮度的变化强度
最后算出锐化后的值。
三、FIFO IP核调用
四、代码
1.v代码
(1)
rust
`timescale 1ns / 1ps
module top_sobel(
input clk ,
input rst_n ,
input [23:0] i_rgb888,
input i_vsync ,
input i_hsync ,
input i_valid ,
//----------------------------
output [23:0] o_rgb888 ,
output o_hsync ,
output o_vsync ,
output o_valid
);
sobel sobel_u(
. clk (clk),
. rst_n (rst_n),
. i_pixel(i_rgb888[23:16]),
. i_vsync(i_vsync),
. i_hsync(i_hsync),
. i_valid(i_valid),
. o_pixel (o_rgb888[23:16]),
. o_hsync (o_hsync),
. o_vsync (o_vsync),
. o_valid (o_valid)
);
sobel sobel_u2(
. clk (clk),
. rst_n (rst_n),
. i_pixel(i_rgb888[15:8]),
. i_vsync(i_vsync),
. i_hsync(i_hsync),
. i_valid(i_valid),
. o_pixel (o_rgb888[15:8]),
. o_hsync (),
. o_vsync (),
. o_valid ()
);
sobel sobel_u3(
. clk (clk),
. rst_n (rst_n),
. i_pixel(i_rgb888[7:0]),
. i_vsync(i_vsync),
. i_hsync(i_hsync),
. i_valid(i_valid),
. o_pixel (o_rgb888[7:0]),
. o_hsync (),
. o_vsync (),
. o_valid ()
);
endmodule
(2)sobel
rust
`timescale 1ns / 1ps
module sobel#(
parameter k = 1
)(
input clk ,
input rst_n ,
input [7:0] i_pixel ,
input i_vsync ,
input i_hsync ,
input i_valid ,
//----------------------------
output [7:0] o_pixel ,
output o_hsync ,
output o_vsync ,
output o_valid
);
wire [7:0] a0,a1,a2 ;
wire [7:0] b0,b1,b2 ;
wire [7:0] c0,c1,c2 ;
reg [4:0] o_hsync_r;
reg [4:0] o_vsync_r;
reg [4:0] o_valid_r;
reg [9:0] gx1,gx2,gy1,gy2;
reg [9:0] GX,GY;
reg [10:0] G;
reg [11:0] sobel;
reg [7:0] pixel_reg0,pixel_reg1,pixel_reg2,pixel_reg3;
//---------------------------------------
always @(posedge clk)begin
if(!rst_n)begin
gx1 <= 0;
gx2 <= 0;
gy1 <= 0;
gy2 <= 0;
end
else begin
gx2 <= a0 + (b0<<1) + c0;
gx1 <= a2 + (b2<<1) + c2;
gy2 <= a0 + (a1<<1) + a2;
gy1 <= c0 + (c1<<1) + c2;
end
end
always @(posedge clk)begin
if(!rst_n)begin
GX <= 0;
GY <= 0;
end
else begin
if(gx1 > gx2)
GX <= gx1 - gx2;
else
GX <= gx2 - gx1;
if( gy1>gy2 )
GY <= gy1 - gy2;
else
GY <= gy2 - gy1;
end
end
always @(posedge clk)begin
if(!rst_n)
G <= 0;
else
G <= GX + GY;
end
always @(posedge clk)begin
if(!rst_n)begin
sobel <= 0;
end
else
sobel <= (G>>1) + pixel_reg3;
end
always @(posedge clk)begin
if(!rst_n)begin
pixel_reg0 <= 0;
pixel_reg1 <= 0;
pixel_reg2 <= 0;
pixel_reg3 <= 0;
end
else begin
pixel_reg0 <= i_pixel;
pixel_reg1 <= pixel_reg0;
pixel_reg2 <= pixel_reg1;
pixel_reg3 <= pixel_reg2;
end
end
assign o_pixel = (sobel[8])?8'hff:sobel[7:0];
//----------------------------------------------
always @(posedge clk) begin
if(!rst_n)begin
o_hsync_r <= 0;
o_vsync_r <= 0;
o_valid_r <= 0;
end
else begin
o_hsync_r <= {o_hsync_r[3:0],i_hsync};
o_vsync_r <= {o_vsync_r[3:0],i_vsync};
o_valid_r <= {o_valid_r[3:0],i_valid};
end
end
assign o_hsync = o_hsync_r[4];
assign o_vsync = o_vsync_r[4];
assign o_valid = o_valid_r[4];
template3x3 template3x3_u(
. clk (clk),
. rst_n (rst_n),
. i_pixel (i_pixel),
. i_vsync (i_vsync),
. i_hsync (i_hsync),
. i_valid (i_valid),
. a0(a0),.a1(a1),.a2 (a2),
. b0(b0),.b1(b1),.b2 (b2),
. c0(c0),.c1(c1),.c2 (c2),
. o_hsync (),
. o_vsync (),
. o_valid ()
);
endmodule
(3)template3x3
rust
`timescale 1ns / 1ps
module template3x3#(
parameter HSYNC = 1280 ,
VSYNC = 720
)(
input clk ,
input rst_n ,
input [7:0] i_pixel ,
input i_vsync ,
input i_hsync ,
input i_valid ,
//----------------------------
output reg [7:0] a0,a1,a2 ,
output reg [7:0] b0,b1,b2 ,
output reg [7:0] c0,c1,c2 ,
output reg o_hsync ,
output reg o_vsync ,
output reg o_valid
);
reg [15:0] cnt_line0;
reg [15:0] cnt_line1;
wire fifo0_rd_en;
wire [7:0] fifo0_rd_data;
wire fifo1_rd_en;
wire [7:0] fifo1_rd_data;
assign fifo0_rd_en = (cnt_line0 >= HSYNC-1 && i_valid); //存完一行图像数据 ,并且新的一行图像数据来了
assign fifo1_rd_en = (cnt_line1 >= HSYNC-1 && i_valid); //存完一行图像数据 ,并且新的一行图像数据来了
always @(posedge clk)begin
if(!rst_n)
cnt_line0 <= 0;
else if(i_valid)begin
if(cnt_line0 == HSYNC-1) //存完一行图像数据
cnt_line0 <= cnt_line0;
else
cnt_line0 <= cnt_line0+1;
end
end
always @(posedge clk)begin
if(!rst_n)
cnt_line1 <= 0;
else if(fifo0_rd_en)begin
if(cnt_line1 == HSYNC-1)
cnt_line1 <= cnt_line1;
else
cnt_line1 <= cnt_line1+1;
end
end
always @(posedge clk)begin
if(!rst_n)begin
a0 <= 0;
a1 <= 0;
a2 <= 0;
b0 <= 0;
b1 <= 0;
b2 <= 0;
c0 <= 0;
c1 <= 0;
c2 <= 0;
end
else begin
a0 <= a1;
a1 <= a2;
a2 <= fifo1_rd_data;
b0 <= b1;
b1 <= b2;
b2 <= fifo0_rd_data;
c0 <= c1;
c1 <= c2;
c2 <= i_pixel;
end
end
always @(posedge clk)begin
o_vsync <= i_vsync;
o_hsync <= i_hsync;
o_valid <= i_valid;
end
fifo8x2048 fifo8x2048_u0 (
.clk(clk), // input wire clk
.srst(~rst_n), // input wire srst
.din(i_pixel), // input wire [7 : 0] din
.wr_en(i_valid), // input wire wr_en
.rd_en(fifo0_rd_en), // input wire rd_en
.dout(fifo0_rd_data), // output wire [7 : 0] dout
.full(), // output wire full
.empty() // output wire empty
);
fifo8x2048 fifo8x2048_u1 (
.clk(clk), // input wire clk
.srst(~rst_n), // input wire srst
.din(fifo0_rd_data), // input wire [7 : 0] din
.wr_en(fifo0_rd_en), // input wire wr_en
.rd_en(fifo1_rd_en), // input wire rd_en
.dout(fifo1_rd_data), // output wire [7 : 0] dout
.full(), // output wire full
.empty() // output wire empty
);
endmodule
2.仿真代码
(1)tb
rust
`timescale 1ns / 1ps
module tb();
reg clk = 0;
reg rst_n = 0;
wire [23:0] i_rgb888;
wire [23:0] o_rgb888;
wire i_valid;
wire o_valid;
always #10 clk = ~clk;
initial begin
#100;
rst_n = 1;
end
top_sobel top_sobel_u(
. clk (clk) ,
. rst_n (rst_n) ,
. i_rgb888(i_rgb888) ,
. i_vsync () ,
. i_hsync () ,
. i_valid (i_valid) ,
. o_rgb888(o_rgb888) ,
. o_hsync () ,
. o_vsync () ,
. o_valid (o_valid)
);
video_source video_source_u(
. pclk (clk) ,
. rstn (rst_n) ,
//----??????----------------------
. source_de_o (i_valid) ,
. source_data_o (i_rgb888),
//----???????----------------------
. de_i (o_valid) ,
. data_i (o_rgb888)
);
endmodule
(2)video_source
rust
`timescale 1ns / 1ps
`define VIDEO_1280_720
module video_source#(
parameter VSYNC=720,
HSYNC=1280,
DELAY1=50_000_000 //图像处理延迟
)(
input pclk ,
input rstn ,
//----图像输出----------------------
output reg source_de_o ,
output [23:0] source_data_o,
//----图像输入----------------------
input de_i ,
input [23:0] data_i
);
//1280X720 74.25MHZ
`ifdef VIDEO_1280_720
parameter H_ACTIVE = 1280;// 行数据有效时??
parameter H_FRONT_PORCH = 110; // 行消隐前肩时??
parameter H_SYNC_TIME = 40; // 行同步信号时??
parameter H_BACK_PORCH = 220; // 行消隐后肩时??
parameter H_POLARITY = 1; // 行同步极??
parameter V_ACTIVE = 720; // 列数据有效时??
parameter V_FRONT_PORCH = 5; // 列消隐前肩时??
parameter V_SYNC_TIME = 5; // 列同步信号时??
parameter V_BACK_PORCH = 20; // 列消隐后肩时??
parameter V_POLARITY = 1; // 场同步极??
`endif
localparam addr_size=HSYNC*VSYNC*3+54; //总字节数
//文件??
integer bmp_file_id;
integer bmp_dout_id;
//文件句柄
integer h;
reg [7:0] rd_data [addr_size-1:0]; //根据自己图片大小 BMP格式为:位图文件头(14字节??+位图信息头(40字节??+实际像素点占内存
reg [7:0] wr_data [addr_size-1:0];
integer i=0;
integer addr_rd=54;
integer addr_wr=54;
initial begin
bmp_file_id = $fopen("D:/intelFPGA_lite/haiyunjiexun/text_Vivado/filter/image_1.bmp","rb"); //打开原始图像
bmp_dout_id = $fopen("D:/intelFPGA_lite/haiyunjiexun/text_Vivado/filter/image_1_out.bmp","wb"); //打开输出图像
h = $fread(rd_data,bmp_file_id); //读取bmp文件 读取到的数据将会依次放入rd_data??
$fclose(bmp_file_id); //读取完毕
#DELAY1 ; //图像处理延迟
for(i = 0; i < addr_size; i = i + 1)begin //图像数据写入文件
if(i < 54)
$fwrite(bmp_dout_id, "%c", rd_data[i]);//注意参数%c
else
$fwrite(bmp_dout_id, "%c", wr_data[i]);//注意参数%c
end
$fclose(bmp_dout_id);
#100;
$stop ;
end
//----读出图像数据--------------------------------
always@(posedge pclk)begin
if(source_de_o) begin
if(addr_rd >= addr_size-3)
addr_rd<=54;
else
addr_rd<=addr_rd+3;
end
end
assign source_data_o={rd_data[addr_rd],rd_data[addr_rd+1],rd_data[addr_rd+2]}; //R + G + B
//----写入图像数据--------------------------------
always@(posedge pclk)begin
if(de_i) begin
if(addr_wr >= addr_size-3)
addr_wr<=54;
else
addr_wr<=addr_wr+3;
end
end
always@(posedge pclk)begin
wr_data[addr_wr]=data_i[23:16]; //写入存储??
wr_data[addr_wr+1]=data_i[15:8];
wr_data[addr_wr+2]=data_i[7:0];
end
localparam H_TOTAL_TIME=H_ACTIVE+H_FRONT_PORCH+H_SYNC_TIME+H_BACK_PORCH;
localparam V_TOTAL_TIME=V_ACTIVE+V_FRONT_PORCH+V_SYNC_TIME+V_BACK_PORCH;
reg [31:0] cnt_v; //场同步计数器
reg [31:0] cnt_h; //行同步计数器
always@(posedge pclk)begin
if(!rstn)
source_de_o<=0;
else if(( cnt_h > (H_SYNC_TIME + H_BACK_PORCH -1)) && (cnt_h <= (H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE -1)) && (cnt_v > (V_SYNC_TIME + V_BACK_PORCH-1)) && (cnt_v <= (V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE-1)))
source_de_o<=1;
else
source_de_o<=0;
end
always@(posedge pclk)begin
if(!rstn)
cnt_h<=0;
else if(cnt_h == H_TOTAL_TIME-1)
cnt_h<=0;
else
cnt_h<=cnt_h+1;
end
always@(posedge pclk)begin
if(!rstn)
cnt_v<=0;
else if(cnt_h == H_TOTAL_TIME-1)begin
if(cnt_v == V_TOTAL_TIME-1)
cnt_v<=0;
else
cnt_v<=cnt_v+1;
end
end
endmodule
五、实验现象

以上就是图像滤波之均值滤波。 (如果有错误的地方,还请大家指出来,谢谢!)