さて、本日は画像の幾何学変換について書いてみようと思います。以下エントリーと同様に OpenCV を使ってみようと思います。
www.gis-py.com
幾何学変換とは
幾何学変換と聞くだけで頭が痛くなりそうな気がしますがそんなに難しく考える必要はありません。まずは画像を拡大・縮小、回転、スキュー(画像を傾けるような処理)するもの、くらいに捉えておけば大丈夫かと思います(もちろん専門的に勉強するならこれだと足りないと思いますが)。
今回試すこと
- 拡大・縮小
- 移動
- 回転
- アフィン変換
- 射影変換
使用する画像
大田区公式PRキャラクターの「はねぴょん」の画像を使用します。
実行環境
Windows 10 64bit
Python 3.6.6
サンプルコード
拡大・縮小
はねぴょんを横に1.5倍、縦に3倍拡大させてみます。cv2.resize の引数の fx、fyを設定することで拡大縮小の調整ができます。
import cv2
def main():
img = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
res = cv2.resize(img, None, fx=1.5, fy=3,
interpolation = cv2.INTER_CUBIC)
cv2.imshow("res", res)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
このようにはねぴょんが拡大されたことがわかります。
移動
はねぴょんを移動させます。
import cv2
import numpy as np
def main():
img = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
rows, cols, _ = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img, M, (cols,rows))
cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
このように画像が移動したことがわかります。
回転
はねぴょんを180度回転させます。
import cv2
import numpy as np
def main():
img = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
rows, cols, _ = img.shape
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 180, 1)
dst = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
このように画像が180度回転したことがわかります。
アフィン変換
アフィン変換は線形変換(拡大や縮小,回転など)と平行移動を組み合わせた変換です。アフィン変換を行うには入力画像と出力画像の対応点の座標が少なくとも3組必要です。今回は以下のように対応点を設定してみました。
import cv2
import numpy as np
def main():
img = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
rows, cols, _ = img.shape
pts1 = np.float32([[16,36],[138,36],[16, 130]])
pts2 = np.float32([[34,67],[154,84],[63,175]])
M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
出力画像の対応点にアフィン変換された結果になりました。
射影変換
任意の四角形を任意の四角形に変形することができる変換が射影変換です。はねぴょんの画像では少しわかりにくいので、射影変換に関しては以下の画像を使用します。
射影変換を使うことで雑誌を真上から見たように補正することができます。射影変換を行うには入力画像と出力画像の対応点の座標が少なくとも4組必要です。今回は以下のように対応点を設定してみました。
import cv2
import numpy as np
def main():
img = cv2.imread(r"D:\blog\data\opencv\book.jpg")
rows, cols, _ = img.shape
pts1 = np.float32([[765,521],[3135,551],[167, 2023],[4025, 1849]])
pts2 = np.float32([[0,0],[cols,0],[0,rows],[cols, rows]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img, M, (cols, rows))
cv2.imwrite(r"D:\blog\data\opencv\book2.jpg", dst)
if __name__ == '__main__':
main()
文字はぼやけてしまっていますが、雑誌を真上から見たように補正することができました。
さいごに
実は意外と GIS をつかっていると画像を幾何学変換する機会はあるかと思います。私の場合は地図上に水道の図面を幾何学変換させていました。その図面を下図に水道管などを作図するイメージですかね。まだ基本的なことしか紹介していませんが、OpenCV を使えば簡単に画像の幾何学変換を行うことができます。興味のある方はぜひ試してみてください。