00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qvprojective.h>
00022 #include <qvmatrixalgebra.h>
00023 #include <qvdefines.h>
00024 #include <qvmath.h>
00025 #include <float.h>
00026 #include <qvnumericalanalysis.h>
00027
00031 void homogenizePoints(const QList< QPointFMatching > &matchings, QVMatrix &premult, QVMatrix &postmult, QList< QPointFMatching > &homogeneizedPairs)
00032 {
00033
00034
00035
00036 float minXS=FLT_MAX, maxXS=-FLT_MAX, minYS=FLT_MAX, maxYS=-FLT_MAX,
00037 minXD=FLT_MAX, maxXD=-FLT_MAX, minYD=FLT_MAX, maxYD=-FLT_MAX;
00038
00039
00040 foreach(QPointFMatching matching, matchings)
00041 {
00042 minXS = MIN(matching.first.x(), minXS);
00043 maxXS = MAX(matching.first.x(), maxXS);
00044 minYS = MIN(matching.first.y(), minYS);
00045 maxYS = MAX(matching.first.y(), maxYS);
00046
00047 minXD = MIN(matching.second.x(), minXD);
00048 maxXD = MAX(matching.second.x(), maxXD);
00049 minYD = MIN(matching.second.y(), minYD);
00050 maxYD = MAX(matching.second.y(), maxYD);
00051 }
00052
00053
00054 if(fabs(minXS-maxXS) < EPSILON)
00055 maxXS += 1.0;
00056 if(fabs(minYS-maxYS) < EPSILON)
00057 maxYS += 1.0;
00058 if(fabs(minXD-maxXD) < EPSILON)
00059 maxXD += 1.0;
00060 if(fabs(minYD-maxYD) < EPSILON)
00061 maxYD += 1.0;
00062
00063 minXS = 0; maxXS = 320;
00064 minYS = 0; maxYS = 240;
00065
00066
00067 foreach(QPointFMatching matching, matchings)
00068 {
00069 const double x = (matching.first.x()-(maxXS+minXS)/2)/(maxXS-minXS),
00070 y = (matching.first.y()-(maxYS+minYS)/2)/(maxYS-minYS),
00071 x_p = (matching.second.x()-(maxXD+minXD)/2)/(maxXD-minXD),
00072 y_p = (matching.second.y()-(maxYD+minYD)/2)/(maxYD-minYD);
00073
00074 homogeneizedPairs.append(QPointFMatching(QPointF(x,y),QPointF(x_p,y_p)));
00075 }
00076
00077 const double dataPremult[9] = {
00078 1/(maxXS-minXS), 0, -(maxXS+minXS)/(2*(maxXS-minXS)),
00079 0, 1/(maxYS-minYS), -(maxYS+minYS)/(2*(maxYS-minYS)),
00080 0, 0, 1
00081 },
00082 dataPostmult[9] = {
00083 maxXD-minXD, 0, (maxXD+minXD)/2,
00084 0, maxYD-minYD, (maxYD+minYD)/2,
00085 0, 0, 1,
00086 };
00087
00088 premult = QVMatrix(3,3, dataPremult);
00089 postmult = QVMatrix(3,3, dataPostmult);
00090 }
00091
00092
00093 QVMatrix getPlanarTransferDLTCoefficientMatrix(const QList<QPointFMatching> &matchings)
00094 {
00095
00096
00097 QVMatrix A(3*matchings.size(),9);
00098 double *ptrA = A.getWriteData();
00099
00100 for (int n = 0; n < matchings.size(); n++)
00101 {
00102 const QPointFMatching matching = matchings.at(n);
00103 const double x = matching.first.x(),
00104 y = matching.first.y(),
00105 xp = matching.second.x(),
00106 yp = matching.second.y(),
00107 x_xp = x*xp,
00108 x_yp = x*yp,
00109 y_xp = y*xp,
00110 y_yp = y*yp;
00111
00112 ptrA[0] = 0; ptrA[1] = 0; ptrA[2] = 0;
00113 ptrA[3] = -x; ptrA[4] = -y; ptrA[5] = -1;
00114 ptrA[6] = x_yp; ptrA[7] = y_yp; ptrA[8] = yp;
00115
00116 ptrA[9] = x; ptrA[10] = y; ptrA[11] = 1;
00117 ptrA[12] = 0; ptrA[13] = 0; ptrA[14] = 0;
00118 ptrA[15] = -x_xp; ptrA[16] = -y_xp; ptrA[17] = -xp;
00119
00120 ptrA[18] = -x_yp; ptrA[19] = -y_yp; ptrA[20] = -yp;
00121 ptrA[21] = x_xp; ptrA[22] = y_xp; ptrA[23] = xp;
00122 ptrA[24] = 0; ptrA[25] = 0; ptrA[26] = 0;
00123
00124 ptrA += 27;
00125 }
00126
00127 return A;
00128 }
00129
00130
00131 bool computeProjectiveHomography(const QList< QPointFMatching > &matchings, QVMatrix &H)
00132 {
00133 if (matchings.size() < 4)
00134 return false;
00135
00136
00137
00138
00139 QList< QPointFMatching > homogeneizedPairs;
00140 QVMatrix premult, postmult;
00141
00142 homogenizePoints(matchings, premult, postmult, homogeneizedPairs);
00143
00144 const QVMatrix A = getPlanarTransferDLTCoefficientMatrix(homogeneizedPairs);
00145
00146
00147 const QVMatrix AtA = A.dotProduct(A, true, false);
00148
00149 QVMatrix U, V;
00150 QVVector s;
00151 singularValueDecomposition(AtA, U, s, V, DEFAULT_TQVSVD_METHOD);
00152
00153
00154 QVMatrix homography(3,3, V.getCol(8));
00155
00156
00157 homography = (postmult * homography) * premult;
00158 homography = homography / homography(2,2);
00159
00160 H = homography;
00161 return true;
00162 }
00163
00164
00165 bool computeProjectiveHomography2(const QList< QPointFMatching > &matchings, QVMatrix &H)
00166 {
00167 if (matchings.size() < 4)
00168 return false;
00169
00170
00171
00172
00173 QList< QPointFMatching > homogeneizedPairs;
00174 QVMatrix premult, postmult;
00175
00176 homogenizePoints(matchings, premult, postmult, homogeneizedPairs);
00177
00178
00179
00180 QVMatrix A(3*homogeneizedPairs.size(),9);
00181 for (int n = 0; n < homogeneizedPairs.size(); n++)
00182 {
00183 const QPointFMatching matching = homogeneizedPairs.at(n);
00184 const double x = matching.first.x(),
00185 y = matching.first.y(),
00186 x_p = matching.second.x(),
00187 y_p = matching.second.y();
00188
00189 const double coefsMatrixData[3 * 9] = {
00190
00191 0, 0, 0,
00192 -x, -y, -1,
00193 x*y_p, y*y_p, y_p,
00194
00195 x, y, 1,
00196 0, 0, 0,
00197 -x*x_p, -y*x_p, -x_p,
00198
00199 -x*y_p, -y*y_p, -y_p,
00200 x*x_p, y*x_p, x_p,
00201 0, 0, 0
00202 };
00203
00204 const QVMatrix coefsMatrix(3,9, coefsMatrixData);
00205
00206 A.setRow(3*n+0, coefsMatrix.getRow(0));
00207 A.setRow(3*n+1, coefsMatrix.getRow(1));
00208 A.setRow(3*n+2, coefsMatrix.getRow(2));
00209 }
00210
00211
00212 QVVector x(9);
00213
00214 solveHomogeneous(A, x);
00215
00216
00217 QVMatrix homography = QVMatrix(x.mid(0,3)) & QVMatrix(x.mid(3,3)) & QVMatrix(x.mid(6,3));
00218
00219
00220 homography = (postmult * homography) * premult;
00221 homography = homography / homography(2,2);
00222
00223 H = homography;
00224 return true;
00225 }
00226
00227 QVMatrix computeAffineHomography(const QList< QPointFMatching > &matchings)
00228 {
00229 Q_ASSERT(matchings.size() >= 3);
00230
00231
00232
00233
00234 QList< QPointFMatching > homogeneizedPairs;
00235 QVMatrix premult, postmult;
00236
00237 homogenizePoints(matchings, premult, postmult, homogeneizedPairs);
00238
00239
00240
00241 QVMatrix A(2*homogeneizedPairs.size(),6);
00242 QVVector b(2*homogeneizedPairs.size());
00243
00244 for (int n = 0; n < homogeneizedPairs.size(); n++)
00245 {
00246 const QPointFMatching matching = homogeneizedPairs.at(n);
00247 const double x = matching.first.x(),
00248 y = matching.first.y(),
00249 x_p = matching.second.x(),
00250 y_p = matching.second.y();
00251
00252 const double coefsMatrixData[2 * 6] = {
00253 x, y, 1, 0, 0, 0,
00254 0, 0, 0, x, y, 1
00255 };
00256
00257 const QVMatrix coefsMatrix(2,6, coefsMatrixData);
00258
00259 A.setRow(2*n+0, coefsMatrix.getRow(0));
00260 A.setRow(2*n+1, coefsMatrix.getRow(1));
00261 b[2*n+0] = x_p;
00262 b[2*n+1] = y_p;
00263 }
00264
00265
00266 const QVVector x = pseudoInverse(A)*b;
00267
00268
00269 const QVMatrix M = QVMatrix(x.mid(0,3)) & QVMatrix(x.mid(3,3)) & (QVVector(2,0.0) << 1);
00270
00271
00272 return (postmult * M) * premult;
00273 }
00274
00275 QVMatrix computeSimilarHomography(const QList< QPointFMatching > &matchings)
00276 {
00277 if (matchings.size() < 2)
00278 return QVMatrix::identity(3);
00279
00280 QPointF meanSource(0.0, 0.0), meanDestination(0.0, 0.0);
00281 foreach(QPointFMatching matching, matchings)
00282 {
00283 meanSource = meanSource + matching.first;
00284 meanDestination = meanDestination + matching.second;
00285 }
00286
00287 meanSource = meanSource / double(matchings.size());
00288 meanDestination = meanDestination / double(matchings.size());
00289
00290 QVVector angles, scales;
00291 foreach(QPointFMatching matching, matchings)
00292 {
00293 const QPointF source = matching.first - meanSource,
00294 destination = matching.second - meanDestination;
00295
00296 angles << qvAngle(destination, source);
00297 scales << norm2(destination) / norm2(source);
00298 }
00299
00300 return QVMatrix::translationMatrix(meanDestination.x(), meanDestination.y()) *
00301 QVMatrix::rotationMatrix(angles.median()) * QVMatrix::scaleMatrix(scales.median()) *
00302 QVMatrix::translationMatrix(-meanSource.x(), -meanSource.y());
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 QVMatrix get8PointsCoefficientMatrix(const QList<QPointFMatching> &matchings, const bool normalize)
00339 {
00340 QVMatrix A(matchings.size(),9);
00341 double *aptr = A.getWriteData();
00342
00343 foreach(QPointFMatching matching,matchings)
00344 {
00345
00346
00347
00348
00349
00350
00351
00352 const QPointF sourcePoint = matching.first, destPoint = matching.second;
00353 const double x = sourcePoint.x(), y = sourcePoint.y(),
00354 x_p = destPoint.x(), y_p = destPoint.y(),
00355 normalizer = normalize?1.0/sqrt((x*x + y*y +1)*(x_p*x_p+y_p*y_p+1)):1.0,
00356 x_ = x * normalizer, y_ = y * normalizer;
00357
00358 *aptr = x_*x_p; aptr++;
00359 *aptr = y_*x_p; aptr++;
00360 *aptr = normalizer*x_p; aptr++;
00361 *aptr = x_*y_p; aptr++;
00362 *aptr = y_*y_p; aptr++;
00363 *aptr = normalizer*y_p; aptr++;
00364 *aptr = x_; aptr++;
00365 *aptr = y_; aptr++;
00366 *aptr = normalizer; aptr++;
00367 }
00368 return A;
00369 }
00370
00371 QVMatrix getTransposeProductOf8PointsCoefficientMatrix(const QList<QPointFMatching> &matchings, const bool normalize)
00372 {
00373 QVMatrix A(9,9, 0.0);
00374 double *ptrA = A.getWriteData();
00375
00376 foreach(QPointFMatching matching,matchings)
00377 {
00378 double v[9];
00379 const QPointF sourcePoint = matching.first, destPoint = matching.second;
00380 const double x = sourcePoint.x(), y = sourcePoint.y(),
00381 x_p = destPoint.x(), y_p = destPoint.y(),
00382 normalizer = normalize?1.0/sqrt((x*x + y*y +1)*(x_p*x_p+y_p*y_p+1)):1.0,
00383 x_ = x * normalizer, y_ = y * normalizer;
00384
00385
00386 v[0] = x_*x_p;
00387 v[1] = y_*x_p;
00388 v[2] = normalizer * x_p;
00389 v[3] = x_*y_p;
00390 v[4] = y_*y_p;
00391 v[5] = normalizer * y_p;
00392 v[6] = x_;
00393 v[7] = y_;
00394 v[8] = normalizer;
00395
00396 for(int i = 0; i < 9; i++)
00397 for(int j = 0; j <= i; j++)
00398 ptrA[9*i+j] += v[i] * v[j];
00399 }
00400
00401
00402 for(int i = 0; i < 9; i++)
00403 for(int j = i+1; j < 9; j++)
00404 ptrA[9*i+j] = ptrA[9*j+i];
00405
00406 return A;
00407 }
00408
00409 QVMatrix getReduced8PointsCoefficientsMatrix( const QList<QPointFMatching> &matchingsList,
00410 const TGEA_decomposition_method decomposition_method,
00411 const bool normalize,
00412 const bool use_gsl,
00413 const double choleskyLambda)
00414 {
00415 if (matchingsList.count() > 9)
00416 {
00417 QVMatrix MtM = getTransposeProductOf8PointsCoefficientMatrix(matchingsList, normalize);
00418
00419 switch(decomposition_method)
00420 {
00421 case GEA_DO_NOT_DECOMPOSE:
00422 return MtM;
00423 break;
00424
00425 case GEA_CHOLESKY_DECOMPOSITION:
00426 {
00427 QVMatrix L;
00428
00429
00430
00431 if (choleskyLambda != 0.0)
00432 {
00433 const int n = MtM.getCols();
00434 double *data = MtM.getWriteData();
00435 for(int i = 0, idx = 0; i < n; i++, idx += n+1)
00436 data[idx] += choleskyLambda;
00437 }
00438
00439 CholeskyDecomposition(MtM, L, use_gsl?GSL_CHOLESKY:LAPACK_CHOLESKY_DPOTRF);
00440
00441 return L;
00442 }
00443 break;
00444
00445 case GEA_EIGEN_DECOMPOSITION:
00446 {
00447 QVMatrix Q;
00448 QVVector lambda;
00449
00450 eigenDecomposition(MtM, lambda, Q, use_gsl?GSL_EIGENSYMM:LAPACK_DSYEV);
00451
00452
00453 double *dataLambda = lambda.data();
00454 for(int i=0; i<lambda.size(); i++)
00455 dataLambda[i] = sqrt(fabs(dataLambda[i]));
00456
00457
00458 double *dataQ = Q.getWriteData();
00459 const int cols = Q.getCols(), rows = Q.getRows();
00460 for(int i = 0, idx = 0; i < rows; i++)
00461 for(int j = 0; j < cols; j++, idx++)
00462 dataQ[idx] *= dataLambda[j];
00463
00464 return Q;
00465 }
00466 break;
00467 }
00468 }
00469 return get8PointsCoefficientMatrix(matchingsList, normalize).transpose();
00470 }
00471
00472 QVMatrix computeFundamentalMatrix(const QList<QPointFMatching> &matchings, const bool normalize)
00473 {
00474 std::cout << "WARNING: 'QVMatrix computeFundamentalMatrix(const QList<QPointFMatching> &, const bool)' deprecated. Use 'bool computeFundamentalMatrix(const QVector<QPointFMatching> &, QVMatrix &, const TQVSVD_Method)' instead." << std::endl;
00475 if (matchings.count() < 8)
00476 return QVMatrix();
00477
00478
00479 QPointF m0c(0.0, 0.0), m1c(0.0, 0.0);
00480 foreach(QPointFMatching matching, matchings)
00481 {
00482 m0c += matching.first;
00483 m1c += matching.second;
00484 }
00485
00486 const int count = matchings.count();
00487 m0c /= count;
00488 m1c /= count;
00489
00490 double scale0 = 0.0, scale1 = 0.0;
00491 foreach(QPointFMatching matching, matchings)
00492 {
00493 scale0 += norm2(matching.first - m0c);
00494 scale1 += norm2(matching.second - m1c);
00495 }
00496
00497
00498
00499
00500
00501 scale0 = count * sqrt(2.) /scale0;
00502 scale1 = count * sqrt(2.) /scale1;
00503
00504
00505 QList<QPointFMatching> correctedMatchings;
00506 foreach(QPointFMatching matching, matchings)
00507 correctedMatchings << QPointFMatching( (matching.first - m0c)*scale0, (matching.second - m1c)*scale1);
00508
00509
00510 QVMatrix U, V;
00511 QVVector s;
00512
00513 singularValueDecomposition(getTransposeProductOf8PointsCoefficientMatrix(correctedMatchings, normalize), U, s, V, DEFAULT_TQVSVD_METHOD);
00514
00515
00516
00517
00518
00519
00520
00521 singularValueDecomposition(QVMatrix(3,3, V.getCol(8)), U, s, V, DEFAULT_TQVSVD_METHOD);
00522
00523
00524 const QVMatrix Q1 = QVMatrix::cameraCalibrationMatrix(scale0, 1.0, -scale0*m0c.x(), -scale0*m0c.y()),
00525 Q2 = QVMatrix::cameraCalibrationMatrix(scale1, 1.0, -scale1*m1c.x(), -scale1*m1c.y());
00526
00527 s[2] = 0.0;
00528
00529 QVMatrix result = Q2.transpose() * U * QVMatrix::diagonal(s) * V.transpose() * Q1;
00530
00531
00532 for(int j = 0; j < 3; j++ )
00533 for(int k = 0; k < 3; k++ )
00534 result(j,k) = float(result(j,k));
00535
00536 return result;
00537 }
00538
00539 #ifdef QVOPENCV
00540 QVMatrix cvFindFundamentalMat(const QList<QPointFMatching> &matchings)
00541 {
00542 const int point_count = matchings.size();
00543
00544 CvMat *points1 = cvCreateMat(1,point_count,CV_32FC2),
00545 *points2 = cvCreateMat(1,point_count,CV_32FC2);
00546
00547 for(int i = 0; i < point_count; i++)
00548 {
00549 points1->data.fl[i*2] = matchings[i].first.x();
00550 points1->data.fl[i*2+1] = matchings[i].first.y();
00551 points2->data.fl[i*2] = matchings[i].second.x();
00552 points2->data.fl[i*2+1] = matchings[i].second.y();
00553 }
00554
00555 CvMat *fundamental_matrix = cvCreateMat(3,3,CV_32FC1);
00556
00557 const int fm_count = cvFindFundamentalMat(points1, points2, fundamental_matrix, CV_FM_8POINT);
00558 const QVMatrix result = fundamental_matrix;
00559
00560
00561 cvReleaseMat(&points1);
00562 cvReleaseMat(&points2);
00563
00564
00565 cvReleaseMat(&fundamental_matrix);
00566
00567 return (fm_count == 1)?result:QVMatrix();
00568 }
00569 #endif
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 QPointF applyHomography(const QVMatrix &H, const QPointF &point)
00647 {
00648 const double h11 = H(0,0), h12 = H(0,1), h13 = H(0,2),
00649 h21 = H(1,0), h22 = H(1,1), h23 = H(1,2),
00650 h31 = H(2,0), h32 = H(2,1), h33 = H(2,2),
00651 x = point.x(), y = point.y(),
00652 homogenizer = h31*x + h32*y + h33;
00653
00654 return QPointF(h11*x + h12*y + h13, h21*x + h22*y + h23)/homogenizer;
00655 }
00656
00657 QList<QPointF> applyHomography(const QVMatrix &homography, const QList<QPointF> &sourcePoints)
00658 {
00659 QList<QPointF> result;
00660 foreach(QPointF point, sourcePoints)
00661 result.append(applyHomography(homography, point));
00662 return result;
00663 }
00664
00665 #ifdef QVIPP
00666 QVImage<uChar, 1> applyHomography(const QVMatrix &homography, const QVImage<uChar, 1> &image, const int interpolation)
00667 {
00668 QVImage<uChar, 1> result(image.getCols(), image.getRows());
00669 WarpPerspective(image, result, homography, interpolation);
00670 return result;
00671 }
00672
00673 QVImage<uChar, 3> applyHomography(const QVMatrix &homography, const QVImage<uChar, 3> &image, const int interpolation)
00674 {
00675 QVImage<uChar, 3> result(image.getCols(), image.getRows());
00676 WarpPerspective(image, result, homography, interpolation);
00677 return result;
00678 }
00679 #endif
00680
00681 double HomographyTestError(const QVMatrix &homography)
00682 {
00683 const QVVector v1 = homography.getCol(0), v2 = homography.getCol(1);
00684 return ABS(v1.norm2() - v2.norm2()) / (v1.norm2() + v2.norm2())
00685 + ABS(v1 * v2) / (v1.norm2() * v2.norm2());
00686 }
00687
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756 void GetExtrinsicCameraMatrixFromHomography(const QVMatrix &K, const QVMatrix &H, QVMatrix &Rt)
00757 {
00758
00759 QVMatrix R12_t = pseudoInverse(K)*pseudoInverse(H);
00760
00761
00762
00763
00764 R12_t = R12_t * 2 / (R12_t.getCol(0).norm2() + R12_t.getCol(1).norm2());
00765
00766
00767 Rt = QVMatrix(4,4);
00768
00769 Rt.setCol(0, R12_t.getCol(0));
00770 Rt.setCol(1, R12_t.getCol(1));
00771 Rt.setCol(2, R12_t.getCol(0) ^ R12_t.getCol(1));
00772 Rt.setCol(3, R12_t.getCol(2));
00773 Rt(3,3) = 1;
00774 }
00775
00776 void GetPinholeCameraIntrinsicsFromPlanarHomography(const QVMatrix &H, QVMatrix &K, const int iterations,
00777 const double maxGradientNorm, const double step, const double tol)
00778 {
00779 Q_UNUSED(H);
00780 Q_UNUSED(K);
00781 Q_UNUSED(iterations);
00782 Q_UNUSED(maxGradientNorm);
00783 Q_UNUSED(step);
00784 Q_UNUSED(tol);
00785 std::cout << "WARNING: Function 'GetPinholeCameraIntrinsicsFromPlanarHomography' is not supported anymore." << std::endl;
00786 exit(0);
00787 }
00788
00789
00790 QList<QVMatrix> getCanonicalCameraMatricesFromEssentialMatrix(const QVMatrix &E)
00791 {
00792 std::cout << "WARNING: getCanonicalCameraMatricesFromEssentialMatrix deprecated. Use getCameraPosesFromEssentialMatrix instead." << std::endl;
00793 QVVector S;
00794 QVMatrix U, V;
00795 singularValueDecomposition(E, U, S, V);
00796
00797 QVMatrix W(3, 3, 0.0);
00798 W(1,0) = 1; W(0,1) = -1; W(2,2) = 1;
00799
00800
00801 const QVVector u3 = U.getCol(2);
00802 const QVMatrix UWVt = U * W * V.transpose(),
00803 UWtVt = U * W.transpose() * V.transpose();
00804
00805
00806 return QList<QVMatrix>() << ( UWVt | u3 ) << ( UWtVt | u3 ) << ( UWVt | u3*(-1) ) << ( UWtVt | u3*(-1) );
00807 }
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860 QVMatrix refineExtrinsicCameraMatrixWithPolarDecomposition(const QVMatrix &P)
00861 {
00862 const QVMatrix M = P.getSubmatrix(0,2,0,2), Mt = M.transpose();
00863
00864 QVMatrix W,V;
00865 QVVector S;
00866 singularValueDecomposition(Mt, W, S, V);
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876 QVMatrix matS(3,3,0.0);
00877 matS(0,0) = S[0];
00878 matS(1,1) = S[1];
00879 matS(2,2) = S[2];
00880
00881 const QVMatrix
00882 Pp = V * matS * V.transpose();
00883
00884 QVMatrix I_Pp = QVMatrix::identity(3);
00885
00886 I_Pp(0,0) = SIGN(Pp(0,0));
00887 I_Pp(1,1) = SIGN(Pp(1,1));
00888 I_Pp(2,2) = SIGN(Pp(2,2));
00889
00890 return pseudoInverse(Pp.transpose()*I_Pp) * P;
00891 }
00892
00893
00894
00895
00896 QVMatrix linearCameraResection(const QList<QPointF> &points2d, const QList<QV3DPointF> &points3d)
00897 {
00898 QVMatrix A(3 * points2d.size(), 12);
00899 double *dataA = A.getWriteData();
00900
00901 QListIterator<QPointF> iterator2D(points2d);
00902 QListIterator<QV3DPointF> iterator3D(points3d);
00903
00904 int i = 0;
00905 while (iterator2D.hasNext())
00906 {
00907 const QPointF p2d = iterator2D.next();
00908 const QV3DPointF p3d = iterator3D.next();
00909
00910 const double xp = p2d.x(), yp = p2d.y(),
00911 x = p3d.x(), y = p3d.y(), z = p3d.z();
00912
00913 double *data = dataA + (3*12*i);
00914 data[0] = 0.0; data[1] = 0.0; data[2] = 0.0; data[3] = 0.0;
00915 data[4] = -x; data[5] = -y; data[6] = -z; data[7] = -1;
00916 data[8] = +x*yp; data[9] = +y*yp; data[10] = +z*yp; data[11] = +yp;
00917
00918 data[12] = +x; data[13] = +y; data[14] = +z; data[15] = +1;
00919 data[16] = 0.0; data[17] = 0.0; data[18] = 0.0; data[19] = 0.0;
00920 data[20] = -x*xp; data[21] = -y*xp; data[22] = -z*xp; data[23] = -xp;
00921
00922 data[24] = -x*yp; data[25] = -y*yp; data[26] = -z*yp; data[27] = -yp;
00923 data[28] = +x*xp; data[29] = +y*xp; data[30] = +z*xp; data[31] = +xp;
00924 data[32] = 0.0; data[33] = 0.0; data[34] = 0.0; data[35] = 0.0;
00925
00926 i++;
00927 }
00928
00929 QVVector vectorP;
00930 solveHomogeneous(A, vectorP);
00931 const QVMatrix P(3, 4, vectorP);
00932
00933
00934
00935 const double *dataP = P.getReadData();
00936 const QV3DPointF p3d = points3d.first();
00937 return P * SIGN(dataP[8] * p3d.x() + dataP[9] * p3d.y() + dataP[10]*p3d.z() + dataP[11]);
00938 }
00939
00940 QVVector linearCameraCenterResection(const QVMatrix &R, const QList<QPointF> &points2D, const QList<QV3DPointF> &points3D)
00941 {
00942 const int n = points2D.size();
00943 QVMatrix A(3*n,3);
00944 QVVector b(3*n);
00945
00946 const double *dataR = R.getReadData();
00947
00948 for(int i = 0; i < n; i++)
00949 {
00950 const QPointF p2d = points2D[i];
00951 const QV3DPointF p3d = points3D[i];
00952 const double p_x = p2d.x(), p_y = p2d.y(), x = p3d.x(), y = p3d.y(), z = p3d.z();
00953
00954 double *dataA = &(A(3*i, 0));
00955
00956 dataA[0] = 0.0; dataA[1] = -1.0; dataA[2] = p_y;
00957 dataA[3] = 1.0; dataA[4] = 0.0; dataA[5] = -p_x;
00958 dataA[6] = -p_y; dataA[7] = p_x; dataA[8] = 0.0;
00959
00960 b[3*i+0] = p_x - ((-dataR[3] + p_y * dataR[6]) * x + (-dataR[4] + p_y * dataR[7]) * y + (-dataR[5] + p_y * dataR[8]) * z);
00961 b[3*i+1] = p_y - ((dataR[0] - p_x * dataR[6]) * x + (dataR[1] - p_x * dataR[7]) * y + (dataR[2] - p_x * dataR[8]) * z);
00962 b[3*i+2] = 1 - ((-p_y * dataR[0] + p_x * dataR[3]) * x + (-p_y * dataR[1] + p_x * dataR[4]) * y + (-p_y * dataR[2] + p_x * dataR[5]) * z);
00963 }
00964
00966 return pseudoInverse(A)*b;
00967 }
00968
00969 QV3DPointF linear3DPointTriangulation(const QList<QVMatrix> &cameraMatrices, const QList<QPointF> &projectionsOfAPoint, const TQVSVD_Method method)
00970 {
00971 if (projectionsOfAPoint.count() < 2)
00972 return QV3DPointF(0.0, 0.0, 0.0);
00973
00974 const QV3DPointF p;
00975
00976 QVMatrix A(2 * projectionsOfAPoint.size(),4);
00977
00978 QListIterator<QPointF> iteratorProjections(projectionsOfAPoint);
00979 QListIterator<QVMatrix> iteratorMatrices(cameraMatrices);
00980
00981 int i = 0;
00982 while (iteratorProjections.hasNext())
00983 {
00984 const QPointF p2d = iteratorProjections.next();
00985 const QVMatrix P = iteratorMatrices.next();
00986
00987 double *a = &(A(2*i,0)), p_x = p2d.x(), p_y = p2d.y();
00988 const double *p = P.getReadData();
00989 a[0] = p[8] * p_x - p[0];
00990 a[1] = p[9] * p_x - p[1];
00991 a[2] = p[10] * p_x - p[2];
00992 a[3] = p[11] * p_x - p[3];
00993 a[4] = p[8] * p_y - p[4];
00994 a[5] = p[9] * p_y - p[5];
00995 a[6] = p[10] * p_y - p[6];
00996 a[7] = p[11] * p_y - p[7];
00997 i++;
00998 }
00999
01000 QVVector x;
01001 #ifdef GSL_AVAILABLE
01002 solveHomogeneousEig(A, x);
01003 Q_UNUSED(method);
01004 #else
01005 solveHomogeneous(A, x, method);
01006 #endif
01007
01008 return QV3DPointF(x[0] / x[3], x[1] / x[3], x[2] / x[3]);
01009 }
01010
01011 QV3DPointF linear3DPointTriangulation(const QVector<QVMatrix> &cameraMatrices, const QHash<int, QPointF> &projectionsOfAPoint, const TQVSVD_Method method)
01012 {
01013 if (projectionsOfAPoint.count() < 2)
01014 return QV3DPointF(0.0, 0.0, 0.0);
01015
01016 QVMatrix A(2 * projectionsOfAPoint.size(),4);
01017
01018 QHashIterator<int, QPointF> it(projectionsOfAPoint);
01019 int i=0;
01020 while (it.hasNext())
01021 {
01022 it.next();
01023 const QPointF p2d = it.value();
01024 const QVMatrix P = cameraMatrices[it.key()];
01025
01026 double *a = &(A(2*i,0));
01027 const double *p = P.getReadData(), p_x = p2d.x(), p_y = p2d.y();
01028 a[0] = p[8] * p_x - p[0];
01029 a[1] = p[9] * p_x - p[1];
01030 a[2] = p[10] * p_x - p[2];
01031 a[3] = p[11] * p_x - p[3];
01032 a[4] = p[8] * p_y - p[4];
01033 a[5] = p[9] * p_y - p[5];
01034 a[6] = p[10] * p_y - p[6];
01035 a[7] = p[11] * p_y - p[7];
01036 i++;
01037 }
01038
01039 QVVector x;
01040 #ifdef GSL_AVAILABLE
01041 solveHomogeneousEig(A, x);
01042 Q_UNUSED(method);
01043 #else
01044 solveHomogeneous(A, x, method);
01045 #endif
01046
01047 return QV3DPointF(x[0] / x[3], x[1] / x[3], x[2] / x[3]);
01048 }
01049
01050 QV3DPointF linear3DPointTriangulation(const QPointFMatching &matching, const QVMatrix &P1, const QVMatrix &P2, const TQVSVD_Method method)
01051 {
01052 QVMatrix A(4,4);
01053 double *a = A.getWriteData();
01054 const double *p1 = P1.getReadData(),
01055 *p2 = P2.getReadData(),
01056 p_x1 = matching.first.x(), p_y1 = matching.first.y(),
01057 p_x2 = matching.second.x(), p_y2 = matching.second.y();
01058
01059 a[0] = p1[8] * p_x1 - p1[0];
01060 a[1] = p1[9] * p_x1 - p1[1];
01061 a[2] = p1[10] * p_x1 - p1[2];
01062 a[3] = p1[11] * p_x1 - p1[3];
01063 a[4] = p1[8] * p_y1 - p1[4];
01064 a[5] = p1[9] * p_y1 - p1[5];
01065 a[6] = p1[10] * p_y1 - p1[6];
01066 a[7] = p1[11] * p_y1 - p1[7];
01067
01068 a[8] = p2[8] * p_x2 - p2[0];
01069 a[9] = p2[9] * p_x2 - p2[1];
01070 a[10] = p2[10] * p_x2 - p2[2];
01071 a[11] = p2[11] * p_x2 - p2[3];
01072 a[12] = p2[8] * p_y2 - p2[4];
01073 a[13] = p2[9] * p_y2 - p2[5];
01074 a[14] = p2[10] * p_y2 - p2[6];
01075 a[15] = p2[11] * p_y2 - p2[7];
01076
01077 QVVector x;
01078 #ifdef GSL_AVAILABLE
01079 solveHomogeneousEig(A, x);
01080 Q_UNUSED(method);
01081 #else
01082 solveHomogeneous(A, x, method);
01083 #endif
01084
01085 return QV3DPointF(x[0] / x[3], x[1] / x[3], x[2] / x[3]);
01086 }
01087
01088 QV3DPointF linear3DPointTriangulation(const QPointFMatching &matching, const QVCameraPose &pose1, const QVCameraPose &pose2, const TQVSVD_Method method)
01089 {
01090 return linear3DPointTriangulation(matching, pose1.toProjectionMatrix(), pose2.toProjectionMatrix() );
01091 }
01092
01093 QVector<QVMatrix> cameraPosesToProjectionMatrices(const QList<QVCameraPose> &cameraPoses)
01094 {
01095 QList<QVMatrix> cameraMatrices;
01096 foreach(QVCameraPose cameraPose, cameraPoses)
01097 cameraMatrices << cameraPose.toProjectionMatrix();
01098
01099 return cameraMatrices.toVector();
01100 }
01101
01102 QVector<QVMatrix> cameraPosesToProjectionMatrices(const QList<QVEuclideanMapping3> &cameras)
01103 {
01104 QList<QVMatrix> cameraMatrices;
01105 foreach(QVEuclideanMapping3 E3, cameras)
01106 cameraMatrices << E3.toRotationTranslationMatrix();
01107
01108 return cameraMatrices.toVector();
01109 }
01110
01111 QList<QV3DPointF> linear3DPointsTriangulation(const QList<QVEuclideanMapping3> &cameras, const QList<QHash<int, QPointF> > &pointTrackings, const TQVSVD_Method method)
01112 {
01113
01114
01115
01116
01117 const QVector<QVMatrix> cameraMatricesVector = cameraPosesToProjectionMatrices(cameras);
01118
01119 QList<QV3DPointF> result;
01120 QHash<int, QPointF> projectionsOfAPoint;
01121 foreach(projectionsOfAPoint, pointTrackings)
01122 result << linear3DPointTriangulation(cameraMatricesVector, projectionsOfAPoint, method);
01123
01124 return result;
01125 }
01126
01127 QList<QV3DPointF> linear3DPointsTriangulation(const QList<QVEuclideanMapping3> &cameras, const QVector<QHash<int, QPointF> > &pointTrackings, const TQVSVD_Method method)
01128 {
01129
01130
01131
01132
01133 const QVector<QVMatrix> cameraMatricesVector = cameraPosesToProjectionMatrices(cameras);
01134
01135 QList<QV3DPointF> result;
01136 QHash<int, QPointF> projectionsOfAPoint;
01137 foreach(projectionsOfAPoint, pointTrackings)
01138 result << linear3DPointTriangulation(cameraMatricesVector, projectionsOfAPoint, method);
01139
01140 return result;
01141 }
01142
01143 QList<QV3DPointF> linear3DPointsTriangulation(const QList<QVCameraPose> &cameraPoses, const QList<QHash<int, QPointF> > &pointTrackings, const TQVSVD_Method method)
01144 {
01145
01146
01147
01148
01149 const QVector<QVMatrix> cameraMatricesVector = cameraPosesToProjectionMatrices(cameraPoses);
01150
01151 QList<QV3DPointF> result;
01152 QHash<int, QPointF> projectionsOfAPoint;
01153 foreach(projectionsOfAPoint, pointTrackings)
01154 result << linear3DPointTriangulation(cameraMatricesVector, projectionsOfAPoint, method);
01155
01156 return result;
01157 }
01158
01159 QList<QV3DPointF> linear3DPointsTriangulation(const QList<QVCameraPose> &cameraPoses, const QVector<QHash<int, QPointF> > &pointTrackings, const TQVSVD_Method method)
01160 {
01161
01162
01163
01164
01165 const QVector<QVMatrix> cameraMatricesVector = cameraPosesToProjectionMatrices(cameraPoses);
01166
01167 QList<QV3DPointF> result;
01168 QHash<int, QPointF> projectionsOfAPoint;
01169 foreach(projectionsOfAPoint, pointTrackings)
01170 result << linear3DPointTriangulation(cameraMatricesVector, projectionsOfAPoint, method);
01171
01172 return result;
01173 }
01174
01175 #ifndef DOXYGEN_IGNORE_THIS
01176 bool getCorrectCameraPoseTestingCheirality(const QPointFMatching matching, const QVMatrix &R1, const QVMatrix &R2, const QV3DPointF t, bool &R1IsCorrect, bool &tIsPossitive)
01177 {
01178
01179 const QVMatrix sourceRt = (QVMatrix::identity(3)|QVVector(3,0.0)),
01180 destRt1 = R1|t,
01181 destRt2 = R1|t*(-1.0),
01182 destRt3 = R2|t,
01183 destRt4 = R2|t*(-1.0);
01184
01185
01186 const bool
01187 cheiralityTest1 = testCheiralityForCameraPoses(sourceRt, matching.first, destRt1, matching.second ),
01188
01189 cheiralityTest2 = testCheiralityForCameraPoses(sourceRt, matching.first, destRt2, matching.second ),
01190
01191 cheiralityTest3 = testCheiralityForCameraPoses(sourceRt, matching.first, destRt3, matching.second ),
01192
01193 cheiralityTest4 = testCheiralityForCameraPoses(sourceRt, matching.first, destRt4, matching.second );
01194
01195
01196 if (cheiralityTest1 and not (cheiralityTest2 or cheiralityTest3 or cheiralityTest4) )
01197
01198 { R1IsCorrect = true; tIsPossitive = true; }
01199
01200 else if ( cheiralityTest2 and not (cheiralityTest1 or cheiralityTest3 or cheiralityTest4) )
01201
01202 { R1IsCorrect = true; tIsPossitive = false; }
01203
01204 else if (cheiralityTest3 and not (cheiralityTest1 or cheiralityTest2 or cheiralityTest4) )
01205
01206 { R1IsCorrect = false; tIsPossitive = true; }
01207
01208 else if ( cheiralityTest4 and not (cheiralityTest1 or cheiralityTest2 or cheiralityTest3) )
01209
01210 { R1IsCorrect = false; tIsPossitive = false; }
01211
01212 else
01213 return false;
01214
01215 return true;
01216 }
01217 #endif // DOXYGEN_IGNORE_THIS
01218
01219 void getCameraPosesFromEssentialMatrix(const QVMatrix &originalE, QVMatrix &R1, QVMatrix &R2, QV3DPointF &t)
01220 {
01221
01222 const QVMatrix E = originalE * ( (determinant(originalE) < 0.0)? -1.0: 1.0);
01223
01224 QVVector S;
01225 QVMatrix U, V;
01226 singularValueDecomposition(E, U, S, V);
01227
01228 QVMatrix W(3, 3, 0.0);
01229 W(1,0) = 1; W(0,1) = -1; W(2,2) = 1;
01230
01231 R1 = U * W * V.transpose();
01232 R2 = U * W.transpose() * V.transpose();
01233
01234
01235
01236
01237
01238 t = U.getCol(2);
01239 }
01240
01241 bool testCheiralityForCameraPoses(const QVMatrix &sourceRt, const QPointF &sourceProjection, const QVMatrix &destRt, const QPointF &destProjection)
01242 {
01243
01244 const QVVector homogeneousP3D = QVVector() << linear3DPointTriangulation( QPointFMatching(sourceProjection, destProjection), sourceRt, destRt) << 1;
01245 return ((sourceRt*homogeneousP3D)[2] > 0) and ((destRt*homogeneousP3D)[2] > 0);
01246 }
01247
01248 QList<QPointFMatching> applyHomographies(const QVMatrix &H1, const QVMatrix &H2, const QList<QPointFMatching> &matchings)
01249 {
01250 QList<QPointFMatching> correctedMatchings;
01251 foreach(QPointFMatching matching, matchings)
01252 correctedMatchings << QPointFMatching( applyHomography(H1, matching.first), applyHomography(H2, matching.second));
01253 return correctedMatchings;
01254 }
01255
01256 QList<QPointFMatching> correctIntrinsics(const QVMatrix &K1, const QVMatrix &K2, const QList<QPointFMatching> &matchings)
01257 {
01258 const QVMatrix invK1 = pseudoInverse(K1),
01259 invK2 = pseudoInverse(K2);
01260
01261 QList<QPointFMatching> correctedMatchings;
01262 foreach(QPointFMatching matching, matchings)
01263 correctedMatchings << QPointFMatching( applyHomography(invK1, matching.first),
01264 applyHomography(invK2, matching.second)
01265 );
01266 return correctedMatchings;
01267 }
01268
01269 QList< QHash< int, QPointF> > correctIntrinsics(const QVMatrix &K, const QList< QHash< int, QPointF> > &pointsProjections)
01270 {
01271 QList< QHash< int, QPointF> > calibratedProjections;
01272
01273 const QVMatrix invK = pseudoInverse(K);
01274 for(int i = 0; i < pointsProjections.size(); i++)
01275 {
01276 calibratedProjections << QHash<int, QPointF>();
01277 foreach(int j, pointsProjections[i].keys())
01278 calibratedProjections[i][j] = applyHomography(invK, pointsProjections[i][j]);
01279 }
01280 return calibratedProjections;
01281 }
01282
01283 double computeCameraFocalFromPlanarHomography(const QVMatrix &H, int w, int h, bool byzero)
01284 {
01285 const QVMatrix transl = QVMatrix::cameraCalibrationMatrix(1.0, 1.0, w/2.0, h/2.0);
01286 const QVMatrix Ht = (H*transl).inverse();
01287 const double ww = byzero? (-Ht(2,0)*Ht(2,1)) / ( Ht(0,0)*Ht(0,1) + Ht(1,0)*Ht(1,1) ) :
01288 (-Ht(2,0)*Ht(2,0) + Ht(2,1)*Ht(2,1)) / (Ht(0,0)*Ht(0,0) - Ht(0,1)*Ht(0,1) + Ht(1,0)*Ht(1,0) - Ht(1,1)*Ht(1,1));
01289 return sqrt(1/ww);
01290 }
01291
01292 QVCameraPose getCameraPoseFromCalibratedHomography(const QVMatrix & K, const QVMatrix & H)
01293 {
01294 if(K.getCols()!=3 or K.getRows()!=3 or H.getCols()!=3 or H.getRows()!=3)
01295 {
01296 std::cerr << "[getCameraPoseFromCalibratedHomography] Warning: homography and calibration matrices are not of size 3x3.";
01297 return QVEuclideanMapping3();
01298 }
01299
01300 const QVMatrix Hc = K.inverse()*H.inverse();
01301 QVVector r0,r1,r2,aux;
01302
01303 r0 = Hc.getCol(0);
01304 r0 = r0/r0.norm2();
01305 aux = Hc.getCol(1);
01306 aux = aux/aux.norm2();
01307 r2 = r0^aux;
01308 r2 = r2/r2.norm2();
01309 r1 = -r0^r2;
01310
01311 QVMatrix R(3,3);
01312 R.setCol(0,r0);
01313 R.setCol(1,r1);
01314 R.setCol(2,r2);
01315
01316 const QVVector C = Hc.getCol(2) / (Hc.getCol(0).norm2());
01317
01318 return QVEuclideanMapping3(QVQuaternion(R),QV3DPointF(C));
01319 }
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329 QVMatrix computeProjectiveHomography(const QList< QPointFMatching > &matchings)
01330 {
01331 std::cout << "WARNING: this version of 'computeProjectiveHomography' is deprecated." << std::endl;
01332 QVMatrix H;
01333 computeProjectiveHomography(matchings, H);
01334 return H;
01335 }
01336
01337 QV3DPointF linear3DPointTriangulation(const QPointF &point1, const QVMatrix &P1, const QPointF &point2, const QVMatrix &P2, const TQVSVD_Method method)
01338 {
01339 std::cout << "WARNING: this version of 'linear3DPointTriangulation' for two views is deprecated." << std::endl;
01340 return linear3DPointTriangulation(QPointFMatching(point1, point2), P1, P2, method);
01341 }
01342
01343 QVMatrix getCameraMatrixFrom2D3DPointCorrespondences(const QList<QPointF> &points2d, const QList<QV3DPointF> &points3d)
01344 {
01345 std::cout << "WARNING: getCameraMatrixFrom2D3DPointCorrespondences deprecated. Use linearCameraResection instead." << std::endl;
01346
01347 const int n = points2d.size();
01348 QVMatrix A(3 * n, 12);
01349 for(int i = 0; i < n; i++)
01350 {
01351 const double xp = points2d[i].x(), yp = points2d[i].y(),
01352 x = points3d[i].x(), y = points3d[i].y(), z = points3d[i].z();
01353
01354 const double dataCoefs[3*12] = {
01355 0, 0, 0, 0, -x, -y, -z, -1, +x*yp, +y*yp, +yp*z, +yp,
01356 +x, +y, +z, +1, 0, 0, 0, 0, -x*xp, -xp*y, -xp*z, -xp,
01357 -x*yp, -y*yp, -yp*z, -yp, +x*xp, +xp*y, +xp*z, +xp, 0, 0, 0, 0
01358 };
01359
01360 const QVMatrix coefs(3, 12, dataCoefs);
01361
01362 A.setRow(3*i+0, coefs.getRow(0));
01363 A.setRow(3*i+1, coefs.getRow(1));
01364 A.setRow(3*i+2, coefs.getRow(2));
01365 }
01366
01367 QVVector vectorP;
01368 solveHomogeneous(A, vectorP);
01369
01370 const QVMatrix P = QVMatrix(vectorP.mid(0,4)) & QVMatrix(vectorP.mid(4,4)) & QVMatrix(vectorP.mid(8,4));
01371
01372
01373
01374 return P * SIGN((P*(QVVector(points3d.first()) << 1))[2]);
01375 }
01376
01377 QV3DPointF triangulate3DPointFrom2Views(const QPointF &point1, const QVMatrix &P1, const QPointF &point2, const QVMatrix &P2)
01378 {
01379 std::cout << "WARNING: triangulate3DPointFrom2Views deprecated. Use linear3DPointTriangulation instead." << std::endl;
01380 QVMatrix A(4,4);
01381
01382 A.setRow(0, P1.getRow(2) * point1.x() - P1.getRow(0));
01383 A.setRow(1, P1.getRow(2) * point1.y() - P1.getRow(1));
01384 A.setRow(2, P2.getRow(2) * point2.x() - P2.getRow(0));
01385 A.setRow(3, P2.getRow(2) * point2.y() - P2.getRow(1));
01386
01387 QVVector x;
01388
01389 solveHomogeneous(A, x);
01390
01391
01392
01393
01394 return QV3DPointF(x[0] / x[3], x[1] / x[3], x[2] / x[3]);
01395
01396
01397 }
01398
01399 QV3DPointF triangulate3DPointFromNViews(const QList<QPointF> &points, const QList<QVMatrix> &Plist)
01400 {
01401 std::cout << "WARNING: triangulate3DPointFromNViews deprecated. Use linear3DPointTriangulation instead." << std::endl;
01402 QVMatrix A(2 * points.size(),4);
01403 for(int i = 0; i < points.size(); i++)
01404 {
01405 double *a = &(A(2*i,0)),
01406 p_x = points[i].x(), p_y = points[i].y();
01407
01408 const double *p = Plist[i].getReadData();
01409
01410
01411 a[0] = p[8] * p_x - p[0];
01412 a[1] = p[9] * p_x - p[1];
01413 a[2] = p[10] * p_x - p[2];
01414 a[3] = p[11] * p_x - p[3];
01415 a[4] = p[8] * p_y - p[4];
01416 a[5] = p[9] * p_y - p[5];
01417 a[6] = p[10] * p_y - p[6];
01418 a[7] = p[11] * p_y - p[7];
01419 }
01420
01421 QVVector x;
01422
01423 solveHomogeneous(A, x);
01424 return QV3DPointF(x[0] / x[3], x[1] / x[3], x[2] / x[3]);
01425 }
01426
01427 QVMatrix ComputeProjectiveHomography(const QList< QPointFMatching > &matchings)
01428 {
01429 std::cout << "WARNING: ComputeProjectiveHomography deprecated. Use 'computeProjectiveHomography' instead." << std::endl;
01430 return computeProjectiveHomography(matchings);
01431 }
01432
01433 QVMatrix ComputeAffineHomography(const QList< QPointFMatching > &matchings)
01434 {
01435 std::cout << "WARNING: ComputeAffineHomography deprecated. Use 'computeAffineHomography' instead." << std::endl;
01436 return ComputeAffineHomography(matchings);
01437 }
01438
01439 QVMatrix ComputeSimilarHomography(const QList< QPointFMatching > &matchings)
01440 {
01441 std::cout << "WARNING: ComputeSimilarHomography deprecated. Use 'computeSimilarHomography' instead." << std::endl;
01442 return computeSimilarHomography(matchings);
01443 }
01444
01445 QVMatrix ComputeEuclideanHomography(const QList< QPointFMatching > &matchings)
01446 {
01447 std::cout << "WARNING: ComputeEuclideanHomography deprecated. Use computeSimilarHomography instead." << std::endl;
01448 return ComputeSimilarHomography(matchings);
01449 }
01450
01451 QPointF ApplyHomography(const QVMatrix &H, const QPointF &point)
01452 {
01453 std::cout << "WARNING: ApplyHomography deprecated. Use 'applyHomography' instead." << std::endl;
01454 return applyHomography(H, point);
01455 }
01456
01457 QList<QPointF> ApplyHomography(const QVMatrix &H, const QList<QPointF> &sourcePoints)
01458 {
01459 std::cout << "WARNING: ApplyHomography deprecated. Use 'applyHomography' instead." << std::endl;
01460 return applyHomography(H, sourcePoints);
01461 }
01462
01463 #ifdef QVIPP
01464 QVImage<uChar, 1> ApplyHomography(const QVMatrix &H, const QVImage<uChar, 1> &image, const int interpolation)
01465 {
01466 std::cout << "WARNING: ApplyHomography deprecated. Use 'applyHomography' instead." << std::endl;
01467 return applyHomography(H, image, interpolation);
01468 }
01469
01470 QVImage<uChar, 3> ApplyHomography(const QVMatrix &H, const QVImage<uChar, 3> &image, const int interpolation)
01471 {
01472 std::cout << "WARNING: ApplyHomography deprecated. Use 'applyHomography' instead." << std::endl;
01473 return applyHomography(H, image, interpolation);
01474 }
01475 #endif
01476
01477