変換行列を元に、画像を変形する

#contents

*void warpPerspective(InputArray before, OutputArray after, InputArray matrix, Size dsize, int flags, int borderMode, const Scalar& borderValue); [#l9bf0984]
*void warpPerspective(InputArray before, OutputArray after, InputArray matrix, Size dsize, int flags, int borderMode, const Scalar& borderValue); [#s6c1bcab]
-beforeをMatrix(ホモグラフィ)に基づいて変換

**引数 [#lea61f4b]
**引数 [#y819908b]
-before:Mat型の画像。座標変換前の画像
-after:Mat型の画像。座標変換後の画像
-matrix:Mat型の変換行列(ホモグラフィ)
-dsize:Size型の出力画像のサイズ
-flag:int型で変換方法のフラグ。詳細は後述。省略した場合はINTER_LINEAR
-borderMode:int型の、境界の対処方法。省略した場合はBORDER_CONSTANT
-borderValue:Scalar型の値。WARP_FILL_OUTLIERSを指定した場合、この色で空いた部分を塗りつぶす

**返り値 [#l3c56b7c]
**返り値 [#a16c0fa4]
-void型なのでなし

*void warpAffine(InputArray before, OutputArray after, InputArray matrix, Size dsize, int flags, int borderMode, const Scalar& borderValue); [#u1a16464]
*void warpAffine(InputArray before, OutputArray after, InputArray matrix, Size dsize, int flags, int borderMode, const Scalar& borderValue); [#g439206c]
-beforeをMatrix(アフィン行列)に基いて変換

**引数 [#y086ff55]
**引数 [#b02d976e]
-基本的にwarpPerspectiveと同じ
-before:Mat型の画像。座標変換前の画像
-after:Mat型の画像。座標変換後の画像
-matrix:Mat型の変換行列。2x3(2 rows , 3 columns)の変換行列
-dsize:Size型の出力画像のサイズ
-flag:int型で変換方法のフラグ。詳細は後述。省略した場合はINTER_LINEAR
-borderMode:int型の、境界の対処方法。省略した場合はBORDER_CONSTANT
-borderValue:Scalar型の値。WARP_FILL_OUTLIERSを指定した場合、この色で空いた部分を塗りつぶす

**返り値 [#h0aa8836]
**返り値 [#b2663204]
-void型なのでなし

*解説 [#l9e56163]
*解説 [#caf29950]
-flag、borderMode、borderValueの引数については下記の通り
**引数flagについて [#w524a10c]
**引数flagについて [#gb8eeeee]
-flagのデフォルト値はINTER_LINEAR。取れる値は以下の通り
--INTER_NEAREST:最近傍補間(0)
--INTER_LINEAR:線型補間(1)
--INTER_CUBIC:バイキュービック補間(2)
--INTER_LANCZOS4:Lanczos補間(4)
--WARP_FILL_OUTLIERS:指定色で外部を塗りつぶす。(8)
--WARP_INVERSE_MAP:逆変換による補間(16)
--INTER_AREAを指定すると、INTER_LINEARに置き換えられる。
**引数borderModeについて [#pa7fbed4]
-flagsは基本的に補間方法を指定する
--補間方法による違いはサンプルコードの実行結果参照
-WARP_INVERSE_MAPは、ホモグラフィ、もしくはアフィン変換を逆方向に行う場合に使う
-WARP_FILL_OUTLIERSは、C時代の名残。指定されても、内部では参照されていないっぽい。
--代わりに、borderModeのBORDER_CONSTANTを使え、ということであろう。
--ちなみに両関数ともCインタフェースはC++インタフェースのラッパー
**引数borderModeについて [#t2d621ad]
-borderModeのデフォルト値はBORDER_CONSTANT。取れる値は以下の通り
--BORDER_CONSTANT    = 0,
--BORDER_REPLICATE   = 1,
--BORDER_REFLECT     = 2,
--BORDER_WRAP        = 3,
--BORDER_REFLECT_101 = 4,
--BORDER_TRANSPARENT = 5,
--BORDER_REFLECT101  = BORDER_REFLECT_101,
--BORDER_DEFAULT     = BORDER_REFLECT_101,
**引数borderValueについて [#kf2c9bff]
--BORDER_CONSTANT:指定した値(borderValue)で塗りつぶす(0)
--BORDER_REPLICATE:縁の画素値を、繰り返し並べる(1)
--BORDER_REFLECT:同じ画像を、反転させながら並べる(2)
--BORDER_WRAP:同じ画像を繰り返し並べる(3)
--BORDER_REFLECT_101:同じ画像を反転させながら並べる(4)
--BORDER_TRANSPARENT:画像の外側には触れない(5)
-画像を変換させるので、もともとの画像の外側、縁をどう扱うか、がborderModeの意味するところ
-各borderModeで生成されうる画像についてはサンプルコードの実行結果を参照のこと
-BORDER_REFLECTとBORDER_REFLECT_101は非常に似た挙動を示すが、微妙に違う
--BORDER_REFLECTは、縁の画素が繰り返されるため、2度現れる
--BORDER_REFLECT_101は、縁の画素は繰り返されない
--サンプルコードで、この挙動の違いが見えるので、参照のこと
-以下2つの定義も存在するが、エイリアスである
--BORDER_REFLECT101とBORDER_DEFAULT、BORDER_REFLECT_101のエイリアス
--ちなみに省略した場合はBORDER_CONSTANTであり、BORDER_DEFAULTでは無いので注意
--このenum定数群を使うのはwarpPerspectiveやwarpAffine以外にもたくさんあり、主にフィルタ処理する関数では、BORDER_DEFAULTが省略した場合のデフォルト値として利用される。
**引数borderValueについて [#vc9bc3b6]
-borderValueのデフォルトは黒(Scalar())
**変換方法について [#e865bc2c]
**変換方法について [#ka29d2bb]
-ホモグラフィを用いて変換する場合はwarpPerspectiveを、アフィン行列を用いて変換する場合はwarpAffineを使用する
-warpPerspectiveは以下の数式に基づいて変換を行う
--&mimetex(\left(\begin{array}{c} x^{\prime} \\ y^{\prime} \\ 1 \end{array}\right) = s\left(\begin{array}{ccc} M_{11} & M_{12} &  M_{13} \\ M _{21} &  M _{22} &  M _{23} \\ M _{31} &  M _{32} &  1 \end{array}\right)\left(\begin{array}{c} x \\ y \\ 1 \end{array}\right));
--書き換えると、ヘッダ/ドキュメントにある様な、下記の式になる
--&mimetex(\left(\begin{array}{c} x^{\prime} \\ y^{\prime} \end{array}\right) =  \left(\begin{array}{c} \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + 1} \\ \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + 1} \end{array} \right));
-warpAffineは以下の数式に基づいて変換を行う
--&mimetex(\left(\begin{array}{c} x^{\prime} \\ y^{\prime} \end{array}\right) = \left(\begin{array}{ccc} M _{11} & M _{12} &  M _{13} \\ M _{21} &  M _{22} &  M _{23} \end{array}\right)\left(\begin{array}{c} x \\ y \end{array}\right));
--書き換えると、ヘッダ/ドキュメントにある様な、下記の式になる
--&mimetex(\left(\begin{array}{c} x^{\prime} \\ y^{\prime} \end{array}\right) = \left(\begin{array}{c} M _{11} x +  M _{12} y +  M _{13} \\ M _{21} x +  M _{22} y +  M _{23}\end{array}\right));


*サンプルコード [#pde0c698]
#geshi(c++){{
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

 // ホモグラフィによる変換
 // 変数宣言
 IplImage *image, *converted;
 CvMat *homography;
 homography = cvCreateMat(3, 3, CV_32F);                    // 領域確保
 cvFindHomography(src_points, dst_points, homography);      // ホモグラフィ計算
 image = cvLoadImage("input.bmp", CV_LOAD_IMAGE_UNCHANGED); // 画像のロード
 converted = cvCreateImage(cvGetSize(image), image->depth, image->nChannels);
                                                            // 画像の領域確保
 cvWarpPerspective(image, converted, homography,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS, cvScalarAll(255));
                                                            // ホモグラフィに基づき変換
const char filename[]      = "/path/to/opencv/samples/data/lena.jpg";
const char windowName[]    = "output";
const float srcPoints[]   = {  0.0,  0.0,1.0,  512.0,  0.0,1.0,  512.0,512.0,1.0,    0.0,512.0,1.0};
const float dstPoints[]   = {218.0,110.0,1.0,  451.0,202.0,1.0,  328.0,395.0,1.0,  112.0,313.0,1.0};
const float dstPoints2[]  = {502.0,-10.0,1.0,  522.0,-10.0,1.0,  522.0, 10.0,1.0,  502.0, 10.0,1.0};
const unsigned int cPoints = 4;

*実体ファイル [#ffff384b]
-cv/include/cv.h
-cv/src/cvcalibration.cpp (cvFindHomography)
-cv/src/cvimgwarp.cpp (cvWarpPerspective)
void warpAffineAndShow(cv::Mat& before, cv::Mat& after, cv::Mat& matrix, cv::Size& dstSize, int flag, int borderMode = cv::BORDER_CONSTANT, int fillval = 0)
{
	using namespace cv;

ジャンル[[:OpenCV]][[:OpenCV 1.0]]準拠
	// warp the image
	warpAffine(before, after, matrix, dstSize, flag, borderMode, fillval);
	imshow(windowName, after);
	waitKey(0);
}

void warpAndShow(cv::Mat& before, cv::Mat& after, cv::Mat& matrix, cv::Size& dstSize, int flag, int borderMode = cv::BORDER_CONSTANT, int fillval = 0)
{
	using namespace cv;

	// warp the image
	warpPerspective(before, after, matrix, dstSize, flag, borderMode, fillval);
	imshow(windowName, after);
	waitKey(0);
}

int main(int argc, char **argv)
{
	using namespace cv;
	Mat lena = imread(filename, IMREAD_GRAYSCALE);

	// prepare the corresponding points
	Mat src        = Mat(cPoints, 3, CV_32FC1, (void*)srcPoints);
	Mat dst        = Mat(cPoints, 3, CV_32FC1, (void*)dstPoints);

	// find the homography
	Mat homography = findHomography(src, dst);

	// prepare the result image
	Mat warpImage;
	Size dstSize = lena.size();

	// make a window
	namedWindow(windowName);

	// warp the image using homography
	warpPerspective(lena, warpImage, homography, dstSize);
	// show the result
	imshow(windowName, warpImage);
	// wait
	waitKey(0);

	// cut out 3 points from corresponding points
	// Affine matrix only acceps 3 x 2 matrix
	Mat src1   = src.colRange(0,2).rowRange(0,3).clone();
	Mat dst1   = dst.colRange(0,2).rowRange(0,3).clone();
	// get affine matrix
	Mat affine = getAffineTransform(src1, dst1);

	// warp the image using affine matrix
	warpAffineAndShow(lena, warpImage, affine, dstSize, INTER_LINEAR); 
	warpAffineAndShow(lena, warpImage, affine, dstSize, INTER_LINEAR, BORDER_REPLICATE); 

	// try various border types
	warpAndShow(lena,    warpImage, homography, dstSize, INTER_LINEAR);
	warpAndShow(lena,    warpImage, homography, dstSize, INTER_LINEAR, BORDER_REPLICATE);
	warpAndShow(lena,    warpImage, homography, dstSize, INTER_LINEAR, BORDER_WRAP);
	warpAndShow(lena,    warpImage, homography, dstSize, INTER_LINEAR, BORDER_REFLECT);
	warpAndShow(lena,    warpImage, homography, dstSize, INTER_LINEAR, BORDER_REFLECT_101);
	warpAndShow(lena.clone(), lena, homography, dstSize, INTER_LINEAR, BORDER_TRANSPARENT);

	// find the homography
	dst = Mat(cPoints, 3, CV_32FC1, (void*)dstPoints2);
	homography = findHomography(src, dst);

	// try various interpolation method
	warpAndShow(lena, warpImage, homography, dstSize, INTER_NEAREST +WARP_INVERSE_MAP);
	warpAndShow(lena, warpImage, homography, dstSize, INTER_LINEAR  +WARP_INVERSE_MAP);
	warpAndShow(lena, warpImage, homography, dstSize, INTER_CUBIC   +WARP_INVERSE_MAP);
	warpAndShow(lena, warpImage, homography, dstSize, INTER_LANCZOS4+WARP_INVERSE_MAP);
	warpAndShow(lena, warpImage, homography, dstSize, INTER_AREA    +WARP_INVERSE_MAP);

	// check difference of BORDER_REFLECT and BORDER_REFLECT_101
	warpAndShow(lena, warpImage, homography, dstSize, INTER_NEAREST+WARP_INVERSE_MAP, BORDER_REFLECT);
	warpAndShow(lena, warpImage, homography, dstSize, INTER_NEAREST+WARP_INVERSE_MAP, BORDER_REFLECT_101);

	destroyAllWindows();

	return 0;
}
}}
**実行結果 [#tff79c15]
-TBW
#ref(result0000AffineConstant.png)
#ref(result0001AffineReplicate.png)
#ref(result0002PerspectiveConstant.png)
#ref(result0003PerspectiveReplicate.png)
#ref(result0004PerspectiveWrap.png)
#ref(result0005PerspectiveReflect.png)
#ref(result0006PerspectiveReflect101.png)
#ref(result0007PerspectiveTransparent.png)
#ref(result0008InterpolationNearest.png)
#ref(result0009InterpolationLinear.png)
#ref(result0010InterpolationCubic.png)
#ref(result0011InterpolationLanczos4.png)
#ref(result0012InterpolationArea.png)
#ref(result0013BorderReflect.png)
#ref(result0014BorderReflect101.png)

*実体ファイル [#me219ce5]
**OpenCV 2.4系列 [#b7c56afd]
-warpPerspective、warpAffine
--modules/imgproc/include/opencv2/imgproc/iimgproc.hpp
--modules/imgproc/src/imgwarp.cpp
**OpenCV 3.0系列 [#fe0ecd83]
-warpPerspective、warpAffine
--modules/imgproc/include/opencv2/imgproc/iimgproc.hpp
--modules/imgproc/src/imgwarp.cpp


ジャンル[[:OpenCV]][[:OpenCV 2.4]][[:OpenCV 3.0]][[:OpenCV 3.1]]準拠


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS