Pythonを使用した指紋認識方法と実装

今学期には、「コンピューター情報を保護する方法と手段」という主題がスケジュールに登場しました。その一部は、生体認証、より具体的には指紋認識に関する実験室作業です。 また、最近、Habréでスキャン対象のデバイスに関する記事がありました。 ここで、認識アルゴリズムについて書くことにしました。





私の前に、学生として、かなり標準的なタスクがあります:指紋の検証(標準との比較)。 この研究室のものは今年だけ登場したので、方法論的なマニュアルはまだありません。 しかし、タスクの面白さを考慮して、Googleに行きました。



奇妙なことに、スキャナに関するトピックで示された記事の2番目の部分が最も有益であることが判明しました。 非常に理解しやすいように、いくつかのアルゴリズムについて説明しています。



1.相関の比較

このアプローチは、得られた結果に基づいて、異なるシフトと回転角度の2つの画像をピクセルごとに比較することで構成され、一致が判断されます。 (高度な複雑さのため、現代の条件では使用されません)



2.パターン比較

必要な精度に応じて、印刷の画像は領域に分割されます。 さらに、各領域のパターンは、パラメーターを使用して正弦波で記述されます。



このクラスのアルゴリズムは、スキャン時に高解像度を必要としません。



3.人のポイントによる比較

特徴点は、エンドポイントと分岐点です。 これらのポイントは両方の画像で強調表示され、その後、相関比較の方法によって、印刷物の一致に関する判定が発行されます。

比較的単純な実装と速度のため、これらのアルゴリズムはより一般的です。

私は、このタイプのアルゴリズムを実験室での実装に選択しました。 したがって、より詳細に説明します。



この記事では一般的なアイデアしか示していないため、引き続きGoogleを使用しました。 配信の3行目はこのプレゼンテーションでした。

選択したアプローチを実装するための手順をかなり詳細に説明しています。



だから、アクションプラン:



実装はPythonで行うことが決定されました。 したがって、 Python自体(バージョン2.7.1があります)に加えて、 PIL(Python Imaging Library)で画像をピクセルに解析する必要があります。



ステップ1.二値化

それから私は発明しなかったし、額で非常に簡単にすべてをした。

defバイナリ( img ) :

bImg = [ ]

範囲内の i ( img。size [ 0 ] ) :

tmp = [ ]

範囲内の j ( img。size [ 1 ] ) :

t = img。 getpixel ( ( i、j ) )

p = t [ 0 ] * 0.3 + t [ 1 ] * 0.59 + t [ 2 ] * 0.11

p > 128の 場合 :

p = 1

その他 :

p = 0

tmp。 追加 ( p )

bImg。 追加 ( tmp )

戻り値


別の結果が必要な場合は、 「画像処理」ブログのトピックを参照してください。ここでは、2値化が頻繁に影響を受けます。



ステップ2.スケルトン化

グーグルのアルゴリズムが最も難しかったので、このステップは最大の困難を引き起こしました。 その結果、4つのアルゴリズムが見つかりました。



テンプレートの方法が選択されました。最初のセットは、テンプレートの2番目のセットとは異なり、画像のクロールが1回だけ必要なためです。 確かに、不正確さのレベルを下げるために、2番目のセットのテンプレートの一部が使用されます。



パターンは3 * 3マトリックスに対応します。ここで、中心要素はイメージトラバーサルの現在のピクセルです。

画像

ここで、グレーは色が重要でないピクセルです



最初の8つのテンプレートが主要部分です。 「ノイズ」を除去するために下から4つ、これら4つは90、180、270度回転させることもでき、画像の2番目のバイパスで検索されます。



テンプレートに遭遇した場合、中央のピクセルは白く塗られます(スケルトンに属していません)。 削除オプションが残っている間、トラバーサルは続行します。



このアクションのコードは、いくつかの機能に分かれています。

def tmpDelete ( img ) : #スケルトン化プロシージャの呼び出し、入力時にリストのリスト(2値化後)

w = len ( img )

h = len ( img [ 0 ] )

カウント= 1

カウントしながら ! = 0 : #少なくとも1つのピクセルが削除されたpokを繰り返します

カウント=削除( img、w、h )

カウントする場合 :

delete2 ( img、w、h )





def delete ( img、w、h ) : #メインセットからピクセルを削除し、削除された数を返します

カウント= 0

範囲内の iの場合( 1 、h- 1 ) :

j が 範囲 ( 1 、w- 1 )の場合 :

if img [ j ] [ i ] == 0 :

削除可能な場合 ( img、j、i ) :

img [ j ] [ i ] = 1

カウント+ = 1

戻り回数



def delete2 ( img、w、h ) : #ノイズセットからピクセルを削除

範囲内の iの場合( 1 、h- 1 ) :

j が 範囲 ( 1 、w- 1 )の場合 :

if img [ j ] [ i ] == 0 :

deletable2 ( img、j、i )の場合 :

img [ j ] [ i ] = 1





def fringe ( a ) : #3 * 3ノイズの定義

t = [ [ 1、1、1、1、0、1、1、1、1 ] 、



[ 1、1、1、1、0、1、1、0、0 ] 、

[1、1、1、0、0、1、0、1、1 ] 、

[ 0、0、1、1、0、1、1、1、1 ] 、

[1、1、0、1、0、0、1、1、1 ] 、



[1、1、1、1、0、1、0、0、1 ] 、

[ 0、1、1、0、0、1、1、1、1 ] 、

[1、0、0、1、0、1、1、1、1 ] 、

[ 1、1、1、1、0、0、1、1、0 ] 、



[ 1、1、1、1、0、1、0、0、0 ] 、

[ 0、1、1、0、0、1、0、1、1 ] 、

[ 0、0、0、1、0、1、1、1、1 ] 、

[ 1、1、0、1、0、0、1、1、0 ] ]

tのiの場合:

a == iの場合 :

真を 返す



def check ( a ) : #3 * 3がメインテンプレートに属するかどうかを判断する

t123457 = [ 1、1、0、0、1、0 ]

t013457 = [ 1、1、1、0、0、0 ]

t134567 = [ 0、1、0、0、1、1 ]

t134578 = [ 0、0、0、1、1、1 ]

t0123457 = [ 1、1、1、0、0、0、0 ]

t0134567 = [ 1、0、1、0、0、1、0 ]

t1345678 = [ 0、0、0、0、1、1、1 ]

t1234578 = [ 0、1、0、0、1、0、1 ]



t = [ a [ 1 ] 、a [ 2 ] 、a [ 3 ] 、a [ 4 ] 、a [ 5 ] 、a [ 7 ] ]

t == t123457の場合 :

真を 返す

t = [ a [ 0 ] 、a [ 1 ] 、a [ 3 ] 、a [ 4 ] 、a [ 5 ] 、a [ 7 ] ]

t == t013457の場合 :

真を 返す

t = [ a [ 1 ] 、a [ 3 ] 、a [ 4 ] 、a [ 5 ] 、a [ 6 ] 、a [ 7 ] ]

t == t134567の場合 :

真を 返す

t = [ a [ 1 ] 、a [ 3 ] 、a [ 4 ] 、a [ 5 ] 、a [ 7 ] 、a [ 8 ] ]

t == t134578の場合 :

真を 返す

t = [ a [ 0 ] 、a [ 1 ] 、a [ 2 ] 、a [ 3 ] 、a [ 4 ] 、a [ 5 ] 、a [ 7 ] ]

t == t0123457の場合 :

真を 返す

t = [ a [ 1 ] 、a [ 3 ] 、a [ 4 ] 、a [ 5 ] 、a [ 6 ] 、a [ 7 ] 、a [ 8 ] ]

t == t1345678の場合 :

真を 返す

t = [ a [ 0 ] 、a [ 1 ] 、a [ 3 ] 、a [ 4 ] 、a [ 5 ] 、a [ 6 ] 、a [ 7 ] ]

t == t0134567の場合 :

真を 返す

t = [ a [ 1 ] 、a [ 2 ] 、a [ 3 ] 、a [ 4 ] 、a [ 5 ] 、a [ 7 ] 、a [ 8 ] ]

t == t1234578の場合 :

真を 返す



def deletable ( img、x、y ) : #受信3 * 3、メインの検証のために送信

a = [ ]

範囲内の iの場合( y- 1 、y + 2 ) :

j が 範囲 ( x- 1 、x + 2 )の場合 :

a。 追加 ( img [ j ] [ i ] )

返却チェック( a )



def deletable2 ( img、x、y ) : #3 * 3を受信し、ノイズのチェックのために送信します

a = [ ]

範囲内の iの場合( y- 1 、y + 2 ) :

j が 範囲 ( x- 1 、x + 2 )の場合 :

a。 追加 ( img [ j ] [ i ] )

戻りフリンジ( a )




ステップ3.特異点を強調表示する

ここではすべてが簡単です。 8ポイントの近傍に黒が1つしかない場合、これが終点です。 それらが2つある場合、これは単なる行のポイントです。 3つは分岐点です。

def checkThisPoint ( img、x、y ) : #近所の黒人を数える

c = 0

範囲 ( x- 1 、x + 2 )の iの場合:

j が 範囲 ( y- 1 、y + 2 )の場合 :

if img [ i ] [ j ] == 0 :

c + = 1

return c- 1



def findCheckPoint ( img ) : #分岐点のリストと終了

x = len ( img )

y = len ( img [ 0 ] )

branchPoint = [ ]

endPoint = [ ]

範囲 ( x )の iの場合:

範囲 ( y )の jの場合:

if img [ i ] [ j ] == 0 :

t = checkThisPoint ( img、i、j )

t == 1の 場合 :

エンドポイント。 追加 ( ( i、j ) )

t == 3の 場合 :

branchPoint。 追加 ( ( i、j ) )

return ( branchPoint、endPoint )


唯一の問題は、ノイズの完全な除去ではなく、特異点として認識されたプロセスの出現につながりました。 それらを考慮に入れないために、密接な(10 * 10)分岐点と終点の削除が行われました。

def __removeDouble ( x、y ) : #別のリストに同じものがない要素のリストを返します

z = [ ]

xのiの場合:

c = true

yのjの場合:

i == jの場合 :

c = False

cの場合 :

z。 追加 ( i )

yのiの場合:

c = true

xのjの場合:

i == jの場合 :

c = False

cの場合 :

z。 追加 ( i )

zを返す



def delNoisePoint ( r ) : #入力タプル(分岐、末尾)

tmp = [ ]

tmp2 = [ ]

for i in r [ 1 ] :

x = 範囲 ( i [ 0 ] -5 、i [ 0 ] + 5 )

y = 範囲 ( i [ 1 ] -5 、i [ 1 ] + 5 )

r [ 0 ]の jの場合:

xのj [ 0 ] および yのj [ 1 ]の場合 :

tmp。 追加 ( i )

tmp2。 追加 ( j )

return ( __removeDouble ( r [ 0 ] 、tmp2 ) 、__ removeDouble ( r [ 1 ] 、tmp ) )




ステップ4.ポイントを比較する

30 * 30の近傍に入り、同じタイプのポイントであるポイントの簡単な検索。

def matchingPoint ( r、v ) : #input:参照点のタプルとチェックされたもののタプル。 出力(一致、合計)

すべて = 0

一致= 0

v [ 0 ]の iの場合:

x = range ( i [ 0 ] -15 、i [ 0 ] + 15 )

y = 範囲 ( i [ 1 ] -15 、i [ 1 ] + 15 )

すべて + = 1

r [ 0 ]の jの場合:

xのj [ 0 ] および yのj [ 1 ]の場合 :

マッチ+ = 1

破る

v [ 1 ]の iの場合:

x = range ( i [ 0 ] -15 、i [ 0 ] + 15 )

y = 範囲 ( i [ 1 ] -15 、i [ 1 ] + 15 )

すべて + = 1

r [ 1 ]の jの場合:

xのj [ 0 ] および yのj [ 1 ]の場合 :

マッチ+ = 1

破る



リターン (一致、 すべて )




オプション:

すべてのコードは、同じサイズの画像に対して有効です(ただし、異なる画像でも機能します)。



結論:

1.この実装は単純で不器用です。 たとえば、特定のポイントで線の角度を調べるなど、いくつかのチェックを追加することができます。 チェック時に、同じタイプの多くのポイントが近傍に落ちた場合に、すでに見つかったペアを破棄します。

2. Pythonでの実装はかなり遅いです。私のマシンでの実行速度は、人の往来が多いアイテムにはまったく適していません。 NumPyを使用するとパフォーマンスが向上する可能性があり、私も最高の実装者ではありません。

3. ここで完全なコードを取得します 。 このキットでテスト済み。



PS pythonの方がやや弱いので、コードについてコメントしたいと思います。 まあ、指紋採取に真剣に取り組んでいる人の意見。



All Articles