00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <qvsfm.h>
00026 #include <QSet>
00027
00028 #ifndef DOXYGEN_IGNORE_THIS
00029 double reconstructionError(const QVMatrix &Rt1, const QVMatrix &Rt2, const QVector<QPointFMatching> &matchings)
00030 {
00031 QList<QV3DPointF> points3D;
00032 foreach(QPointFMatching matching, matchings)
00033 points3D << linear3DPointTriangulation(matching, Rt1, Rt2);
00034
00035 return reconstructionError(Rt1, Rt2, points3D, matchings);
00036 }
00037 #endif // DOXYGEN_IGNORE_THIS
00038
00039 bool linearCameraPairInitialization(const QVector<QPointFMatching> &matchings, QVMatrix &Rt1, QVMatrix &Rt2)
00040 {
00041 QVMatrix E;
00042 if (not computeFundamentalMatrix(matchings, E))
00043 {
00044
00045
00046
00047 return false;
00048 }
00049
00050
00051 QVMatrix R1, R2;
00052 QV3DPointF t;
00053 getCameraPosesFromEssentialMatrix(E, R1, R2, t);
00054
00055
00056
00057
00058
00059
00060
00061
00062 Q_ASSERT(not R1.containsNaN());
00063 Q_ASSERT(not R2.containsNaN());
00064 Q_ASSERT(not t.containsNaN());
00065
00066 const QVMatrix sourceRt = (QVMatrix::identity(3)|QVVector(3,0.0)),
00067 destRt1 = R1|t,
00068 destRt2 = R1|t*(-1.0),
00069 destRt3 = R2|t,
00070 destRt4 = R2|t*(-1.0);
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 const QPointFMatching matching = matchings[0];
00082
00083 int R1Correct = 0, R2Correct = 0, tPossitive = 0, tNegative = 0;
00084
00085
00086 foreach(QPointFMatching matching, matchings)
00087 {
00088 const bool
00089 cheiralityTest1 = testCheiralityForCameraPoses(sourceRt, matching.first, destRt1, matching.second ),
00090
00091 cheiralityTest2 = testCheiralityForCameraPoses(sourceRt, matching.first, destRt2, matching.second ),
00092
00093 cheiralityTest3 = testCheiralityForCameraPoses(sourceRt, matching.first, destRt3, matching.second ),
00094
00095 cheiralityTest4 = testCheiralityForCameraPoses(sourceRt, matching.first, destRt4, matching.second );
00096
00097
00098 if (cheiralityTest1 + cheiralityTest2 + cheiralityTest3 + cheiralityTest4 != 1)
00099 {
00100
00101
00102
00103 return false;
00104 }
00105
00106
00107 if (cheiralityTest1)
00108
00109 { R1Correct ++; tPossitive++; }
00110 else if (cheiralityTest2)
00111
00112 { R1Correct ++; tNegative++; }
00113 else if (cheiralityTest3)
00114
00115 { R2Correct ++; tPossitive++; }
00116 else if (cheiralityTest4)
00117
00118 { R2Correct ++; tNegative++; }
00119 }
00120
00121 if ( (MIN(R1Correct, R2Correct) > 0) or (MIN(tPossitive, tNegative) > 0) )
00122 {
00123
00124
00125
00126
00127
00128
00129
00130
00131 }
00132
00133 const bool R1IsCorrect = (R1Correct > R2Correct),
00134 tIsPossitive = (tPossitive > tNegative);
00135
00136
00137 Rt1 = QVMatrix::identity(3)|QV3DPointF(0.0, 0.0, 0.0);
00138 Rt2 = (R1IsCorrect?R1:R2)|(tIsPossitive?t:(t*-1.0));
00139
00140 return true;
00141 }
00142
00143 QList< QHash< int, QPointF> > correctIntrinsics(const QList< QVMatrix > &Ks, const QList< QHash< int, QPointF> > &pointsProjections)
00144 {
00145 QList<QVMatrix> KsInv;
00146 foreach(QVMatrix K, Ks)
00147 KsInv << pseudoInverse(K);
00148
00149 QList< QHash< int, QPointF> > result;
00150
00151 QHash< int, QPointF> pointProjections;
00152 foreach(pointProjections, pointsProjections)
00153 {
00154 QHash< int, QPointF> correctedPointProjections;
00155 foreach(int numCamera, pointProjections.keys())
00156 correctedPointProjections[numCamera] = applyHomography(KsInv[MIN(Ks.count()-1, numCamera)], pointProjections[numCamera]);
00157 result << correctedPointProjections;
00158 }
00159
00160 return result;
00161 }
00162
00163 bool testCheirality(const QList<QVCameraPose> cameraPoses, const QList< QHash< int, QPointF> > calibratedPointsProjections)
00164 {
00165
00166 const QList<int> cameraIndexesForPoint1 = calibratedPointsProjections.first().keys();
00167 const int frame1 = cameraIndexesForPoint1[0],
00168 frame2 = cameraIndexesForPoint1[1];
00169
00170
00171 const QVCameraPose cameraPose0 = cameraPoses[frame1], cameraPose1 = cameraPoses[frame2];
00172
00173 const bool cheiralityTest = testCheiralityForCameraPoses( cameraPose0.toProjectionMatrix().getSubmatrix(0,2,0,3), calibratedPointsProjections[0][frame1],
00174 cameraPose1.toProjectionMatrix().getSubmatrix(0,2,0,3), calibratedPointsProjections[0][frame2]);
00175 return cheiralityTest;
00176 }
00177
00178 void invertCheirality(QList<QVCameraPose> &cameraPoses, QList<QV3DPointF> &points3D)
00179 {
00180 for(int i = 0; i < cameraPoses.count(); i++)
00181 cameraPoses[i] = QVCameraPose(cameraPoses[i].getOrientation(), -cameraPoses[i].getCenter());
00182
00183 for(int i = 0; i < points3D.count(); i++)
00184 points3D[i] = -points3D[i];
00185 }
00186
00187 double reconstructionError( const QList<QVCameraPose> &cameraPoses, const QList< QHash<int, QPointF> > &pointProjections, const QVector<bool> &evaluateTracking)
00188 {
00189 return reconstructionError(cameraPoses, linear3DPointsTriangulation(cameraPoses, pointProjections), pointProjections, evaluateTracking);
00190 }
00191
00192 double reconstructionError( const QList<QVCameraPose> &cameraPoses, const QList< QHash<int, QPointF> > &pointProjections)
00193 {
00194 return reconstructionError(cameraPoses, linear3DPointsTriangulation(cameraPoses, pointProjections), pointProjections);
00195 }
00196
00197 #ifdef DEBUG
00198 double reconstructionError2( const QList<QVCameraPose> &cameraPoses,
00199 const QList<QV3DPointF> &points3D,
00200 const QList< QHash<int, QPointF> > &pointProjections)
00201 {
00202 int count = 0;
00203 double error = 0.0;
00204 for(int i = 0; i < pointProjections.size(); i++)
00205 foreach(int j, pointProjections[i].keys())
00206 {
00207 const QPointF p = pointProjections[i][j] - cameraPoses[j].project(points3D[i]);
00208
00209 error += p.x()*p.x() + p.y()*p.y();
00210 count+=2;
00211 }
00212
00213 return sqrt(error / double(count));
00214 }
00215 #endif // DEBUG
00216
00217 QVVector squaredReprojectionErrorResidualsNew( const QV3DPointF &point3D,
00218 const QList<QVCameraPose> &cameraPoses,
00219 const QHash<int, QPointF> &pointProjections)
00220 {
00221 QVVector result;
00222 result.reserve(pointProjections.count() * 2);
00223
00224 int count = 0;
00225 double error = 0.0;
00226 foreach(int j, pointProjections.keys())
00227 {
00228 const QPointF p = pointProjections[j] - cameraPoses[j].project(point3D);
00229
00230 result << p.x()*p.x();
00231 result << p.y()*p.y();
00232 }
00233
00234 Q_ASSERT(result.count() == 2 * pointProjections.count() );
00235
00236 return result;
00237 }
00238
00239 double squaredReprojectionErrorResiduals( const QV3DPointF &point3D,
00240 const QList<QVCameraPose> &cameraPoses,
00241 const QHash<int, QPointF> &pointProjections)
00242 {
00243 int count = 0;
00244 double error = 0.0;
00245 foreach(int j, pointProjections.keys())
00246 {
00247 const QPointF p = pointProjections[j] - cameraPoses[j].project(point3D);
00248
00249 error += p.x()*p.x() + p.y()*p.y();
00250 count+=2;
00251 }
00252
00253 Q_ASSERT(count == 2 * pointProjections.count() );
00254
00255 return error;
00256 }
00257
00258 double squaredReprojectionErrorResiduals( const QV3DPointF &point3D,
00259 const QVCameraPose &cameraPose,
00260 const QPointF &pointProjection)
00261 {
00262 const QPointF p = pointProjection - cameraPose.project(point3D);
00263 return p.x()*p.x() + p.y()*p.y();
00264 }
00265
00266 double reconstructionError( const QList<QVCameraPose> &cameraPoses,
00267 const QList<QV3DPointF> &points3D,
00268 const QList< QHash<int, QPointF> > &pointProjections)
00269 {
00270 int count = 0;
00271 double error = 0.0;
00272 for(int i = 0; i < pointProjections.size(); i++)
00273 {
00274 error += squaredReprojectionErrorResiduals(points3D[i], cameraPoses, pointProjections[i]);
00275 count += 2 * pointProjections[i].count();
00276 }
00277
00278 const double re = sqrt(error / double(count));
00279
00280
00281
00282
00283
00284
00285 return re;
00286 }
00287
00288 double reconstructionError( const QList<QVCameraPose> &cameraPoses,
00289 const QList<QV3DPointF> &points3D,
00290 const QList< QHash<int, QPointF> > &pointProjections,
00291 const QVector<bool> &evaluateTracking)
00292 {
00293 Q_ASSERT(pointProjections.count() == evaluateTracking.count());
00294 int count = 0;
00295 double error = 0.0;
00296 for(int i = 0; i < pointProjections.size(); i++)
00297 if (evaluateTracking[i])
00298 {
00299 error += squaredReprojectionErrorResiduals(points3D[i], cameraPoses, pointProjections[i]);
00300 count += 2 * pointProjections[i].count();
00301 }
00302
00303 if (count > 0)
00304 return sqrt(error / double(count));
00305 else
00306 return 0.0;
00307 }
00308
00309 double reconstructionError(const QVMatrix &Rt1, const QVMatrix &Rt2, const QList<QV3DPointF> &points3D, const QVector<QPointFMatching> &matchings)
00310 {
00311 double error = 0.0;
00312 int count = 0;
00313 for(int i = 0; i < matchings.size(); i++)
00314 {
00315 const QV3DPointF &point = points3D[i];
00316 const QPointFMatching &matching = matchings[i];
00317
00318 const QPointF p1 = matchings[i].first - Rt1 * point.homogeneousCoordinates(),
00319 p2 = matchings[i].second - Rt2 * point.homogeneousCoordinates();
00320
00321 error += p1.x()*p1.x() + p1.y()*p1.y() + p2.x()*p2.x() + p2.y()*p2.y();
00322 count+=4;
00323 }
00324 return sqrt(error / double(count));
00325 }
00326
00327 QVVector reconstructionErrorResiduals( const QList<QVCameraPose> &cameraPoses,
00328 const QList<QV3DPointF> &points3D,
00329 const QList< QHash<int, QPointF> > &pointTrackings)
00330 {
00331 QList<double> residuals;
00332 for(int i = 0; i < pointTrackings.size(); i++)
00333 foreach(int j, pointTrackings[i].keys())
00334 {
00335 const QPointF p = pointTrackings[i][j] - cameraPoses[j].project(points3D[i]);
00336
00337 residuals << p.x();
00338 residuals << p.y();
00339 }
00340
00341 return residuals.toVector();
00342 }
00343
00344
00345 bool checkForNaNValues(const QList<QVCameraPose> &cameraPoses)
00346 {
00347 int camerasNaN = 0;
00348
00349 foreach(QVCameraPose cameraPose, cameraPoses)
00350 if(cameraPose.containsNaN())
00351 camerasNaN ++;
00352
00353 if (camerasNaN > 0)
00354 std::cout << "[checkReconstructionForNaN] Error: found " << camerasNaN << " camera poses containing NaN values" << std::endl;
00355
00356 return (camerasNaN == 0);
00357 }
00358
00359
00360 bool checkForNaNValues(const QList<QV3DPointF> &points3D)
00361 {
00362 int pointsNaN = 0;
00363
00364 foreach(QV3DPointF point, points3D)
00365 if(point.containsNaN())
00366 pointsNaN ++;
00367
00368 if (pointsNaN > 0)
00369 std::cout << "[checkReconstructionForNaN] Error: found " << pointsNaN << " 3D points containing NaN values" << std::endl;
00370
00371 return (pointsNaN == 0);
00372 }
00373
00374
00375 bool checkForNaNValues(const QList< QHash< int, QPointF > > &pointTrackings)
00376 {
00377 int projectionsNaN = 0;
00378
00379 for(int i = 0; i < pointTrackings.count(); i++)
00380 foreach(int j, pointTrackings[i].keys())
00381 if (isnan(pointTrackings[i][j].x()) or isnan(pointTrackings[i][j].y()))
00382 projectionsNaN++;
00383
00384 if (projectionsNaN > 0)
00385 std::cout << "[checkReconstructionForNaN] Error: found " << projectionsNaN << " projections containing NaN values" << std::endl;
00386
00387 return (projectionsNaN == 0);
00388 }
00389
00390
00391 QVector<QVIndexPair> combineMatchingLists(const QVector<QVIndexPair> &matchingsAB, const QVector<QVIndexPair> &matchingsBC)
00392 {
00393 QMap<int, int> mapBC;
00394 foreach(QVIndexPair m, matchingsBC)
00395 mapBC[m.first] = m.second;
00396
00397 QList<QVIndexPair> matchingsAC;
00398 foreach(QVIndexPair m, matchingsAB)
00399 if (mapBC.contains(m.second))
00400 matchingsAC << QVIndexPair(m.first, mapBC[m.second]);
00401
00402 #ifdef DEBUG
00403 QSet<int> A, B, C;
00404
00405 foreach(QVIndexPair m, matchingsAB)
00406 {
00407 Q_ASSERT(not A.contains(m.first));
00408 Q_ASSERT(not B.contains(m.second));
00409 A << m.first;
00410 B << m.second;
00411 }
00412
00413
00414 B.clear();
00415 C.clear();
00416 foreach(QVIndexPair m, matchingsBC)
00417 {
00418 Q_ASSERT(not B.contains(m.first));
00419 Q_ASSERT(not C.contains(m.second));
00420 B << m.first;
00421 C << m.second;
00422 }
00423
00424
00425 A.clear();
00426 C.clear();
00427 foreach(QVIndexPair m, matchingsAC)
00428 {
00429 Q_ASSERT(not A.contains(m.first));
00430 Q_ASSERT(not C.contains(m.second));
00431 A << m.first;
00432 C << m.second;
00433 }
00434 #endif // DEBUG
00435
00436 return matchingsAC.toVector();
00437 }
00438
00439 void estimate3DPointsMeanAndVariance(const QList<QV3DPointF> &points3D, QV3DPointF &mean, double &variance)
00440 {
00441 mean = QV3DPointF(0.0, 0.0, 0.0);
00442
00443 foreach(QV3DPointF point3D, points3D)
00444 mean = mean + point3D;
00445
00446 mean = mean / points3D.count();
00447
00448 variance = 0;
00449 foreach(QV3DPointF point3D, points3D)
00450 variance += (point3D - mean) * (point3D - mean);
00451
00452 variance = sqrt(variance) / points3D.count();
00453 }
00454