Pynote

Python、機械学習、画像処理について

OpenCV - 画像にアフィン変換を適用する方法について

概要

OpenCV で画像にアフィン変換を適用する関数 warpAffine() について解説する。
この関数を利用することで、画像を回転、拡大縮小できる。また、応用的な使い方として、ある画像を別の画像に貼り付けることもできる。

画像を回転させる。

回転行列の作成方法については下記記事を参照されたい。

pynote.hatenablog.com

OpenCVcv2.warpAffine() でアフィン変換を画像に適用することができる。

dst = cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])

引数

  • src: 入力画像
  • M: 2 \times 3 のアフィン変換行列
  • dsize: 出力画像の大きさ
  • dst: 出力画像 (引数経由で受け取る場合)
  • flags: フラグ。デフォルトは cv2.INTER_LINEAR。
    • 補完方法 InterpolationFlags 及び cv2.WARP_INVERSE_MAP の組み合わせを指定できる。
    • アフィン変換行列 M が入力画像から出力画像の変換でなく、出力画像から入力画像への変換を表す場合、cv2.WARP_INVERSE_MAP を指定する。
    • 例: cv2.WARP_INVERSE_MAP + cv2.WARP_INVERSE_MAP
  • borderMode: 値がないピクセルを外挿する方法。BorderTypes を指定できる。デフォルトは cv2.BORDER_CONSTANT。
  • borderValue: 外挿を cv2.BORDER_CONSTANT で行う場合、その値。デフォルトは (0, 0, 0)[tex:。

返り値

  • dst: 出力画像

解説

1. 入力画像の各ピクセルの値をアフィン変換行列に従い、移動する。

アフィン変換行列を

 \displaystyle
M = \begin{pmatrix}
m_{11} & m_{12} & m_{13} \\
m_{21} & m_{22} & m_{23} \\
\end{pmatrix}

としたとき、入力画像のピクセル (x, y) の値は、M (x, y, 1)^T より、(m_{11} x + m_{12} y + m_{13}, m_{21} x + m_{22} y + m_{23}) に移される。

2. 補完方法に従い、離散化を行う。

アフィン変換行列に従って配置された値を元に離散化を行う。
離散化する際の大きさは dsize 引数で指定する。
離散化した際の各ピクセルの値は flags 引数で指定した補完方法 InterpolationFlags によって決まる。

3. 値がないピクセルは、外挿する。

borderMode 引数で指定した方法に従い、値がないピクセルを外挿する。
デフォルトは borderMode=cv2.BORDER_CONSTANT で borderValue=(0, 0, 0)] なので、黒で埋められる。


サンプルコード

画像を回転させる。

使用する画像

import cv2

# 画像を読み込む。
img = cv2.imread('tux.png')

# 反時計回りに画像の中心回りに120度回転し、3倍に拡大するアフィン変換行列を作成する。
h, w, c = img.shape
M = cv2.getRotationMatrix2D(center=(w / 2, h / 2), angle=120, scale=3.)

# 画像にアフィン変換行列を適用する。
rotated = cv2.warpAffine(img, M, dsize=(w * 2, h * 2))


ある画像に別の画像を埋め込む。

使用する画像

外挿方法を borderMode=cv2.BORDER_TRANSPARENT と指定すると、dst 引数で指定した画像の画素値が外挿に使用される。
これを利用することである画像を別の画像に埋め込むことができる。

import cv2

# 前景画像、背景画像を読み込む。
fg_img = cv2.imread('tux.png')  
bg_img = cv2.imread('sea.jpg')

# 反時計回りに画像の中心回りに120度回転し、0.5倍に縮小するアフィン変換行列を作成する。
h, w, c = fg_img.shape
M = cv2.getRotationMatrix2D(center=(w / 2, h / 2), angle=120, scale=0.5)

# 画像にアフィン変換行列を適用する。
h, w, c = bg_img.shape
combined = cv2.warpAffine(img, M, dsize=(w, h), dst=bg_img, borderMode=cv2.BORDER_TRANSPARENT)