#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/calib3d/calib3d.hpp>
cv::Mat homography_dlt(const std::vector< cv::Point2d > &x1, const std::vector< cv::Point2d > &x2)
{
int npoints = (int)x1.size();
cv::Mat A(2*npoints, 9, CV_64F, cv::Scalar(0));
if (npoints == 4)
A.resize(2*npoints+1, cv::Scalar(0));
for(int i = 0; i < npoints; i++) {
A.at<double>(2*i,3) = -x1[i].x;
A.at<double>(2*i,4) = -x1[i].y;
A.at<double>(2*i,5) = -1;
A.at<double>(2*i,6) = x2[i].y * x1[i].x;
A.at<double>(2*i,7) = x2[i].y * x1[i].y;
A.at<double>(2*i,8) = x2[i].y;
A.at<double>(2*i+1,0) = x1[i].x;
A.at<double>(2*i+1,1) = x1[i].y;
A.at<double>(2*i+1,2) = 1;
A.at<double>(2*i+1,6) = -x2[i].x * x1[i].x;
A.at<double>(2*i+1,7) = -x2[i].x * x1[i].y;
A.at<double>(2*i+1,8) = -x2[i].x;
}
if (npoints == 4) {
for (int i=0; i < 9; i ++) {
A.at<double>(2*npoints,i) = 0;
}
}
cv::Mat w, u, vt;
cv::SVD::compute(A, w, u, vt);
double smallestSv = w.at<double>(0, 0);
unsigned int indexSmallestSv = 0 ;
for (int i = 1; i < w.rows; i++) {
if ((w.at<double>(i, 0) < smallestSv) ) {
smallestSv = w.at<double>(i, 0);
indexSmallestSv = i;
}
}
cv::Mat h = vt.row(indexSmallestSv);
if (h.at<double>(0, 8) < 0)
h *=-1;
cv::Mat _2H1(3, 3, CV_64F);
for (int i = 0 ; i < 3 ; i++)
for (int j = 0 ; j < 3 ; j++)
_2H1.at<double>(i,j) = h.at<double>(0, 3*i+j);
return _2H1;
}
int main()
{
std::vector< cv::Point2d > x1;
std::vector< cv::Point2d > x2;
std::vector< cv::Point3d > wX;
cv::Mat c1tw_truth = (cv::Mat_<double>(3,1) << -0.1, 0.1, 1.2);
cv::Mat c1rw_truth = (cv::Mat_<double>(3,1) << CV_PI/180*(5), CV_PI/180*(0), CV_PI/180*(45));
cv::Mat c1Rw_truth(3,3,cv::DataType<double>::type);
cv::Rodrigues(c1rw_truth, c1Rw_truth);
cv::Mat c2tc1 = (cv::Mat_<double>(3,1) << 0.01, 0.01, 0.2);
cv::Mat c2rc1 = (cv::Mat_<double>(3,1) << CV_PI/180*(0), CV_PI/180*(3), CV_PI/180*(5));
cv::Mat c2Rc1(3,3,cv::DataType<double>::type);
cv::Rodrigues(c2rc1, c2Rc1);
double L = 0.2;
wX.push_back( cv::Point3d( -L, -L, 0) );
wX.push_back( cv::Point3d( 2*L, -L, 0) );
wX.push_back( cv::Point3d( L, L, 0) );
wX.push_back( cv::Point3d( -L, L, 0) );
for(int i = 0; i < wX.size(); i++) {
cv::Mat c1X = c1Rw_truth*cv::Mat(wX[i]) + c1tw_truth;
x1.push_back( cv::Point2d( c1X.at<double>(0, 0)/c1X.at<double>(2, 0),
c1X.at<double>(1, 0)/c1X.at<double>(2, 0) ) );
cv::Mat c2X = c2Rc1*cv::Mat(c1X) + c2tc1;
x2.push_back( cv::Point2d( c2X.at<double>(0, 0)/c2X.at<double>(2, 0),
c2X.at<double>(1, 0)/c2X.at<double>(2, 0) ) );
}
cv::Mat _2H1 = homography_dlt(x1, x2);
std::cout << "2H1 (computed with DLT):\n" << _2H1 << std::endl;
return 0;
}