Sobel边缘检测-FPGA

Sobel边缘检测

 

// sobel 算法
`timescale 1ns/1ns
module sobel_top(
	clk			,
	rst_n		,
	pre_vs		,
	pre_hs		,
	pre_en		,
	pre_img_Y   ,
	
	post_vs		,
	post_hs		,
	post_en		,
	post_img_Y
);

/************************** input and output ******************/
	input			clk			;
	input			rst_n		;
	input			pre_vs		;
	input			pre_hs		;
	input			pre_en		;
	input	[7:0]	pre_img_Y   ;
	
	output			post_vs		;
	output			post_hs		;
	output			post_en		;
	output	[7:0]	post_img_Y  ;

/************************* main code **************************/
wire [7:0] matrixp11 ;
wire [7:0] matrixp12 ;
wire [7:0] matrixp13 ;
wire [7:0] matrixp21 ;
wire [7:0] matrixp22 ;
wire [7:0] matrixp23 ;
wire [7:0] matrixp31 ;
wire [7:0] matrixp32 ;
wire [7:0] matrixp33 ;
wire       matrix_vs ;
wire       matrix_hs ;
wire       matrix_en ;

Generate_Matrix_3x3_8bit Generate_Matrix_3x3_8bit(
	//system 
	.clk			(clk		),         //鍍忕礌鏃堕挓鐨勫悓姝ワ紝coms_clk , vga_clk
	.rst_n			(rst_n		),		  //澶嶄綅淇″彿		
	//coms or vga
	.pre_vs			(pre_vs		),          //鍓嶈�鍚屾�				
	.pre_hs			(pre_hs		),          //鍓嶅満鍚屾�  			
	.pre_en			(pre_en		),          //鍓嶆暟鎹�湁鏁	
	.pre_img_Y		(pre_img_Y	),		 //鏁版嵁鐏板害鍥惧儚		
	.matrixp11		(matrixp11	),
	.matrixp12		(matrixp12	),
	.matrixp13		(matrixp13	),
	.matrixp21		(matrixp21	),
	.matrixp22		(matrixp22	),
	.matrixp23		(matrixp23	),
    .matrixp31		(matrixp31	),
	.matrixp32		(matrixp32	),
	.matrixp33		(matrixp33	),
	.matrix_vs		(matrix_vs	),
	.matrix_hs		(matrix_hs	),
	.matrix_en		(matrix_en	)
);



//消耗4个时钟
wire [7:0] sobel_data;
sobel sobel(
	.clk			(clk		),
	.rst_n			(rst_n		),
	.Soble_Threshold(8'd15		),
	.matrixp11		(matrixp11	),
	.matrixp12		(matrixp12	),
	.matrixp13		(matrixp13	),
	.matrixp21		(matrixp21	),
	.matrixp22		(matrixp22	),
	.matrixp23		(matrixp23	),
	.matrixp31		(matrixp31	),
	.matrixp32		(matrixp32	),
	.matrixp33		(matrixp33	),
	.sobel_data	    (sobel_data )
);

//延迟4个时钟
reg [3:0] matrix_vs_r;
reg [3:0] matrix_hs_r;
reg [3:0] matrix_en_r;
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		matrix_vs_r <= 'd0;
		matrix_hs_r <= 'd0;
		matrix_en_r <= 'd0;
	end
	else begin
		matrix_vs_r <= {matrix_vs_r[2:0],matrix_vs};
	    matrix_hs_r <= {matrix_hs_r[2:0],matrix_hs};
	    matrix_en_r <= {matrix_en_r[2:0],matrix_en};
	end
end

	assign  post_vs	= matrix_vs_r[3];	
	assign  post_hs	= matrix_hs_r[3];	
	assign  post_en	= matrix_en_r[3];	
    assign  post_img_Y = post_en ? sobel_data : 8'd0;


endmodule

  

//sobel边缘检测算法
/*
      [ -1  0  +1 ]            [ +1  +2  +1 ]
Gx =  [ -2  0  +2 ]*A    Gy =  [  0   0   0 ] * A
      [ -1  0  +1 ]            [ -1  -2  -1 ]

G = sqrt(Gx^2 + Gy^2);
G = |Gx| + |Gy| ;
*/

module sobel
(
    clk            ,
    rst_n        ,
    Soble_Threshold,   //阈值的选取,可以做一个按键调节
    matrixp11    ,
    matrixp12    ,
    matrixp13    ,
    matrixp21    ,
    matrixp22    ,
    matrixp23    ,
    matrixp31    ,
    matrixp32    ,
    matrixp33    ,
    sobel_data  
);

//************************ input and output *******************//
    
    input         clk;
    input          rst_n;
    input  [7:0]  Soble_Threshold; 
    input  [7:0]  matrixp11 ;
    input  [7:0]  matrixp12 ;
    input  [7:0]  matrixp13 ;
    input  [7:0]  matrixp21 ;
    input  [7:0]  matrixp22 ;
    input  [7:0]  matrixp23 ;
    input  [7:0]  matrixp31 ;
    input  [7:0]  matrixp32 ;
    input  [7:0]  matrixp33 ;
    output reg [7:0]  sobel_data;

//************************ main code **************************//
//      [ -1  0  +1 ]            [ +1  +2  +1 ]
//Gx =  [ -2  0  +2 ]*A    Gy =  [  0   0   0 ] * A
//      [ -1  0  +1 ]            [ -1  -2  -1 ]
//        matrixp11*(-1)+matrixp12*(0)+matrixp13*(1),
//Gx    matrixp21*(-2)+matrixp22*(0)+matrixp23*(2),
//         matrixp31*(1)+matrixp32*(0) +matrixp33*(1),
//        matrixp11*(1)+matrixp12*(2)+matrixp13*(1),
//Gy    matrixp21*(0)+matrixp22*(0)+matrixp23*(0),
//         matrixp31*(-1)+matrixp32*(-2)+matrixp33*(-1),

reg        [11:0]    Gx_data_col1;
reg        [11:0]    Gx_data_col3;
reg        [11:0]    Gy_data_row1;
reg        [11:0]    Gy_data_row3;
//求卷积 第一步
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        Gx_data_col1 <= 'd0;
        Gx_data_col3 <= 'd0;        
    end
    else begin
        Gx_data_col1 <= matrixp11 + (matrixp21 << 1) + matrixp31;
        Gx_data_col3 <= matrixp13 + (matrixp23 << 1) + matrixp33;    
    end
end

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        Gy_data_row1 <= 'd0;
        Gy_data_row3 <= 'd0;    
    end
    else begin
        Gy_data_row1 <= matrixp11 + (matrixp12 << 1) + matrixp13;
        Gy_data_row3 <= matrixp31 + (matrixp32 << 1) + matrixp33;
    end
end

//判断大小 第二步
reg [11:0]  Gx_data;
reg [11:0]  Gy_data;
always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
        Gx_data <= 'd0;
    else if(Gx_data_col1 >= Gx_data_col3)
        Gx_data <= Gx_data_col1 - Gx_data_col3;
    else 
        Gx_data <= Gx_data_col3 - Gx_data_col1;
end
always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
        Gy_data <= 'd0;
    else if(Gy_data_row1 >= Gy_data_row3)
        Gy_data <= Gy_data_row1 - Gy_data_row3;
    else 
        Gy_data <= Gy_data_row3 - Gy_data_row1;
end

//第三步 求平方
reg [20:0] sum_data;
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) 
        sum_data <= 'd0;
    else 
        sum_data <= Gx_data*Gx_data + Gy_data*Gy_data;
end

//第四步 开方
wire [10:0] q;
sqrt sqrt(
    .radical        (sum_data),
    .q                (q),
    .remainder  ()    
);

//第五步 取阈值
//White: 24'hFF;    Black: 24'h00
//实际情况大于Soble_Threshold为黑色,在后期处理需要注意
always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
        sobel_data <= 'd0;
    else if(q >= Soble_Threshold)
        sobel_data <= 8'd255;
    else
        sobel_data <= 8'd0;
end

endmodule
`timescale 1ns/1ns
module sobel_top_tb;




    //system 
    reg                clk                ;          //像素时钟的同步,coms_clk , vga_clk
    reg                rst_n            ;          //复位信号        
    //coms or vga                
    reg                pre_vs            ;       //前行同步
    reg                pre_hs            ;       //前场同步  
    reg                pre_en            ;       //前数据有效
    reg        [7:0]    pre_img_Y        ;         //数据灰度图像
    
    wire            post_vs            ;       //输出行同步
    wire            post_hs            ;       //输出场同步  
    wire            post_en            ;       //输出数据有效
    wire    [7:0]    post_img_Y        ;         //输出数据灰度图像

initial clk = 1;
    always #5 clk = ~clk;
    
    initial begin
        rst_n = 0;
        pre_vs =0 ;
        pre_hs = 0;
        pre_en = 0;
        pre_img_Y = 0;
        #51;
        rst_n = 1;
        pre_vs = 1;
        #20;
        pre_hs = 1;
        #20;
        pre_en = 1;
        #60;
        pre_en = 0;
        #20;
        pre_hs = 0;
        #20;
        pre_hs = 1;
        #20;
        pre_en = 1;
        #60;
        pre_en = 0;
        #20;
        pre_hs = 0;
        #20;
        pre_hs = 1;
        #20;
        pre_en = 1;
        #60;
        pre_en = 0;
        #20;
        pre_hs = 0;
        #20;
        pre_hs = 1;
        #20;
        pre_en = 1;
        #60;
        pre_en = 0;
        #20;
        pre_hs = 0;
        #20;
        pre_hs = 1;
        #20;
        pre_en = 1;
        #60;
        pre_en = 0;
        #20;
        pre_hs = 0;
        $stop;
    end
    
    reg [7:0] shiftin;
    always@(posedge clk or negedge rst_n ) begin
        if(!rst_n)
            shiftin <= 'd1;
        else if(pre_en) 
            shiftin <= shiftin + 1'b1;
        else
            shiftin <= shiftin;
    end


sobel_top sobel_top(
    //system 
    .clk                (clk        ),          //像素时钟的同步,coms_clk , vga_clk
    .rst_n                (rst_n        ),          //复位信号        
    //coms or vga                    
    .pre_vs                (pre_vs        ),       //前行同步
    .pre_hs                (pre_hs        ),       //前场同步  
    .pre_en                (pre_en        ),       //前数据有效
    .pre_img_Y            (shiftin    ),         //数据灰度图像
    //output                                
    .post_vs            (post_vs    ),       //输出行同步
    .post_hs            (post_hs    ),       //输出场同步  
    .post_en            (post_en    ),       //输出数据有效
    .post_img_Y            (post_img_Y    )     //输出数据灰度图像

);




endmodule

还有一个开方ip核

原文地址:https://www.cnblogs.com/wanglinwensi/p/12851814.html