画像の幾何学変換 ======================== .. highlight:: c このサブセクションで述べる関数は,2次元画像の様々な幾何学変換を行います.つまり,画像の内容は変更せずにピクセルグリッドだけを変形し,変形したグリッドを出力画像にマッピングします.実際には,サンプリングによる余計な値や不定な値を排除するために,出力画像から入力画像という逆方向へのマッピングが行われます.つまり,出力画像の各ピクセル :math:`(x, y)` に対して,入力画像中の対応する「ドナー」ピクセルの座標を求め,そのピクセル値をコピーします: .. math:: \texttt{dst} (x,y)= \texttt{src} (f_x(x,y), f_y(x,y)) ユーザが正順のマッピング: :math:`\left: \texttt{src} \rightarrow \texttt{dst}` を指定した場合,OpenCV の関数は最初に,対応する逆マッピング: :math:`\left: \texttt{dst} \rightarrow \texttt{src}` を求めてから上述の式を利用します. 幾何学変換の実際の実装では,最も汎用的な :func:`remap` から,最も単純で高速な :func:`resize` まで,上述の式を用いて2つの主な問題を解く必要があります: #. 存在しないピクセルの外挿. フィルタリング関数 と同様に,ある :math:`(x,y)` に対して, :math:`f_x(x,y)` または :math:`f_y(x,y)` のどちらか,あるいは両方が画像の外側にはみ出してしまう可能性があります.この場合,何らかの外挿手法が必要になります.OpenCVでは,フィルタリング関数の場合と同じく,いくつかの外挿手法が提供されています.さらに別の手法も追加されており,その ``BORDER_TRANSPARENT`` は,出力画像中の対応するピクセルが全く変更されないことを意味します. #. ピクセル値の内挿.通常 :math:`f_x(x,y)` と :math:`f_y(x,y)` は,浮動小数点数(つまり, :math:`\left` は,アフィン変換,透視変換,または半径方向のレンズ歪み係数など)です.よって,小数点座標上に存在するピクセル値が必要になります.最も単純なケースでは,この座標は単に最も近い整数値の座標に丸められ,そこのピクセル値が利用されます.これは,最近傍補間と呼ばれます.しかし,より洗練された `補間手法 `_ を用いることで,より良い結果が得られます.この場合,求められたピクセル :math:`(f_x(x,y), f_y(x,y))` 近傍に対して多項式関数をフィッティングし, :math:`(f_x(x,y), f_y(x,y))` における多項式の値を,補間されたピクセル値として利用します.OpenCVでは,複数の補間手法から選択することができます.詳しくは :func:`resize` を参照してください. .. index:: GetRotationMatrix2D .. _GetRotationMatrix2D: GetRotationMatrix2D ------------------- `id=0.637804091412 Comments from the Wiki `__ .. cfunction:: CvMat* cv2DRotationMatrix( CvPoint2D32f center, double angle, double scale, CvMat* mapMatrix ) 2次元回転のアフィン変換行列を求めます. :param center: 入力画像における回転中心 :param angle: 度単位で表される回転角度.正の値は,反時計回りの回転を意味します(座標原点は左上にあると仮定されます) :param scale: 等方性スケーリング係数 :param mapMatrix: :math:`2\times 3` の出力行列へのポインタ 関数 ``cv2DRotationMatrix`` は,次のような変換行列を求めます: .. math:: \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} ここで, .. math:: \alpha = \texttt{scale} \cdot cos( \texttt{angle} ), \beta = \texttt{scale} \cdot sin( \texttt{angle} ) です. この変換は,回転中心をそれ自身に写像します.それを意図していない場合は,並進を調整しなければいけません. .. index:: GetAffineTransform .. _GetAffineTransform: GetAffineTransform ------------------ `id=0.370056348383 Comments from the Wiki `__ .. cfunction:: CvMat* cvGetAffineTransform( const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* mapMatrix ) 3組の対応点を用いてアフィン変換行列を求めます. :param src: 入力画像における三角形の3つの頂点座標 :param dst: 出力画像における,入力画像の3点に対応する3つの頂点座標 :param mapMatrix: :math:`2 \times 3` の出力行列へのポインタ この関数は,次のようなアフィン変換行列を求めます: .. math:: \begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{mapMatrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix} ここで .. math:: dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2 です. .. index:: GetPerspectiveTransform .. _GetPerspectiveTransform: GetPerspectiveTransform ----------------------- `id=0.0307844935887 Comments from the Wiki `__ .. cfunction:: CvMat* cvGetPerspectiveTransform( const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* mapMatrix ) 3組の対応点を用いて透視変換行列を求めます. :param src: 入力画像における四角形の4つの頂点座標 :param dst: 出力画像における,入力画像の4点に対応する4つの頂点座標 :param map_matrix: :math:`3 \times 3` の出力行列へのポインタ この関数は,次のような透視変換行列を求めます: .. math:: \begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{mapMatrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix} ここで .. math:: dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2,3 です. .. index:: GetQuadrangleSubPix .. _GetQuadrangleSubPix: GetQuadrangleSubPix ------------------- `id=0.665594035733 Comments from the Wiki `__ .. cfunction:: void cvGetQuadrangleSubPix( const CvArr* src, CvArr* dst, const CvMat* mapMatrix ) 画像から,四角形領域のピクセル値をサブピクセル精度で取得します. :param src: 入力画像 :param dst: 抽出された四角形領域 :param mapMatrix: :math:`2 \times 3` の変換行列 :math:`[A|b]` (以下の説明を参照してください) この関数は,以下のようにして ``src`` からサブピクセル精度でピクセル値を取得し,それを ``dst`` に格納します: .. math:: dst(x, y)= src( A_{11} x' + A_{12} y' + b_1, A_{21} x' + A_{22} y' + b_2) ここで .. math:: x'=x- \frac{(width(dst)-1)}{2} , y'=y- \frac{(height(dst)-1)}{2} であり,また .. math:: \texttt{mapMatrix} = \begin{bmatrix} A_{11} & A_{12} & b_1 \\ A_{21} & A_{22} & b_2 \end{bmatrix} です. 非整数の座標におけるピクセル値は,バイリニア補間を用いて取得されます.画像外部にある領域のピクセル値を取得する場合は,複製境界モードを利用します.また,マルチチャンネル画像の各チャンネルは,それぞれ独立に処理されます. .. index:: GetRectSubPix .. _GetRectSubPix: GetRectSubPix ------------- `id=0.266351282605 Comments from the Wiki `__ .. cfunction:: void cvGetRectSubPix( const CvArr* src, CvArr* dst, CvPoint2D32f center ) 画像から,矩形領域のピクセル値をサブピクセル精度で取得します. :param src: 入力画像 :param dst: 抽出された矩形領域 :param center: 浮動小数点数で表現された,矩形領域の中心座標.中心座標は,必ず画像内になければいけません この関数は,以下のように, ``src`` からピクセル値を取得します: .. math:: dst(x, y) = src(x + \texttt{center.x} - (width( \texttt{dst} )-1)*0.5, y + \texttt{center.y} - (height( \texttt{dst} )-1)*0.5) ここで,非整数の座標におけるピクセル値は,バイリニア補間を用いて取得されます.また,マルチチャンネル画像の各チャンネルは,それぞれ独立に処理されます.矩形領域のの中心は,必ず画像内部になければいけませんが,矩形領域の一部が画像外部にはみ出していても構いません.その場合は,画像外部にある領域のピクセル値を取得するために,複製境界モードを利用します. .. index:: LogPolar .. _LogPolar: LogPolar -------- `id=0.13296809359 Comments from the Wiki `__ .. cfunction:: void cvLogPolar( const CvArr* src, CvArr* dst, CvPoint2D32f center, double M, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS ) 画像を対数極座標空間に写像します. :param src: 入力画像 :param dst: 出力画像 :param center: 変換中心.この場所で,出力の精度が最大となります :param M: スケーリング係数の大きさ.以下の説明を参照してください :param flags: 補間手法,および以下に示すオプションフラグの組み合わせ: * **CV_WARP_FILL_OUTLIERS** 出力画像の全ピクセルを埋めます.対応するピクセルが入力画像の範囲外であるようなピクセルには,値として 0がセットされます * **CV_WARP_INVERSE_MAP** 以下の説明を参照してください この関数は,入力画像に対して次のような変換を行います: 順変換( ``CV_WARP_INVERSE_MAP`` が指定されていない場合 ): .. math:: dst( \phi , \rho ) = src(x,y) 逆変換( ``CV_WARP_INVERSE_MAP`` が指定されている場合 ): .. math:: dst(x,y) = src( \phi , \rho ) ここで .. math:: \rho = M \cdot \log{\sqrt{x^2 + y^2}} , \phi =atan(y/x) です. この関数は,人間の「中心」視を模倣したものであり,物体追跡などのための,高速なスケーリングと回転に不変なテンプレートマッチングに利用できます.また,この関数は,置換モードでは動作しないことに注意してください. .. code-block:: c #include #include 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`` を渡した場合の結果を以下に示します. .. image:: ../../pics/logpolar.jpg .. image:: ../../pics/inv_logpolar.jpg .. index:: Remap .. _Remap: Remap ----- `id=0.841828507042 Comments from the Wiki `__ .. cfunction:: 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) ) 画像の幾何学変換を行います. :param src: 入力画像 :param dst: 出力画像 :param mapx: x座標の写像(32fC1 画像) :param mapy: y座標の写像(32fC1 画像) :param flags: 補間手法,および以下に示すオプションフラグの組み合わせ: * **CV_WARP_FILL_OUTLIERS** 出力画像の全ピクセルを埋めます.対応するピクセルが入力画像の範囲外であるようなピクセルには,値として ``fillval`` がセットされます :param fillval: 対応のとれない点を埋める値 この関数は,指定された写像を用いて次のように入力画像を変換します: .. math:: \texttt{dst} (x,y) = \texttt{src} ( \texttt{mapx} (x,y), \texttt{mapy} (x,y)) 他の幾何変換と同様,非整数の座標におけるピクセル値を求めるために,(ユーザが指定する)補間手法が用いられます.また,この関数は,置換モードでは動作しないことに注意してください. .. index:: Resize .. _Resize: Resize ------ `id=0.694967495257 Comments from the Wiki `__ .. cfunction:: void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR ) 画像をリサイズします. :param src: 入力画像 :param dst: 出力画像 :param interpolation: 補間手法: * **CV_INTER_NN** 最近隣接補間 * **CV_INTER_LINEAR** バイリニア補間(デフォルト) * **CV_INTER_AREA** ピクセル領域同士の関係を利用したリサンプリング.画像縮小の際は,モアレの無い処理結果を得ることができる手法です.拡大の際は, ``CV_INTER_NN`` と同様です * **CV_INTER_CUBIC** バイキュービック補間 この関数は,画像 ``src`` を ``dst`` に正確に一致するようにリサイズします.また,ROIが設定されている場合には,それを考慮します. .. index:: WarpAffine .. _WarpAffine: WarpAffine ---------- `id=0.7591865389 Comments from the Wiki `__ .. cfunction:: void cvWarpAffine( const CvArr* src, CvArr* dst, const CvMat* mapMatrix, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0) ) 画像のアフィン変換を行います. :param src: 入力画像 :param dst: 出力画像 :param mapMatrix: :math:`2\times 3` の変換行列 :param flags: 補間手法,および以下に示すオプションフラグの組み合わせ: * **CV_WARP_FILL_OUTLIERS** 出力画像の全ピクセルを埋めます.対応するピクセルが入力画像の範囲外であるようなピクセルには,値として ``fillval`` がセットされます * **CV_WARP_INVERSE_MAP** これは, ``matrix`` が出力画像から入力画像への逆変換であることを表します.したがって,この行列を直接ピクセル補間に利用できます.このフラグが指定されていない場合は,この関数が ``mapMatrix`` の逆変換を求めます :param fillval: 対応のとれない点を埋める値 この関数は,指定された行列を用いて入力画像を以下のように変換します: .. math:: dst(x',y') = src(x,y) ここで .. math:: \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} です. この関数は, :ref:`GetQuadrangleSubPix` と似ていますが,完全に等価というわけではありません :ref:`WarpAffine` は,入力画像と出力画像が同じデータ型でなければならず,オーバーヘッドも大きいです(よって,小さい画像を変換するのには適していません).さらに,出力画像の一部を変更しないままにしておく事もできます.一方, :ref:`GetQuadrangleSubPix` は,8ビット画像から抽出した矩形領域のピクセル値を浮動小数点型のバッファに保存しますし,オーバーヘッドも小さいです.さらに,常に出力画像全体が変更され,すべてのピクセルが埋められます.また,この関数は,置換モードでは動作しないことに注意してください. 疎な点集合を変換する場合は,cxcore の関数 :ref:`Transform` を利用します. .. index:: WarpPerspective .. _WarpPerspective: WarpPerspective --------------- `id=0.503662126043 Comments from the Wiki `__ .. cfunction:: void cvWarpPerspective( const CvArr* src, CvArr* dst, const CvMat* mapMatrix, int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, CvScalar fillval=cvScalarAll(0) ) 画像の透視変換を行います. :param src: 入力画像 :param dst: 出力画像 :param mapMatrix: :math:`3\times 3` の変換行列 :param flags: 補間手法,および以下に示すオプションフラグの組み合わせ: * **CV_WARP_FILL_OUTLIERS** 出力画像の全ピクセルを埋める.対応するピクセルが入力画像の範囲外であるようなピクセルには,値として ``fillval`` がセットされます * **CV_WARP_INVERSE_MAP** これは, ``matrix`` が出力画像から入力画像への逆変換であることを表します.したがって,この行列を直接ピクセル補間に利用できます.このフラグが指定されていない場合は,この関数が ``map_matrix`` の逆変換を求めます :param fillval: 対応のとれない点を埋める値 この関数は,指定された行列を用いて入力画像を以下のように変換します: .. math:: \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 の関数 :ref:`PerspectiveTransform` を利用します.