4点同士の対応点情報からホモグラフィを線型に求める
#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})
#geshi(c++,number){{
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
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;
} }}