加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • 一、mif文件的制作
    • 二、ip 核生成 rom 及仿真時(shí)需要注意的問題
    • 仿真注意問題:
    • 三、灰度處理
    • 四、均值濾波
    • 五、sobel?邊緣檢測(cè)
    • 六、圖片的顯示
    • 七、結(jié)果展示
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

算法系列:基于FPGA的圖像邊緣檢測(cè)系統(tǒng)設(shè)計(jì)(sobel算法)

07/05 11:10
3489
閱讀需 22 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

大俠好,歡迎來到FPGA技術(shù)江湖,江湖偌大,相見即是緣分。大俠可以關(guān)注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。“煮酒言歡”進(jìn)入IC技術(shù)圈,這里有近100個(gè)IC技術(shù)公眾號(hào)。

今天給大俠帶來基于 FPGA 的圖像邊緣檢測(cè)設(shè)計(jì),話不多說,上貨。

設(shè)計(jì)流程如下:mif文件的制作→?調(diào)用 ip 核生成rom以及仿真注意問題→?灰度處理→?均值濾波:重點(diǎn)是3*3 像素陣列的生成→?sobel邊緣檢測(cè)→?圖片的顯示→?結(jié)果展示?。

一、mif文件的制作

受資源限制,將圖片像素定為 160 * 120,將圖片數(shù)據(jù)制成 mif 文件,對(duì) rom ip 核進(jìn)行初始化。mif文件的制作方法網(wǎng)上有好多辦法,因此就不再敘述了,重點(diǎn)說mif文件的格式。?mif文件的格式為:

WIDTH=16 ;    //數(shù)據(jù)位寬DEPTH=19200 ;   // rom 深度即圖片像素點(diǎn)的個(gè)數(shù)ADDRESS_RADIX=UNS?;???//地址數(shù)據(jù)格式DATA_RADIX=BIN ;   //數(shù)據(jù)格式CONTENTBEGIN0:1010110011010000?;?????//?地址?:數(shù)據(jù)?;注意格式要和上面定義的保持統(tǒng)一1:1010110011010000?;2:1010010010110000?;......19198:1110011011111001?;19199:1110011011011000?;END;

二、ip 核生成 rom 及仿真時(shí)需要注意的問題

ip?核生成 rom

1、Tools -> MegaWizard Plug-In Manager


2、Create a new custom megafuction variation

3、Memory Compier -> ROM -> Verilog HDL -> 自定義名稱

???

仿真注意問題:

1、仿真時(shí)要注意是否有 altera_mf 庫(kù)文件,否則會(huì)報(bào)錯(cuò)。Module 'altsyncram' is not define解決方案:

(1).下載 altera_mf 庫(kù)文件;

(2).?仿真時(shí)將 altera_mf.v 與其他文件一起加入到 project 中。

2、要將 .mif 文件放在仿真工程目錄下,即與 .mpf 文件在一起,否則將不會(huì)有數(shù)據(jù)輸出。

三、灰度處理

任何顏色都由紅、綠、藍(lán)三原色組成,假如原來某點(diǎn)的顏色為( R,G,B )那么,我們可以通過下面幾種方法,將其轉(zhuǎn)換為灰度:

浮點(diǎn)算法:Gray=0.299R+0.587G+0.114B

平均值法:Gray=(R+G+B)/3;

僅取單色(如綠色):Gray=G;

將計(jì)算出來的Gray值同時(shí)賦值給 RGB 三個(gè)通道即RGB為(Gray,Gray,Gray),此時(shí)顯示的就是灰度圖。通過觀察調(diào)色板就能看明了。?通過觀察可知,當(dāng)RGB三個(gè)通道的值相同時(shí)即為灰色,Gray的值越大,顏色越接近白色,反之越接近黑色(這是我自己的理解,不嚴(yán)謹(jǐn)錯(cuò)誤之處請(qǐng)大神指正)。這是在線調(diào)色板網(wǎng)址,可以進(jìn)去自己研究一下。

站長(zhǎng)工具顏色代碼查詢、RGB顏色值:

http://tool.chinaz.com/tools/selectcolor.aspx

此次采用是浮點(diǎn)算法來實(shí)現(xiàn)灰度圖的,我的圖片數(shù)據(jù)是RGB565 格式 ,難點(diǎn): 如何進(jìn)行浮點(diǎn)運(yùn)算。思路:先將數(shù)據(jù)放大,然后再縮小。例如:

Gray=0.299R+0.587G+0.114B轉(zhuǎn)化為 Gray=(77R+150G+29B)>>8 即可,這里有一個(gè)技巧,若 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 ;    endend
always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        Gray <= 0;    // 三個(gè)數(shù)之和    end    else begin        Gray <= red_r1 + green_r1 + blue_r1;            endend
always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin       post_data_in <= 0;  //輸出的灰度數(shù)據(jù)    end    else begin       post_data_in <= { Gray[13:9], Gray[13:8], Gray[13:9] };//將Gray值賦值給RGB三個(gè)通道    endend

四、均值濾波

均值濾波的原理做圖像處理,?“把每個(gè)像素都用周圍的8個(gè)像素來做均值操作 ”, 比如:

圖通常是最能說明問題的東西, 非常明顯的, 這個(gè)3*3區(qū)域像素的顏色值分別是5,3,6,2,1,9,8,4,7那么中間的1這個(gè)像素的過濾后的值就是這些值的平均值, 也就是前面的計(jì)算方法:(5+3+6+2+1+9+8+4+7)/9=5一目了然。那么這個(gè)均值濾波有什么用處呢?主要還是平滑圖像的用處, 有的圖像的銳度很高,用這樣的均值算法,可以把銳度降低。使得圖像看上去更加自然,下面就有幾幅圖我們可以看出一些端倪:原圖:

平滑處理后:

這里還是可以明顯的感覺到不同的, 沒有好壞之分,就是第二幅圖片看上去更為平滑。繼續(xù)我們的問題, 那這里均值平滑是否具有去除噪聲的功能呢?我們搞來了椒鹽噪聲(就是隨機(jī)的白點(diǎn),黑點(diǎn))來試試手:

噪聲圖(5%):? ? ? ? ? ? ? ? ? ??

平滑處理之后:

首先這里的噪聲還是比較小的, 只有5%,從均值的效果來看的話, 我可以說幾乎沒有用,其實(shí)直觀的想也可以判斷, 因?yàn)檫@里的處理并沒有剔除這些噪聲點(diǎn), 而只是微弱地降低了噪聲,所以效果可以想見的。?最后的時(shí)候還是貼上一段處理的代碼:

void?meanFilter?(unsigned?char*?corrupted,?unsigned?char*?smooth,?int?width,?int?height){
  memcpy ( smooth, corrupted, width*height*sizeof(unsigned char) );
  for (int j=1;j<height-1;j++)  {    for (int i=1;i<width-1;i++)    {      smooth [ j*width+i ] = (  corrupted [ (j-1)*width+(i-1) ] + corrupted [ (j-1)*width+i] + corrupted [ (j-1)*width+(i+1) ] +                    corrupted [ j*width+(i-1) ]    + corrupted [ j*width+i]   + corrupted [ j*width+(i+1) ] +                    corrupted [ (j+1)*width+(i-1) ] + corrupted [ (j+1)*width+i] + corrupted [ (j+1)*width+(i+1) ] ) / 9;    }  }}

簡(jiǎn)單的從1...width-1來處理, 所以第一個(gè)和最后一個(gè)像素就簡(jiǎn)單的拋掉了, 如果只是簡(jiǎn)單的看看效果還是沒有問題的。

如何生成 3*3 的像素陣列??梢岳?ip 核生成移位寄存器 ,方法與 ip 核生成 rom 一樣,詳情見?ip 核 生成 rom?操作?。

仿真波形如下 row_1 , row_2 , row_3 是指圖像的第一、二、三行的數(shù)據(jù),Per_href 是行有效信號(hào)(受VGA時(shí)序的啟發(fā),從 rom 中讀取數(shù)據(jù)時(shí)設(shè)計(jì)了行有效和場(chǎng)有效的控制信號(hào),事半功倍,有了利于仿真查錯(cuò)和數(shù)據(jù)的控制)。從 3 開始就出現(xiàn)了3*3 的像素陣列,這時(shí)候就可以求取周圍 8 個(gè)像素點(diǎn)的平均值,進(jìn)行均值濾波。

下面這個(gè)圖表示的是FPGA 如何將矩陣數(shù)據(jù)處理成并行的像素點(diǎn),可以結(jié)合下面的代碼好好理解,這也是精華所在。正方形紅框框起來的是第一個(gè)完整的 3*3 矩陣,長(zhǎng)方形紅框框起來的是并行的像素點(diǎn),在此基礎(chǔ)上就可以求得平均值,進(jìn)行均值濾波。從下圖也能看到 3*3 矩陣從左往右滑動(dòng)。第一個(gè)3*3 陣列。0 ?1 ?2 ? -- > ?p11 p12 p133 ?4 ?5 ? -- > ?p21 p22 p236 ?7 ?8 ? -- > ?p31 p32 p33

核心代碼如下:

reg [5:0]p_11,p_12,p_13;  // 3 * 3 卷積核中的像素點(diǎn)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   endend
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;    endend
wire [8:0]mean_value;//8位數(shù)之和wire [5:0]fin_y_data; //平均數(shù),除以8,相當(dāng)于左移三位。
assign mean_value=mean_value_add1+mean_value_add2+mean_value_add3;assign?fin_y_data=mean_value[8:3];?

五、sobel?邊緣檢測(cè)

邊緣檢測(cè)的原理該算子包含兩組 3x3 的矩陣,分別為橫向及縱向,將之與圖像作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。A代表原始圖像的 3*3 像素陣列,Gx及Gy分別代表經(jīng)橫向及縱向邊緣檢測(cè)的圖像,其公式如下:
圖像的每一個(gè)像素的橫向及縱向梯度近似值可用以下的公式結(jié)合,來計(jì)算梯度的大小。

如果梯度G大于某一閥值則認(rèn)為該點(diǎn)(x,y)為邊緣點(diǎn)。用的是邊緣檢測(cè)算法。難點(diǎn):(1)掌握了 3*3 像素陣列,Gx 與 Gy 就很好計(jì)算了。注意問題:為了避免計(jì)算過程中出現(xiàn)負(fù)值,所以將正負(fù)值分開單獨(dú)計(jì)算,具體見代碼)(2)G的計(jì)算需要開平方,如何進(jìn)行開平方運(yùn)算Quartus ii 提供了開平方 ip 核,因此我們直接調(diào)用就好了 。

代碼如下:

reg [8:0] p_x_data ,p_y_data ;  // x 和 y 的正值之和reg [8:0] n_x_data ,n_y_data ; // x 和 y 的負(fù)值之和reg [8:0] gx_data  ,gy_data  ; //最終結(jié)果
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;   endend
//求平方和,調(diào)用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 ;    endend
wire [8:0] squart_out ; altsquart  u1_altsquart (     //例化開平方的ip核    .radical (gxy),    .q       (squart_out),  //輸出的結(jié)果    .remainder()                       );
//與閾值進(jìn)行比較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 來顯示圖片的,由于條件的限制沒能實(shí)現(xiàn),最終只能將處理完的數(shù)據(jù)輸出保存在 .txt 文件中,然后借助網(wǎng)頁(yè)進(jìn)行顯示。難點(diǎn):(1) 如何將數(shù)據(jù)流輸出保存到 .txt 文件中。(2) 網(wǎng)頁(yè)的使用及注意事項(xiàng)。在testbench里加入下面所示代碼即可將圖片數(shù)據(jù)保存到 .txt 文本。

代碼如下:

     integer w_file;       initial     w_file = $fopen("data_out_3.txt");   //保存數(shù)據(jù)的文件名
     always @(posedge clk or negedge rst_n)       begin        if(flag_write==1&&post_href==1)//根據(jù)自己的需求定義        $fdisplay(w_file,"%b",post_y_data);   ??????end??????

網(wǎng)頁(yè)的界面如下,將參數(shù)設(shè)置好以后就可以顯示圖片。

下載鏈接:

鏈接:https://pan.baidu.com/s/1pwkJHtAxVHWWijSLczH0Ng

提取碼:e87j

注意:由于此網(wǎng)站是量身定做的,所以只能顯示數(shù)據(jù)格式為RGB565的16位二進(jìn)制的數(shù)才能正確顯示,注意不能有分號(hào),正確格式示例如下,必須嚴(yán)格遵守。

七、結(jié)果展示

小結(jié):均值濾波處理后的圖片有明顯的黑邊,產(chǎn)生這一現(xiàn)象的原因就是生成 3*3 像素矩陣和取像素值時(shí)數(shù)據(jù)有損失造成的,但是這也是可以優(yōu)化的,后續(xù)我會(huì)繼續(xù)努力不斷完善。本次只是簡(jiǎn)單對(duì)一幅圖像進(jìn)行邊緣檢測(cè),我的后續(xù)目標(biāo)是實(shí)現(xiàn)圖片的實(shí)時(shí)處理,這又需要學(xué)習(xí)很多東西了,SDRAM、攝像頭驅(qū)動(dòng)等等等,越學(xué)習(xí)越發(fā)現(xiàn)自己知道的實(shí)在是太少了,永遠(yuǎn)在路上,學(xué)無止境。希望我的分享能夠幫助一些和我一樣熱愛 FPGA 圖像處理的朋友。

推薦器件

更多器件
器件型號(hào) 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊(cè) ECAD模型 風(fēng)險(xiǎn)等級(jí) 參考價(jià)格 更多信息
10M08SCU324C8G 1 Intel Corporation Field Programmable Gate Array,
$148.65 查看
EP4CE6U14I7N 1 Altera Corporation Field Programmable Gate Array, 6272-Cell, PBGA256, LEAD FREE, UBGA-256
$19.6 查看
EP4CE6E22C8N 1 Intel Corporation Field Programmable Gate Array, 392 CLBs, 472.5MHz, 6272-Cell, PQFP144, 22 X 22 MM, 0.50 MM PITCH, LEAD FREE, EQFP-144

ECAD模型

下載ECAD模型
$32.64 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

任何技術(shù)的學(xué)習(xí)就好比一個(gè)江湖,對(duì)于每一位俠客都需要不斷的歷練,從初入江湖的小白到歸隱山林的隱世高人,需要不斷的自我感悟自己修煉,讓我們一起仗劍闖FPGA乃至更大的江湖。