#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/calib3d/calib3d.hpp>
void pose_dementhon(const std::vector< cv::Point3d > &wX,
const std::vector< cv::Point2d > &x,
cv::Mat &ctw, cv::Mat &cRw)
{
int npoints = (int)wX.size();
cv::Mat r1, r2, r3;
cv::Mat A(npoints, 4, CV_64F);
for(int i = 0; i < npoints; i++) {
A.at<double>(i,0) = wX[i].x;
A.at<double>(i,1) = wX[i].y;
A.at<double>(i,2) = wX[i].z;
A.at<double>(i,3) = 1;
}
cv::Mat Ap = A.inv(cv::DECOMP_SVD);
cv::Mat eps(npoints, 1, CV_64F, cv::Scalar(0));
cv::Mat Bx(npoints, 1, CV_64F);
cv::Mat By(npoints, 1, CV_64F);
double tx, ty, tz;
cv::Mat I, J;
cv::Mat Istar(3, 1, CV_64F), Jstar(3, 1, CV_64F);
for(unsigned int iter = 0; iter < 20; iter ++) {
for(int i = 0; i < npoints; i++) {
Bx.at<double>(i,0) = x[i].x * (eps.at<double>(i,0) + 1.);
By.at<double>(i,0) = x[i].y * (eps.at<double>(i,0) + 1.);
}
I = Ap * Bx;
J = Ap * By;
for (int i = 0; i < 3; i++) {
Istar.at<double>(i,0) = I.at<double>(i,0);
Jstar.at<double>(i,0) = J.at<double>(i,0);
}
double normI=0, normJ=0;
for (int i = 0; i < 3; i++) {
normI += Istar.at<double>(i,0)*Istar.at<double>(i,0);
normJ += Jstar.at<double>(i,0)*Jstar.at<double>(i,0);
}
normI = sqrt(normI);
normJ = sqrt(normJ);
r1 = Istar / normI;
r2 = Jstar / normJ;
r3 = r1.cross(r2);
tz = 1/normI;
tx = tz * I.at<double>(3,0);
ty = tz * J.at<double>(3,0);
for(int i = 0; i < npoints; i++) {
eps.at<double>(i,0) = (r3.at<double>(0,0) * wX[i].x
+ r3.at<double>(1,0) * wX[i].y
+ r3.at<double>(2,0) * wX[i].z) / tz;
}
}
ctw.at<double>(0,0) = tx;
ctw.at<double>(1,0) = ty;
ctw.at<double>(2,0) = tz;
for (int i = 0 ; i < 3 ; i++) {
cRw.at<double>(0,i) = r1.at<double>(i, 0);
cRw.at<double>(1,i) = r2.at<double>(i, 0);
cRw.at<double>(2,i) = r3.at<double>(i, 0);
}
}
int main()
{
std::vector< cv::Point3d > wX;
std::vector< cv::Point2d > x;
cv::Mat ctw_truth = (cv::Mat_<double>(3,1) << -0.1, 0.1, 0.5);
cv::Mat crw_truth = (cv::Mat_<double>(3,1) << CV_PI/180*(5), CV_PI/180*(0), CV_PI/180*(45));
cv::Mat cRw_truth(3,3,cv::DataType<double>::type);
cv::Rodrigues(crw_truth, cRw_truth);
double L = 0.2;
wX.push_back( cv::Point3d( -L, -L, 0 ) );
wX.push_back( cv::Point3d( L, -L, 0.2) );
wX.push_back( cv::Point3d( L, L,-0.1) );
wX.push_back( cv::Point3d( -L, L, 0 ) );
for(int i = 0; i < wX.size(); i++) {
cv::Mat cX = cRw_truth*cv::Mat(wX[i]) + ctw_truth;
x.push_back( cv::Point2d( cX.at<double>(0, 0)/cX.at<double>(2, 0),
cX.at<double>(1, 0)/cX.at<double>(2, 0) ) );
}
cv::Mat ctw(3, 1, CV_64F);
cv::Mat cRw(3, 3, CV_64F);
pose_dementhon(wX, x, ctw, cRw);
std::cout << "ctw (ground truth):\n" << ctw_truth << std::endl;
std::cout << "ctw (computed with DLT):\n" << ctw << std::endl;
std::cout << "cRw (ground truth):\n" << cRw_truth << std::endl;
std::cout << "cRw (computed with DLT):\n" << cRw << std::endl;
return 0;
}