5
3

More than 5 years have passed since last update.

Python3系でORB+RANSACでの画像間マッチングの実装

Last updated at Posted at 2019-05-24

はじめに

今回は、二枚の画像に対してORB特徴量を抽出し,
二枚の画像で得た特徴点を元にマッチングを行う方法について説明します。
以下の画像のように二枚の画像それぞれ特徴点を抽出し、対応する特徴点を結びます。
draw_match.jpg

ORB (Oriented FAST and Rotated BRIEF)

ORBは、特徴点、特徴量を抽出するアルゴリズムで、カメラの運動(移動、回転、ズーム)にロバスト(不変)なアルゴリズムで、ORBができた経緯としてもともとSIFTというアルゴリズムが、移動、回転に加えてズームにロバストなアルゴリズムであったが、SIFTは計算量が多く、低速だったため、速度を改良したSURFというアルゴリズムがでてきました。ただし、SIFTもSURFも特許で守られているため、使用するためには特許料を払う必要があります。
そこで、移動、回転、ズームに対してロバストであり、計算速度も速く、フリーで使うことができるORBというアルゴリズムが2011年に開発されました。

RANSAC

今回のように、画像から特徴点を取るといった場合に、ノイズなどの原因で法則性から大きく外れた、外れ値がデータに含まれる場合があります。その外れ値をうまく無視して、法則性を推定する手法としてRANSACがあります。

ORB+RANSACのマッチング

今回のプログラムでは画像間のマッチングを行う際に、抽出したORB特徴量を用い、マッチングの信頼度を上げるために、RANSACを適用します。
また、今回のプログラムを動かすPythonの環境はPython3系とします。
手順は以下のようになります。

  1. 画像ファイルの読み込み
  2. ORBで特徴点&特徴量の抽出
  3. RANSAC
  4. 画像に特徴点を書き込み
  5. 結果の出力
import numpy as np
import cv2
from matplotlib import pyplot as plt

MIN_MATCH_COUNT = 10 
good_match_rate = 0.15 #得られた特徴点のうち使用する点の割合

img1 = cv2.imread('./image1.png',0) # 一枚目
img2 = cv2.imread('./image2.png',0) # 二枚目

# Initiate ORB detector
orb = cv2.ORB_create()

# キーポイント検出,ORB記述
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# create BFmatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
#bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=False)
# Match descriptors.
matches = bf.match(des1,des2)


matches = sorted(matches, key = lambda x:x.distance)
good = matches[:int(len(matches) * good_match_rate)]

#MIN_MATCH_COUNT以上なら出力,それ以下ならelseへ
if len(good)>MIN_MATCH_COUNT:
    src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
    dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
#RANSAC
    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
    matchesMask = mask.ravel().tolist()

    h,w = img1.shape
    pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
    dst = cv2.perspectiveTransform(pts,M)

    img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA)

else:
    print ("Not enough matches are found - %d/%d") % (len(good),MIN_MATCH_COUNT)
    matchesMask = None

draw_params = dict(matchColor = (0,255,0), # draw matches in green color
                   singlePointColor = None,
                   matchesMask = matchesMask, # draw only inliers
                   flags = 2)

img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)

#出力
plt.imshow(img3, 'gray'),plt.show()

結果

結果は以下に示すように、はじめにで示した図と比べて、
精度の高いマッチングが行えていることがわかります。
ransac-lena1.png

5
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3