本文主要內容是實現圖像的邊緣檢測功能 目錄 mif文件的製作 受資源限制,將圖片像素定為 160 * 120,將圖片數據製成 mif 文件,對 rom ip 核進行初始化。mif文件的製作方法網上有好多辦法,因此就不再敘述了,重點說mif文件的格式。 1、mif文件的格式為: 調用ip 核生成 ro ...
本文主要內容是實現圖像的邊緣檢測功能
目錄
- mif文件的製作
- 調用 ip 核生成rom以及在 questasim 模擬註意問題
- 灰度處理
- 均值濾波
- sobel邊緣檢測
- 圖片的顯示
- 結果展示
mif文件的製作
受資源限制,將圖片像素定為 160 * 120,將圖片數據製成 mif 文件,對 rom ip 核進行初始化。mif文件的製作方法網上有好多辦法,因此就不再敘述了,重點說mif文件的格式。
1、mif文件的格式為:
1 WIDTH=16 ; //數據位寬 2 DEPTH=19200 ; // rom 深度即圖片像素點的個數 3 ADDRESS_RADIX=UNS ; //地址數據格式 4 DATA_RADIX=BIN ; //數據格式 5 CONTENT 6 BEGIN 7 0:1010110011010000 ; // 地址 :數據 ;註意格式要和上面定義的保持統一 8 1:1010110011010000 ; 9 2:1010010010110000 ; 10 ...... 11 19198:1110011011111001 ; 12 19199:1110011011011000 ; 13 END;
調用ip 核生成 rom 以及在 questasim 模擬註意問題
這部分內容已經在上篇博文中詳細描述過,詳情請見http://www.cnblogs.com/aslmer/p/5780107.html
灰度處理
任何顏色都由紅、綠、藍三原色組成,假如原來某點的顏色為( R,G,B )那麼,我們可以通過下麵幾種方法,將其轉換為灰度:- 浮點演算法:Gray=0.299R+0.587G+0.114B
- 平均值法:Gray=(R+G+B)/3;
- 僅取單色(如綠色):Gray=G;
--------------------------------------------------------------------------------------------------------------------
此次我採用是浮點演算法來實現灰度圖的,我的圖片數據是RGB565 格式 ,
難點: 如何進行浮點運算。
思路:先將數據放大,然後再縮小。
例如: Gray=0.299R+0.587G+0.114B轉化為 Gray=(77R+150G+29B)>>8 即可,這裡有一個技巧,若 a 為 16 位即 a [15:0],那麼 a>>8 與 a [15:8]是一樣的。 核心代碼如下:always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin red_r1 <= 0 ; green_r1 <= 0 ; blue_r1 <= 0 ; end else begin red_r1 <= red * 77 ; //放大後的值 green_r1 <= green * 150; blue_r1 <= blue * 29 ; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin Gray <= 0; // 三個數之和 end else begin Gray <= red_r1 + green_r1 + blue_r1; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin post_data_in <= 0; //輸出的灰度數據 end else begin post_data_in <= { Gray[13:9], Gray[13:8], Gray[13:9] };//將Gray值賦值給RGB三個通道 end end
均值濾波
均值濾波的原理
http://blog.csdn.net/hhygcy/article/details/4325304 (此處引用 hhygcy 的文章)
難點:如何生成 3*3 的像素陣列。
我們可以利用 ip 核生成移位寄存器 ,方法與 ip 核 生成 rom 一樣,詳情見目錄 2 因此不再贅述 。
模擬波形如下 row_1 , row_2 , row_3 是指圖像的第一、二、三行的數據,Per_href 是行有效信號(受VGA時序的啟發,從 rom 中讀取數據時設計了行有效和場有效的控制信號,事半功倍,有了利於模擬查錯和數據的控制)。從 3 開始就出現了3*3 的像素陣列,這時候就可以求取周圍 8 個像素點的平均值,進行均值濾波。
核心代碼如下:
reg [5:0]p_11,p_12,p_13; // 3 * 3 捲積核中的像素點 reg [5:0]p_21,p_22,p_23; reg [5:0]p_31,p_32,p_33; reg [8:0]mean_value_add1,mean_value_add2,mean_value_add3;//每一行之和 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin {p_11,p_12,p_13} <= {5'b0,5'b0,5'b0} ; {p_21,p_22,p_23} <= {15'b0,15'b0,15'b0}; {p_31,p_32,p_33} <= {15'b0,15'b0,15'b0}; end else begin if(per_href_ff0==1&&flag_do==1)begin {p_11,p_12,p_13}<={p_12,p_13,row_1}; {p_21,p_22,p_23}<={p_22,p_23,row_2}; {p_31,p_32,p_33}<={p_32,p_33,row_3}; end else begin {p_11,p_12,p_13}<={5'b0,5'b0,5'b0}; {p_21,p_22,p_23}<={5'b0,5'b0,5'b0} {p_31,p_32,p_33}<={5'b0,5'b0,5'b0} end end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin mean_value_add1<=0; mean_value_add2<=0; mean_value_add3<=0; end else if(per_href_ff1)begin mean_value_add1<=p_11+p_12+p_13; mean_value_add2<=p_21+ 0 +p_23; mean_value_add3<=p_31+p_32+p_33; end end wire [8:0]mean_value;//8位數之和 wire [5:0]fin_y_data; //平均數,除以8,相當於左移三位。 assign mean_value=mean_value_add1+mean_value_add2+mean_value_add3; assign fin_y_data=mean_value[8:3];
sobel 邊緣檢測
邊緣檢測的原理
該運算元包含兩組 3x3 的矩陣,分別為橫向及縱向,將之與圖像作平面捲積,即可分別得出橫向及縱向的亮度差分近似值。A代表原始圖像的 3*3 像素陣列,Gx及Gy分別代表經橫向及縱向邊緣檢測的圖像,其公式如下:
圖像的每一個像素的橫向及縱向梯度近似值可用以下的公式結合,來計算梯度的大小。
如果梯度G大於某一閥值則認為該點(x,y)為邊緣點。
-------------------------------------------------------------------------------------------------------------------
用的是 邊緣檢測演算法。
難點:(1)掌握了 3*3 像素陣列,Gx 與 Gy 就很好計算了 (註意問題:為了避免計算過程中出現負值,所以將正負值分開單獨計算,具體見代碼)
(2)G的計算需要開平方,如何進行開平方運算
Quartus 提供了開平方 ip 核,因此我們直接調用就好了 。
代碼:
reg [8:0] p_x_data ,p_y_data ; // x 和 y 的正值之和 reg [8:0] n_x_data ,n_y_data ; // x 和 y 的負值之和 reg [8:0] gx_data ,gy_data ; //最終結果 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin p_x_data <=0; n_x_data <=0; gx_data <=0; end else if(per_href_ff1==1) begin p_x_data <= p_13 + (p_23<<1) + p_33 ; n_x_data <= p_11 + (p_12<<1 )+ p_13 ; gx_data <= (p_x_data >=n_x_data)? p_x_data - n_x_data : n_x_data - p_x_data ; end else begin p_x_data<=0; n_x_data<=0; gx_data <=0; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin p_y_data <=0; n_y_data <=0; gy_data <=0; end else if(per_href_ff1==1) begin p_y_data <= p_11 + (p_12<<1) + p_13 ; n_y_data <= p_31 + (p_32<<1) + p_33 ; gy_data <= (p_y_data >=n_y_data)? p_y_data - n_y_data : n_y_data - p_y_data ; end else begin p_y_data <=0; n_y_data <=0; gy_data <=0; end end //求平方和,調用ip核開平方 reg [16:0] gxy; // Gx 與 Gy 的平方和 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin gxy<=0; end else begin gxy<= gy_data* gy_data + gx_data* gx_data ; end end wire [8:0] squart_out ; altsquart u1_altsquart ( //例化開平方的ip核 .radical (gxy), .q (squart_out), //輸出的結果 .remainder() ); //與閾值進行比較 reg [15:0] post_y_data_r; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin post_y_data_r<=16'h00; end else if(squart_out>=threshold) post_y_data_r<=16'h00 ; else post_y_data_r<=16'hffff ; end
圖片的顯示
本來是想用 VGA 來顯示圖片的,由於條件的限制沒能實現,最終只能將處理完的數據輸出保存在 .txt 文件中,然後藉助好友寫的網頁進行顯示。
難點:(1) 如何將數據流輸出保存到 .txt 文件中。
(2) 網頁的使用及註意事項
在testbench裡加入下麵所示代碼即可將圖片數據保存到 .txt 文本
代碼如下:
integer w_file; initial w_file = $fopen("data_out_3.txt"); //保存數據的文件名 always @(posedge clk or negedge rst_n) begin if(flag_write==1&&post_href==1)//根據自己的需求定義 $fdisplay(w_file,"%b",post_y_data); end
------------------------------------------------------------------------------------------------
網頁的界面如下,將參數設置好以後就可以顯示圖片。
下載鏈接 http://files.cnblogs.com/files/aslmer/aggregrate.zip
註意:由於此網站是量身定做的,所以只能顯示數據格式為RGB565的16位二進位的數才能正確顯示,註意不能有分號,正確格式示例如下,必須嚴格遵守
結果展示
1 原圖 |
2 灰度圖 |
3 均值濾波 |
4 邊緣檢測 閾值為5 |
5 閾值為 10 |
6 閾值為 16 |
小結:均值濾波處理後的圖片有明顯的黑邊,產生這一現象的原因就是生成 3*3 像素矩陣和取像素值時數據有損失造成的,但是這也是可以優化的,後續我會繼續努力不斷完善。本次只是簡單對一幅圖像進行邊緣檢測,我的後續目標是實現圖片的實時處理,這又需要學習很多東西了,SDRAM、攝像頭驅動等等等,越學習越發現自己知道的實在是太少了,永遠在路上,學無止境。希望我的分享能夠幫助一些和我一樣熱愛 FPGA 圖像處理的朋友。
每天進步一點點,開心就好
aslmer
轉載請註明出處 http://www.cnblogs.com/aslmer/p/5779079.html