入力画像中に目的画像がある場合に、入力画像を目的画像にフィットするように透視変換行列を使って変形させる方法
※opencv-python 3.4にて動作確認済み
サンプル画像
今回は例として目的画像をレトロな写真とし、入力画像は目的画像をPIXUSでL判印刷して適当な角度で撮影したものを使用している。この工程によって用紙の変形や照明の反射が映りこむなどの外乱を発生させられる。
目的画像 | |
---|---|
入力画像 | |
変換結果 |
ソースコード
-
img1
: 目的画像 -
img2
: 入力画像 -
max_pts
:検出する特徴量の最大数 -
good_match_rate
:全体の特徴量から透視変換行列に使用する割合(上位から取得する)
import cv2
def alignImages(img1, img2,
max_pts=500, good_match_rate=0.15, min_match=10):
# https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html#feature-homography
# [1] ORBを用いて特徴量を検出する
# Initiate ORB detector
detector = cv2.ORB_create(max_pts)
# find the keypoints and descriptors with SIFT
kp1, des1 = detector.detectAndCompute(
cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY), None
)
kp2, des2 = detector.detectAndCompute(
cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY), None
)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# [2] 検出した特徴量の比較をしてマッチングをする
# Match descriptors.
matches = bf.match(des1, des2)
# Sort them in the order of their distance.
matches = sorted(matches, key=lambda x: x.distance)
good = matches[:int(len(matches) * good_match_rate)]
# [3] 十分な特徴量が集まったらそれを使って入力画像を変形する
if len(good) > min_match:
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)
# Find homography
h, mask = cv2.findHomography(dst_pts, src_pts, cv2.RANSAC)
# cv2.imwrite('draw_match.jpg', cv2.drawMatches(
# img1, kp1, img2, kp2, matches, None, flags=2))
# Use homography
height, width, channels = img1.shape
dst_img = cv2.warpPerspective(img2, h, (width, height))
return dst_img, h
else:
return img1, np.zeros((3, 3))
各工程の解説
[1] ORBを用いて特徴量を検出する
SIFTやSURFなど特徴量検出器はいろいろ種類があるが、速度を重視してORBを選択した。ORB以外の検出器を利用したい場合は下記を参照。
Feature Detection and Description
https://docs.opencv.org/3.0-beta/modules/features2d/doc/feature_detection_and_description.html
[2] 検出した特徴量の比較をしてマッチングをする
目的画像の特徴量des1
と、入力画像の特徴量des2
を比較してマッチングする。今回は総当たりのBasics of Brute-Force Matcherを使用しているが、FLANNなど他のマッチング方法を利用したい場合は下記を参照。
Feature Matching
https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_matcher/py_matcher.html
[3] 十分な特徴量が集まったらそれを使って入力画像を変形する
マッチングした特徴量を変換し、目的画像特徴点src_pts
と入力画像特徴点dst_pts
を用意する。findHomography()
ではRANSACを用いて透視変換行列h
を導出している。RANSACにより使用された特徴量の情報はmask
に格納されている。最後warpPerspective()
に入力画像と先ほど得られたh
を入力して画像を変換する。
findHomography
https://docs.opencv.org/3.0-beta/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#findhomography
warpPerspective
https://docs.opencv.org/3.0-beta/modules/imgproc/doc/geometric_transformations.html#warpperspective
以上