00001
00002 #include <Eigen/SVD>
00003 #include <Eigen/LU>
00004 #include <iostream>
00005 #include <limits>
00006 #include "opencv2/core/core.hpp"
00007 #include "opencv2/features2d/features2d.hpp"
00008 #include "opencv2/highgui/highgui.hpp"
00009 #include <ndt_feature_reg/ndt_frame.h>
00010
00011 namespace ndt_feature_reg
00012 {
00013
00014 PoseEstimator::PoseEstimator(int NRansac,
00015 double maxidx, double maxidd)
00016 {
00017 numRansac = NRansac;
00018 maxInlierXDist2 = maxidx*maxidx;
00019 maxInlierDDist2 = maxidd*maxidd;
00020 rot.setIdentity();
00021 trans.setZero();
00022
00023
00024 matcher = new cv::BFMatcher(cv::NORM_L2);
00025 wx = 92;
00026 wy = 48;
00027 windowed = false;
00028 projectMatches = true;
00029
00030 maxDist = std::numeric_limits<double>::max();
00031 minDist = -1.;
00032 }
00033
00034 void
00035 PoseEstimator::matchFrames(const NDTFrame& f0, const NDTFrame& f1, std::vector<cv::DMatch>& fwd_matches)
00036 {
00037 cv::Mat mask;
00038 if (windowed)
00039 mask = cv::windowedMatchingMask(f0.kpts, f1.kpts, wx, wy);
00040
00041
00042 if(f0.kpts.size() > 3 && f1.kpts.size() > 3)
00043 {
00044 matcher->match(f0.dtors, f1.dtors, fwd_matches, mask);
00045 }
00046 }
00047
00048
00049 size_t PoseEstimator::estimate(const NDTFrame &f0, const NDTFrame &f1)
00050 {
00051
00052 matches.clear();
00053 inliers.clear();
00054
00055
00056
00057
00058
00059 std::vector<cv::DMatch> fwd_matches, rev_matches;
00060 matchFrames(f0, f1, fwd_matches);
00061 matchFrames(f1, f0, rev_matches);
00062
00063
00064
00065 for (int i = 0; i < (int)fwd_matches.size(); ++i)
00066 {
00067 if (fwd_matches[i].trainIdx >= 0)
00068 matches.push_back( cv::DMatch(i, fwd_matches[i].trainIdx, fwd_matches[i].distance) );
00069
00070 }
00071 for (int i = 0; i < (int)rev_matches.size(); ++i)
00072 {
00073 if (rev_matches[i].trainIdx >= 0 && i != fwd_matches[rev_matches[i].trainIdx].trainIdx)
00074 matches.push_back( cv::DMatch(rev_matches[i].trainIdx, i, rev_matches[i].distance) );
00075
00076 }
00077
00078
00079
00080 return estimate(f0, f1, matches);
00081 }
00082
00083
00084 size_t PoseEstimator::estimate(const NDTFrame& f0, const NDTFrame& f1,
00085 const std::vector<cv::DMatch> &matches)
00086 {
00087
00088 std::vector<Eigen::Vector4d, Eigen::aligned_allocator<Eigen::Vector4d> > p0;
00089 std::vector<Eigen::Vector4d, Eigen::aligned_allocator<Eigen::Vector4d> > p1;
00090
00091 int nmatch = matches.size();
00092
00093
00094
00095
00096 std::vector<int> m0, m1;
00097 for (int i=0; i<nmatch; i++)
00098 {
00099 m0.push_back(matches[i].queryIdx);
00100 m1.push_back(matches[i].trainIdx);
00101
00102 }
00103
00104 nmatch = m0.size();
00105
00106 if (nmatch < 3) return 0;
00107
00108 int bestinl = 0;
00109
00110
00111
00112 for (int i=0; i<numRansac; i++)
00113 {
00114
00115
00116 int a=rand()%nmatch;
00117 int b = a;
00118 while (a==b)
00119 b=rand()%nmatch;
00120 int c = a;
00121 while (a==c || b==c)
00122 c=rand()%nmatch;
00123
00124 int i0a = m0[a];
00125 int i0b = m0[b];
00126 int i0c = m0[c];
00127 int i1a = m1[a];
00128 int i1b = m1[b];
00129 int i1c = m1[c];
00130
00131 if (i0a == i0b || i0a == i0c || i0b == i0c ||
00132 i1a == i1b || i1a == i1c || i1b == i1c)
00133 continue;
00134
00135
00136
00137
00138
00139
00140 Eigen::Vector3d p0a = f0.pts[i0a].head(3);
00141 Eigen::Vector3d p0b = f0.pts[i0b].head(3);
00142 Eigen::Vector3d p0c = f0.pts[i0c].head(3);
00143 Eigen::Vector3d p1a = f1.pts[i1a].head(3);
00144 Eigen::Vector3d p1b = f1.pts[i1b].head(3);
00145 Eigen::Vector3d p1c = f1.pts[i1c].head(3);
00146
00147 Eigen::Vector3d c0 = (p0a+p0b+p0c)*(1.0/3.0);
00148 Eigen::Vector3d c1 = (p1a+p1b+p1c)*(1.0/3.0);
00149
00150
00151
00152
00153 p0a -= c0;
00154 p0b -= c0;
00155 p0c -= c0;
00156 p1a -= c1;
00157 p1b -= c1;
00158 p1c -= c1;
00159
00160 Eigen::Matrix3d H = p1a*p0a.transpose() + p1b*p0b.transpose() +
00161 p1c*p0c.transpose();
00162
00163
00164 Eigen::JacobiSVD<Eigen::Matrix3d> svd(H, Eigen::ComputeFullU | Eigen::ComputeFullV);
00165 Eigen::Matrix3d V = svd.matrixV();
00166 Eigen::Matrix3d R = V * svd.matrixU().transpose();
00167 double det = R.determinant();
00168
00169 if (det < 0.0)
00170 {
00171
00172 V.col(2) = V.col(2)*-1.0;
00173 R = V * svd.matrixU().transpose();
00174 }
00175 Eigen::Vector3d tr = c0-R*c1;
00176
00177
00178 Eigen::Matrix<double,3,4> tfm;
00179
00180
00181 tfm.block<3,3>(0,0) = R;
00182 tfm.col(3) = tr;
00183
00184 #if 0
00185
00186 int inl = 0;
00187 for (int i=0; i<nmatch; i++)
00188 {
00189 Vector3d pt = tfm*f1.pts[m1[i]];
00190 Vector3d ipt = f0.cam2pix(pt);
00191 const cv::KeyPoint &kp = f0.kpts[m0[i]];
00192 double dx = kp.pt.x - ipt.x();
00193 double dy = kp.pt.y - ipt.y();
00194 double dd = f0.disps[m0[i]] - ipt.z();
00195 if (dx*dx < maxInlierXDist2 && dy*dy < maxInlierXDist2 &&
00196 dd*dd < maxInlierDDist2)
00197 {
00198 inl+=(int)sqrt(ipt.z());
00199
00200
00201
00202 }
00203 }
00204 #endif
00205 int inl = 0;
00206 for (int i=0; i<nmatch; i++)
00207 {
00208 Eigen::Vector3d pt1 = tfm*f1.pts[m1[i]];
00209 Eigen::Vector3d pt0 = f0.pts[m0[i]].head(3);
00210
00211
00212 double z = pt1.z();
00213 double dx = pt1.x() - pt0.x();
00214 double dy = pt1.y() - pt0.y();
00215 double dd = pt1.z() - pt0.z();
00216
00217 if (projectMatches)
00218 {
00219
00220 dx = dx / z;
00221 dy = dy / z;
00222 }
00223 if (dx*dx < maxInlierXDist2 && dy*dy < maxInlierXDist2 &&
00224 dd*dd < maxInlierDDist2)
00225 {
00226
00227
00228
00229 inl++;
00230 }
00231 }
00232
00233
00234 if (inl > bestinl)
00235 {
00236 bestinl = inl;
00237 rot = R;
00238 trans = tr;
00239
00240 }
00241 }
00242
00243
00244
00245
00246
00247 std::vector<cv::DMatch> inls;
00248 inliers.clear();
00249 Eigen::Matrix<double,3,4> tfm;
00250 tfm.block<3,3>(0,0) = rot;
00251 tfm.col(3) = trans;
00252
00253
00254
00255
00256 nmatch = matches.size();
00257 for (int i=0; i<nmatch; i++)
00258 {
00259 Eigen::Vector3d pt1 = tfm*f1.pts[matches[i].trainIdx];
00260
00261
00262 #if 0
00263 Vector3d ipt = f0.cam2pix(pt);
00264 const cv::KeyPoint &kp = f0.kpts[matches[i].queryIdx];
00265 double dx = kp.pt.x - ipt.x();
00266 double dy = kp.pt.y - ipt.y();
00267 double dd = f0.disps[matches[i].queryIdx] - ipt.z();
00268 #endif
00269 Eigen::Vector3d pt0 = f0.pts[matches[i].queryIdx].head(3);
00270
00271
00272 double z = pt1.z();
00273 double dx = pt1.x() - pt0.x();
00274 double dy = pt1.y() - pt0.y();
00275 double dd = pt1.z() - pt0.z();
00276
00277 if (projectMatches)
00278 {
00279
00280 dx = dx / z;
00281 dy = dy / z;
00282 }
00283
00284 if (dx*dx < maxInlierXDist2 && dy*dy < maxInlierXDist2 &&
00285 dd*dd < maxInlierDDist2)
00286 {
00287 if (z < maxDist && z > minDist)
00288
00289
00290 {
00291
00292
00293 inliers.push_back(matches[i]);
00294 }
00295 }
00296 }
00297
00298 #if 0
00299
00300 {
00301
00302 SysSBA sba;
00303 sba.verbose = 0;
00304
00305 #if 0
00306
00307
00308 Vector4d v0 = Vector4d(0,0,0,1);
00309 Quaterniond q0 = Quaternion<double>(Vector4d(0,0,0,1));
00310 sba.addNode(v0, q0, f0.cam, true);
00311
00312 Quaterniond qr1(rot);
00313 Vector4d temptrans = Vector4d(trans(0), trans(1), trans(2), 1.0);
00314
00315
00316 qr1.normalize();
00317 sba.addNode(temptrans, qr1, f1.cam, false);
00318
00319 int in = 3;
00320 if (in > (int)inls.size())
00321 in = inls.size();
00322
00323
00324 for (int i=0; i<(int)inls.size(); i++)
00325 {
00326
00327 int i0 = inls[i].queryIdx;
00328 int i1 = inls[i].trainIdx;
00329 Vector4d pt = f0.pts[i0];
00330 sba.addPoint(pt);
00331
00332
00333 Vector3d ipt;
00334 ipt(0) = f0.kpts[i0].pt.x;
00335 ipt(1) = f0.kpts[i0].pt.y;
00336 ipt(2) = ipt(0)-f0.disps[i0];
00337 sba.addStereoProj(0, i, ipt);
00338
00339
00340 ipt(0) = f1.kpts[i1].pt.x;
00341 ipt(1) = f1.kpts[i1].pt.y;
00342 ipt(2) = ipt(0)-f1.disps[i1];
00343 sba.addStereoProj(1, i, ipt);
00344 }
00345
00346 sba.huber = 2.0;
00347 sba.doSBA(5,10e-4,SBA_DENSE_CHOLESKY);
00348 int nbad = sba.removeBad(2.0);
00349 cout << endl << "Removed " << nbad << " projections > 2 pixels error" << endl;
00350 sba.doSBA(5,10e-5,SBA_DENSE_CHOLESKY);
00351
00352
00353
00354
00355 trans = sba.nodes[1].trans.head(3);
00356 Quaterniond q1;
00357 q1 = sba.nodes[1].qrot;
00358 quat = q1;
00359 rot = q1.toRotationMatrix();
00360
00361
00362 inliers.clear();
00363 for (int i=0; i<(int)inls.size(); i++)
00364 {
00365 ProjMap &prjs = sba.tracks[i].projections;
00366 if (prjs[0].isValid && prjs[1].isValid)
00367 inliers.push_back(inls[i]);
00368 }
00369
00370 printf("Inliers: %d After polish: %d\n", (int)inls.size(), (int)inliers.size());
00371 #endif
00372 }
00373 #endif
00374
00375
00376
00377
00378 return inliers.size();
00379 }
00380 }