end0tknr's kipple - 新web写経開発

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

SIFT特徴点検出結果の対応点探索 (python)

正規化相互相関を用いた Harrisコーナー検出結果の対応点探索 (python) - end0tknr's kipple - 新web写経開発

画像処理 - vlfeatによるSIFT特徴点検出 - end0tknr's kipple - 新web写経開発

上記のエントリの続きです。

最も一致する特徴点への距離の比を双方向で比較する がポイントです

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

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

#imname1 = 'crans_1_small.jpg'
#imname2 = 'crans_2_small.jpg'
imname1 = 'sf_view1.jpg'
imname2 = 'sf_view2.jpg'
#imname1 = 'climbing_1_small.jpg'
#imname2 = 'climbing_2_small.jpg'

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

def main():
    im1 = numpy.array(Image.open(imname1).convert('L'))
    im2 = numpy.array(Image.open(imname2).convert('L'))
    # 特徴量検出
    process_image(imname1,imname1 + '.sift')
    l1,d1 = read_features_from_file(imname1 + '.sift')
    process_image(imname2,imname2 + '.sift')
    l2,d2 = read_features_from_file(imname2 + '.sift')

    # 特徴量のマッチング
    matches = match_twosided(d1,d2)

    # マッチング結果の表示
    plb.figure()
    plb.gray()
    plot_matches(im1,im2,l1,l2,matches)
    plb.savefig( '2_3_4.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 sift to', resultname


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


def match_twosided(desc1,desc2):
    """ 双方向対称バージョンのmatch() """

    matches_12 = match(desc1,desc2)
    matches_21 = match(desc2,desc1)

    ndx_12 = matches_12.nonzero()[0]

    # 対称でないものは除去する
    for n in ndx_12:
        if matches_21[int(matches_12[n])] != n:
            matches_12[n] = 0

    return matches_12

def match(desc1,desc2):
    """ 第1の画像の各記述子について、第2の画像の対応点を求める。
    入力:desc1(第1の画像の記述子)、desc2(第2の画像の記述子)"""

    desc1 = numpy.array([d/numpy.linalg.norm(d) for d in desc1])
    desc2 = numpy.array([d/numpy.linalg.norm(d) for d in desc2])

    dist_ratio = 0.6
    desc1_size = desc1.shape

    matchscores = numpy.zeros(desc1_size[0],'int')
    desc2t = desc2.T # あらかじめ転置行列を計算しておく

    for i in range(desc1_size[0]):
        dotprods = numpy.dot(desc1[i,:],desc2t) # 内積ベクトル
        dotprods = 0.9999*dotprods
        # 第2の画像の特徴点の逆余弦を求め、ソートし、番号を返す
        indx = numpy.argsort(numpy.arccos(dotprods))

        # 最も近い近接点との角度が、2番目に近いもののdist_rasio倍以下か?
        if numpy.arccos(dotprods)[indx[0]]<dist_ratio * numpy.arccos(dotprods)[indx[1]]:
            matchscores[i] = int(indx[0])

    return matchscores

def plot_matches(im1,im2,locs1,locs2,matchscores,show_below=True):
    """ 対応点を線で結んで画像を表示する
    入力: im1,im2(配列形式の画像)、locs1,locs2(特徴点座標)
    machescores(match()の出力)、
    show_below(対応の下に画像を表示するならTrue)"""

    im3 = appendimages(im1,im2)
    if show_below:
        im3 = numpy.vstack((im3,im3))

    plb.imshow(im3)

    cols1 = im1.shape[1]
    for i,m in enumerate(matchscores):
        if m>0: plb.plot([locs1[i][0],locs2[m][0]+cols1],[locs1[i][1],locs2[m][1]],'c')
    plb.axis('off')


def appendimages(im1,im2):
    """ 2つの画像を左右に並べた画像を返す """
    
    # 行の少ない方を選び、空行を0で埋める
    rows1 = im1.shape[0]
    rows2 = im2.shape[0]

    if rows1 < rows2:
        im1 = numpy.concatenate((im1,numpy.zeros((rows2-rows1,im1.shape[1]))),axis=0)
    elif rows1 > rows2:
        im2 = numpy.concatenate((im2,numpy.zeros((rows1-rows2,im2.shape[1]))),axis=0)
    # 行が同じなら、0で埋める必要はない
    return numpy.concatenate((im1,im2), axis=1)


if __name__ == '__main__':
    main()

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