轉載於: http://blog.chinaaet.com/crazybingo/p/33388
同上一篇,還是為了體現FPGA的強大功能,實現實時的邊緣檢測能力!這一部分簡單的可以用Sobel實現,如果想做的好,可以用高斯+Canny來實現,總是,只要你想做,FPGA沒有什么做不到的,只要你靜得下心來!!!!以下僅僅介紹Soebl算法的Matlab算法實現,希望大家各自努力!
1. Sobel算子的邊緣檢測實現
1.1. 邊緣檢測概念
所謂邊緣是指其周圍像素灰度急劇變化的那些象素的集合,它是圖像最基本的特征。邊緣存在於目標、背景和區域之間,所以,它是圖像分割所依賴的最重要的依據。由於邊緣是位置的標志,對灰度的變化不敏感,,因此,邊緣也是圖像匹配的重要的特征。
邊緣檢測和區域划分是圖像分割的兩種不同的方法,二者具有相互補充的特點。在邊緣檢測中,是提取圖像中不連續部分的特征,根據閉合的邊緣確定區域。而在區 域划分中,是把圖像分割成特征相同的區域,區域之間的邊界就是邊緣。由於邊緣檢測方法不需要將圖像逐個像素地分割,因此更適合大圖像的分割。
邊緣大致可以分為兩種,一種是階躍狀邊緣,邊緣兩邊像素的灰度值明顯不同;另一種為屋頂狀邊緣,邊緣處於灰度值由小到大再到小的變化轉折點處。
邊緣檢測的主要工具是邊緣檢測模板。
邊緣檢測的有很多,典型的有索貝爾算子,普里維特算子,羅伯茨交叉邊緣檢測等邊緣檢測技術,在Matlab中有現成的IPT函數,提供邊緣檢測,如下,Sobel邊緣檢測:
IMG1 = imread('D:\Matlab_Project\BMP\Lenna.jpg'); % 讀取RGB文件,Lanna PlayBoy
subplot(1,3,1)
imshow(IMG1);
title('原圖像');
IMG1 = rgb2gray(IMG1);
[m,n] = size(IMG1); %用Sobel微分算子進行邊緣檢測
IMG2 = edge(IMG1,'sobel');
subplot(1,3,2);
imshow(IMG2);
title('Sobel邊緣檢測得到的圖像');
但效果不佳,靈活性也不高。此處我主要介紹Sobel算子的使用:
1.2. Sobel算法實現
1.2.1. Sobel算法分析
索貝爾算子(Sobel operator)主要用作邊緣檢測,在技術上,它是一離散性差分算子,用來運算圖像亮度函數的灰度之近似值。在圖像的任何一點使用此算子,將會產生對應的灰度矢量或是其法矢量。
Sobel卷積因子為:
該算子包含兩組3x3的矩陣,分別為橫向及縱向,將之與圖像作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。如果以A代表原始圖像,Gx及Gy分別代表經橫向及縱向邊緣檢測的圖像灰度值,其公式如下:
圖像的每一個像素的橫向及縱向灰度值通過以下公式結合,來計算該點灰度的大小:
通常,為了提高效率 使用不開平方的近似值,但這樣做會損失精度
如果梯度G大於某一閥值 則認為該點(x,y)為邊緣點。
if(temp3 > THRESHOLD)
IMG_Sobel(i,j) = 0; %Black
else
IMG_Sobel(i,j) = 255; %White
end
然后可用以下公式計算梯度方向(當然只要檢測邊緣,則不用計算方向):
1.2.2. Sobel算子Matlab算法的實現
Sobel算子根據像素點上下、左右鄰點灰度加權差,在邊緣處達到極值這一現象檢測邊緣。對噪聲具有平滑作用,提供較為精確的邊緣方向信息,邊緣定位精度不夠高。當對精度要求不是很高時,是一種較為常用的邊緣檢測方法。
Soble算子操作的是灰度圖像,因此必須首先對圖像進行灰度化。這一部分在第一章中詳細介紹過,不再做具體分析,一下算法直接應用灰度圖像。
(1)Sobel算子卷積
% -----------------------------------------------------------------------
% Gx Gy Pixel
% [ -1 0 +1 ] [ +1 +2 +1 ] [ P1 P2 P3 ]
% [ -2 0 +2 ] [ 0 0 0 ] [ P4 P5 P6 ]
% [ -1 0 +1 ] [ -1 -2 -1 ] [ P7 P8 P9 ]
Sobel_X = [-1, 0, 1, -2, 0, 2, -1, 0, 1]; % Mask x
Sobel_Y = [1, 2, 1, 0, 0, 0, -1, -2, -1]; % Mask y
(2)點對點卷積運算實現梯度的計算
IMG_Gray = double(IMG2); %將圖片轉換為雙精度類型
IMG_Sobel = true(h,w); %新建一個二值矩陣
THRESHOLD =90;
for i = 2 : h-1 %舍棄了邊緣信息
for j = 2 : w-1
temp1 = Sobel_X(1) * IMG_Gray(i-1,j-1) + Sobel_X(2) * IMG_Gray(i-1,j) + Sobel_X(3) * IMG_Gray(i-1,j+1) +...
Sobel_X(4) * IMG_Gray(i,j-1) + Sobel_X(5) * IMG_Gray(i,j) + Sobel_X(6) * IMG_Gray(i,j+1) +...
Sobel_X(7) * IMG_Gray(i+1,j-1) + Sobel_X(8) * IMG_Gray(i+1,j) + Sobel_X(9) * IMG_Gray(i+1,j+1);
temp2 = Sobel_Y(1) * IMG_Gray(i-1,j-1) + Sobel_Y(2) * IMG_Gray(i-1,j) + Sobel_Y(3) * IMG_Gray(i-1,j+1) +...
Sobel_Y(4) * IMG_Gray(i,j-1) + Sobel_Y(5) * IMG_Gray(i,j) + Sobel_Y(6) * IMG_Gray(i,j+1) +...
Sobel_Y(7) * IMG_Gray(i+1,j-1) + Sobel_Y(8) * IMG_Gray(i+1,j) + Sobel_Y(9) * IMG_Gray(i+1,j+1);
temp3 = sqrt(temp1^2 + temp2^2);
%temp3 = abs(temp1) + abs(temp2); %just for speed
if(temp3 > THRESHOLD)
IMG_Sobel(i,j) = 0; %Black
else
IMG_Sobel(i,j) = 1; %White
end
end
end
(3)THRESHOLD為手動設定,此處為90。根據圖像的質量來調節,針對於邊緣檢測而言,不需要進行梯度方向計算,因此直接進行梯度計算,與閥值對比,既可以實現邊緣檢測。
1.2.3. 效果圖
THRESHOLD = 90下的圖像
最后曬個圖吧,呵呵FPGA移植的,絕對不是抄襲 “無雙OO”,他那個寫的實在是太惡心了(無意冒犯前輩,不好意思)。。。。。。
實際上簡化后的算法如下:
//--------------------------------------- //Caculate vertical Grade with |abs| reg [9:0] Gy_temp1; //postive result reg [9:0] Gy_temp2; //negetive result reg [9:0] Gy_data; //Vertical grade data always@(posedge clk or negedge rst_n) begin if(!rst_n) begin Gy_temp1 <= 0; Gy_temp2 <= 0; Gy_data <= 0; end else begin Gy_temp1 <= image_p11 + (image_p12 << 1) + image_p13; //postive result Gy_temp2 <= image_p31 + (image_p32 << 1) + image_p33; //negetive result Gy_data <= (Gy_temp1 >= Gy_temp2) ? Gy_temp1 - Gy_temp2 : Gy_temp2 - Gy_temp1; end end //--------------------------------------- //Caculate the square of distance = (Gx^2 + Gy^2) reg [20:0] Gxy_square; always@(posedge clk or negedge rst_n) begin if(!rst_n) Gxy_square <= 0; else Gxy_square <= Gx_data * Gx_data + Gy_data * Gy_data; end //--------------------------------------- //Caculate the distance of P5 = (Gx^2 + Gy^2)^0.5 wire [10:0] Dim; SQRT u_SQRT ( .radical (Gxy_square), .q (Dim), .remainder () );