OpenCVの使い方5 ~ 幾何変換
OpenCVの使用方法について、今回は画像の幾何変換について紹介したい。
1. 幾何変換
画像の幾何変換とは、画像を点群としてとらえたときに、ある変換行列によって新しい点群へ変換されることを示す。例えば並進はX,Yにそれぞれtx,tyだけ動かす行列で
と表される。
2. スケール、並進、回転変換
OpenCVを使って画像に対して幾何変換を実行する方法について示す。まず、Google Colabでは処理する画像を以下のようにロードする。src
が処理を施す画像データになっている。
import cv2 import numpy as np from matplotlib import pyplot as plt from google.colab import files uploaded_file = files.upload() orig = cv2.imread(uploaded_file_name) src = cv2.cvtColor(orig, cv2.COLOR_BGR2RGB)
画像のスケーリングは、単純にOpenCVのリサイズを実行するcv2.resize(src,(newWidth,newHeight),interpolation)
を利用する。srcはリサイズ前の画像データ、newWidth,newHeightはリサイズ後の画像の幅、高さ、interpolationはリサイズ時の画素の補間方法で拡大には cv2.INTER_CUBIC (処理が遅い) や cv2.INTER_LINEARが用いられ、縮小時にはcv2.INTER_AREA が用いられる。
height, width = src.shape[:2] res = cv2.resize(src,(2*width, 2*height), interpolation = cv2.INTER_CUBIC) plt.subplot(1,2,1) plt.imshow(src) plt.subplot(1,2,2) plt.imshow(res)
左が元画像srcで右が2倍にリサイズした画像resになっている。
次に画像を幾何変換する方法について説明する。まず並進変換では、上の行列Mをnumpyを使って定義し、cv2.warpAffine(src,M,(width,height))
を用いてM
をsrc
の作用させる。なお3番目の引数は出力する画像サイズとなる。
tx=100 ty=50 M = np.float32([[1,0,tx],[0,1,ty]]) dst = cv2.warpAffine(src,M,(width,height))
行列Mにより元の画像は横方向に100ピクセル、縦方向に50ピクセル移動したことが確認できる。
回転変換も並進変換と同様に具体的な行列を定義してcv2.warpAffine
を適用するが、cv2.getRotationMatrix2D((cx,cy),rot,scale)
を用いることでOpenVCVでは回転と拡大縮小を同時に実行する行列を生成することができる。なお回転と拡大縮小を行う行列は以下のようになっている。
画像を0.6に縮小し、画像中心を軸に90°回転する行列M2をgetRotationMatrix2D
により取得し、warpAffine
を用いてsrcに適用する。
M2 = cv2.getRotationMatrix2D((int(width/2),int(height/2)),90,0.6) rot = cv2.warpAffine(src,M2,(width,height)) plt.imshow(rot)
元の画像が縮小回転された画像が以下に得られる。
3. 一般的なアフィン変換
ここでは一般的なアフィン変換を画像に適用する方法について紹介する。上の並進や回転縮小変換はアフィン変換の特殊な例になっている。アフィン変換の効果がわかりやすいように別の画像(方眼紙)を読み込み、画像データをsrc2
とする。
uploaded_file2 = files.upload() uploaded_file_name2 = next(iter(uploaded_file2)) orig2 = cv2.imread(uploaded_file_name2) src2 = cv2.cvtColor(orig2, cv2.COLOR_BGR2RGB)
入力画像pts1と出力画像pts2の対応点として3組用意して、getAffineTransform(pts1,pts2)
でアフィン変換の行列式M3を算出し、warpAffine
を用いてsrc2
に適用する。
rows,cols,ch = src2.shape pts1 = np.float32([[50,50],[200,50],[50,200]]) pts2 = np.float32([[10,100],[200,50],[100,250]]) M3 = cv2.getAffineTransform(pts1,pts2) aff = cv2.warpAffine(src2,M3,(cols,rows))
以下アフィン変換前後の画像を表示すると、方眼紙の並行性を保った変換であることが確認できる。
plt.figure(figsize=(10,8)) plt.subplot(1,2,1) plt.imshow(src2) plt.title('Input') plt.subplot(1,2,2) plt.imshow(aff) plt.title('Output')
4. まとめ
今回はOpenCVを用いた幾何変換として画像をリサイズ、並進、回転、アフィン変換する方法について紹介した。