1. 程式人生 > >基於FPGA灰度影象的膨脹演算法的實現

基於FPGA灰度影象的膨脹演算法的實現

基於FPGA灰度影象的膨脹演算法的實現

1 背景知識

    腐蝕與膨脹是形態學濾波的兩個基本運算,通過腐蝕和膨脹兩種運算可以實現多種功能,主要如下:

(1) 消除噪聲;

(2)分割出獨立的影象元素;

(3)在影象中連線相鄰的元素;

(4)尋找影象中明顯的極大值和極小值區域;

(5)求出影象的梯度。


圖1 腐蝕膨脹示意圖

圖1 a為大小為448X425畫素的灰度級X射線影象;b使用半徑為2個畫素的圓盤形結構元對影象的腐蝕結果;c用相同的結構元對影象的膨脹結果。原圖有Lixi公司提供。

1)形態學濾波之膨脹

   膨脹(dialate)就是求區域性最大值的操作。

   從數學角度來看就是將影象f和核(結構元)b進行卷積的一個過程。

   當b的原點位於(x,y)處時,用一個平坦的結構元b在(x,y)處對影象f的膨脹,定義為影象f中與b重合區域的最大值,即:

     

   為了方便起見,將膨脹操作記為:

 

(x,y)表示當前輸入影象的行列座標;

f(x,y)表示座標點(x,y)處的影象畫素值;

g(x,y)表示座標點(x,y)處的濾波結果;

(s,t)表示作用域。

2 matlab模擬灰度影象的膨脹

Matlab膨脹原始碼:

%%imagedilate

clc

clearall

img_a= imread('flower.bmp');

figure,imshow(img_a);

title('img_a rgb');

img_b= rgb2gray(img_a);

figure,imshow(img_b);

title('img_b gary');

a= [1,1,1;

     1,1,1;

     1,1,1]; %structural element

b= [1,1,1,1,1;

     1,1,1,1,1;

     1,1,1,1,1;

     1,1,1,1,1;

     1,1,1,1,1];

 c = [1,1,1,1,1,1,1;

      1,1,1,1,1,1,1;

      1,1,1,1,1,1,1;

      1,1,1,1,1,1,1;

      1,1,1,1,1,1,1;

      1,1,1,1,1,1,1;

      1,1,1,1,1,1,1];

img_c= imdilate(img_b,a);

figure,imshow(img_c);

title('img_c 3x3');

img_d= imdilate(img_b,b);

figure,imshow(img_d);

title('img_d 5x5');

img_e= imdilate(img_b,c);

figure,imshow(img_e);

title('img_e 7x7');



3.1 膨脹模組的設計

1)比較子模組

2)一維形態學膨脹子模組

3)二維形態學膨脹子模組

(1) 比較子模組

為了程式碼更好的移植,我們將比較子模組設計為獨立的子模組。

Erode:輸出倆個數據的較小值。

比較子模組原始碼:

/*

Module name:  minmax.v

Description: 

Data:         2018/03/14

Engineer:     lipu

e-mail:       [email protected]

*/

`timescale1ns/1ps

moduleminmax(

      clk,  //pixel clock

         rst_n,

         data_valid,

         din,

         din_r,

         dout_min,

         dout_max

         );

parameterWIDTH = 8;       // data width 8 bit  

parameterUSE_REG = 1; // USE_REG = 1Data delay 1ns output.  USE_REG = 0 Don'tdelay.  

input               clk;  //pixel clock

input               rst_n;

input               data_valid;

input  [WIDTH-1:0] din;

input  [WIDTH-1:0] din_r;

output[WIDTH-1:0] dout_min;

output[WIDTH-1:0] dout_max;    

wireminmax_flag;

wire[WIDTH-1:0] min_temp;

wire[WIDTH-1:0] max_temp;

reg  [WIDTH-1:0] min_reg;

reg  [WIDTH-1:0] max_reg;

// min or max flag

assignminmax_flag = (din > din_r) ? 1'b1:1'b0;

// min

assignmin_temp = (minmax_flag == 1'b1) ? din_r : din;

// max

assignmax_temp = (minmax_flag == 1'b1) ? din : din_r;

// USE_REG == 1

generate

if(USE_REG== 1)

begin: MAP0

  always @(posedge clk) begin

    if(data_valid) begin

        min_reg <= #1 min_temp;

        max_reg <= #1 max_temp;

       end

  end

  assign dout_min = min_reg;

  assign dout_max = max_reg;

end

endgenerate

//USE_REG == 0

generate

if(~(USE_REG== 1))

begin: MAP1

  assign dout_min = min_temp;

  assign dout_max = max_temp;

end

endgenerate

endmodule

比較子模組模擬原始碼:

/*

Module name:  minmax_tb.v

Description:            

*/

`timescale1ns/1ps

`defineWIDTH 8

`defineCLK_PERIOD 10

moduleminmax_tb();

       reg               clk;  //pixel clock

         reg               rst_n;

         reg               data_valid;

         reg  [`WIDTH-1:0] din;

         reg  [`WIDTH-1:0] din_r;

         wire [`WIDTH-1:0] dout_min;

         wire [`WIDTH-1:0] dout_max;

minmaxminmax_inst(

        .clk(clk),  //pixel clock

          .rst_n(rst_n),

          .data_valid(data_valid),

          .din(din),

              .din_r(din_r),

          .dout_min(dout_min),

          .dout_max(dout_max)

         );

         initial begin

           clk = 0;

               rst_n = 0;

               data_valid = 0;

               #(`CLK_PERIOD*10);

               rst_n = 1;

           #(`CLK_PERIOD*10);

               data_valid = 1;

               #(`CLK_PERIOD*100);

               data_valid = 0;

               #(`CLK_PERIOD*10);

               $stop;

         end

always#(`CLK_PERIOD/2)       clk = ~clk; 

[email protected](posedge clk or negedge rst_n) begin

  if(!rst_n)

    din <= 8'd0;

  else if(data_valid)

    din <= {$random}%255;

  else

    din <= 8'b0;

end

[email protected](posedge clk or negedge rst_n) begin

  if(!rst_n)

    din_r <= 8'd0;

  else if(data_valid)

    din_r <= din;

  else

    din_r <= 8'b0;

end

Endmodule

比較子模組模擬波形

t

t+1

t+2

t+3

t+4

t+5

t+6

t+7

t+8

t+9

t+10

din

128

42

232

92

72

77

95

37

216

184

198

din_r

X

128

42

232

92

72

77

95

37

216

184

dout_min

X

X

42

42

92

72

72

77

37

37

184

dout_max

X

X

128

232

232

92

77

95

95

216

216

當我們需要做膨脹演算法時,資料取dout_max;當我們需要做腐蝕演算法時,資料取dout_min。

(2)一維形態學膨脹模組設計

我們要完成對nxn視窗的腐蝕或者膨脹首先我們要做影象行的一維腐蝕或膨脹。例如我們要做3x3視窗的腐蝕或膨脹,一維形態學腐蝕或膨脹如圖所示:

(3) 二維形態學腐蝕與膨脹子模組設計

形態學膨脹結果演示:

頂層原始碼:

////////////////////////////////////////////////////////////////

wire[15:0] rgb;

wire hs;

wirevs;

wirede; 

wireo_hs;

wireo_vs;

wireo_de;                                

wire[7 : 0]            o_y_8b;

wire[7 : 0]            o_cb_8b;

wire[7 : 0]            o_cr_8b;

wire[7 : 0]      dout;

//assign TFT_rgb ={o_y_8b[7:3],o_y_8b[7:2],o_y_8b[7:3]};    //Y

//assign TFT_rgb = {o_cb_8b[7:3],o_cb_8b[7:2],o_cb_8b[7:3]};  //cb

//assign TFT_rgb ={o_cr_8b[7:3],o_cr_8b[7:2],o_cr_8b[7:3]}; //cr

tft_ctrltft_ctrl(

       .Clk9M(clk9M),    //系統輸入時鐘9MHZ

       .Rst_n(Rst_n),     //復位輸入,低電平復位

       .data_in({Rd_data[7:0],Rd_data[15:8]}),  //待顯示資料

       .hcount(),             //TFT行掃描計數器

       .vcount(),             //TFT場掃描計數器

       .TFT_RGB(rgb),  //TFT資料輸出

       .TFT_HS(hs),             //TFT行同步訊號

       .TFT_VS(vs),              //TFT場同步訊號

       .TFT_CLK(TFT_clk),         //TFT畫素時鐘

       .TFT_DE(de),             //TFT資料使能

       .TFT_begin(tft_begin),

       .TFT_PWM(TFT_pwm)            //TFT背光控制

       );

rgb_to_ycbcr  rgb_to_ycbcr_inst(

                              .clk(TFT_clk),

                              .i_r_8b({rgb[15:11],3'b0}),

                              .i_g_8b({rgb[10:5],2'b0}),

                              .i_b_8b({rgb[4:0],3'b0}),

                              .i_h_sync(hs),

                              .i_v_sync(vs),

                              .i_data_en(de),

                              .o_y_8b(o_y_8b),

                              .o_cb_8b(o_cb_8b),

                              .o_cr_8b(o_cr_8b),

                              .o_h_sync(o_hs),

                              .o_v_sync(o_vs),                                                                                                 

                              .o_data_en(o_de)                                                                                               

                                          );

/*                                       

erode erode_inst(

     .clk(TFT_clk),

              .rst_n(Rst_n),

              .hs_in(o_hs),

              .vs_in(o_vs),

              .din(o_y_8b),

              .din_valid(o_de),

              .dout(dout),

              .dout_valid(TFT_de),

              .hs_out(TFT_hs),

              .vs_out(TFT_vs)

              );    

*/

dilatedilate_inst(

      .clk(TFT_clk),

              .rst_n(Rst_n),

              .hs_in(o_hs),

              .vs_in(o_vs),

              .din(o_y_8b),

              .din_valid(o_de),

              .dout(dout),

              .dout_valid(TFT_de),

              .hs_out(TFT_hs),

              .vs_out(TFT_vs)

              );           

assignTFT_rgb = {dout[7:3],dout[7:2],dout[7:3]};    //Y

//assign TFT_rgb ={o_y_8b[7:3],o_y_8b[7:2],o_y_8b[7:3]};    //Y     


歡迎大家關注我的微信公眾號:FPGA開源工作室: