2711|2

20

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

国产FPGA安路SF1系列测评【使用 FPGA 进行图像处理】 [复制链接]

  本帖最后由 Grayson__ 于 2023-4-14 21:11 编辑

        本次测评我们将进行 FPGA 的图像处理,将图像数据先通过RGB转YCbCr模块转为灰度数据后进行中值滤波,测评主要分析 SF1 的资源使用量。

工程中各模块的层次如下图所示:

        中值滤波算法就是取一个滤波窗口内的中间值进行计算的算法,选用中间值进行计算,理论上可以消除噪声。本测评使用 3x3 窗口进行中值滤波的实现方案。  

        PART 1: RGB图像格式转YCbCr图像格式

        YCbCr由 Y、Cb、Cr 组成,Y代表颜色的明亮度和浓度,Cb代表颜色的蓝色浓度偏移,Cr代表颜色的红色浓度偏移。Y分量就是我们常说的灰度值,因为很多图像处理不关注色彩,只需在灰度域处理即可,所以使用 Y 分量可以对传输带宽进行一定程度的压缩。YCbCr分为两种格式:tv range和full range,其中full range是我们本次使用的转换格式,对应的R、G、B范围均是0-255,Y、Cb、Cr也都是0-255。公式如下:

          FPGA对浮点数进行运算要使用大量资源,所以我们将公式做如下转换,可大大减少资源的使用量并提高运算速度,这种运算转换的思想也是FPGA在进行图像处理或数字信号处理中一些算法常用的思想:

    

        在运算过程中使用三级流水线,第一级是各分量的值对应相乘,第二级进行相乘后的值得相加,第三级就是右移8bit。由于是三级流水线,最后输出的数据延迟了三个时钟周期,所以我们需要对输出的行场同步信号以及使能信号进行打三拍的操作,才能使输出的数据在时序上对齐。完整代码如下:

module rgb2ycbcr(
    //module clock
    input               clk             ,   // 模块驱动时钟
    input               rst_n           ,   // 复位信号

    //图像处理前的数据接口
    input               pre_frame_vsync ,   // vsync信号
    input               pre_frame_hsync ,   // hsync信号
    input               pre_frame_de    ,   // data enable信号
    input       [4:0]   img_red         ,   // 输入图像数据R
    input       [5:0]   img_green       ,   // 输入图像数据G
    input       [4:0]   img_blue        ,   // 输入图像数据B

    //图像处理后的数据接口
    output              post_frame_vsync,   // vsync信号
    output              post_frame_hsync,   // hsync信号
    output              post_frame_de   ,   // data enable信号
    output      [7:0]   img_y           ,   // 输出图像Y数据
    output      [7:0]   img_cb          ,   // 输出图像Cb数据
    output      [7:0]   img_cr              // 输出图像Cr数据
);

//reg define
reg	 [4:0]    img_red_r0;  
reg  [5:0]    img_green_r0;
reg  [4:0]    img_blue_r0;
reg	 [4:0]    img_red_r1;  
reg  [5:0]    img_green_r1;
reg  [4:0]    img_blue_r1;

reg  [15:0]   rgb_r_m0, rgb_r_m1, rgb_r_m2;
reg  [15:0]   rgb_g_m0, rgb_g_m1, rgb_g_m2;
reg  [15:0]   rgb_b_m0, rgb_b_m1, rgb_b_m2;
reg  [15:0]   img_y0 ;
reg  [15:0]   img_cb0;
reg  [15:0]   img_cr0;
reg  [ 7:0]   img_y1 ;
reg  [ 7:0]   img_cb1;
reg  [ 7:0]   img_cr1;
reg  [ 2:0]   pre_frame_vsync_d;
reg  [ 2:0]   pre_frame_hsync_d;
reg  [ 2:0]   pre_frame_de_d;

//wire define
wire [ 7:0]   rgb888_r;
wire [ 7:0]   rgb888_g;
wire [ 7:0]   rgb888_b;


//RGB565 to RGB 888,使用高位进行量化补偿
assign rgb888_r         = {img_red  , img_red[4:2]  };
assign rgb888_g         = {img_green, img_green[5:4]};
assign rgb888_b         = {img_blue , img_blue[4:2] };
//同步输出数据接口信号
assign post_frame_vsync = pre_frame_vsync_d[2];
assign post_frame_hsync = pre_frame_hsync_d[2];
assign post_frame_de    = pre_frame_de_d[2]   ;
assign img_y            = img_y1;
assign img_cb           = img_cb1;
assign img_cr           = img_cr1;



//--------------------------------------------
//RGB 888 to YCbCr
/********************************************************
            RGB888 to YCbCr888
 Y  = 0.299R +0.587G + 0.114B
 Cb = 0.568(B-Y) + 128 = -0.172R-0.339G + 0.511B + 128
 CR = 0.713(R-Y) + 128 = 0.511R-0.428G -0.083B + 128

 Y  = (77 *R    +    150*G    +    29 *B)>>8
 Cb = (-43*R    -    85 *G    +    128*B)>>8 + 128
 Cr = (128*R    -    107*G    -    21 *B)>>8 + 128

 Y  = (77 *R    +    150*G    +    29 *B        )>>8
 Cb = (-43*R    -    85 *G    +    128*B + 32768)>>8
 Cr = (128*R    -    107*G    -    21 *B + 32768)>>8
*********************************************************/

//step1 pipeline mult
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        rgb_r_m0 <= 16'd0;
        rgb_r_m1 <= 16'd0;
        rgb_r_m2 <= 16'd0;
        rgb_g_m0 <= 16'd0;
        rgb_g_m1 <= 16'd0;
        rgb_g_m2 <= 16'd0;
        rgb_b_m0 <= 16'd0;
        rgb_b_m1 <= 16'd0;
        rgb_b_m2 <= 16'd0;
    end
    else begin
        rgb_r_m0 <= rgb888_r * 8'd77 ;
        rgb_r_m1 <= rgb888_r * 8'd43 ;
        rgb_r_m2 <= rgb888_r << 3'd7 ;
        rgb_g_m0 <= rgb888_g * 8'd150;
        rgb_g_m1 <= rgb888_g * 8'd85 ;
        rgb_g_m2 <= rgb888_g * 8'd107;
        rgb_b_m0 <= rgb888_b * 8'd29 ;
        rgb_b_m1 <= rgb888_b << 3'd7 ;
        rgb_b_m2 <= rgb888_b * 8'd21 ;
    end
end

//step2 pipeline add
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        img_y0  <= 16'd0;
        img_cb0 <= 16'd0;
        img_cr0 <= 16'd0;
    end
    else begin
        img_y0  <= rgb_r_m0 + rgb_g_m0 + rgb_b_m0;
        img_cb0 <= rgb_b_m1 - rgb_r_m1 - rgb_g_m1 + 16'd32768;
        img_cr0 <= rgb_r_m2 - rgb_g_m2 - rgb_b_m2 + 16'd32768;
    end
end

//step3 pipeline div
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        img_y1  <= 8'd0;
        img_cb1 <= 8'd0;
        img_cr1 <= 8'd0;
    end
    else begin
        img_y1  <= img_y0 [15:8];
        img_cb1 <= img_cb0[15:8];
        img_cr1 <= img_cr0[15:8];
    end
end

//延时3拍以同步数据信号
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        pre_frame_vsync_d <= 3'd0;
        pre_frame_hsync_d <= 3'd0;
        pre_frame_de_d    <= 3'd0;
		img_red_r0  	  <= 5'd0;
		img_green_r0      <= 6'd0;
		img_blue_r0       <= 5'd0;
		img_red_r1  	  <= 5'd0;
		img_green_r1      <= 6'd0;
		img_blue_r1       <= 5'd0;
    end
    else begin
        pre_frame_vsync_d <= {pre_frame_vsync_d[1:0], pre_frame_vsync};
        pre_frame_hsync_d <= {pre_frame_hsync_d[1:0], pre_frame_hsync};
        pre_frame_de_d    <= {pre_frame_de_d[1:0]   , pre_frame_de   };
		img_red_r0  	  <= img_red; 
		img_green_r0      <= img_green;
		img_blue_r0       <= img_blue; 
		img_red_r1  	  <= img_red_r0;  
		img_green_r1      <= img_green_r0;
		img_blue_r1       <= img_blue_r0;	
    end
end

endmodule

 

        PART 2 :中值滤波模块

        1.生成 3x3 格式的矩阵。

        由于本测评中使用的是 3x3 的滤波窗口,所以我们首先要生成一个 3x3 矩阵模块,这里我们使用 FPGA 中的 RAM IP核,使用简单双端口ram,数据位宽为8bit,深度为256,读写时钟,写使能,读写地址配置如下:

        这样,在 line_shift_ram_8bit 模块中调用ram模块可以获得三行一列的数据:

module line_shift_ram_8bit(
	input          clock,   
    input          clken,
    input          per_frame_href,
    
    input   [7:0]  shiftin,  		//当前行(第三行)
    output  [7:0]  taps0x,   		//第二行
    output  [7:0]  taps1x    		//第一行
);


//reg define
reg  [2:0]  clken_dly;
reg  [9:0]  ram_rd_addr;
reg  [9:0]  ram_rd_addr_d0;
reg  [9:0]  ram_rd_addr_d1;
reg  [7:0]  shiftin_d0;
reg  [7:0]  shiftin_d1;
reg  [7:0]  shiftin_d2;
reg  [7:0]  taps0x_d0;


//在数据来到时,ram地址累加
always@(posedge clock)begin
    if(per_frame_href)
        if(clken)
            ram_rd_addr <= ram_rd_addr + 1 ;
        else
            ram_rd_addr <= ram_rd_addr ;
    else
        ram_rd_addr <= 0 ;
end

//时钟使能信号延迟三拍,从RAM中读取,以及向RAM0 RAM1中更新数据各需要一个时钟
always@(posedge clock) begin
    clken_dly <= { clken_dly[1:0] , clken };
end


//将ram地址延迟二拍
always@(posedge clock) begin
    ram_rd_addr_d0 <= ram_rd_addr;
    ram_rd_addr_d1 <= ram_rd_addr_d0;
end

//输入数据延迟三拍
always@(posedge clock)begin
    shiftin_d0 <= shiftin;
    shiftin_d1 <= shiftin_d0;
    shiftin_d2 <= shiftin_d1;
end

//用于存储前一行图像的RAM
ram_8x256  u_ram_8x256_0(    
    .clka  (clock), 
    .cea   (clken_dly[2]),    //在延迟的第三个时钟周期,将当前行的数据写入RAM0
    .addra (ram_rd_addr_d1),
    .dia   (shiftin_d2),
    .clkb  (clock),
    .addrb (ram_rd_addr),
    .dob   (taps0x)           //延迟一个时钟周期,输出RAM0中前一行图像的数据
); 

//寄存一次前一行图像的数据
always@(posedge clock) begin
    taps0x_d0 <= taps0x;
end

//用于存储前前一行图像的RAM
ram_8x256  u_ram_8x256_1(    
    .clka  (clock),           
    .cea   (clken_dly[1]),    //在延迟的第二个时钟周期,将前一行图像的数据写入RAM1
    .addra (ram_rd_addr_d0),
    .dia   (taps0x_d0),
    .clkb  (clock),
    .addrb (ram_rd_addr),
    .dob   (taps1x)           //延迟一个时钟周期,输出RAM1中前前一行图像的数据
); 




endmodule

         之后生成 3x3 的矩阵:

module matrix_generate_3x3_8bit(
    input             clk,  
    input             rst_n,

    input             per_frame_vsync,
    input             per_frame_href,
    input             per_frame_clken,
    input      [7:0]  per_img_y,
    
    output            matrix_frame_vsync,
    output            matrix_frame_href,
    output            matrix_frame_clken,
    output reg [7:0]  matrix_p11,
    output reg [7:0]  matrix_p12, 
    output reg [7:0]  matrix_p13,
    output reg [7:0]  matrix_p21, 
    output reg [7:0]  matrix_p22, 
    output reg [7:0]  matrix_p23,
    output reg [7:0]  matrix_p31, 
    output reg [7:0]  matrix_p32, 
    output reg [7:0]  matrix_p33
);


//wire define
wire [7:0] row1_data;  			//第一行
wire [7:0] row2_data;  			//第二行
wire       read_frame_href;
wire       read_frame_clken;

//reg define
reg  [7:0] row3_data;  			//当前行
reg  [1:0] per_frame_vsync_r;
reg  [1:0] per_frame_href_r;
reg  [1:0] per_frame_clken_r;


assign read_frame_href    = per_frame_href_r[0] ;
assign read_frame_clken   = per_frame_clken_r[0];
assign matrix_frame_vsync = per_frame_vsync_r[1];
assign matrix_frame_href  = per_frame_href_r[1] ;
assign matrix_frame_clken = per_frame_clken_r[1];


//当前数据放在第3行
always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
        row3_data <= 0;
    else begin
        if(per_frame_clken)
            row3_data <= per_img_y ;
        else
            row3_data <= row3_data ;
    end
end

//用于存储列数据的RAM,消耗一个时钟周期
line_shift_ram_8bit  u_line_shift_ram_8bit
(
    .clock          (clk),
    .clken          (per_frame_clken),
    .per_frame_href (per_frame_href),
    
    .shiftin        (per_img_y),   
    .taps0x         (row2_data),   
    .taps1x         (row1_data)    
);

//将同步信号延迟两拍,用于同步化处理
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        per_frame_vsync_r <= 0;
        per_frame_href_r  <= 0;
        per_frame_clken_r <= 0;
    end
    else begin
        per_frame_vsync_r <= { per_frame_vsync_r[0], per_frame_vsync };
        per_frame_href_r  <= { per_frame_href_r[0],  per_frame_href  };
        per_frame_clken_r <= { per_frame_clken_r[0], per_frame_clken };
    end
end

//在同步处理后的控制信号下,输出图像矩阵,消耗一个时钟周期
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        {matrix_p11, matrix_p12, matrix_p13} <= 24'h0;
        {matrix_p21, matrix_p22, matrix_p23} <= 24'h0;
        {matrix_p31, matrix_p32, matrix_p33} <= 24'h0;
    end
    else if(read_frame_href) begin
        if(read_frame_clken) begin
            {matrix_p11, matrix_p12, matrix_p13} <= {matrix_p12, matrix_p13, row1_data};
            {matrix_p21, matrix_p22, matrix_p23} <= {matrix_p22, matrix_p23, row2_data};
            {matrix_p31, matrix_p32, matrix_p33} <= {matrix_p32, matrix_p33, row3_data};
        end
        else begin
            {matrix_p11, matrix_p12, matrix_p13} <= {matrix_p11, matrix_p12, matrix_p13};
            {matrix_p21, matrix_p22, matrix_p23} <= {matrix_p21, matrix_p22, matrix_p23};
            {matrix_p31, matrix_p32, matrix_p33} <= {matrix_p31, matrix_p32, matrix_p33};
        end
    end
    else begin
        {matrix_p11, matrix_p12, matrix_p13} <= 24'h0;
        {matrix_p21, matrix_p22, matrix_p23} <= 24'h0;
        {matrix_p31, matrix_p32, matrix_p33} <= 24'h0;
    end
end


endmodule

        2.下面就开始进行矩阵中值的寻找,流程如下:

        先将每行3个数据进行两两比较,得到最大值Max,中间值Mid,最小值Min;

        再求3个最大值的最小值Max_min,3个中间值的中间值Mid_mid,3个最小值的最大值Min_max;

        最后求Max_min、Mid_mid、Min_max的中间值,即为最终结果。

         求最大最小中间值需要对三个数进行排序才可得出,此处使用sort3模块,代码如下:

module sort3(
    input            clk,
    input            rst_n,
    input [7:0]      data1, 
    input [7:0]      data2, 
    input [7:0]      data3,
    
    output reg [7:0] max_data, 
    output reg [7:0] mid_data, 
    output reg [7:0] min_data
);

//对三个数据进行排序
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        max_data <= 0;
        mid_data <= 0;
        min_data <= 0;
    end
    else begin
        //取最大值
        if(data1 >= data2 && data1 >= data3)
            max_data <= data1;
        else if(data2 >= data1 && data2 >= data3)
            max_data <= data2;
        else//(data3 >= data1 && data3 >= data2)
            max_data <= data3;

        //取中值
        if((data1 >= data2 && data1 <= data3) || (data1 >= data3 && data1 <= data2))
            mid_data <= data1;
        else if((data2 >= data1 && data2 <= data3) || (data2 >= data3 && data2 <= data1))
            mid_data <= data2;
        else//((data3 >= data1 && data3 <= data2) || (data3 >= data2 && data3 <= data1))
            mid_data <= data3;

        //取最小值
        if(data1 <= data2 && data1 <= data3)
            min_data <= data1;
        else if(data2 <= data1 && data2 <= data3)
            min_data <= data2;
        else//(data3 <= data1 && data3 <= data2)
            min_data <= data3;        
     end
end
endmodule

        之后在median_filter_3x3模块中进行上述三步骤的实现:

module median_filter_3x3(
    input       clk,
    input       rst_n,
    input       median_frame_vsync,
    input       median_frame_href,
    input       median_frame_clken,
   
    input [7:0]  data11, 
    input [7:0]  data12, 
    input [7:0]  data13,
    input [7:0]  data21, 
    input [7:0]  data22, 
    input [7:0]  data23,
    input [7:0]  data31, 
    input [7:0]  data32, 
    input [7:0]  data33,
   
    output [7:0] target_data,
    output       pos_median_vsync,
    output       pos_median_href,
    output       pos_median_clken
);

//--------------------------------------------------------------------------------------
//FPGA Median Filter Sort order
//       Pixel -- Sort1 -- Sort2 -- Sort3
// [ P1  P2  P3 ] --> [   Max1  Mid1   Min1 ]
// [ P4  P5  P6 ] --> [   Max2  Mid2   Min2 ] --> [Max_min, Mid_mid, Min_max] --> mid_valid
// [ P7  P8  P9 ] --> [   Max3  Mid3   Min3 ]

//reg define
reg [2:0]   median_frame_vsync_r;
reg [2:0]   median_frame_href_r;
reg [2:0]   median_frame_clken_r;
//wire define
wire [7:0] max_data1; 
wire [7:0] mid_data1; 
wire [7:0] min_data1;
wire [7:0] max_data2; 
wire [7:0] mid_data2; 
wire [7:0] min_data2;
wire [7:0] max_data3; 
wire [7:0] mid_data3; 
wire [7:0] min_data3;
wire [7:0] max_min_data; 
wire [7:0] mid_mid_data; 
wire [7:0] min_max_data;


assign pos_median_vsync = median_frame_vsync_r[2];
assign pos_median_href  = median_frame_href_r[2];
assign pos_median_clken = median_frame_clken_r[2];

//Step1 对stor3进行三次例化操作
sort3  u_sort3_1(     //第一行数据排序
    .clk      (clk),
    .rst_n    (rst_n),
    
    .data1    (data11), 
    .data2    (data12), 
    .data3    (data13),
    
    .max_data (max_data1),
    .mid_data (mid_data1),
    .min_data (min_data1)
);

sort3  u_sort3_2(      //第二行数据排序
    .clk      (clk),
    .rst_n    (rst_n),

    .data1    (data21), 
    .data2    (data22), 
    .data3    (data23),
    
    .max_data (max_data2),
    .mid_data (mid_data2),
    .min_data (min_data2)
);

sort3  u_sort3_3(      //第三行数据排序
    .clk      (clk),
    .rst_n    (rst_n),

    .data1    (data31), 
    .data2    (data32), 
    .data3    (data33),
    
    .max_data (max_data3),
    .mid_data (mid_data3),
    .min_data (min_data3)
);

//Step2 对三行像素取得的排序进行处理
sort3 u_sort3_4(        //取三行最大值的最小值
    .clk      (clk),
    .rst_n    (rst_n),

    .data1    (max_data1), 
    .data2    (max_data2), 
    .data3    (max_data3),
    
    .max_data (),
    .mid_data (),
    .min_data (max_min_data)
);

sort3 u_sort3_5(        //取三行中值的最小值
    .clk      (clk),
    .rst_n    (rst_n),

    .data1    (mid_data1), 
    .data2    (mid_data2), 
    .data3    (mid_data3),
    
    .max_data (),
    .mid_data (mid_mid_data),
    .min_data ()
);

sort3 u_sort3_6(        //取三行最小值的最大值
    .clk      (clk),
    .rst_n    (rst_n),

    .data1    (min_data1), 
    .data2    (min_data2), 
    .data3    (min_data3),
    
    .max_data (min_max_data),
    .mid_data (),
    .min_data ()
);

//step3 将step2 中得到的三个值,再次取中值
sort3 u_sort3_7(
    .clk      (clk),
    .rst_n    (rst_n),

    .data1    (max_min_data), 
    .data2    (mid_mid_data), 
    .data3    (min_max_data),
    
    .max_data (),
    .mid_data (target_data),
    .min_data ()
);

//延迟三个周期进行同步
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        median_frame_vsync_r <= 0;
        median_frame_href_r  <= 0;
        median_frame_clken_r <= 0;
    end
    else begin
        median_frame_vsync_r <= {median_frame_vsync_r[1:0],median_frame_vsync};
        median_frame_href_r  <= {median_frame_href_r [1:0], median_frame_href};
        median_frame_clken_r <= {median_frame_clken_r[1:0],median_frame_clken};
    end
end


endmodule

        

        最后在gray_median_filter模块中例化matrix_generate_3x3_8bit与median_filter_3x3模块,需要注意的是3x3阵列的中值滤波,需要3个时钟:

module gray_median_filter(
    //时钟
    input       clk,  //50MHz
    input       rst_n,
    
    //处理前图像数据
    input       pe_frame_vsync,  //处理前图像数据场信号
    input       pe_frame_href,   //处理前图像数据行信号 
    input       pe_frame_clken,  //处理前图像数据输入使能效信号
    input [7:0] pe_img,        //灰度数据             
    
    //处理后的图像数据
    output       pos_frame_vsync, //处理后的图像数据场信号   
    output       pos_frame_href,  //处理后的图像数据行信号  
    output       pos_frame_clken, //处理后的图像数据输出使能效信号
    output [7:0] pos_img          //处理后的灰度数据   
);


//wire define
wire        matrix_frame_vsync;
wire        matrix_frame_href;
wire        matrix_frame_clken;
wire [7:0]  matrix_p11; //3X3 阵列输出
wire [7:0]  matrix_p12; 
wire [7:0]  matrix_p13;
wire [7:0]  matrix_p21; 
wire [7:0]  matrix_p22; 
wire [7:0]  matrix_p23;
wire [7:0]  matrix_p31; 
wire [7:0]  matrix_p32; 
wire [7:0]  matrix_p33;
wire [7:0]  mid_value;


//在延迟后的行信号有效,将中值赋给灰度输出值
assign pos_img = pos_frame_href ? mid_value : 8'd0;

matrix_generate_3x3_8bit u_matrix_generate_3x3_8bit(
    .clk        (clk), 
    .rst_n      (rst_n),
    
    //处理前图像数据
    .per_frame_vsync    (pe_frame_vsync),
    .per_frame_href     (pe_frame_href), 
    .per_frame_clken    (pe_frame_clken),
    .per_img_y          (pe_img),
    
    //处理后的图像数据
    .matrix_frame_vsync (matrix_frame_vsync),
    .matrix_frame_href  (matrix_frame_href),
    .matrix_frame_clken (matrix_frame_clken),
    .matrix_p11         (matrix_p11),    
    .matrix_p12         (matrix_p12),    
    .matrix_p13         (matrix_p13),
    .matrix_p21         (matrix_p21),    
    .matrix_p22         (matrix_p22),    
    .matrix_p23         (matrix_p23),
    .matrix_p31         (matrix_p31),    
    .matrix_p32         (matrix_p32),    
    .matrix_p33         (matrix_p33)
);

//3x3阵列的中值滤波,需要3个时钟
median_filter_3x3 u_median_filter_3x3(
    .clk        (clk),
    .rst_n      (rst_n),
    
    .median_frame_vsync (matrix_frame_vsync),
    .median_frame_href  (matrix_frame_href),
    .median_frame_clken (matrix_frame_clken),
    
    //第一行
    .data11           (matrix_p11), 
    .data12           (matrix_p12), 
    .data13           (matrix_p13),
    //第二行              
    .data21           (matrix_p21), 
    .data22           (matrix_p22), 
    .data23           (matrix_p23),
    //第三行              
    .data31           (matrix_p31), 
    .data32           (matrix_p32), 
    .data33           (matrix_p33),
    
    .pos_median_vsync (pos_frame_vsync),
    .pos_median_href  (pos_frame_href),
    .pos_median_clken (pos_frame_clken),
    .target_data      (mid_value)
);


endmodule

 

        PART 3 :图像处理顶层

        在图像处理顶层模块中,我们将例化各个处理算法,此次例化的是rgb转ycbcr的模块以及中值滤波模块:

module vip_top( 
	input				clk				,
    input				rst_n			,
    
    input               pre_frame_vsync ,
	input               pre_frame_hsync ,
	input               pre_frame_de    ,
	input       [4:0]   img_red         ,
	input       [5:0]   img_green       ,
	input       [4:0]   img_blue        ,

	output      	 	pos_frame_vsync	,
	output      	 	pos_frame_href	, 
	output       		pos_frame_clken	,
	output 		[7:0] 	pos_img         
);

//wire define
wire			pe1_frame_vsync;
wire			pe1_frame_hsync;
wire			pe1_frame_de;
wire	[7:0]	pe1_img_y;
wire	[7:0]	pe1_img_Cb;
wire	[7:0]	pe1_img_Cr;


rgb2ycbcr u_rgb2ycbcr(
    //module clock
    .clk             (clk),   // 模块驱动时钟
    .rst_n           (rst_n),   // 复位信号

    //图像处理前的数据接口
    .pre_frame_vsync (pre_frame_vsync),   // vsync信号
    .pre_frame_hsync (pre_frame_hsync),   // hsync信号
    .pre_frame_de    (pre_frame_de),   	  // data enable信号
    .img_red         (img_red),           // 输入图像数据R
    .img_green       (img_green),   	  // 输入图像数据G
    .img_blue        (img_blue),   		  // 输入图像数据B

    //图像处理后的数据接口
    .post_frame_vsync(pe1_frame_vsync),   // vsync信号
    .post_frame_hsync(pe1_frame_hsync),   // hsync信号
    .post_frame_de   (pe1_frame_de),   	  // data enable信号
    .img_y           (pe1_img_y),   	  // 输出图像Y数据
    .img_cb          (pe1_img_Cb),   	  // 输出图像Cb数据
    .img_cr          (pe1_img_Cr)    	  // 输出图像Cr数据
);

gray_median_filter u_gray_median_filter(
    //时钟
    .clk             (clk),   	// 模块驱动时钟
    .rst_n           (rst_n),   // 复位信号
    
    //处理前图像数据
    .pe_frame_vsync	 (pe1_frame_vsync),   //处理前图像数据场信号
    .pe_frame_href	 (pe1_frame_hsync),   //处理前图像数据行信号 
    .pe_frame_clken	 (pe1_frame_de),  	  //处理前图像数据输入使能效信号
    .pe_img			 (pe1_img_y),         //灰度数据             
    
    //处理后的图像数据
    .pos_frame_vsync (pos_frame_vsync), //处理后的图像数据场信号   
    .pos_frame_href	 (pos_frame_href),  //处理后的图像数据行信号  
    .pos_frame_clken (pos_frame_clken), //处理后的图像数据输出使能效信号
    .pos_img		 (pos_img)          //处理后的灰度数据   
);

endmodule

        至此,图像中值滤波已在 FPGA 上实现,下面是FPGA的资源占用率:

 

        可见,使用 SF1 FPGA 部分进行图像的处理加速,其资源是绰绰有余的,感兴趣的读者可以继续研究并在FPGA上实现其他算法,例如均值滤波,其与中值滤波的区别只是在所求数据上(均值)不同,模块层次基本一致,当然还有腐蚀、膨胀、二值化、sobel边缘检测等图像处理常见的操作。安路的SF1同时具备FPGA 与 MCU两部分资源,FPGA在进行算法加速的方面优势突出,而MCU则适合进行一些控制操作,将二者结合起来使用会大大减少开发难度,当然前提是需要同时了解MCU与FPGA的相关知识与运用。

        遗憾的是,SF1 DEMO板上使用的均是mipi接口的摄像头与屏幕,目前身边没有这样的摄像头与屏幕,所以上板测试只能缓缓,有机会一定测试一下。

 

最新回复

谢谢分享,好久没看verilog代码了,都看不懂了。。。   详情 回复 发表于 2023-4-28 15:42
点赞 关注
 
 

回复
举报

6807

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

跟着楼主看看SF1 的资源使用量的学习

 
 
 

回复

7608

帖子

2

TA的资源

五彩晶圆(高级)

板凳
 

谢谢分享,好久没看verilog代码了,都看不懂了。。。

个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表