00001
00015 #ifndef DLR_COMPUTERVISION_THREEPOINTALGORITHM_H
00016 #define DLR_COMPUTERVISION_THREEPOINTALGORITHM_H
00017
00018 #include <dlrComputerVision/cameraIntrinsicsPinhole.h>
00019 #include <dlrNumeric/transform3D.h>
00020 #include <dlrNumeric/vector2D.h>
00021 #include <dlrNumeric/vector3D.h>
00022 #include <dlrRandom/pseudoRandom.h>
00023
00024 namespace dlr {
00025
00026 namespace computerVision {
00027
00095 template <class IterType>
00096 unsigned int
00097 threePointAlgorithm(dlr::numeric::Vector3D const& w0,
00098 dlr::numeric::Vector3D const& w1,
00099 dlr::numeric::Vector3D const& w2,
00100 dlr::numeric::Vector2D const& u0,
00101 dlr::numeric::Vector2D const& u1,
00102 dlr::numeric::Vector2D const& u2,
00103 CameraIntrinsicsPinhole const& intrinsics,
00104 IterType p0OutputIter,
00105 IterType p1OutputIter,
00106 IterType p2OutputIter,
00107 double epsilon = 1.0E-8);
00108
00152 template<class InIter3D, class InIter2D, class OutIter3D>
00153 dlr::numeric::Transform3D
00154 threePointAlgorithmRobust(InIter3D worldPointsBegin,
00155 InIter3D worldPointsEnd,
00156 InIter2D imagePointsBegin,
00157 CameraIntrinsicsPinhole const& intrinsics,
00158 size_t iterations,
00159 double inlierProportion,
00160 double& score,
00161 dlr::random::PseudoRandom& pRandom
00162 = dlr::random::PseudoRandom());
00163
00164
00165 template <class OutIter>
00166 unsigned int
00167 solveThreePointAlgorithmQuarticSystem(
00168 double cosAlpha, double cosBeta, double cosGamma,
00169 double a2, double b2, double c2, double epsilon,
00170 OutIter s0Iter, OutIter s1Iter, OutIter s2Iter,
00171 double& condition);
00172
00173 }
00174
00175 }
00176
00177
00178
00179
00180
00181 #include <cmath>
00182 #include <complex>
00183 #include <limits>
00184 #include <dlrComputerVision/registerPoints3D.h>
00185 #include <dlrNumeric/solveQuartic.h>
00186 #include <dlrNumeric/utilities.h>
00187
00188 namespace dlr {
00189
00190 namespace computerVision {
00191
00192
00193
00194
00195
00196
00197 template <class IterType>
00198 unsigned int
00199 threePointAlgorithm(dlr::numeric::Vector3D const& w0,
00200 dlr::numeric::Vector3D const& w1,
00201 dlr::numeric::Vector3D const& w2,
00202 dlr::numeric::Vector2D const& u0,
00203 dlr::numeric::Vector2D const& u1,
00204 dlr::numeric::Vector2D const& u2,
00205 CameraIntrinsicsPinhole const& intrinsics,
00206 IterType p0OutputIter,
00207 IterType p1OutputIter,
00208 IterType p2OutputIter,
00209 double epsilon)
00210 {
00211 unsigned int numberOfSolutions = 0;
00212
00213
00214
00215
00216 dlr::numeric::Vector3D j0 =
00217 intrinsics.reverseProject(u0).getDirectionVector();
00218 dlr::numeric::Vector3D j1 =
00219 intrinsics.reverseProject(u1).getDirectionVector();
00220 dlr::numeric::Vector3D j2 =
00221 intrinsics.reverseProject(u2).getDirectionVector();
00222
00223
00224
00225
00226 double cosAlpha = dlr::numeric::dot(j1, j2);
00227 double cosBeta = dlr::numeric::dot(j0, j2);
00228 double cosGamma = dlr::numeric::dot(j0, j1);
00229
00230
00231
00232
00233
00234 double a2 = dlr::numeric::magnitudeSquared(w1 - w2);
00235 double b2 = dlr::numeric::magnitudeSquared(w0 - w2);
00236 double c2 = dlr::numeric::magnitudeSquared(w0 - w1);
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 double s0Array0[4];
00266 double s1Array0[4];
00267 double s2Array0[4];
00268 double condition0;
00269 unsigned int newSolutions0 = solveThreePointAlgorithmQuarticSystem(
00270 cosAlpha, cosBeta, cosGamma, a2, b2, c2, epsilon,
00271 &(s0Array0[0]), &(s1Array0[0]), &(s2Array0[0]),
00272 condition0);
00273 double s0Array1[4];
00274 double s1Array1[4];
00275 double s2Array1[4];
00276 double condition1;
00277 unsigned int newSolutions1 = solveThreePointAlgorithmQuarticSystem(
00278 cosBeta, cosAlpha, cosGamma, b2, a2, c2, epsilon,
00279 &(s1Array1[0]), &(s0Array1[0]), &(s2Array1[0]),
00280 condition1);
00281 double s0Array2[4];
00282 double s1Array2[4];
00283 double s2Array2[4];
00284 double condition2;
00285 unsigned int newSolutions2 = solveThreePointAlgorithmQuarticSystem(
00286 cosBeta, cosGamma, cosAlpha, b2, c2, a2, epsilon,
00287 &(s1Array2[0]), &(s2Array2[0]), &(s0Array2[0]),
00288 condition2);
00289
00290 double* s0Array;
00291 double* s1Array;
00292 double* s2Array;
00293 unsigned int newSolutions;
00294 if((condition0 >= condition1) && (condition0 >= condition2) ) {
00295 s0Array = s0Array0;
00296 s1Array = s1Array0;
00297 s2Array = s2Array0;
00298 newSolutions = newSolutions0;
00299 } else if((condition1 >= condition0) && (condition1 >= condition2) ) {
00300 s0Array = s0Array1;
00301 s1Array = s1Array1;
00302 s2Array = s2Array1;
00303 newSolutions = newSolutions1;
00304 } else {
00305 s0Array = s0Array2;
00306 s1Array = s1Array2;
00307 s2Array = s2Array2;
00308 newSolutions = newSolutions2;
00309 }
00310
00311 for(unsigned int ii = 0; ii < newSolutions; ++ii) {
00312 *p0OutputIter = s0Array[ii] * j0;
00313 *p1OutputIter = s1Array[ii] * j1;
00314 *p2OutputIter = s2Array[ii] * j2;
00315
00316 ++p0OutputIter;
00317 ++p1OutputIter;
00318 ++p2OutputIter;
00319 ++numberOfSolutions;
00320 }
00321 return numberOfSolutions;
00322 }
00323
00324
00325 template<class InIter3D, class InIter2D>
00326 dlr::numeric::Transform3D
00327 threePointAlgorithmRobust(InIter3D worldPointsBegin,
00328 InIter3D worldPointsEnd,
00329 InIter2D imagePointsBegin,
00330 CameraIntrinsicsPinhole const& intrinsics,
00331 size_t iterations,
00332 double inlierProportion,
00333 double& score,
00334 dlr::random::PseudoRandom& pRandom)
00335 {
00336
00337
00338 double bestErrorSoFar = std::numeric_limits<double>::max();
00339 dlr::numeric::Transform3D selectedCandidate;
00340
00341
00342 size_t numberOfPoints = worldPointsEnd - worldPointsBegin;
00343 if(numberOfPoints < 4) {
00344 DLR_THROW(ValueException, "threePointAlgorithmRobust()",
00345 "Input sequence must have at least four elements.");
00346 }
00347
00348
00349 std::vector<dlr::numeric::Vector3D> worldPoints(numberOfPoints);
00350 std::vector<dlr::numeric::Vector2D> imagePoints(numberOfPoints);
00351 std::copy(worldPointsBegin, worldPointsEnd, worldPoints.begin());
00352 std::copy(imagePointsBegin, imagePointsBegin + numberOfPoints,
00353 imagePoints.begin());
00354
00355
00356
00357 std::vector<dlr::numeric::Vector3D> cameraPoints(numberOfPoints);
00358
00359
00360 for(size_t ii = 0; ii < iterations; ++ii) {
00361
00362
00363 for(size_t jj = 0; jj < 3; ++jj) {
00364 int selectedIndex = pRandom.uniformInt(jj, numberOfPoints);
00365 if(selectedIndex != static_cast<int>(jj)) {
00366 std::swap(worldPoints[jj], worldPoints[selectedIndex]);
00367 std::swap(imagePoints[jj], imagePoints[selectedIndex]);
00368 }
00369 }
00370
00371
00372 dlr::numeric::Vector3D testPoints0_cam[4];
00373 dlr::numeric::Vector3D testPoints1_cam[4];
00374 dlr::numeric::Vector3D testPoints2_cam[4];
00375 unsigned int numberOfSolutions = threePointAlgorithm(
00376 worldPoints[0], worldPoints[1], worldPoints[2],
00377 imagePoints[0], imagePoints[1], imagePoints[2], intrinsics,
00378 testPoints0_cam, testPoints1_cam, testPoints2_cam);
00379
00380
00381 for(size_t jj = 0; jj < numberOfSolutions; ++jj) {
00382
00383
00384
00385 cameraPoints[0] = testPoints0_cam[jj];
00386 cameraPoints[1] = testPoints1_cam[jj];
00387 cameraPoints[2] = testPoints2_cam[jj];
00388 dlr::numeric::Transform3D camTworld = registerPoints3D(
00389 worldPoints.begin(), worldPoints.begin() + 3, cameraPoints.begin());
00390
00391
00392 std::transform(worldPoints.begin(), worldPoints.end(),
00393 cameraPoints.begin(), camTworld.getFunctor());
00394
00395
00396
00397 std::vector<double> residualVector(numberOfPoints);
00398 for(size_t kk = 0; kk < cameraPoints.size(); ++kk) {
00399 dlr::numeric::Vector2D testPoint_image =
00400 intrinsics.project(cameraPoints[kk]);
00401 residualVector[kk] = dlr::numeric::magnitudeSquared(
00402 testPoint_image - imagePoints[kk]);
00403 }
00404
00405
00406
00407
00408
00409 std::sort(residualVector.begin(), residualVector.end());
00410 int testIndex = static_cast<int>(
00411 inlierProportion * (residualVector.size() - 1) + 0.5);
00412 double errorValue = residualVector[testIndex];
00413
00414
00415 if(errorValue < bestErrorSoFar) {
00416 selectedCandidate = camTworld;
00417 bestErrorSoFar = errorValue;
00418 }
00419 }
00420 }
00421 score = bestErrorSoFar;
00422 return selectedCandidate;
00423 }
00424
00425
00426 template <class OutIter>
00427 unsigned int
00428 solveThreePointAlgorithmQuarticSystem(
00429 double cosAlpha, double cosBeta, double cosGamma,
00430 double a2, double b2, double c2,
00431 double epsilon,
00432 OutIter s0Iter, OutIter s1Iter, OutIter s2Iter,
00433 double& condition)
00434 {
00435 unsigned int numberOfSolutions = 0;
00436 condition = std::numeric_limits<double>::max();
00437
00438 double cos2Alpha = cosAlpha * cosAlpha;
00439 double cos2Beta = cosBeta * cosBeta;
00440 double cos2Gamma = cosGamma * cosGamma;
00441 double a2OverB2 = a2 / b2;
00442 double a2MinusC2OverB2 = (a2 - c2) / b2;
00443 double a2MinusC2OverB2Sq = a2MinusC2OverB2 * a2MinusC2OverB2;
00444 double a2MinusC2OverB2Minus1 = a2MinusC2OverB2 - 1.0;
00445 double a2PlusC2OverB2 = (a2 + c2) / b2;
00446 double b2MinusA2OverB2 = (b2 - a2) / b2;
00447 double b2MinusC2OverB2 = (b2 - c2) / b2;
00448 double c2OverB2 = c2 / b2;
00449 double oneMinusA2PlusC2OverB2 = (1.0 - a2PlusC2OverB2);
00450 double oneMinusA2MinusC2OverB2 = (1.0 - a2MinusC2OverB2);
00451 double onePlusA2MinusC2OverB2 = (1.0 + a2MinusC2OverB2);
00452
00453 double A0 = (onePlusA2MinusC2OverB2 * onePlusA2MinusC2OverB2
00454 - 4.0 * a2OverB2 * cos2Gamma);
00455
00456 double A1 = 4.0 * ((-a2MinusC2OverB2 * onePlusA2MinusC2OverB2 * cosBeta)
00457 + (2.0 * a2OverB2 * cos2Gamma * cosBeta)
00458 - (oneMinusA2PlusC2OverB2 * cosAlpha * cosGamma));
00459
00460 double A2 = 2.0 * (a2MinusC2OverB2Sq - 1.0
00461 + 2.0 * a2MinusC2OverB2Sq * cos2Beta
00462 + 2.0 * b2MinusC2OverB2 * cos2Alpha
00463 - 4.0 * a2PlusC2OverB2 * cosAlpha * cosBeta * cosGamma
00464 + 2.0 * b2MinusA2OverB2 * cos2Gamma);
00465
00466 double A3 = 4.0 * (a2MinusC2OverB2 * oneMinusA2MinusC2OverB2 * cosBeta
00467 - oneMinusA2PlusC2OverB2 * cosAlpha * cosGamma
00468 + 2.0 * c2OverB2 * cos2Alpha * cosBeta);
00469
00470 double A4 = (a2MinusC2OverB2Minus1 * a2MinusC2OverB2Minus1
00471 - 4.0 * c2OverB2 * cos2Alpha);
00472
00473
00474
00475
00476 std::complex<double> k2Roots[4];
00477 dlr::numeric::solveQuartic(
00478 A3 / A4, A2 / A4, A1 / A4, A0 / A4,
00479 k2Roots[0], k2Roots[1], k2Roots[2], k2Roots[3]);
00480
00481
00482
00483 for(unsigned int ii = 0; ii < 4; ++ii) {
00484 bool isReal = std::fabs(k2Roots[ii].imag()) <= epsilon;
00485 if(isReal) {
00486 double k2 = k2Roots[ii].real();
00487 double numerator = (a2MinusC2OverB2Minus1 * k2 * k2
00488 - 2.0 * a2MinusC2OverB2 * cosBeta * k2
00489 + onePlusA2MinusC2OverB2);
00490 double denominator = 2.0 * (cosGamma - k2 * cosAlpha);
00491 double magDenominator = std::fabs(denominator);
00492 if(magDenominator < condition) {
00493 condition = magDenominator;
00494 }
00495 if(magDenominator < epsilon) {
00496 continue;
00497 }
00498 double k1 = numerator / denominator;
00499
00500
00501
00502 double s0Sq = c2 / (1.0 + k1 * k1 - 2.0 * k1 * cosGamma);
00503 if(s0Sq < 0.0) {
00504 continue;
00505 }
00506 *s0Iter = std::sqrt(s0Sq);
00507 *s1Iter = k1 * (*s0Iter);
00508 *s2Iter = k2 * (*s0Iter);
00509
00510 ++s0Iter;
00511 ++s1Iter;
00512 ++s2Iter;
00513 ++numberOfSolutions;
00514 }
00515 }
00516 if(numberOfSolutions == 0) {
00517 condition = 0.0;
00518 }
00519 return numberOfSolutions;
00520 }
00521
00522 }
00523
00524 }
00525
00526 #endif