基於 Sobel 算子的邊緣檢測的FPGA 算法實現和MATLAB的實現

 

1. 背景知識

       邊緣檢測是圖像處理和計算機視覺中的基本問題,邊緣檢測的目的是標識數字圖像中亮度變化明顯的點。圖像屬性中的顯著變化通常反映了屬性的重要事件和變化。 這些包括(i)深度上的不連續、(ii)表面方向不連續、(iii)物質屬性變化和(iv)場景照明變化。 邊緣檢測是圖像處理和計算機視覺中,尤其是特徵提取中的一個研究領域。

2. 邊緣檢測算子

一階:Roberts Cross 算子,Prewitt 算子,Sobel 算子, Kirsch 算子,羅盤算子;
二階: Marr-Hildreth,在梯度方向的二階導數過零點,Canny 算子,Laplacian 算子。

今天要說的是基於 Sobel 算子的邊緣檢測的 FPGA 算法和MATLAB的實現。

3. Sobel濾波原理

Sobel 濾波,也稱Sobel算子,是像素邊緣檢測中最重要的算子之一,在機器學習、數字媒體、計算機視覺等信息科技領域起着舉足輕重的作用。邊緣點其實是圖像灰度跳變劇烈的點,所以先計算梯度圖像,然後將梯度圖像中較亮的那一部分提取出來就是簡單的邊緣部分。根據該原理,Sobel算子首先用兩組3×3的濾波器分別對圖像橫向及縱向進行濾波,從而得到橫向和縱向的梯度圖像(亮度差分近似值)。若A表示原始圖像,和分別代表經橫向及縱向邊緣檢測的圖像,其公式如下:

    

圖像的每一個像素的橫向及縱向梯度近似值可用結合。然後計算梯度方向:  此外,計算梯度圖像時一般會使用,用絕對值消除梯度方向的影響。

如果以上的角度Θ等於零,即代表圖像該處擁有縱向邊緣,左方較右方暗。

缺點是Sobel算子並沒有將圖像的主題與背景嚴格地區分開來,換言之就是Sobel算子並沒有基於圖像灰度進行處理,由於Sobel算子並沒有嚴格地模擬人的視覺生理特徵,所以提取的圖像輪廓有時並不能令人滿意。

首先一篇他文讓大家瞭解下sobel的工作原理 : 徹底理解數字圖像處理中的卷積-以Sobel算子爲例

clear all; 
close all;
imag = imread('sobel.jpg');  %讀取關鍵幀
subplot(131);imshow(imag);title('原圖');
imag = rgb2gray(imag);        %轉化爲灰度圖 
[high,width] = size(imag);   % 獲得圖像的高度和寬度
F2 = double(imag);        
U = double(imag);       
uSobel = imag;
for i = 2:high - 1   %sobel邊緣檢測
    for j = 2:width - 1
        Gx = (U(i+1,j-1) + 2*U(i+1,j) + F2(i+1,j+1)) - (U(i-1,j-1) + 2*U(i-1,j) + F2(i-1,j+1));
        Gy = (U(i-1,j+1) + 2*U(i,j+1) + F2(i+1,j+1)) - (U(i-1,j-1) + 2*U(i,j-1) + F2(i+1,j-1));
        uSobel(i,j) = sqrt(Gx^2 + Gy^2); 
    end
end 
subplot(132);imshow(im2uint8(uSobel));title('邊緣檢測後');  %畫出邊緣檢測後的圖像
% Matlab自帶函數邊緣檢測
% K爲獲取得到的關鍵幀的灰度圖
BW3 = edge(imag,'sobel', 0.07);
subplot(133);imshow(BW3,[]);title('Matlab自帶函數邊緣檢測');

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    18:56:27 09/11/2019 
// Design Name: 
// Module Name:    sobel 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////

module sobel#(
       parameter DW = 8,
	   parameter LINE_N  = 3,
	   parameter iTHRESHOLD = 150
	   )
	(
	input            pixelclk_i,
    input            rst_n,
    input            clk,
    input [DW-1:0]   din,
	output           pixelclk_o,
	output           dout
    );
	
	localparam DATA_IN_WIDTH = 11;
	
	//Sobel x
    localparam  X1 = 3'd1, X2 = 3'd0, X3 = 3'd1,
				X4 = 3'd2, X5 = 3'd0, X6 = 3'd2,
				X7 = 3'd1, X8 = 3'd0, X9 = 3'd1;
   //Sobel y
   localparam   Y1 = 3'd1, Y2 = 3'd2, Y3 = 3'd1,
                Y4 = 3'd0, Y5 = 3'd0, Y6 = 3'd0,
                Y7 = 3'd1, Y8 = 3'd2, Y9 = 3'd1;
	
	reg  [DW-1:0] din_r0[0:LINE_N-1];
    reg  [DW-1:0] din_r1[0:LINE_N-1];
    reg  [DW-1:0] din_r2[0:LINE_N-1];
	wire matrix_clken;
	matrix_3x3 uut_matrix_3x3(
		.clk(clk),						
		.rst_n(rst_n),							
		.per_clken(pixelclk_i),
		.per_img(din),
		.matrix_clken(matrix_clken),	
		.matrix_p11(din_r0[0]),						
		.matrix_p12(din_r0[1]),						
		.matrix_p13(din_r0[2]),	
		.matrix_p21(din_r1[0]),						
		.matrix_p22(din_r1[1]),						
		.matrix_p23(din_r1[2]),						
		.matrix_p31(din_r2[0]),						
		.matrix_p32(din_r2[1]),						
		.matrix_p33(din_r2[2])	
    );
	//1clk
	//1.Gx = P ★Sobelx -- 原始圖像與 Sobel 算子 X 方向卷積;
	reg 	[9:0] 	Gx_temp1;//postive result
	reg 	[9:0] 	Gx_temp2;//negetive result
	reg 	[9:0] 	Gx_data;//Horizontal grade data
	
	always @(posedge clk or negedge rst_n)
	begin
		if(!rst_n)begin
			Gx_temp1 <= 10'd0;
			Gx_temp2 <= 10'd0;
			Gx_data  <= 10'd0;
		end 
		else begin
			Gx_temp1 <= din_r0[2]*X3 + din_r1[2]*X6 + din_r2[2]*X9;//postive result
			Gx_temp2 <= din_r0[0]*X1 + din_r1[0]*X4 + din_r2[0]*X7;//negetive result
			Gx_data  <= (Gx_temp1 >= Gx_temp2)? Gx_temp1 - Gx_temp2 : Gx_temp2 - Gx_temp1;
		end
	end
	// 2. Gy = P★Sobely -- 原始圖像與 Sobel 算子 Y 方向卷積;
	always @(posedge clk or negedge rst_n)
	begin
		if(!rst_n)begin
			Gy_temp1 <= 10'd0;
			Gy_temp2 <= 10'd0;
		end 
		else begin
			Gy_temp1 <= din_r0[0]*X1 + din_r0[1]*X2 + din_r0[2]*X3;//postive result
			Gy_temp2 <= din_r2[0]*X1 + din_r2[1]*X2 + din_r2[2]*X3;//negetive result
		end
	end
	
	//得到GY和GX 1clk
	 always @(posedge clk or negedge rst_n)
	 begin	
		if(!rst_n)begin
			Gx_data  <= 10'd0;
			Gy_data	 <= 10'd0;
		end 
		else begin
			Gx_data  <= (Gx_temp1 >= Gx_temp2)? Gx_temp1 - Gx_temp2 : Gx_temp2 - Gx_temp1;
			Gy_data  <= (Gy_temp1 >= Gy_temp2)? Gy_temp1 - Gy_temp2 : Gy_temp2 - Gy_temp1;
		end
	 end	
	 // 3. 實現平方和
	wire 	[10:0] 	dim;
	assign dim = Gx_data + Gy_data;
	
	// 4. 閾值比較形成邊緣查找後的二值圖像
	//1clk
	reg 	post_img_bit_r;
	always @(posedge clk or negedge rst_n)
	begin
		if(!rst_n)
			post_img_bit_r <= 1'b0;
		else if(dim >= iTHRESHOLD)
			post_img_bit_r <= 1'b1;
		else 
			post_img_bit_r <= 1'b0;
	end	
	assign dout = post_img_bit_r;
	
	//per_clken delay 3clk	
	reg 	[2:0]	per_clken_r;
	always @(posedge clk or negedge rst_n)begin
		if(!rst_n)
			per_clken_r <= 3'b0;
		else 
			per_clken_r <= {per_clken_r[1:0], matrix_clken};
	end
	assign	pixelclk_o = per_clken_r[2];
	
endmodule

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章