4点同士の対応点情報からホモグラフィを線型に求める

Mat findHomography(InputArray src, InputArray dst, int method, double ransacReprojThreshold, OutputArray mask, const int maxIters, const double confidence)

引数

返り値

Mat findHomography(InputArray src, InputArray dst, OutputArray mask, int method, double ransacReprojThreshold);

引数

返り値

解説

methodについて

導出

#mimetex(\left(\begin{array}{ccc}h_{11}&h_{12}&h_{13}\\h_{21}&h_{22}&h_{23}\\h_{31}&h_{32}&1\\\end{array}\right)\left(\begin{array}{c}x\\y\\1\\\end{array}\right)=\left(\begin{array}{c}sx^\prime\\sy^\prime\\s\\\end{array}\right))

#mimetex(\left\{\begin{array}{l}h_{11}x+h_{12}y+h_{13}=sx^\prime\\h_{21}x+h_{22}y+h_{23}=sy^\prime\\h_{31}x+h_{32}y+1=s\\\end{array})

#mimetex(\left\{\begin{array}{c}h_{11}x+h_{12}y+h_{13}&=\(h_{31}x+h_{32}y+1\)x^\prime\\h_{21}x+h_{22}y+h_{23}&=\(h_{31}x+h_{32}y+1\)y^\prime\\\end{array})

#mimetex(\left\{\begin{array}{c}h_{11}x+h_{12}y+h_{13}-h_{31}xx^\prime-h_{32}yx^\prime&=x^\prime\\h_{21}x+h_{22}y+h_{23}-h_{31}xy^\prime-h_{32}yy^\prime&=y^\prime\\\end{array})

#mimetex(\left(\begin{array}{cccccccc}x&y&1&0&0&0&-xx^\prime&-yx^\prime\\0&0&0&x&y&1&-xy^\prime&-yy^\prime\\\end{array}\right)\left(\begin{array}{c}h_{11}\\h_{12}\\h_{13}\\h_{21}\\h_{22}\\h_{23}\\h_{31}\\h_{32}\\\end{array}\right)=\left(\begin{array}{c}x^\prime\\y^\prime\\\end{array}\right))

#mimetex(\left(\begin{array}{cccccccc}x_1&y_1&1&0&0&0&-x_1x_1^\prime&-y_1x_1^\prime\\0&0&0&x_1&y_1&1&-x_1y_1^\prime&-y_1y_1^\prime\\x_2&y_2&1&0&0&0&-x_2x_2^\prime&-y_2x_2^\prime\\0&0&0&x_2&y_2&1&-x_2y_2^\prime&-y_2y_2^\prime\\x_3&y_3&1&0&0&0&-x_3x_3^\prime&-y_3x_3^\prime\\0&0&0&x_3&y_3&1&-x_3y_3^\prime&-y_3y_3^\prime\\x_4&y_4&1&0&0&0&-x_4x_4^\prime&-y_4x_4^\prime\\0&0&0&x_4&y_4&1&-x_4y_4^\prime&-y_4y_4^\prime\\\end{array}\right)\left(\begin{array}{c}h_{11}\\h_{12}\\h_{13}\\h_{21}\\h_{22}\\h_{23}\\h_{31}\\h_{32}\\\end{array}\right)=\left(\begin{array}{c}x_1^\prime\\y_1^\prime\\x_2^\prime\\y_2^\prime\\x_3^\prime\\y_3^\prime\\x_4^\prime\\y_4^\prime\\\end{array}\right))

#mimetex(\rm{A}\rm{X}=\rm{B})

サンプルコード

const char inputForegroundImageFilename[] = "file/path/to/opencv/samples/data/box.png"; const char inputBackgroundImageFilename[] = "file/path/to/opencv/samples/data/box_in_scene.png"; const unsigned char kHigh = 255; const double kSigma = 1.0;

const double srcPoints[] = {

	224, 53,1,145,161,1,240,185,1,204,135,1,159,174,1,200,63, 1,236,154,1,229,163,1,170,170,1,
	218,155,1,237,152,1, 83, 54,1,188,166,1, 95,145,1,201,193,1,132,140,1,180,159,1,150, 46,1,
	180,183,1,180,132,1,155,152,1,145, 93,1, 63,132,1, 89,101,1,148, 95,1,228,130,1,210,147,1,
	133,175,1,154, 44,1, 70, 89,1,167,146,1,158,167,1,166,150,1,159, 85,1, 53, 73,1, 37, 91,1,
	 90,117,1,107,163,1,

};

const double dstPoints[] = {

	243, 53,1,173,249,1,222,269,1,207,239,1,179,257,1,211,199,1,223,250,1,218,256,1,186,256,1,
	213,251,1,223,250,1,152,191,1,195,254,1,147,237,1,338,324,1,168,234,1,192,252,1,188,190,1,
	190,264,1,194,235,1,187,298,1,181,213,1,133,229,1,149,214,1,349,320,1,218,256,1,209,247,1,
	163,255,1,188,190,1,176,239,1,185,245,1,278,156,1,185,245,1,370,288,1,136,198,1,149,214,1,
	149,230,1,123,264,1,

}; const unsigned int cPoints = 38; const cv::Scalar lineColor = cv::Scalar(kHigh,kHigh,kHigh,0);

void drawCorrespondingLine(const cv::Mat& foreground, const cv::Mat& background, cv::Mat& result, const cv::Mat& src, const cv::Mat& dst, const cv::Mat Mask) {

	using namespace cv;
	int heightDiff = background.rows - foreground.rows;
	if(heightDiff < 0)
	{
		// to connect in one image, foreground image must be equall or shorter than background in height
		result = background.clone();
		return;
	}
	Mat object;
	Mat space;
	if(heightDiff > 0)
	{
		// add a blank space below the foreground
		space = Mat(heightDiff, foreground.cols, CV_8UC1);
		vconcat(foreground, space, object);
	}
	else
	{
		// foreground and background are same height
		// just copy the foreground
		object = foreground.clone();
	}
	// concatenate them horizontally
	hconcat(object, background, result);
	// draw lines
	for(int iColumn = 0;iColumn < dst.rows;iColumn++)
	{
		if(Mask.data[iColumn] != 0)
		{
			Point objPoint  = Point((int)src.at<double>(iColumn, 0),                 (int)src.at<double>(iColumn, 1));
			Point backPoint = Point((int)dst.at<double>(iColumn, 0)+foreground.cols, (int)dst.at<double>(iColumn, 1));
			line(result, objPoint, backPoint, lineColor);
		}
	}

}

void estimateHomography(cv::Mat& src, cv::Mat& dst, int method, const char* windowName) {

	using namespace cv;
	Mat pointMask  = src.clone();
	Mat homography = Mat(3, 3, CV_64FC1);
	// estimate the homography
	homography = findHomography(src, dst, method, 3.0f, pointMask);
	Mat foreground = imread(inputForegroundImageFilename, IMREAD_GRAYSCALE);
	Mat background = imread(inputBackgroundImageFilename, IMREAD_GRAYSCALE);
	Mat result     = background.clone();
	Mat whiteImage = Mat().zeros(foreground.size(), CV_8UC1);
	Mat maskImage  = Mat().zeros(background.size(), CV_8UC1);
	Mat correspondence;
	// draw lines between corresponding lines
	drawCorrespondingLine(foreground, background, correspondence, src, dst, pointMask);
	// warp the image based on homography
	warpPerspective(foreground, result, homography, result.size(),INTER_LINEAR, BORDER_TRANSPARENT);
	// resize the mask to show which points are used
	resize(pointMask, pointMask, Size(20, background.rows), 0, 0, INTER_NEAREST);
	pointMask.convertTo(pointMask, CV_8U);
	pointMask *= kHigh;
	// concatenate them horizontally
	std::vector<Mat> inputLists;
	inputLists.push_back(correspondence);
	inputLists.push_back(result.clone());
	inputLists.push_back(pointMask);
	hconcat(inputLists, result);
	// show the image
	namedWindow(windowName);
	imshow(windowName, result);
	waitKey(0);
	destroyAllWindows();

};

int main(int argc, char **argv){

	using namespace cv;
	Mat src        = Mat(cPoints, 3, CV_64FC1, (void*)srcPoints);
	Mat dst        = Mat(cPoints, 3, CV_64FC1, (void*)dstPoints);
	// estimate homography using default method
	estimateHomography(src, dst, 0,      "default");
	// estimate homography using RANSAC estimation method
	estimateHomography(src, dst, RANSAC, "RANSAC");
	// estimate homography using LMeDS estimation method
	estimateHomography(src, dst, LMEDS,  "LMeDS");
	// estimate homography using RHO estimation method
	estimateHomography(src, dst, RHO,    "RHO");
	// estimate homography with some noise on the coordinates
	// in order to show the tolerance against the noise
	Mat srcNoiseAdded = src.clone();
	Mat dstNoiseAdded = dst.clone();
	RNG noise;
	// add gaussian noise
	for(int i = 0;i < src.rows;i++)
	{
		srcNoiseAdded.at<double>(i,0) += noise.gaussian(kSigma);
		srcNoiseAdded.at<double>(i,1) += noise.gaussian(kSigma);
		dstNoiseAdded.at<double>(i,0) += noise.gaussian(kSigma);
		dstNoiseAdded.at<double>(i,1) += noise.gaussian(kSigma);
	}
	// estimate the homography using each method
	estimateHomography(srcNoiseAdded, dstNoiseAdded, RANSAC, "RANSAC");
	estimateHomography(srcNoiseAdded, dstNoiseAdded, LMEDS,  "LMeDS");
	estimateHomography(srcNoiseAdded, dstNoiseAdded, RHO,    "RHO");
	// estimate homography with wrong correspondence
	// add ranndom correspondence coordinates and see if estimation can reject them
	srcNoiseAdded = src.clone();
	dstNoiseAdded = dst.clone();
	// fill the noisePart with random coordinates
	// concatenate them using push_back()
	Mat noisePart = Mat(20, 3, CV_64FC1);
	noise.fill(noisePart, RNG::UNIFORM, Mat::zeros(1, 1, CV_64FC1), Mat::ones(1, 1, CV_64FC1) * 200);
	srcNoiseAdded.push_back(noisePart);
	noise.fill(noisePart, RNG::UNIFORM, Mat::zeros(1, 1, CV_64FC1), Mat::ones(1, 1, CV_64FC1) * 200);
	dstNoiseAdded.push_back(noisePart);
	// estimate the homography using each method
	estimateHomography(srcNoiseAdded, dstNoiseAdded, RANSAC, "RANSAC");
	estimateHomography(srcNoiseAdded, dstNoiseAdded, LMEDS,  "LMeDS");
	estimateHomography(srcNoiseAdded, dstNoiseAdded, RHO,    "RHO");
	return 0;

} }}

実行結果

実体ファイル

OpenCV 3.0系列

OpenCV 2.4系列

その他

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


*1 厳密には等式(=)でなく,相似&mimetex(\(\simeq\

添付ファイル: fileresult000-noEstimation.png 1589件 [詳細] fileresult001-RANSAC.png 1432件 [詳細] fileresult002-LMeD.png 1487件 [詳細] fileresult003-RHO.png 1515件 [詳細] fileresult004.png 1379件 [詳細] fileresult004-RansacWithNoise.png 1515件 [詳細] fileresult005-LmedWithNoise.png 1453件 [詳細] fileresult006-RhoWithNoise.png 1494件 [詳細] fileresult007-RansacWithWrongCorrespondence.png 1383件 [詳細] fileresult008-LmedWithWrongCorrespondence.png 1421件 [詳細] fileresult009-RhoWithWrongCorrespondence.png 1358件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-01-14 (木) 12:32:40