00001
00016 #ifndef _DLRCOMPUTERVISION_REGISTERPOINTS3D_H_
00017 #define _DLRCOMPUTERVISION_REGISTERPOINTS3D_H_
00018
00019 #include <dlrNumeric/transform3D.h>
00020
00021 namespace dlr {
00022
00023 namespace computerVision {
00024
00054 template <class InIter0, class InIter1>
00055 Transform3D
00056 registerPoints3D(InIter0 fromPointsBegin, InIter0 fromPointsEnd,
00057 InIter1 toPointsBegin);
00058
00059
00096 template <class InIter0, class InIter1, class InIter2>
00097 Transform3D
00098 registerPoints3D(InIter0 fromPointsBegin, InIter0 fromPointsEnd,
00099 InIter1 toPointsBegin, InIter2 selectedFlagsBegin);
00100
00101
00102
00166 template <class InIter0, class InIter1, class OutIter0>
00167 Transform3D
00168 registerPoints3D(InIter0 fromPointsBegin, InIter0 fromPointsEnd,
00169 InIter1 toPointsBegin, OutIter0 selectedFlagsBegin,
00170 double inclusion, double maximumResidual = -1.0,
00171 size_t maximumIterations = 5);
00172
00173
00174 }
00175
00176 }
00177
00178
00179
00180 #include <limits>
00181 #include <dlrCommon/functional.h>
00182 #include <dlrCommon/types.h>
00183 #include <dlrNumeric/array1D.h>
00184 #include <dlrNumeric/array2D.h>
00185 #include <dlrNumeric/quaternion.h>
00186 #include <dlrNumeric/rotations.h>
00187 #include <dlrNumeric/utilities.h>
00188 #include <dlrNumeric/vector3D.h>
00189 #include <dlrLinearAlgebra/linearAlgebra.h>
00190
00191 namespace dlr {
00192
00193 namespace computerVision {
00194
00196 namespace privateCode {
00197
00198 const Array2D<double>&
00199 getHornNCoefficientMatrix()
00200 {
00201 static Array2D<double> _NCoefficients(
00202 "[[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0], "
00203 " [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -1.0, 0.0], "
00204 " [0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0], "
00205 " [0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0], "
00206 " [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -1.0, 0.0], "
00207 " [1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0], "
00208 " [0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], "
00209 " [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0], "
00210 " [0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0], "
00211 " [0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], "
00212 " [-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0], "
00213 " [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0], "
00214 " [0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0], "
00215 " [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0], "
00216 " [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0], "
00217 " [-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0]]");
00218 return _NCoefficients;
00219 }
00220
00221 }
00223
00224
00225 template <class InIter0, class InIter1>
00226 Transform3D
00227 registerPoints3D(InIter0 fromPointsBegin, InIter0 fromPointsEnd,
00228 InIter1 toPointsBegin)
00229 {
00230 std::vector<bool> flags(fromPointsEnd - fromPointsBegin, true);
00231 return registerPoints3D(
00232 fromPointsBegin, fromPointsEnd, toPointsBegin, flags.begin());
00233 }
00234
00235
00236 template <class InIter0, class InIter1, class InIter2>
00237 Transform3D
00238 registerPoints3D(InIter0 fromPointsBegin, InIter0 fromPointsEnd,
00239 InIter1 toPointsBegin, InIter2 flagsBegin)
00240 {
00241
00242
00243 InIter0 fromIter = fromPointsBegin;
00244 InIter1 toIter = toPointsBegin;
00245 InIter2 flagsIter = flagsBegin;
00246 Vector3D fromMean(0.0, 0.0, 0.0);
00247 Vector3D toMean(0.0, 0.0, 0.0);
00248 size_t count = 0;
00249 while(fromIter != fromPointsEnd) {
00250 if(*flagsIter) {
00251 fromMean += *fromIter;
00252 toMean += *toIter;
00253 ++count;
00254 }
00255 ++fromIter;
00256 ++toIter;
00257 ++flagsIter;
00258 }
00259 if(count == 0) {
00260 DLR_THROW(ValueException, "registerPoints3D()",
00261 "No points to register!");
00262 }
00263 fromMean /= static_cast<double>(count);
00264 toMean /= static_cast<double>(count);
00265
00266
00267
00268
00269
00270
00271 fromIter = fromPointsBegin;
00272 toIter = toPointsBegin;
00273 flagsIter = flagsBegin;
00274 Array2D<double> translatedFromPoints(count, 3);
00275 Array2D<double> translatedToPoints(count, 3);
00276 size_t arrayIndex = 0;
00277 while(fromIter != fromPointsEnd) {
00278 if(*flagsIter) {
00279 Vector3D& fromPoint = *fromIter;
00280 Vector3D& toPoint = *toIter;
00281
00282
00283 translatedFromPoints[arrayIndex] = fromPoint.x() - fromMean.x();
00284 translatedToPoints[arrayIndex] = toPoint.x() - toMean.x();
00285
00286
00287 ++arrayIndex;
00288 translatedFromPoints[arrayIndex] = fromPoint.y() - fromMean.y();
00289 translatedToPoints[arrayIndex] = toPoint.y() - toMean.y();
00290
00291
00292 ++arrayIndex;
00293 translatedFromPoints[arrayIndex] = fromPoint.z() - fromMean.z();
00294 translatedToPoints[arrayIndex] = toPoint.z() - toMean.z();
00295
00296
00297 ++arrayIndex;
00298 }
00299
00300 ++fromIter;
00301 ++toIter;
00302 ++flagsIter;
00303 }
00304
00305
00306
00307 Array2D<double> matrixM = matrixMultiply(
00308 translatedFromPoints.transpose(), translatedToPoints);
00309
00310
00311
00312
00313 Array1D<double> vectorN = matrixMultiply(
00314 privateCode::getHornNCoefficientMatrix(), matrixM.ravel());
00315 Array2D<double> matrixN(4, 4, vectorN.data(), vectorN.refCountPtr());
00316
00317
00318
00319 Array1D<Float64> eValues;
00320 Array2D<Float64> eVectors;
00321 if(sizeof(double) == sizeof(Float64)) {
00322 eigenvectorsSymmetric(matrixN, eValues, eVectors);
00323 } else {
00324 Array2D<Float64> tempArray(matrixN.rows(), matrixN.columns());
00325 tempArray.copy(matrixN);
00326 eigenvectorsSymmetric(matrixN, eValues, eVectors);
00327 }
00328
00329
00330
00331 size_t index0 = argmax(eValues);
00332 Quaternion q0(static_cast<double>(eVectors(0, index0)),
00333 static_cast<double>(eVectors(1, index0)),
00334 static_cast<double>(eVectors(2, index0)),
00335 static_cast<double>(eVectors(3, index0)));
00336
00337
00338 Transform3D xf = quaternionToTransform3D(q0);
00339
00340
00341 Vector3D bestFitTranslation = toMean - xf * fromMean;
00342 xf.setValue<0, 3>(bestFitTranslation.x());
00343 xf.setValue<1, 3>(bestFitTranslation.y());
00344 xf.setValue<2, 3>(bestFitTranslation.z());
00345 return xf;
00346 }
00347
00348
00349 template <class InIter0, class InIter1, class OutIter0>
00350 Transform3D
00351 registerPoints3D(InIter0 fromPointsBegin, InIter0 fromPointsEnd,
00352 InIter1 toPointsBegin, OutIter0 selectedFlagsBegin,
00353 double inclusion, double maximumResidual,
00354 size_t maximumIterations)
00355 {
00356
00357 size_t numberOfPoints = fromPointsEnd - fromPointsBegin;
00358 size_t numberToExclude = 0;
00359 if(inclusion > 0.0 && inclusion < 1.0) {
00360 size_t numberToInclude = static_cast<size_t>(
00361 std::floor(inclusion * numberOfPoints));
00362 if(numberToInclude >= numberOfPoints) {
00363 DLR_THROW(ValueException, "registerPoints3D()",
00364 "Inclusion percentage is too low... all points excluded.");
00365 }
00366 numberToExclude = numberOfPoints - numberToInclude;
00367 }
00368
00369
00370 Transform3D resultTransform;
00371 std::vector<bool> flags(numberOfPoints, true);
00372 for(size_t iterationIndex = 0;
00373 iterationIndex < maximumIterations;
00374 ++iterationIndex) {
00375
00376 resultTransform = registerPoints3D(
00377 fromPointsBegin, fromPointsEnd, toPointsBegin, flags.begin());
00378
00379
00380 std::vector<Vector3D> transformedPoints(numberOfPoints);
00381 std::transform(fromPointsBegin, fromPointsEnd,
00382 transformedPoints.begin(), resultTransform.getFunctor());
00383
00384 std::vector<double> squaredResiduals(numberOfPoints);
00385 typedef double (*magVec3D)(const Vector3D&);
00386 std::transform(
00387 transformedPoints.begin(), transformedPoints.end(),
00388 toPointsBegin, squaredResiduals.begin(),
00389 composeFunctor_1_2(
00390 std::ptr_fun(static_cast<magVec3D>(magnitudeSquared)),
00391 std::minus<Vector3D>()));
00392
00393
00394
00395 double residualThreshold =
00396 (maximumResidual > 0.0)
00397 ? maximumResidual : std::numeric_limits<double>::max();
00398 if(numberToExclude != 0) {
00399
00400 std::vector<double> sortedSquaredResiduals(numberToExclude);
00401 std::partial_sort_copy(
00402 squaredResiduals.begin(), squaredResiduals.end(),
00403 sortedSquaredResiduals.begin(), sortedSquaredResiduals.end(),
00404 std::greater<double>());
00405 double threshold = sortedSquaredResiduals[numberToExclude - 1];
00406 if(threshold < residualThreshold) {
00407 residualThreshold = threshold;
00408 }
00409 }
00410
00411
00412
00413 std::vector<bool> newFlags(numberOfPoints);
00414 std::transform(
00415 squaredResiduals.begin(), squaredResiduals.end(), newFlags.begin(),
00416 std::bind2nd(std::less<double>(), residualThreshold));
00417
00418
00419 if(std::equal(flags.begin(), flags.end(), newFlags.begin())) {
00420
00421 break;
00422 }
00423
00424
00425
00426 std::copy(newFlags.begin(), newFlags.end(), flags.begin());
00427 }
00428
00429 std::copy(flags.begin(), flags.end(), selectedFlagsBegin);
00430 return resultTransform;
00431 }
00432
00433 }
00434
00435 }
00436
00437 #endif