00001 #include <posest/peh.h>
00002 #include <sba/sba.h>
00003 #include <Eigen/SVD>
00004 #include <Eigen/LU>
00005 #include <iostream>
00006 #include <opencv2/core/core.hpp>
00007 #include <opencv2/features2d/features2d.hpp>
00008
00009 using namespace Eigen;
00010 using namespace sba;
00011 using namespace frame_common;
00012 using namespace std;
00013 using namespace cv;
00014
00015 namespace pe
00016 {
00017
00018 void invert(Mat& rvec, Mat& tvec)
00019 {
00020 Mat R, RInv;
00021 Rodrigues(rvec, R);
00022 RInv = R.inv();
00023 Rodrigues(RInv, rvec);
00024 tvec = RInv * tvec;
00025 tvec = tvec * (-1);
00026 }
00027
00028 int PoseEstimatorH::estimate(const Frame& frame1, const Frame& frame2)
00029 {
00030 matches.clear();
00031 inliers.clear();
00032
00033 Mat mask;
00034 if (windowed)
00035 mask = cv::windowedMatchingMask(frame1.kpts, frame2.kpts, wx, wy);
00036 howardMatcher->match(frame1, frame2, matches, filteredIndices, mask);
00037 return estimate(frame1, frame2, matches);
00038 }
00039
00040 void project3dPoints(const vector<Point3f>& points, const Mat& rvec, const Mat& tvec, vector<Point3f>& modif_points)
00041 {
00042 modif_points.clear();
00043 modif_points.resize(points.size());
00044 Mat R(3, 3, CV_64FC1);
00045 Rodrigues(rvec, R);
00046 for (size_t i = 0; i < points.size(); i++)
00047 {
00048 modif_points[i].x = R.at<double> (0, 0) * points[i].x + R.at<double> (0, 1) * points[i].y + R.at<double> (0, 2)
00049 * points[i].z + tvec.at<double> (0, 0);
00050 modif_points[i].y = R.at<double> (1, 0) * points[i].x + R.at<double> (1, 1) * points[i].y + R.at<double> (1, 2)
00051 * points[i].z + tvec.at<double> (1, 0);
00052 modif_points[i].z = R.at<double> (2, 0) * points[i].x + R.at<double> (2, 1) * points[i].y + R.at<double> (2, 2)
00053 * points[i].z + tvec.at<double> (2, 0);
00054 }
00055 }
00056
00057 int PoseEstimatorH::estimate(const Frame& f0, const Frame& f1, const std::vector<cv::DMatch> &peMatches)
00058 {
00059 int nmatch = (int)peMatches.size();
00060
00061 std::vector<cv::DMatch> matches;
00062
00063 for (size_t i = 0; i < filteredIndices.size(); i++)
00064 {
00065 if (f0.disps[peMatches[filteredIndices[i]].queryIdx] > minMatchDisp
00066 && f1.disps[peMatches[filteredIndices[i]].trainIdx] > minMatchDisp)
00067 {
00068 if (f0.goodPts[peMatches[filteredIndices[i]].queryIdx] && f1.goodPts[peMatches[filteredIndices[i]].trainIdx])
00069 matches.push_back(peMatches[filteredIndices[i]]);
00070 }
00071 }
00072
00073 vector<Point3f> opoints;
00074 vector<Point3f> opointsFrame2;
00075 vector<Point2f> ipoints;
00076 vector<cv::DMatch> inls;
00077 vector<int> indices;
00078
00079 for (size_t i = 0; i < matches.size(); ++i)
00080 {
00081 if (f0.goodPts[matches[i].queryIdx] && f1.goodPts[matches[i].trainIdx])
00082 {
00083 ipoints.push_back(f1.kpts[matches[i].trainIdx].pt);
00084 Eigen::Vector4d vec = f0.pts[matches[i].queryIdx];
00085 Point3f op(vec(0), vec(1), vec(2));
00086 opoints.push_back(op);
00087
00088 Eigen::Vector4d vec2 = f1.pts[matches[i].trainIdx];
00089 Point3f op2(vec2(0), vec2(1), vec2(2));
00090 opointsFrame2.push_back(op2);
00091
00092 indices.push_back(i);
00093 }
00094 }
00095
00096 bool matched = (int)matches.size() > minMatchesCount;
00097
00098 #if 0
00099 if (matched)
00100 {
00101 cout << "Clique matches size = " << ipoints.size() << endl;
00102 Mat rvec, tvec;
00103 Mat intrinsic = Mat::zeros(Size(3, 3), CV_64F);
00104 intrinsic.at<double>(0, 0) = f1.cam.fx;
00105 intrinsic.at<double>(0, 2) = f1.cam.cx;
00106 intrinsic.at<double>(1, 1) = f1.cam.fy;
00107 intrinsic.at<double>(1, 2) = f1.cam.cy;
00108 intrinsic.at<double>(2, 2) = 1.0;
00109 solvePnP(Mat(opoints), Mat(ipoints), intrinsic, Mat::zeros(Size(1, 5), CV_64F), rvec, tvec, false);
00110 vector<Point2f> projectedPoints;
00111 projectPoints(Mat(opoints), rvec, tvec, intrinsic, Mat::zeros(Size(1, 5), CV_64F), projectedPoints);
00112
00113 vector<Point3f> inliersOpoints;
00114 vector<Point2f> inliersIpoints;
00115 for (size_t pointInd = 0; pointInd < projectedPoints.size(); pointInd++)
00116 {
00117 double dx = ipoints[pointInd].x - projectedPoints[pointInd].x;
00118 double dy = ipoints[pointInd].y - projectedPoints[pointInd].y;
00119 double dd = f1.disps[matches[indices[pointInd]].trainIdx] - f1.cam.fx*f1.cam.tx/opoints[pointInd].z;
00120
00121 if (dx*dx < maxInlierXDist2 && dy*dy < maxInlierXDist2 &&
00122 dd*dd < maxInlierDDist2 && norm(projectedPoints[pointInd] - ipoints[pointInd]) < 1.)
00123 {
00124 inliersIpoints.push_back(ipoints[pointInd]);
00125 inliersOpoints.push_back(opoints[pointInd]);
00126 }
00127 }
00128 cout << "Inliers matches size = " << inliersIpoints.size() << endl;
00129
00130 if (inliersIpoints.size() > 5)
00131 {
00132 solvePnP(Mat(inliersOpoints), Mat(inliersIpoints), intrinsic, Mat::zeros(Size(1, 5), CV_64F), rvec, tvec, true);
00133 projectedPoints.clear();
00134 projectPoints(Mat(inliersOpoints), rvec, tvec, intrinsic, Mat::zeros(Size(1, 5), CV_64F), projectedPoints);
00135
00136 float reprojectionError = 0.0;
00137 float avgReprojectionError = 0.0;
00138 for (size_t pointInd = 0; pointInd < projectedPoints.size(); pointInd++)
00139 {
00140 float error = norm(projectedPoints[pointInd] - inliersIpoints[pointInd]);
00141 avgReprojectionError += error;
00142 if (error > reprojectionError)
00143 {
00144 reprojectionError = error;
00145 }
00146 }
00147 avgReprojectionError /= projectedPoints.size();
00148 cout << "Reprojection error = " << reprojectionError << ", avg = " << avgReprojectionError << endl;
00149 }
00150 else
00151 {
00152 inls.clear();
00153 matched = false;
00154 }
00155
00156 if (matched)
00157 {
00158 vector<Point3f> mopoints;
00159 vector<Point2f> mipoints;
00160 vector<int> mindices;
00161 for (size_t i = 0; i < peMatches.size(); ++i)
00162 {
00163 if (f0.goodPts[peMatches[i].queryIdx] && f1.goodPts[peMatches[i].trainIdx])
00164 {
00165 mipoints.push_back(f1.kpts[peMatches[i].trainIdx].pt);
00166 Eigen::Vector4d vec = f0.pts[peMatches[i].queryIdx];
00167 Point3f op(vec(0), vec(1), vec(2));
00168 mopoints.push_back(op);
00169 mindices.push_back(i);
00170 }
00171 }
00172 vector<Point2f> mprojectedPoints;
00173 projectPoints(Mat(mopoints), rvec, tvec, intrinsic, Mat::zeros(Size(1, 5), CV_64F), mprojectedPoints);
00174 for (size_t pointInd = 0; pointInd < mprojectedPoints.size(); pointInd++)
00175 {
00176 double dx = mipoints[pointInd].x - mprojectedPoints[pointInd].x;
00177 double dy = mipoints[pointInd].y - mprojectedPoints[pointInd].y;
00178 double dd = f1.disps[peMatches[mindices[pointInd]].trainIdx] - f1.cam.fx*f1.cam.tx/mopoints[pointInd].z;
00179
00180 if (dx*dx < maxInlierXDist2 && dy*dy < maxInlierXDist2 &&
00181 dd*dd < maxInlierDDist2)
00182 {
00183 inls.push_back(peMatches[mindices[pointInd]]);
00184 }
00185 }
00186 cout << "inls size = " << inls.size() << endl;
00187
00188 if (norm(tvec) > 1.0)
00189 {
00190 cout << "*****************************************************************" << endl;
00191 cout << endl << endl << "Removed from tvec!!!!" << endl << endl;
00192 cout << "*****************************************************************" << endl;
00193 inls.clear();
00194 return 0;
00195 }
00196
00197 invert(rvec, tvec);
00198 Mat R;
00199 cv::Rodrigues(rvec, R);
00200 Matrix3d R2;
00201 Vector3d tr;
00202 R2 << R.at<double>(0,0), R.at<double>(0,1), R.at<double>(0,2),
00203 R.at<double>(1,0), R.at<double>(1,1), R.at<double>(1,2),
00204 R.at<double>(2,0), R.at<double>(2,1), R.at<double>(2,2);
00205 tr << tvec.at<double>(0,0), tvec.at<double>(0,1), tvec.at<double>(0,2);
00206 rot = R2;
00207 trans = tr;
00208 inliers = inls;
00209 return inliers.size();
00210 }
00211 else
00212 return 0;
00213 }
00214 #endif
00215
00216 #if 0
00217 if (matched)
00218 {
00219 int bestinl = 0;
00220 cout << "RANSAC iterations count = " << numRansac << endl;
00221 for (int iter = 0; iter < numRansac; iter++)
00222 {
00223 vector<int> randomIndices(3);
00224 randomIndices[0] = rand() % opoints.size();
00225 randomIndices[1] = randomIndices[0];
00226 while (randomIndices[0] == randomIndices[1])
00227 randomIndices[1] = rand() % opoints.size();
00228 randomIndices[2] = randomIndices[0];
00229 while (randomIndices[0] == randomIndices[2] || randomIndices[1] == randomIndices[2])
00230 randomIndices[2] = rand() % opoints.size();
00231
00232 vector<Vector3d> pointsFrame0(randomIndices.size()), pointsFrame1(randomIndices.size());
00233 Vector3d c0, c1;
00234 for (size_t pointInd = 0; pointInd < randomIndices.size(); pointInd++)
00235 {
00236 Vector3d pf0(opoints[randomIndices[pointInd]].x, opoints[randomIndices[pointInd]].y, opoints[randomIndices[pointInd]].z);
00237 pointsFrame0[pointInd] = pf0;
00238 Vector3d pf1(opointsFrame2[randomIndices[pointInd]].x, opointsFrame2[randomIndices[pointInd]].y,
00239 opointsFrame2[randomIndices[pointInd]].z);
00240 pointsFrame1[pointInd] = pf1;
00241 c0 += pf0;
00242 c1 += pf1;
00243 }
00244
00245 c0 *= 1.0 / randomIndices.size();
00246 c1 *= 1.0 / randomIndices.size();
00247
00248 Matrix3d H;
00249 H << 0, 0, 0, 0, 0, 0, 0, 0, 0;
00250 for (size_t pointInd = 0; pointInd < pointsFrame0.size(); pointInd++)
00251 {
00252 pointsFrame0[pointInd] -= c0;
00253 pointsFrame1[pointInd] -= c1;
00254 H += pointsFrame1[pointInd] * pointsFrame0[pointInd].transpose();
00255 }
00256 JacobiSVD<Matrix3d> svd(H, ComputeFullU | ComputeFullV);
00257 Matrix3d V = svd.matrixV();
00258 Matrix3d R = V * svd.matrixU().transpose();
00259 double det = R.determinant();
00260 if (det < 0.0)
00261 {
00262
00263 V.col(2) = V.col(2) * -1.0;
00264 R = V * svd.matrixU().transpose();
00265 }
00266 Vector3d tr = c0 - R * c1;
00267
00268
00269 Matrix<double, 3, 4> tfm;
00270 tfm.block<3, 3> (0, 0) = R;
00271 tfm.col(3) = tr;
00272
00273 int inl = 0;
00274 for (int i = 0; i < peMatches.size(); i++)
00275 {
00276 Vector3d pt = tfm * f1.pts[peMatches[i].trainIdx];
00277 Vector3d ipt = f0.cam2pix(pt);
00278 const cv::KeyPoint &kp = f0.kpts[peMatches[i].queryIdx];
00279 double dx = kp.pt.x - ipt.x();
00280 double dy = kp.pt.y - ipt.y();
00281 double dd = f0.disps[peMatches[i].queryIdx] - ipt.z();
00282 if (dx * dx < maxInlierXDist2 && dy * dy < maxInlierXDist2 && dd * dd < maxInlierDDist2)
00283 if (f0.goodPts[peMatches[i].queryIdx] && f1.goodPts[peMatches[i].trainIdx])
00284 inl += (int)sqrt(ipt.z());
00285
00286 }
00287
00288 #pragma omp critical
00289 if (inl > bestinl)
00290 {
00291
00292
00293
00294 bestinl = inl;
00295 rot = R;
00296 trans = tr;
00297 }
00298 }
00299
00300 inliers.clear();
00301 inls.clear();
00302 Matrix<double,3,4> tfm;
00303 tfm.block<3,3>(0,0) = rot;
00304 tfm.col(3) = trans;
00305 for (int i=0; i<peMatches.size(); i++)
00306 {
00307 Vector3d pt = tfm*f1.pts[peMatches[i].trainIdx];
00308 Vector3d ipt = f0.cam2pix(pt);
00309 const cv::KeyPoint &kp = f0.kpts[peMatches[i].queryIdx];
00310 double dx = kp.pt.x - ipt.x();
00311 double dy = kp.pt.y - ipt.y();
00312 double dd = f0.disps[peMatches[i].queryIdx] - ipt.z();
00313 if (dx*dx < maxInlierXDist2 && dy*dy < maxInlierXDist2 &&
00314 dd*dd < maxInlierDDist2)
00315 {
00316 if (f0.goodPts[peMatches[i].queryIdx] && f1.goodPts[peMatches[i].trainIdx])
00317 inls.push_back(peMatches[i]);
00318 }
00319 }
00320 inliers = inls;
00321 cout << "Found " << inls.size() << " inliers" << endl;
00322 }
00323 #endif
00324
00325 #if 1
00326 if (matched)
00327 {
00328 cout << "Clique size = " << opoints.size() << endl;
00329 vector<Vector3d> pointsFrame0(opoints.size()), pointsFrame1(opoints.size());
00330 Vector3d c0, c1;
00331 for (size_t pointInd = 0; pointInd < opoints.size(); pointInd++)
00332 {
00333 Vector3d pf0(opoints[pointInd].x, opoints[pointInd].y, opoints[pointInd].z);
00334 pointsFrame0[pointInd] = pf0;
00335 Vector3d pf1(opointsFrame2[pointInd].x, opointsFrame2[pointInd].y, opointsFrame2[pointInd].z);
00336 pointsFrame1[pointInd] = pf1;
00337 c0 += pf0;
00338 c1 += pf1;
00339 }
00340 c0 *= 1.0/opoints.size();
00341 c1 *= 1.0/opoints.size();
00342
00343 Matrix3d H;
00344 H << 0, 0, 0,
00345 0, 0, 0,
00346 0, 0, 0;
00347 for (size_t pointInd = 0; pointInd < pointsFrame0.size(); pointInd++)
00348 {
00349 pointsFrame0[pointInd] -= c0;
00350 pointsFrame1[pointInd] -= c1;
00351 H += pointsFrame1[pointInd]*pointsFrame0[pointInd].transpose();
00352 }
00353 JacobiSVD<Matrix3d> svd(H, ComputeFullU | ComputeFullV);
00354 Matrix3d V = svd.matrixV();
00355 Matrix3d R = V * svd.matrixU().transpose();
00356 double det = R.determinant();
00357 if (det < 0.0)
00358 {
00359 V.col(2) = V.col(2)*-1.0;
00360 R = V * svd.matrixU().transpose();
00361 }
00362 Vector3d tr = c0-R*c1;
00363
00364 Matrix<double,3,4> tfm;
00365 tfm.block<3,3>(0,0) = R;
00366 tfm.col(3) = tr;
00367
00368
00369 vector<DMatch>::iterator m;
00370 for (m = matches.begin(); m != matches.end(); )
00371 {
00372 Vector3d pt = tfm*f1.pts[(*m).trainIdx];
00373 Vector3d ipt = f0.cam2pix(pt);
00374 const cv::KeyPoint &kp = f0.kpts[(*m).queryIdx];
00375 double dx = kp.pt.x - ipt.x();
00376 double dy = kp.pt.y - ipt.y();
00377 double dd = f0.disps[(*m).queryIdx] - ipt.z();
00378 bool condition = dx * dx < maxInlierXDist2 && dy * dy < maxInlierXDist2 && dd * dd < maxInlierDDist2;
00379 if (!condition)
00380 {
00381 m = matches.erase(m);
00382 }
00383 else
00384 {
00385 m++;
00386 }
00387 }
00388
00389 ipoints.clear();
00390 opoints.clear();
00391 opointsFrame2.clear();
00392 indices.clear();
00393 for (size_t i = 0; i < matches.size(); ++i)
00394 {
00395 ipoints.push_back(f1.kpts[matches[i].trainIdx].pt);
00396 Eigen::Vector4d vec = f0.pts[matches[i].queryIdx];
00397 Point3f op(vec(0), vec(1), vec(2));
00398 opoints.push_back(op);
00399
00400 Eigen::Vector4d vec2 = f1.pts[matches[i].trainIdx];
00401 Point3f op2(vec2(0), vec2(1), vec2(2));
00402 opointsFrame2.push_back(op2);
00403
00404 indices.push_back(i);
00405 }
00406 cout << "Clique size after filtering using found transformation matrix = " << opoints.size() << endl;
00407 if (opoints.size() < 5)
00408 return 0;
00409 pointsFrame0.resize(opoints.size());
00410 pointsFrame1.resize(opoints.size());
00411 c0 = Vector3d(0, 0, 0);
00412 c1 = Vector3d(0, 0, 0);
00413 for (size_t pointInd = 0; pointInd < opoints.size(); pointInd++)
00414 {
00415 Vector3d pf0(opoints[pointInd].x, opoints[pointInd].y, opoints[pointInd].z);
00416 pointsFrame0[pointInd] = pf0;
00417 Vector3d pf1(opointsFrame2[pointInd].x, opointsFrame2[pointInd].y, opointsFrame2[pointInd].z);
00418 pointsFrame1[pointInd] = pf1;
00419 c0 += pf0;
00420 c1 += pf1;
00421 }
00422 c0 *= 1.0/opoints.size();
00423 c1 *= 1.0/opoints.size();
00424
00425 H << 0, 0, 0,
00426 0, 0, 0,
00427 0, 0, 0;
00428 for (size_t pointInd = 0; pointInd < pointsFrame0.size(); pointInd++)
00429 {
00430 pointsFrame0[pointInd] -= c0;
00431 pointsFrame1[pointInd] -= c1;
00432 H += pointsFrame1[pointInd]*pointsFrame0[pointInd].transpose();
00433 }
00434 JacobiSVD<Matrix3d> svdR(H, ComputeFullU | ComputeFullV);
00435 V = svdR.matrixV();
00436 R = V * svdR.matrixU().transpose();
00437 det = R.determinant();
00438 if (det < 0.0)
00439 {
00440 V.col(2) = V.col(2)*-1.0;
00441 R = V * svdR.matrixU().transpose();
00442 }
00443 tr = c0-R*c1;
00444 tfm.block<3,3>(0,0) = R;
00445 tfm.col(3) = tr;
00446
00447
00448
00449 inls.clear();
00450 for (int i=0; i<nmatch; i++)
00451 {
00452 Vector3d pt = tfm*f1.pts[peMatches[i].trainIdx];
00453 Vector3d ipt = f0.cam2pix(pt);
00454 const cv::KeyPoint &kp = f0.kpts[peMatches[i].queryIdx];
00455 double dx = kp.pt.x - ipt.x();
00456 double dy = kp.pt.y - ipt.y();
00457 double dd = f0.disps[peMatches[i].queryIdx] - ipt.z();
00458 if (dx*dx < maxInlierXDist2 && dy*dy < maxInlierXDist2 &&
00459 dd*dd < maxInlierDDist2)
00460 {
00461 if (f0.goodPts[peMatches[i].queryIdx] && f1.goodPts[peMatches[i].trainIdx])
00462 inls.push_back(peMatches[i]);
00463 }
00464 }
00465 rot = R;
00466 trans = tr;
00467 inliers = inls;
00468 cout << "Found " << inls.size() << " inliers" << endl;
00469 }
00470 #endif
00471
00472 if (polish)
00473 {
00474 SysSBA sba;
00475 sba.verbose = 0;
00476
00477
00478
00479 Vector4d v0 = Vector4d(0, 0, 0, 1);
00480 Quaterniond q0 = Quaternion<double> (Vector4d(0, 0, 0, 1));
00481 sba.addNode(v0, q0, f0.cam, true);
00482
00483 Quaterniond qr1(rot);
00484 Vector4d temptrans = Vector4d(trans(0), trans(1), trans(2), 1.0);
00485
00486
00487 qr1.normalize();
00488 sba.addNode(temptrans, qr1, f1.cam, false);
00489
00490 int in = 3;
00491 if (in > (int)inls.size())
00492 in = inls.size();
00493
00494 for (int i = 0; i < (int)inls.size(); i++)
00495 {
00496 int i0 = inls[i].queryIdx;
00497 int i1 = inls[i].trainIdx;
00498 Vector4d pt = f0.pts[i0];
00499 sba.addPoint(pt);
00500
00501 Vector3d ipt;
00502 ipt(0) = f0.kpts[i0].pt.x;
00503 ipt(1) = f0.kpts[i0].pt.y;
00504 ipt(2) = ipt(0) - f0.disps[i0];
00505
00506 sba.addStereoProj(0, i, ipt);
00507
00508 ipt(0) = f1.kpts[i1].pt.x;
00509 ipt(1) = f1.kpts[i1].pt.y;
00510 ipt(2) = ipt(0) - f1.disps[i1];
00511 sba.addStereoProj(1, i, ipt);
00512 }
00513
00514 sba.huber = 2.0;
00515 sba.doSBA(5, 10e-4, SBA_DENSE_CHOLESKY);
00516 sba.removeBad(2.0);
00517
00518 sba.doSBA(5, 10e-5, SBA_DENSE_CHOLESKY);
00519
00520 trans = sba.nodes[1].trans.head(3);
00521 Quaterniond q1;
00522 q1 = sba.nodes[1].qrot;
00523 rot = q1.toRotationMatrix();
00524
00525 inliers.clear();
00526 for (int i = 0; i < (int)inls.size(); i++)
00527 {
00528 ProjMap &prjs = sba.tracks[i].projections;
00529 if (prjs[0].isValid && prjs[1].isValid)
00530 inliers.push_back(inls[i]);
00531 }
00532 #if 0
00533 cout << "Inliers: " << inls.size() << ", after polish: " << inliers.size() << endl;
00534 #endif
00535 return inliers.size();
00536 }
00537 return inliers.size();
00538 }
00539 }