天天看點

【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作

1.軟體版本

MATLAB2013b,vivado2019.2

2.本算法理論知識

       指紋識别技術是指使用取像裝置讀取指紋圖像,通過識别軟體提取出指紋圖像中的特征資料,然後根據比對算法得到的結果鑒别指紋所有人身份的生物特征識别技術。指紋識别系統主要涉及三大步驟:指紋圖像預處理、特征提取、特征比對三個部分,其中預處理部分又可分為歸一化、圖像濾波增強、二值化和細化等幾個步驟。系統流程框圖如圖1-1所示。下面對這三個個部分做一下簡單的介紹。

【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作
  1. 指紋的基本特征

指紋其實是比較複雜的。與人工處理不同,許多生物識别技術公司并不直接存儲指紋的圖象。多年來在各個公司及其研究機構産生了許多數字化的算法(美國有關法律認為,指紋圖象屬于個人隐私,是以不能直接存儲指紋圖象)。但指紋識别算法最終都歸結為在指紋圖象上找到并比對指紋的特征。

指紋識别系統中,通常采用全局和局部兩種層次的結構特征。兩枚指紋可能具有相同的全局特征,但局部特征卻不可能完全相同。

  1. 全局特征

全局特征是指那些用人眼直接就可以觀察到的特征,包括:基本紋路圖案環型(loop),弓型(arch),螺旋型(whorl)如圖2-1所示。其他的指紋圖案都基于這三種基本圖案。僅僅依靠圖案類型來分辨指紋是遠遠不夠的,這隻是一個粗略的分類,但通過分類使得在大資料庫中搜尋指紋更為友善。

【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作

模式區是指指紋上包括了總體特征的區域,即從模式區就能夠分辨出指紋是屬于那一種類型的。有的指紋識别算法隻使用模式區的資料。Secure Touch的指紋識别算法使用了所取得的完整指紋而不僅僅是模式區進行分析和識别,如圖2所示。

【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作

 圖2模式區

核心點位于指紋紋路的漸進中心,它在讀取指紋和比對指紋時作為參考點。許多算法是基于核心點的,既隻能處理和識别具有核心點的指紋。核心點對于Secure Touch的指紋識别算法很重要,但沒有核心點的指紋它仍然能夠處理,如圖3所示。

【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作

 圖3核心點

三角點位于從核心點開始的第一個分叉點或者斷點、或者兩條紋路會聚處、孤立點、折轉處,或者指向這些奇異點。三角點提供了指紋紋路的計數跟蹤的開始之處,如圖4所示。

【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作

 指模式區内指紋紋路的數量。在計算指紋的紋數時,一般先在連接配接核心點和三角點,這條連線與指紋紋路相交的數量即可認為是指紋的紋數,如圖2-5所示。

【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作

細節特征提取的方法分為兩種:一種是從灰階圖像中提取特征,另一種是從細化二值圖像中提取特征。直接從灰階圖像中提取特征的算法一般是對灰階指紋紋線進行跟蹤,根據跟蹤結果尋找特征的位置和判斷特征的類型。這種方法省去了複雜的指紋圖像預處理過程,但是特征提取的算法卻十分複雜,而且由于噪聲等因素影響,特征資訊(位置、方向等)也不夠準确。目前大多數系統采用第二種方法,從細化二值圖像中提取特征,該方法比較簡單,在得到可靠的細化二值圖像後,隻需要一個3×3的模闆就可以将端點和分叉點提取出來。

特征點提取的好壞将直接影響比對的結果。現實中,指紋輸入時,由于汗漬、幹燥、按壓力度不同等影響,得到的指紋圖像大都含有斷紋、褶皺、模糊、灰階不均勻等品質問題,雖然經過預處理,圖像品質會有所改觀,但預處理算法對各個指紋的适應性和有效性也會不同,并且會引入新的噪聲,是以得到的細化二值圖像往往含有大量的僞特征點。僞特征點不僅會影響比對的速度,嚴重的會影響整個識别的正确率。是以提取特征點後要進行去僞處理,盡可能濾除僞特征點、保留真特征點。實踐中發現,僞特征點的數量一般占總特征數量的一半以上,是以去僞是必不可少的過程。去僞過程可以在兩個階段進行:一是在特征提取之前對細化二值圖像進行平滑、去除毛刺、連接配接斷紋等操作,然後提取特征作為真特征;另一種是在特征提取之後,根據特征之間的互相關系,盡可能準确的識别僞特征點并濾除它們。前者直接對圖像進行修補,操作比較複雜,容易引入新的僞特征;後者對特征提取後的資料進行判斷,識别比較麻煩,但是速度較快本文采用第二種方法,即從已提取的特征點中濾除僞特征,保留真特征。

3.部分核心代碼

`timescale 1ns / 1ps
//
// Company: 
// Engineer:       ThinkSpark(CJY)
// 
// Create Date:    10:46:32 08/21/2009 
// Design Name: 
// Module Name:    spisensor 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//

`define effectvalue   1


module spisensor(//Output
                 cmd2tx_din_w,
         rd_data_cmd_w,
         send_rd_spidata_cmd_n_w,
                 clk180,        //spi transfer enable
         SCK_CPOL_0,               //clk for slave
         send_n_w,               
                 tx_rd_en_w,
                 tx_wr_en_w,
                 rx_wr_en_w,
                 locked_out0,
                 clk_24MHz,
         div10_cnt_w,
         sck_cnt8_w,
         //Input
         rx_full_n,
         rx_first_n,
         rx_empty_n,
         
         clk,                //system clock
         rst
                      
        );
   
output [7:0]     cmd2tx_din_w;
output [7:0]     rd_data_cmd_w;
output           SCK_CPOL_0;
output           clk180;
output           send_n_w;
output           tx_wr_en_w;
output           tx_rd_en_w;
output           rx_wr_en_w;
output           locked_out0;
output           clk_24MHz;
output [3:0]     div10_cnt_w;
output [2:0]     sck_cnt8_w;
output           send_rd_spidata_cmd_n_w;

input            clk;
input            rst;

input            rx_full_n;
input            rx_empty_n;
input            rx_first_n;



reg   [7:0]      cmdpad[31:0];    //filled with commands to be sent to slave after initialization
reg   [7:0]      rd_data_cmd_pad[1:0];
reg   [7:0]      cmd2tx_din;
reg   [7:0]      rd_data_cmd;
reg   [3:0]      div10_cnt;      //the time while div10_cnt=0 and div10_cnt=0- equals to an SCK period 
reg   [2:0]      sck_cnt8;       //sck_cnt8=7 indicates that 8bits have been transferred

reg   [3:0]      dcm_rst_delaycnt;
reg   [1:0]      rd_spidata_cmd_cnt;
reg              rd_spidata_cmd_cnt_en;
reg              send_rd_spidata_cmd_n;
reg              rd_data_cmd_rd_en;

reg   [15:0]     bytecnt;
reg   [5:0]      incr;
reg              tx_wr_en;
reg              tx_rd_en;
reg              rx_wr_en;
reg              transmision_done;
reg              addr;

reg              delaycnt_ctrl_n;
reg              transfer_n;    //data transfer enable bit,active low
reg              send_n;        //data send enable bit,active low
reg              recv_n;        //data receive enable bit,active low

reg    [7:0]     pre_state;
reg    [7:0]     nx_state;

wire             clk0_out0;
wire             locked_out0;
wire             clk0_out1;
wire             locked_out1;

wire             clk_24MHz;
wire             clk180;
wire             SCK_CPOL_0;
wire             SCK_CPOL_1;
wire             send_n_w;
//wire             transfer_n_w;
wire             tx_rd_en_w;
wire             tx_wr_en_w;
wire             rx_wr_en_w;
wire  [7:0]      cmd2tx_din_w; 
wire  [3:0]      div10_cnt_w;
wire  [2:0]      sck_cnt8_w; 
wire             send_rd_spidata_cmd_n_w;       

parameter        idle                     = 8'b00000000,
                 cmd2fifo                 = 8'b00000001,
                 sensor_initial           = 8'b00000010,
         rd_sensor                = 8'b00000100,
         rd_spistat               = 8'b00001000,
         rd_spidata               = 8'b00010000,
         send_data2uart           = 8'b00100000,
         last_data2uart           = 8'b01000000,
         spi_stop                 = 8'b10000000;
         
         

   
dcm0 mydcm0 (
    .CLKIN_IN(clk), 
    .RST_IN(transfer_n), 
    .CLKFX_OUT(SCK_CPOL_1), 
    .CLKFX180_OUT(SCK_CPOL_0),    
    .CLK0_OUT(), 
    .LOCKED_OUT(locked_out0)
    );   
 

dcm1 mydcm1 (
    .CLKIN_IN(clk), 
    .CLKFX_OUT(clk_24MHz),    
    .CLK0_OUT(), 
    .CLK180_OUT(clk180), 
    .LOCKED_OUT(locked_out1)
    );
//assign transfer_n_w =transfer_n; 

assign tx_wr_en_w=tx_wr_en;
assign tx_rd_en_w=tx_rd_en;
assign rx_wr_en_w=rx_wr_en;
assign send_n_w  =send_n;
assign cmd2tx_din_w=cmd2tx_din;
assign rd_data_cmd_w = rd_data_cmd;

assign div10_cnt_w = div10_cnt;
assign sck_cnt8_w  = sck_cnt8;
assign send_rd_spidata_cmd_n_w = send_rd_spidata_cmd_n;

//initialize cmdpad and transfer data in pad to Tx_fifo
always @(posedge clk)
begin
   if(rst == `effectvalue)
   begin
   cmdpad[0] <= 8'h75;
   cmdpad[1] <= 8'h7F;
   cmdpad[2] <= 8'h76;
   cmdpad[3] <= 8'h02;
   cmdpad[4] <= 8'h77;
   cmdpad[5] <= 8'h01;
   cmdpad[6] <= 8'h11;
   cmdpad[7] <= 8'h00;
   cmdpad[8] <= 8'h21;
   cmdpad[9] <= 8'h00;
   cmdpad[10] <= 8'h20;
   cmdpad[11] <= 8'h00;
   cmdpad[12] <= 8'h50;   
   cmdpad[13] <= 8'h00;
   cmdpad[14] <= 8'h00;
   cmdpad[15] <= 8'h00;
   end
   
end   

always @(posedge clk)
begin
   if(rst == `effectvalue)
      begin
       rd_data_cmd_pad[0] <= 8'h20;
     rd_data_cmd_pad[1] <= 8'h00;
    end
end


always @(posedge clk)
begin
   if(rst == `effectvalue)
      cmd2tx_din <= 8'b0;
   else      
    cmd2tx_din <= cmdpad[incr];
end


//address point to data be wrote to Tx_fifo 
always @(posedge clk)
begin
   if(rst == `effectvalue)
      incr <= 6'b0;   
   else if(incr == 31)  
      incr <= 31 ;
   else   
      incr <= incr + 1;   
end




//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

//transfer_n-\________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
//clk        |--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|
//div10_cnt   [  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ]    
//SCK       XXXXXXX________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/
//sck_cnt8         [00000000000000000000000000000000000000000000000000000][1111111111111111111111111111111111111111111111111111111111][2222222222222222222222222222222222222222222222222222222222][3333333333333333333333333333333333333333333333333333333333][4444444444444444444444444444444444444444444444444444444444][5555555555555555555555555555555555555555555555555555555555][6666666666666666666666666666666666666666666666666666666666][7777777777777777777777777777777777777777777777777777777777][0000000000000000000000000000000000000000000000000000000000][11111111111111111111111111111111111111]
//tx_rd_en      ------|_____|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/----------------------------------------------------------------------------------
//tx_shifterOOOOOOOOOOOOOOOOOOO[            d7 d6 d5 d4 d3 d2 d1 d0      ][         d6 d5 d4 d3 d2 d1 d0 0                           ][                  d5 d4 d3 d2 d1 d0 0 0                   ][                  d4 d3 d2 d1 d0 0 0 0                    ][                    d3 d2 d1 d0 0 0 0 0                   ][                        d2 d1 d0 0 0 0 0 0                ][                  d1  d0  0  0  0  0  0  0                ][                      d0  0  0  0  0  0  0  0                               ][     d7 d6 d5 d4 d3 d2 d1 d0            ][           d6 d5 d4 d3 d2 d1 d0 0 ] 
//MOSI     OOOOOOOOOOOOOO000000000000000000[----------------------------d7----------------------------][----------------------------d6----------------------------][----------------------------d5----------------------------][----------------------------d4----------------------------][----------------------------d3----------------------------][----------------------------d2----------------------------][----------------------------d1----------------------------][----------------------------d0----------------------------][----------------------------d7----------------------------][--d6--]
//MISO  XXXXX[----------------------------D7-----------------------------][----------------------------D6----------------------------][----------------------------D5----------------------------][----------------------------D4----------------------------][----------------------------D3----------------------------][----------------------------D2----------------------------][----------------------------D1----------------------------][----------------------------D0----------------------------][----------------------------D7----------------------------][----------------------------D7--------
//rx_shifter0000000000000000000000000000000[                        0 0 0 0 0 0 0 D7                  ][                        0 0 0 0 0 0 D7 D6                 ][                       0 0 0 0 0 D7 D6 D5                 ][                        0 0 0 0 D7 D6 D5 D4               ][                      0 0 0 D7 D6 D5 D4 D3                ][                    0 0 D7 D6 D5 D4 D3 D2                 ][                       0 D7 D6 D5 D4 D3 D2 D1             ][                     D7 D6 D5 D4 D3 D2 D1 D0              ][                        0 0 0 0 0 0 0 D7                  ] 
//rx_wr_en------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/-----------------------------------------------------------------
//----------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------
//the time while div10_cnt=0 and div10_cnt=0- equals to an SCK period   
always @(posedge clk)
begin
   if( (rst == `effectvalue) || (transfer_n == 1'b1) )
      div10_cnt <= 4'b0;
   else if(div10_cnt == 9)
      div10_cnt <= 4'b0;
   else if(locked_out0 == 1'b1)
      div10_cnt <= div10_cnt + 1;
end
  
//----------------------------------------------------------------------------------------  
//3bits counter for SCK cycles, one counting cycle indicates one Byte transmission done 
always @ (posedge clk)
begin
   if( (rst == `effectvalue) || (transfer_n == 1'b1) )
      sck_cnt8 <= 3'b0;
   else if( (div10_cnt == 9) && (locked_out0 == 1'b1) )          //?????????????????????
      sck_cnt8 <= sck_cnt8 + 1;
   
end

//--------------------------------------------------------------------------------------------------
//------------control reading from tx_fifo and writing to rx_fifo----------------------------------
//---------------------------------begin-----------------------------------------------------------
always @(posedge clk180)                      //---- @posedge clk180 will work more precisely-----
begin
   if( (rst == `effectvalue) || (send_n == 1'b1) )        //not to read data from tx_fifo when send_n=1
      tx_rd_en <= 1'b1;
   else if( (locked_out0 == 1'b1) && (sck_cnt8 == 0) &&
            (div10_cnt == 0) )
      tx_rd_en <= 1'b0;
   else
      tx_rd_en <= 1'b1;   
end


always @(posedge clk180)
begin
   if( (rst == `effectvalue) || (send_rd_spidata_cmd_n == 1'b1) )
     rd_data_cmd_rd_en <= 1'b1;
   else if( (locked_out0 == 1'b1) && (sck_cnt8 == 0) &&
            (div10_cnt == 0) )
   rd_data_cmd_rd_en <= 1'b0;
   else
     rd_data_cmd_rd_en <= 1'b1;
end

always @(posedge clk)
begin
   if(rst == `effectvalue)
      rd_data_cmd <= 8'b0;
   else if(rd_data_cmd_rd_en == 1'b0)
      rd_data_cmd <= rd_data_cmd_pad[addr];
end

always @(posedge clk)
begin
   if(rst == `effectvalue)
      addr <= 1'b0;
   else if (rd_data_cmd_rd_en == 1'b0) 
      addr <= ~addr;
end

always @(posedge clk)
begin
   if( (rst == `effectvalue) || (rx_full_n == 1'b0) )
      rd_spidata_cmd_cnt <= 2'b0;
   else if(rd_spidata_cmd_cnt == 2)
      rd_spidata_cmd_cnt <= 2;
   else if( (rd_spidata_cmd_cnt_en == 1'b0) && ( sck_cnt8 == 7 ) &&
             (div10_cnt == 9) )
      rd_spidata_cmd_cnt <= rd_spidata_cmd_cnt + 1;
end
///

always @(posedge clk180)                                 //---- @posedge clk180 will work more precisely-----
begin
   if( (rst == `effectvalue) || (recv_n == 1'b1) )       //not to write to rx_fifo when recv_n=1
      rx_wr_en <= 1'b1;
   else if( (locked_out0 == 1'b1) && (sck_cnt8 == 7) &&
            (div10_cnt == 6)  )                          //rx_wr_en be active while div10_cnt=6 and sck_cnt8=7 can 
    rx_wr_en <= 1'b0;                                  //leave some time space for bytecnt
   else
      rx_wr_en <= 1'b1;
end

//------------control reading from tx_fifo and writing to rx_fifo----------------------------------
//---------------------------------end-----------------------------------------------------------

always @(posedge clk)
begin
   if( (rst == `effectvalue) || 
       ( (transfer_n == 1'b1) && (transmision_done == 1'b1) ) )
     bytecnt <= 16'b0;   
   else if( (sck_cnt8 == 7) && ( div10_cnt == 7 ) )            // one more byte has been sent and received the moment
     bytecnt <= bytecnt + 1;                                   //sck_cnt8=7 and div10_cnt=7(as the wave showed following)
   else 
     bytecnt <= bytecnt;
end 


always @(posedge clk)
begin
   if( rst == `effectvalue )
      transmision_done <= 1'b0;
   else if( (transmision_done == 1'b1) && (div10_cnt == 0) )
      transmision_done <= 1'b0;
   else if( (pre_state == sensor_initial) && (bytecnt == 6) )
      transmision_done <= 1'b1;
   else if( (pre_state == rd_sensor) && (bytecnt == 370) )
      transmision_done <= 1'b1;
   else if( (pre_state == rd_spistat) && (bytecnt == 3) )
      transmision_done <= 1'b1;
   //else if( (pre_state == rd_regs) && (bytecnt == 18) )
      //transmision_done <= 1'b1;
   else if( (pre_state == rd_spidata) && (bytecnt == 31352) )
      transmision_done <= 1'b1;
   
end

always @( posedge clk )
begin
   if( (rst == `effectvalue) || (transmision_done == 1'b1) || (rx_full_n == 1'b0) )
      dcm_rst_delaycnt <= 4'b0;
   else if( dcm_rst_delaycnt == 9 )
      dcm_rst_delaycnt <= 9;
   else if( delaycnt_ctrl_n == 1'b0 )
      dcm_rst_delaycnt <= dcm_rst_delaycnt + 1;
end

//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

//transfer_n-\________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
//clk        |--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|
//div10_cnt   [  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ][  6 ][  7 ][  8 ][  9 ][  0 ][  1 ][  2 ][  3 ][  4 ][  5 ]    
//SCK       XXXXXXX________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/
//sck_cnt8         [00000000000000000000000000000000000000000000000000000][1111111111111111111111111111111111111111111111111111111111][2222222222222222222222222222222222222222222222222222222222][3333333333333333333333333333333333333333333333333333333333][4444444444444444444444444444444444444444444444444444444444][5555555555555555555555555555555555555555555555555555555555][6666666666666666666666666666666666666666666666666666666666][7777777777777777777777777777777777777777777777777777777777][0000000000000000000000000000000000000000000000000000000000][11111111111111111111111111111111111111]
//tx_rd_en      ------\_____/-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/----------------------------------------------------------------------------------
//tx_shifterOOOOOOOOOOOOOOOOOOO[            d7 d6 d5 d4 d3 d2 d1 d0      ][         d6 d5 d4 d3 d2 d1 d0 0                           ][                  d5 d4 d3 d2 d1 d0 0 0                   ][                  d4 d3 d2 d1 d0 0 0 0                    ][                    d3 d2 d1 d0 0 0 0 0                   ][                        d2 d1 d0 0 0 0 0 0                ][                  d1  d0  0  0  0  0  0  0                ][                      d0  0  0  0  0  0  0  0                               ][     d7 d6 d5 d4 d3 d2 d1 d0            ][           d6 d5 d4 d3 d2 d1 d0 0 ] 
//MOSI     OOOOOOOOOOOOOO000000000000000000[----------------------------d7----------------------------][----------------------------d6----------------------------][----------------------------d5----------------------------][----------------------------d4----------------------------][----------------------------d3----------------------------][----------------------------d2----------------------------][----------------------------d1----------------------------][----------------------------d0----------------------------][----------------------------d7----------------------------][--d6--]
//MISO  XXXXX[----------------------------D7-----------------------------][----------------------------D6----------------------------][----------------------------D5----------------------------][----------------------------D4----------------------------][----------------------------D3----------------------------][----------------------------D2----------------------------][----------------------------D1----------------------------][----------------------------D0----------------------------][----------------------------D7----------------------------][----------------------------D7--------
//rx_shifter0000000000000000000000000000000[                        0 0 0 0 0 0 0 D7                  ][                        0 0 0 0 0 0 D7 D6                 ][                       0 0 0 0 0 D7 D6 D5                 ][                        0 0 0 0 D7 D6 D5 D4               ][                      0 0 0 D7 D6 D5 D4 D3                ][                    0 0 D7 D6 D5 D4 D3 D2                 ][                       0 D7 D6 D5 D4 D3 D2 D1             ][                     D7 D6 D5 D4 D3 D2 D1 D0              ][                        0 0 0 0 0 0 0 D7                  ] 
//rx_wr_en------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/-------------------------------------------------------------
//----------------------------------------------------------------------------------------


//-------------------------------------------------------------------------------
//-------------------------------FSM---------------------------------------------
always @(posedge clk)
begin
   if(rst == `effectvalue)
      pre_state <= idle;
   else
      pre_state <= nx_state;
end

//-----------------------------------------------------------------------
//FSM state transform---------------------------------------------------
always @(pre_state or div10_cnt or incr or transmision_done or 
         rx_empty_n or rx_full_n)
begin
   case(pre_state)
   
      idle          : nx_state = cmd2fifo;
    
    cmd2fifo      : begin
                    if( incr == 31)                      //all 16 commands in cmdpad were wrote to Tx_fifo when incr=15
               nx_state = sensor_initial;
            else
               nx_state = cmd2fifo;              
            end
      
      sensor_initial: begin
                    if( (transmision_done == 1'b1) && (div10_cnt == 0))
               nx_state = rd_sensor;
            else
               nx_state = sensor_initial;              
            end
      
      rd_sensor      :begin
                      if( (transmision_done == 1'b1) && (div10_cnt == 0))
               nx_state = rd_spistat;
            else
               nx_state = rd_sensor;
            end
    
    rd_spistat     :begin
                    if( (transmision_done == 1'b1) && (div10_cnt == 0))
               nx_state = rd_spidata;
            else
               nx_state = rd_spistat;
            end
    
    rd_spidata     :begin
                    if( (transmision_done == 1'b1) && (div10_cnt == 0))
               nx_state = last_data2uart;
            else if(rx_full_n == 1'b0)                             //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!               
               nx_state = send_data2uart;
            else
               nx_state = rd_spidata;
            end
    send_data2uart:begin
                   if(rx_empty_n == 1'b0)
              nx_state = rd_spidata;
           else
              nx_state = send_data2uart;
           end
           
   last_data2uart:begin
                  if(rx_empty_n == 1'b0)
            nx_state = spi_stop;
          else
            nx_state = last_data2uart;
          end
            
      spi_stop       :   nx_state = spi_stop; 
    default        :   nx_state = idle;
            
   endcase
end
//---------FSM state transform-----------------------------------------------
//-----------------------------------------------------------------------------


//-------------------------------------------
//FSM control signals output
always @(pre_state  or rx_full_n or div10_cnt or
          incr  or bytecnt or dcm_rst_delaycnt or
      rd_spidata_cmd_cnt or rx_empty_n or rx_first_n )
begin
   case(pre_state)
   
      idle            :begin
                     tx_wr_en    = 1'b1;
             transfer_n  = 1'b1;
             send_n      = 1'b1;
             recv_n      = 1'b1;
             delaycnt_ctrl_n = 1'b1;
             send_rd_spidata_cmd_n = 1'b1;
             rd_spidata_cmd_cnt_en = 1'b1;
             end
    
    cmd2fifo        :begin
                     if( (incr == 0) && (incr == 31) )
                begin
                 tx_wr_en    = 1'b1;
               transfer_n  = 1'b1;
               send_n      = 1'b1;
               recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             else
                begin       
               tx_wr_en    = 1'b0;
               transfer_n  = 1'b1;
               send_n      = 1'b1;
               recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
                          end              
             end
    sensor_initial  :begin
                     if( (bytecnt == 6) && ( div10_cnt == 9) )
                begin
                 tx_wr_en    = 1'b1;
               transfer_n  = 1'b1;            // this will reset bytecnt when div10_cnt=9 
               send_n      = 1'b1;
               recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;               
                 
              end
             else if( dcm_rst_delaycnt <= 8)
                begin
                           tx_wr_en    = 1'b1;
               transfer_n  = 1'b1;                   
               send_n      = 1'b1;
               recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b0;
                             send_rd_spidata_cmd_n = 1'b1;
                             rd_spidata_cmd_cnt_en = 1'b1;               
                end
             else if(dcm_rst_delaycnt == 9)
                begin
                 tx_wr_en    = 1'b1;
               transfer_n  = 1'b0;                   
               send_n      = 1'b0;
               recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             else 
                begin
                 tx_wr_en    = 1'b1;
               transfer_n  = 1'b1;            // this will reset bytecnt when div10_cnt=9 
               send_n      = 1'b1;
               recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
                 
              end
             
             end
    rd_sensor       :begin
                     if( dcm_rst_delaycnt <= 8)
                begin
                 tx_wr_en    = 1'b1;
               transfer_n  = 1'b1;                   
               send_n      = 1'b1;
               recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b0;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             else if( (bytecnt < 2 ) && (dcm_rst_delaycnt == 9) )
                begin 
                   tx_wr_en    = 1'b1;
                 transfer_n  = 1'b0;                   
                 send_n      = 1'b0;
                 recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
                end
             else if( (bytecnt >=2) && (bytecnt <=370) && (dcm_rst_delaycnt == 9))
                begin
                 tx_wr_en    = 1'b1;
                 transfer_n  = 1'b0;                   
                 send_n      = 1'b1;
                 recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             else
                begin
                 tx_wr_en    = 1'b1;
                 transfer_n  = 1'b1;                   
                 send_n      = 1'b1;
                 recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             end
      rd_spistat      :begin
                     if( dcm_rst_delaycnt <= 8)
                begin
                 tx_wr_en    = 1'b1;
               transfer_n  = 1'b1;                   
               send_n      = 1'b1;
               recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b0;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
                     else if( (bytecnt < 2) && (dcm_rst_delaycnt == 9) )
                begin 
                   tx_wr_en    = 1'b1;
                 transfer_n  = 1'b0;                   
                 send_n      = 1'b0;
                 recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             else if( (bytecnt >= 2) && (dcm_rst_delaycnt == 9) )
                begin                 
                   tx_wr_en    = 1'b1;
                 transfer_n  = 1'b0;                   
                 send_n      = 1'b1;
                 recv_n      = 1'b0;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             else
                begin                 
                   tx_wr_en    = 1'b1;
                 transfer_n  = 1'b1;                   
                 send_n      = 1'b1;
                 recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             end
      rd_spidata      :begin
                     if( dcm_rst_delaycnt <= 8)
                begin
                 tx_wr_en    = 1'b1;
               transfer_n  = 1'b1;                   
               send_n      = 1'b1;
               recv_n      = 1'b1;
                             delaycnt_ctrl_n = 1'b0;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
                     
             else if( (bytecnt > 10) && (rx_first_n == 1'b1) &&
                      (rx_empty_n == 1'b0) && ( rd_spidata_cmd_cnt < 2 ) )
              begin   
               tx_wr_en    = 1'b1;
                 transfer_n  = 1'b0;                   
                 send_n      = 1'b1;
                 recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b0;
               rd_spidata_cmd_cnt_en = 1'b0;
                end
             else if( (bytecnt > 10) && (rd_spidata_cmd_cnt == 2) )
                begin
                 tx_wr_en    = 1'b1;
                 transfer_n  = 1'b0;                   
                 send_n      = 1'b1;
                 recv_n      = 1'b0;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              
              end
             else if( (bytecnt < 2) && (dcm_rst_delaycnt == 9)  )  
              begin 
                   tx_wr_en    = 1'b1;
                 transfer_n  = 1'b0;                   
                 send_n      = 1'b0;
                 recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             else if( (bytecnt >= 2) && (rx_full_n == 1'b1) )
                begin                 
                   tx_wr_en    = 1'b1;
                 transfer_n  = 1'b0;                   
                 send_n      = 1'b1;
                 recv_n      = 1'b0;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             else
                begin                 
                   tx_wr_en    = 1'b1;
                 transfer_n  = 1'b1;                   
                 send_n      = 1'b1;
                 recv_n      = 1'b1;
               delaycnt_ctrl_n = 1'b1;
               send_rd_spidata_cmd_n = 1'b1;
               rd_spidata_cmd_cnt_en = 1'b1;
              end
             end
             
    send_data2uart,
    last_data2uart, 
      spi_stop        :begin
                        tx_wr_en    = 1'b1;
              transfer_n  = 1'b1;                   
              send_n      = 1'b1;
              recv_n      = 1'b1;
              delaycnt_ctrl_n = 1'b1;
              send_rd_spidata_cmd_n = 1'b1;
              rd_spidata_cmd_cnt_en = 1'b1;
             end
     default         : begin
                        tx_wr_en    = 1'b1;
              transfer_n  = 1'b1;                   
              send_n      = 1'b1;
              recv_n      = 1'b1;
              delaycnt_ctrl_n = 1'b1;
              send_rd_spidata_cmd_n = 1'b1;
              rd_spidata_cmd_cnt_en = 1'b1;
             end
   
  endcase
end
//FSM control signals output
//--------------------------------------------


endmodule      
%ProcessOfFingerPrint.m
clc;
clear;
clear all;
%--------------加載指紋文本檔案-----------------------
fid=fopen('1x1.txt','r');
dd=fscanf(fid,'%x');
fclose(fid);
array=dd';
for i=0:199
    OriginFingerPrint(i+1,1:152)=array(i*152+1:i*152+152);
end
figure('name','OriginFingerPrint');
imshow(uint8(OriginFingerPrint));
%---------------灰階圖像取反--------------------------
ReverseFingerPrint=255-OriginFingerPrint;
figure('name','ReverseFingerPrint');
imshow(uint8(ReverseFingerPrint));
%---------------進行二維适應性去噪過濾處理------------
FrontFilt=wiener2(ReverseFingerPrint,[3 3]);
figure('name','FrontFilt');
imshow(uint8(FrontFilt));
%---------------擴大圖像的像素至400x304---------------
EnhanceFingerPrint=enhance_finger(FrontFilt);
%---------------取圖像的中心點------------------------
[XofCenter,YofCenter] = centralizing(EnhanceFingerPrint);
figure('name','EnhanceFingerPrint');
imshow(uint8(EnhanceFingerPrint));
hold on;
plot(XofCenter,YofCenter,'or');
hold off;
%---------------二值化圖像-----------------------------
[BinarizationFingerPrint,theta]=orientation(EnhanceFingerPrint);
figure('name','BinarizationFingerPrint');
imshow(uint8(BinarizationFingerPrint));
%----------------進行中值濾波處理----------------------
AfterFilt=median_filter(BinarizationFingerPrint);
figure('name','AfterFilt');
imshow(uint8(AfterFilt));
%----------------二值化圖像細化處理--------------------
ThinFingerPrint=thinning(AfterFilt);
figure('name','ThinFingerPrint');
imshow(uint8(ThinFingerPrint));
%----------------找尋細化圖像的特征點------------------
[Dpx,Dpy,Dpcount,Fpx,Fpy,Fpcount]=characterpoint(ThinFingerPrint);
hold on;
plot(Dpy,Dpx,'o');%特征端點用'o'标注
plot(Fpy,Fpx,'+');%特征分叉點用'+'标注
plot(XofCenter,YofCenter,'*r');%中心點用紅色'*'标注
hold off;
%-----------------生成各特征點相對中心點的距離向量---------------
Dpcount=size(Dpx,2);
Fpcount=size(Fpx,2);
for i=1:Dpcount
    Dpdistant(i)=sqrt((Dpx(i)-YofCenter)^2+(Dpy(i)-XofCenter)^2);
end
for j=1:Fpcount
    Fpdistant(j)=sqrt((Fpx(j)-YofCenter)^2+(Fpy(j)-XofCenter)^2);
end   
%------------------特征模闆建立----------------------------------------------
for i=1:Dpcount
    PointOfModel(i,1)=1;%特征端點分類為1
    PointOfModel(i,2)=Dpdistant(i);%特征端點相對中心點的距離向量
    PointOfModel(i,3)=theta(Dpx(i),Dpy(i))-theta(YofCenter,XofCenter);%特征端點相對中心點的方向向量
end
for i=Dpcount+1:Dpcount+Fpcount
    PointOfModel(i,1)=2;%特征分叉點分類為2
    PointOfModel(i,2)=Fpdistant(i-Dpcount);%特征分叉點相對中心點的距離向量
    PointOfModel(i,3)=theta(Fpx(i-Dpcount),Fpy(i-Dpcount))-theta(YofCenter,XofCenter);%特征分叉點相對中心點的方向向量
end    
%--------------------------------------------------------
      

4.操作步驟與仿真結論

【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作
【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作
【指紋識别】基于MATLAB/FPGA的指紋識别算法仿真實作
  1. FSM子產品:其主要的功能是在系統複位後初始化Tx FIFO(發送FIFO),即把随後要發送給SPI傳感器的指令寫入Tx FIFO内,然後在滿足SPI傳感器時序的前提下,FSM子產品通過控制Tx_rd_en信号讀出Tx FIFO裡的指令并傳送到SPI子產品;在Rx FIFO接收指紋資料時,當數滿标志位Rx_full_n有效後說明接收FIFO裡的資料已滿,這時FSM就會通過相關信号來控制SPI停止接收資料,當檢測到Rx_empty_n有效後(接收FIFO已空),FSM就會發出相應的信号啟動SPI繼續接收資料,直到指紋資料全部接收完畢。
  2. Tx FIFO子產品:主要功能是在初始化的時候裝載待發指令,然後在Tx_rd_en信号的控制下把指令發送出去,因為總的指令數不超過FIFO的深度,是以無須空滿标志位。
  3. SPI子產品:其主要功能是在與外部傳感器通信的時候向傳感器提供時鐘信号SCK,以及片選信号SS,其中SCK和SS信号最初由FSM産生并由FSM進行控制;當需要向傳感器發送指令時,FSM會啟動SCK和SS信号,同時SPI接受從Tx FIFO讀出的指令并暫存到一個8bit移位寄存器tx_shifter[7:0]中,每過一個SCK周期發送一位到至MOSI,發送完1Byte後tx_shifter會重新裝載新指令繼續發送直到指令發送完畢;當SPI從傳感器接收資料時,FSM會啟動SCK和SS信号,SPI中移位寄存器rx_shifter[7:0]會在SCK的上升沿采集輸入端口MISO的資料并移一位,每8個SCK時鐘周期rx_shifter中的資料就會在FSM的控制下寫入Rx FIFO,直到資料接收完畢。
  4. Rx FIFO子產品:此子產品的主要功能是對已接收到的指紋資料進行緩存,避免指紋的資料丢失,因為此系統中SPI序列槽的工作頻率為5MHz,而UART序列槽的工作頻率為38400Hz,UART從Rx FIFO取資料的速度遠小于SPI往Rx FIFO中寫資料的速度。Rx FIFO可以向UART和FSM提供數空和數滿标志位rx_empty_n,和rx_full_n,是以SPI和UART可以協調工作。
  5. UART子產品:些子產品主要功能是和計算機進行通信,把接收到的指紋資料通過計算機的終端顯示出來。當UART檢測到rx_full_n有效後,就會發出讀信号Rx_rd_en讀出FIFO中的資料發送給計算機,當檢測到rx_empty_n有效後停止。

5.參考文獻 

繼續閱讀