Pythonで透視変換

PythonとOpenCVを使った透視変換(Homography Transform)のコード例です。変換前後の4点ずつ、計8点からgetPerspectiveTransform関数によって3*3の変換行列を求め、warpPerspective関数によって画像を変換します。なお、今回は使っていませんが、逆行列はinvM = np.linalg.inv(M)というようにしてnumpyの関数で計算することができます。

import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

img = cv2.imread('img.jpg')
rows,cols,ch = img.shape
print img.shape

pts1 = np.float32([[0,0],[cols,0],[0,rows],[cols,rows]])
pts2 = np.float32([[1000,0],[3160,500],[0,3120],[4160,3120]])

M = cv2.getPerspectiveTransform(pts1,pts2)
print M
dst = cv2.warpPerspective(img,M,(cols,rows))
cv2.imwrite("img_out.jpg", dst)

plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
(3120, 4160, 3)
[[ 6.64195537e-01 -3.20512821e-01 1.00000000e+03]
[ 1.43129771e-01 4.73355843e-01 -1.13686838e-13]
[ 4.58749266e-05 -1.68796204e-04 1.00000000e+00]]

 

実際の変形に関わる関数はcv2.warpPerspectiveです。リファレンスを見ると、flagsオプションで補間手法を指定できます。
http://opencv.jp/opencv-2.1/cpp/geometric_image_transformations.html#cv-warpperspective
  • interpolation –
    補間手法:
    • INTER_NEAREST 最近傍補間
    • INTER_LINEAR バイリニア補間(デフォルト)
    • INTER_AREA ピクセル領域の関係を利用したリサンプリング.画像を大幅に縮小する場合は,モアレを避けることができる良い手法です.しかし,画像を拡大する場合は,  INTER_NEARESTメソッドと同様になります
    • INTER_CUBIC 4×4 の近傍領域を利用するバイキュービック補間
    • INTER_LANCZOS4 8×8 の近傍領域を利用する Lanczos法の補間
色々ありますが、画像が伸びたからと言ってその分色が薄くなったりすることはありません。仮に、変形がx方向に3ピクセルシフトするだけ、あるいは90度回転するだけ、というようなものであれば補間手法の指定は無意味です。補間手法を指定する必要があるのは、変形前のピクセルの値として参照すべきピクセルが1つに定まらないときです。そういう場合には一番近いピクセルの値を採用するのか(INTER_NEAREST)、距離で重み付けした平均を取るのか(INTER_LINEAR)、あるいは輝度値変化の微分まで考慮するか、といった色々な補間手法から選ぶ必要があります。
最近傍補完以外は大きく結果は変わらないような気がしています。元が白黒2値画像のとき、最近傍補完では結果画像も白黒になりますが、それ以外の方法だと、平均を取られて灰色の画素が出現します。