FPGA学习笔记——图像锐化之Sobel算子

目录

一、任务

二、Sobel算子

[三、FIFO IP核调用](#三、FIFO IP核调用)

四、代码

1.v代码

(1)

(2)sobel

(3)template3x3

2.仿真代码

(1)tb

(2)video_source

五、实验现象


一、任务

将下面这幅图片进行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核调用

FIFO调用


四、代码

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

五、实验现象


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

相关推荐
156082072193 小时前
多相DDC数据FIR抽取滤波实例
fpga开发
羽落·星辰3 小时前
NAFNet (Simple Baselines for Image Restoration) 阅读笔记
笔记·深度学习·机器学习
没头脑的男大4 小时前
信号处理与系统设计,第二节课笔记
笔记·信号处理
.鸣4 小时前
idea学习日记7: StringBuilder的基本操作
学习
凉、介4 小时前
ARM Synchronization Primitives
arm开发·笔记·学习
iconball5 小时前
个人用云计算学习笔记 --14( Linux 逻辑卷管理、Linux 交换空间管理)
linux·运维·笔记·学习·云计算
GilgameshJSS5 小时前
STM32H743-ARM例程6-RS422
arm开发·stm32·单片机·嵌入式硬件·学习
峰顶听歌的鲸鱼5 小时前
32.Linux NFS 服务
linux·运维·服务器·笔记·学习方法
geilip5 小时前
知识体系_分布式内存计算框架_spark
笔记