end0tknr's kipple - 新web写経開発

http://d.hatena.ne.jp/end0tknr/ から移転しました

画像処理 - vlfeatによるSIFT特徴点検出

先日のHarrisコーナー検出をその後、試してみましたが、どうも検出精度がイマイチ。

どうやら Harrisコーナー検出は拡大縮小のスケール変化に弱いらしい。

テイラー/マクローリン展開からのHarrisコーナー検出 (その2) - end0tknr's kipple - 新web写経開発

そこで、今回はSIFT特徴点検出を写経(Scale-Invariant Feature Transform).

実践コンピュータビジョン サンプルプログラム

SIFT特徴点の定義等については、別の機会で

SIFT特徴点検出とは?

http://www.vision.cs.chubu.ac.jp/sift/

上記urlに丁寧が解説がありますが、私の理解は次の通り。

SIFTでは、ガウシアン差分(DoG)を用いて抽出します。

{ \Large{
  D(x,σ) = [ G_{kσ}(x) - G_{σ}(x) ] \ast I(x) = \\\
  [ G_{kσ} - G_{σ} ] \ast I = I_{kσ} - I_σ
} }
  • Iσは、Gσによってぼかした画像
  • kは、スケールの分離度を決める定数
  • *は、畳み込みの意味

特徴点は、座標とスケールσの空間におけるD(x,σ)の極大点、極小点。

以上で特徴点の座標とスケールを得ることができ、次に特徴点の記述を行います。

SIFTでは回転に対し不変にする為、周辺の画像勾配と向きに基き、 主要な参照方向を決定します。 先日のHarrisでは正規化相互相関を用いましたが、 SIFTでは明度に対しロバストにする為、画像勾配を用います。

前準備 - install vlfeat

http://www.vlfeat.org/

SIFT特徴量検出自体は、外部ライブラリに任せます

cd ~/local
wget http://www.vlfeat.org/download/vlfeat-0.9.20.tar.gz
tar -xvf vlfeat-0.9.20.tar.gz
cd vlfeat-0.9.20
make
cd ..
ln -s vlfeat-0.9.20/bin/glnxa64 vlfeat

vlfeat を使った python script

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

from PIL import Image
import numpy
import matplotlib
matplotlib.use('Agg')
import matplotlib.pylab as plb
import os

IMNAME = 'empire.jpg'
SIFT_CMD = '/home/endo/local/vlfeat/sift'
PROCESS_IMAGE_PARAMS = "--edge-thresh 10 --peak-thresh 5"

def main():
    im1 = numpy.array(Image.open(IMNAME).convert('L'))
    # SIFT特徴点検出し、保存
    process_image(IMNAME,'empire.sift')
    # SIFT特徴点を読み出し
    l1,d1 = read_features_from_file('empire.sift')

    # SIFT特徴点を描画
    plb.figure()
    plb.gray()
    plot_features(im1,l1,circle=True)
    plb.savefig( '2_3_3.png' )


# 画像の特徴点を検出しfileに保存
def process_image(imagename,resultname,params=PROCESS_IMAGE_PARAMS):
    if imagename[-3:] != 'pgm':
        # pgmファイルを作成する
        im = Image.open(imagename).convert('L')
        imagename = 'tmp.pgm'
        im.save(imagename)

    cmmd = str(SIFT_CMD +" "+imagename+" --output="+resultname+ " "+params)
    os.system(cmmd)
    print 'processed to', resultname

# SIFT特徴量を読み込んで行列形式で返す
def read_features_from_file(filename):
    f = numpy.loadtxt(filename)
    return f[:,:4],f[:,4:] # 特徴点の配置と記述子


# 画像を特徴量とともに描画.
#   入力:im(配列形式の画像)、locs(各特徴量の座標とスケール、方向)
def plot_features(im,locs,circle=False):
    plb.imshow(im)
    if circle:
        for p in locs:
            draw_circle(p[:2],p[2])
    else:
        plb.plot(locs[:,0],locs[:,1],'ob')
    plb.axis('off')

def draw_circle(c,r):
    t = numpy.arange(0,1.01,.01)*2* numpy.pi
    x = r * numpy.cos(t) + c[0]
    y = r * numpy.sin(t) + c[1]
    plb.plot(x,y,'b',linewidth=2)

if __name__ == '__main__':
    main()

↑こう書くと↓こう表示されます f:id:end0tknr:20171001072748p:plain