画像の幾何学変換

このサブセクションで述べる関数は,2次元画像の様々な幾何学変換を行います.つまり,画像の内容は変更せずにピクセルグリッドだけを変形し,変形したグリッドを出力画像にマッピングします.実際には,サンプリングによる余計な値や不定な値を排除するために,出力画像から入力画像という逆方向へのマッピングが行われます.つまり,出力画像の各ピクセル (x, y) に対して,入力画像中の対応する「ドナー」ピクセルの座標を求め,そのピクセル値をコピーします:

\texttt{dst} (x,y)= \texttt{src} (f_x(x,y), f_y(x,y))

ユーザが正順のマッピング: \left<g_x, g_y\right>: \texttt{src} \rightarrow \texttt{dst} を指定した場合,OpenCV の関数は最初に,対応する逆マッピング: \left<f_x, f_y\right>: \texttt{dst} \rightarrow \texttt{src} を求めてから上述の式を利用します.

幾何学変換の実際の実装では,最も汎用的な remap() から,最も単純で高速な resize() まで,上述の式を用いて2つの主な問題を解く必要があります:

  1. 存在しないピクセルの外挿. と同様に,ある (x,y) に対して, f_x(x,y) または f_y(x,y) のどちらか,あるいは両方が画像の外側にはみ出してしまう可能性があります.この場合,何らかの外挿手法が必要になります.OpenCVでは,フィルタリング関数の場合と同じく,いくつかの外挿手法が提供されています.さらに別の手法も追加されており,その BORDER_TRANSPARENT は,出力画像中の対応するピクセルが全く変更されないことを意味します.
  2. ピクセル値の内挿.通常 f_x(x,y)f_y(x,y) は,浮動小数点数(つまり, \left<f_x, f_y\right> は,アフィン変換,透視変換,または半径方向のレンズ歪み係数など)です.よって,小数点座標上に存在するピクセル値が必要になります.最も単純なケースでは,この座標は単に最も近い整数値の座標に丸められ,そこのピクセル値が利用されます.これは,最近傍補間と呼ばれます.しかし,より洗練された 補間手法 を用いることで,より良い結果が得られます.この場合,求められたピクセル (f_x(x,y), f_y(x,y)) 近傍に対して多項式関数をフィッティングし, (f_x(x,y), f_y(x,y)) における多項式の値を,補間されたピクセル値として利用します.OpenCVでは,複数の補間手法から選択することができます.詳しくは resize() を参照してください.

cv::GetRotationMatrix2D

CvMat* cv2DRotationMatrix(CvPoint2D32f center, double angle, double scale, CvMat* mapMatrix)

2次元回転のアフィン変換行列を求めます.

パラメタ:
  • center – 入力画像における回転中心
  • angle – 度単位で表される回転角度.正の値は,反時計回りの回転を意味します(座標原点は左上にあると仮定されます)
  • scale – 等方性スケーリング係数
  • mapMatrix2\times 3 の出力行列へのポインタ

関数 cv2DRotationMatrix は,次のような変換行列を求めます:

\begin{bmatrix} \alpha &  \beta & (1- \alpha )  \cdot \texttt{center.x} -  \beta \cdot \texttt{center.y} \\ - \beta &  \alpha &  \beta \cdot \texttt{center.x} - (1- \alpha )  \cdot \texttt{center.y} \end{bmatrix}

ここで,

\alpha =  \texttt{scale} \cdot cos( \texttt{angle} ),  \beta =  \texttt{scale} \cdot sin( \texttt{angle} )

です. この変換は,回転中心をそれ自身に写像します.それを意図していない場合は,並進を調整しなければいけません.

cv::GetAffineTransform

CvMat* cvGetAffineTransform(const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* mapMatrix)

3組の対応点を用いてアフィン変換行列を求めます.

パラメタ:
  • src – 入力画像における三角形の3つの頂点座標
  • dst – 出力画像における,入力画像の3点に対応する3つの頂点座標
  • mapMatrix2 \times 3 の出力行列へのポインタ

この関数は,次のようなアフィン変換行列を求めます:

\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{mapMatrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}

ここで

dst(i)=(x'_i,y'_i),
src(i)=(x_i, y_i),
i=0,1,2

です.

cv::GetPerspectiveTransform

CvMat* cvGetPerspectiveTransform(const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* mapMatrix)

3組の対応点を用いて透視変換行列を求めます.

パラメタ:
  • src – 入力画像における四角形の4つの頂点座標
  • dst – 出力画像における,入力画像の4点に対応する4つの頂点座標
  • map_matrix3 \times 3 の出力行列へのポインタ

この関数は,次のような透視変換行列を求めます:

\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{mapMatrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}

ここで

dst(i)=(x'_i,y'_i),
src(i)=(x_i, y_i),
i=0,1,2,3

です.

cv::GetQuadrangleSubPix

void cvGetQuadrangleSubPix(const CvArr* src, CvArr* dst, const CvMat* mapMatrix)

画像から,四角形領域のピクセル値をサブピクセル精度で取得します.

パラメタ:
  • src – 入力画像
  • dst – 抽出された四角形領域
  • mapMatrix2 \times 3 の変換行列 [A|b] (以下の説明を参照してください)

この関数は,以下のようにして src からサブピクセル精度でピクセル値を取得し,それを dst に格納します:

dst(x, y)= src( A_{11} x' + A_{12} y' + b_1, A_{21} x' + A_{22} y' + b_2)

ここで

x'=x- \frac{(width(dst)-1)}{2} ,
y'=y- \frac{(height(dst)-1)}{2}

であり,また

\texttt{mapMatrix} =  \begin{bmatrix} A_{11} & A_{12} & b_1 \\ A_{21} & A_{22} & b_2 \end{bmatrix}

です.

非整数の座標におけるピクセル値は,バイリニア補間を用いて取得されます.画像外部にある領域のピクセル値を取得する場合は,複製境界モードを利用します.また,マルチチャンネル画像の各チャンネルは,それぞれ独立に処理されます.

cv::GetRectSubPix

void cvGetRectSubPix(const CvArr* src, CvArr* dst, CvPoint2D32f center)

画像から,矩形領域のピクセル値をサブピクセル精度で取得します.

パラメタ:
  • src – 入力画像
  • dst – 抽出された矩形領域
  • center – 浮動小数点数で表現された,矩形領域の中心座標.中心座標は,必ず画像内になければいけません

この関数は,以下のように, src からピクセル値を取得します:

dst(x, y) = src(x +  \texttt{center.x} - (width( \texttt{dst} )-1)*0.5, y +  \texttt{center.y} - (height( \texttt{dst} )-1)*0.5)

ここで,非整数の座標におけるピクセル値は,バイリニア補間を用いて取得されます.また,マルチチャンネル画像の各チャンネルは,それぞれ独立に処理されます.矩形領域のの中心は,必ず画像内部になければいけませんが,矩形領域の一部が画像外部にはみ出していても構いません.その場合は,画像外部にある領域のピクセル値を取得するために,複製境界モードを利用します.

cv::LogPolar

void cvLogPolar(const CvArr* src, CvArr* dst, CvPoint2D32f center, double M, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS)

画像を対数極座標空間に写像します.

パラメタ:
  • src – 入力画像
  • dst – 出力画像
  • center – 変換中心.この場所で,出力の精度が最大となります
  • M – スケーリング係数の大きさ.以下の説明を参照してください
  • flags

    補間手法,および以下に示すオプションフラグの組み合わせ:

    • CV_WARP_FILL_OUTLIERS 出力画像の全ピクセルを埋めます.対応するピクセルが入力画像の範囲外であるようなピクセルには,値として 0がセットされます
    • CV_WARP_INVERSE_MAP 以下の説明を参照してください

この関数は,入力画像に対して次のような変換を行います:

順変換( CV_WARP_INVERSE_MAP が指定されていない場合 ):

dst( \phi , \rho ) = src(x,y)

逆変換( CV_WARP_INVERSE_MAP が指定されている場合 ):

dst(x,y) = src( \phi , \rho )

ここで

\rho = M  \cdot \log{\sqrt{x^2 + y^2}} , \phi =atan(y/x)

です.

この関数は,人間の「中心」視を模倣したものであり,物体追跡などのための,高速なスケーリングと回転に不変なテンプレートマッチングに利用できます.また,この関数は,置換モードでは動作しないことに注意してください.

#include <cv.h>
#include <highgui.h>

int main(int argc, char** argv)
{
    IplImage* src;

    if( argc == 2 && (src=cvLoadImage(argv[1],1) != 0 )
    {
        IplImage* dst = cvCreateImage( cvSize(256,256), 8, 3 );
        IplImage* src2 = cvCreateImage( cvGetSize(src), 8, 3 );
        cvLogPolar( src, dst, cvPoint2D32f(src->width/2,src->height/2), 40,
        CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );
        cvLogPolar( dst, src2, cvPoint2D32f(src->width/2,src->height/2), 40,
        CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS+CV_WARP_INVERSE_MAP );
        cvNamedWindow( "log-polar", 1 );
        cvShowImage( "log-polar", dst );
        cvNamedWindow( "inverse log-polar", 1 );
        cvShowImage( "inverse log-polar", src2 );
        cvWaitKey();
    }
    return 0;
}

このプログラムに, opencv/samples/c/fruits.jpg を渡した場合の結果を以下に示します.

_images/logpolar.jpg _images/inv_logpolar.jpg

cv::Remap

void cvRemap(const CvArr* src, CvArr* dst, const CvArr* mapx, const CvArr* mapy, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0))

画像の幾何学変換を行います.

パラメタ:
  • src – 入力画像
  • dst – 出力画像
  • mapx – x座標の写像(32fC1 画像)
  • mapy – y座標の写像(32fC1 画像)
  • flags

    補間手法,および以下に示すオプションフラグの組み合わせ:

    • CV_WARP_FILL_OUTLIERS 出力画像の全ピクセルを埋めます.対応するピクセルが入力画像の範囲外であるようなピクセルには,値として fillval がセットされます
  • fillval – 対応のとれない点を埋める値

この関数は,指定された写像を用いて次のように入力画像を変換します:

\texttt{dst} (x,y) =  \texttt{src} ( \texttt{mapx} (x,y), \texttt{mapy} (x,y))

他の幾何変換と同様,非整数の座標におけるピクセル値を求めるために,(ユーザが指定する)補間手法が用いられます.また,この関数は,置換モードでは動作しないことに注意してください.

cv::Resize

void cvResize(const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR)

画像をリサイズします.

パラメタ:
  • src – 入力画像
  • dst – 出力画像
  • interpolation

    補間手法:

    • CV_INTER_NN 最近隣接補間
    • CV_INTER_LINEAR バイリニア補間(デフォルト)
    • CV_INTER_AREA ピクセル領域同士の関係を利用したリサンプリング.画像縮小の際は,モアレの無い処理結果を得ることができる手法です.拡大の際は, CV_INTER_NN と同様です
    • CV_INTER_CUBIC バイキュービック補間

この関数は,画像 srcdst に正確に一致するようにリサイズします.また,ROIが設定されている場合には,それを考慮します.

cv::WarpAffine

void cvWarpAffine(const CvArr* src, CvArr* dst, const CvMat* mapMatrix, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0))

画像のアフィン変換を行います.

パラメタ:
  • src – 入力画像
  • dst – 出力画像
  • mapMatrix2\times 3 の変換行列
  • flags

    補間手法,および以下に示すオプションフラグの組み合わせ:

    • CV_WARP_FILL_OUTLIERS 出力画像の全ピクセルを埋めます.対応するピクセルが入力画像の範囲外であるようなピクセルには,値として fillval がセットされます
    • CV_WARP_INVERSE_MAP これは, matrix が出力画像から入力画像への逆変換であることを表します.したがって,この行列を直接ピクセル補間に利用できます.このフラグが指定されていない場合は,この関数が mapMatrix の逆変換を求めます
  • fillval – 対応のとれない点を埋める値

この関数は,指定された行列を用いて入力画像を以下のように変換します:

dst(x',y') = src(x,y)

ここで

\begin{matrix} \begin{bmatrix} x' \\ y' \end{bmatrix} =  \texttt{mapMatrix} \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} &  \mbox{if CV\_WARP\_INVERSE\_MAP is not set} \\ \begin{bmatrix} x \\ y \end{bmatrix} =  \texttt{mapMatrix} \cdot \begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} &  \mbox{otherwise} \end{matrix}

です.

この関数は, GetQuadrangleSubPix と似ていますが,完全に等価というわけではありません WarpAffine は,入力画像と出力画像が同じデータ型でなければならず,オーバーヘッドも大きいです(よって,小さい画像を変換するのには適していません).さらに,出力画像の一部を変更しないままにしておく事もできます.一方, GetQuadrangleSubPix は,8ビット画像から抽出した矩形領域のピクセル値を浮動小数点型のバッファに保存しますし,オーバーヘッドも小さいです.さらに,常に出力画像全体が変更され,すべてのピクセルが埋められます.また,この関数は,置換モードでは動作しないことに注意してください.

疎な点集合を変換する場合は,cxcore の関数 Transform を利用します.

cv::WarpPerspective

void cvWarpPerspective(const CvArr* src, CvArr* dst, const CvMat* mapMatrix, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0))

画像の透視変換を行います.

パラメタ:
  • src – 入力画像
  • dst – 出力画像
  • mapMatrix3\times 3 の変換行列
  • flags

    補間手法,および以下に示すオプションフラグの組み合わせ:

    • CV_WARP_FILL_OUTLIERS 出力画像の全ピクセルを埋める.対応するピクセルが入力画像の範囲外であるようなピクセルには,値として fillval がセットされます
    • CV_WARP_INVERSE_MAP これは, matrix が出力画像から入力画像への逆変換であることを表します.したがって,この行列を直接ピクセル補間に利用できます.このフラグが指定されていない場合は,この関数が map_matrix の逆変換を求めます
  • fillval – 対応のとれない点を埋める値

この関数は,指定された行列を用いて入力画像を以下のように変換します:

\begin{matrix} \begin{bmatrix} x' \\ y' \end{bmatrix} =  \texttt{mapMatrix} \cdot \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} &  \mbox{if CV\_WARP\_INVERSE\_MAP is not set} \\ \begin{bmatrix} x \\ y \end{bmatrix} =  \texttt{mapMatrix} \cdot \begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} &  \mbox{otherwise} \end{matrix}

この関数は,置換モードでは動作しないことに注意してください.また,疎な点集合を変換する場合は,cxcore の関数 PerspectiveTransform を利用します.