写真画像上に写っている物体の位置、つまり座標が実際にはどんな座標なのかを知りたいシーンがあると思います。下図のように座標または大きさが既知の四角形が実物にも画像上にも存在する場合は、射影変換(Homography transformation)を使うことで、画像上の座標から、実際の座標を算出することができます。実際にOepnCV (Visual Studio Code + Python) を使って算出する方法を説明します。
写真上の座標と実物の座標間において、下図のような数式が成り立つ射影変換行列を算出します。この射影変換行列はOpenCVのgetPerspectiveTransform関数を用いて算出することが出来ます。
そして下図の式のように計算することで、画像上に写っているピンの座標から、射影変換行列を用いて、実際のピンの座標を算出することが可能です。
理論はここまでとして、実際にOpenCVを使って算出してみましょう。下記が実際にOpenCVのgetPerspectiveTransform関数を用いて射影変換行列を算出し、さらにその射影変換行列を用いて画像上の座標から実際の座標を算出するPythonのソースコードです。
import cv2
import numpy as np
def compute_real_coord(coord_in_pic, hom_M):
pt = np.append(coord_in_pic, 1.0)
pt = np.dot(hom_M, pt)
pt = pt / pt[2]
pt = pt[:2]
return tuple(pt.astype(int).tolist())
# 写真画像上の座標を設定
coord_pic = np.float32([[551,1527], [3988,644], [999, 3466], [4983, 2130]])
# 実際の座標を設定
coord_real = np.float32([[11,31], [283,31], [11,181], [283,181]])
# 射影変換行列の算出
hom_M = cv2.getPerspectiveTransform(coord_pic, coord_real)
# 射影変換行列の表示
np.set_printoptions(precision=8, suppress=True)
print ('Homography transformation matrix:')
print (hom_M)
# 画像上におけるピン座標
pin_coords = [(2283, 1882), (3409, 1294), (3507, 2279),]
# 射影変換行列を使い写真上の座標から実座標を算出
print('coords on pic : coords on real')
for a_coord in pin_coords:
real_coord = compute_real_coord(a_coord, hom_M)
print(f'{a_coord} : {real_coord}')
ソースコード上に記載した実際の座標は下図の通りです。紙に印刷して、実際の位置をミリメータ単位で確認しました。緑が既知の四角形の座標です。オレンジが算出したいピンの実際の座標、つまり正解座標です。
下図が上記の実物(印刷した紙)を撮影した写真画像とその画像上の座標です。
それではPythonを実行してみます。実行結果は下記の通りです。
Homography transformation matrix:
[[ 0.07775223 -0.01653121 -4.43339341]
[ 0.02685756 0.10996206 -145.60942736]
[ -0.00001081 0.00013279 1. ]]
coords on pic : coords on real
(2283, 1882) : (115, 100)
(3409, 1294) : (210, 77)
(3507, 2279) : (182, 157)
画像上のピンの座標(図中のオレンジ)に対して、算出した実際の座標が出力されています。多少の誤差はありますが、ほぼ実際の正解座標に近い座標を算出することが出来ました。
説明は以上となります。