9 #include <QCoreApplication> 15 #include <boost/lexical_cast.hpp> 16 #include <boost/numeric/ublas/io.hpp> 17 #include <boost/numeric/ublas/matrix_sparse.hpp> 18 #include <boost/numeric/ublas/vector_proxy.hpp> 37 #include "ImageList.h" 65 const char* message) {
79 errlog +=
". (See print.prt for details)";
95 const QString &cnetFile,
96 const QString &cubeList,
103 m_printSummary = printSummary;
105 m_cnetFileName = cnetFile;
108 bundleSettings->controlPointCoordTypeReports()) );
113 m_bundleResults.setOutputControlNet(m_controlNet);
115 m_bundleSettings = bundleSettings;
116 m_bundleTargetBody = bundleSettings->bundleTargetBody();
141 m_printSummary = printSummary;
143 m_cnetFileName = cnetFile;
150 m_bundleResults.setOutputControlNet(m_controlNet);
151 m_serialNumberList = &snlist;
152 m_bundleSettings = bundleSettings;
153 m_bundleTargetBody = bundleSettings->bundleTargetBody();
178 m_printSummary = printSummary;
187 m_bundleResults.setOutputControlNet(m_controlNet);
188 m_serialNumberList = &snlist;
189 m_bundleSettings = bundleSettings;
190 m_bundleTargetBody = bundleSettings->bundleTargetBody();
214 m_printSummary = printSummary;
223 m_bundleResults.setOutputControlNet(m_controlNet);
224 m_serialNumberList = &snlist;
225 m_bundleSettings = bundleSettings;
226 m_bundleTargetBody = bundleSettings->bundleTargetBody();
242 const QString &cubeList,
245 m_printSummary = printSummary;
254 m_bundleResults.setOutputControlNet(m_controlNet);
256 m_bundleSettings = bundleSettings;
257 m_bundleTargetBody = bundleSettings->bundleTargetBody();
276 m_bundleSettings = bundleSettings;
285 m_bundleResults.setOutputControlNet(m_controlNet);
287 m_imageLists = imgLists;
295 foreach (
Image *image, *imgList) {
301 m_bundleTargetBody = bundleSettings->bundleTargetBody();
303 m_printSummary = printSummary;
306 m_cnetFileName = control.
fileName();
320 BundleAdjust::~BundleAdjust() {
323 delete m_serialNumberList;
326 freeCHOLMODLibraryVariables();
363 emit(statusUpdate(
"Initialization"));
364 m_previousNumberImagePartials = 0;
372 m_iterationSummary =
"";
378 m_controlNet->SetImages(*m_serialNumberList, progress);
381 m_controlNet->ClearJigsawRejected();
384 int numImages = m_serialNumberList->size();
387 m_normalInverse.clear();
389 m_imageSolution.clear();
394 m_cholmodNormal = NULL;
395 m_cholmodTriplet = NULL;
402 for (
int i = 0; i < numImages; i++) {
405 QString observationNumber = m_serialNumberList->observationNumber(i);
406 QString instrumentId = m_serialNumberList->spacecraftInstrumentId(i);
407 QString serialNumber = m_serialNumberList->serialNumber(i);
408 QString fileName = m_serialNumberList->fileName(i);
415 QString msg =
"In BundleAdjust::init(): image " + fileName +
"is null." +
"\n";
420 m_bundleObservations.addNew(image, observationNumber, instrumentId, m_bundleSettings);
423 QString msg =
"In BundleAdjust::init(): observation " 424 + observationNumber +
"is null." +
"\n";
431 m_bundleObservations.initializeExteriorOrientation();
433 if (m_bundleSettings->solveTargetBody()) {
434 m_bundleObservations.initializeBodyRotation();
438 int numControlPoints = m_controlNet->GetNumPoints();
439 for (
int i = 0; i < numControlPoints; i++) {
441 if (point->IsIgnored()) {
446 (m_bundleSettings, point));
447 m_bundleControlPoints.append(bundleControlPoint);
451 int numMeasures = bundleControlPoint->size();
452 for (
int j=0; j < numMeasures; j++) {
454 QString cubeSerialNumber = measure->cubeSerialNumber();
457 m_bundleObservations.observationByCubeSerialNumber(cubeSerialNumber);
458 BundleImageQsp image = observation->imageByCubeSerialNumber(cubeSerialNumber);
460 measure->setParentObservation(observation);
461 measure->setParentImage(image);
475 if (m_bundleSettings->validateNetwork()) {
478 m_bundleResults.maximumLikelihoodSetUp(m_bundleSettings->maximumLikelihoodEstimatorModels());
494 m_rank = m_bundleObservations.numberParameters();
496 if (m_bundleSettings->solveTargetBody()) {
497 m_rank += m_bundleSettings->numberTargetBodyParameters();
500 int num3DPoints = m_bundleControlPoints.size();
502 m_bundleResults.setNumberUnknownParameters(m_rank + 3 * num3DPoints);
504 m_imageSolution.resize(m_rank);
508 initializeCHOLMODLibraryVariables();
511 initializeNormalEquationsMatrix();
534 bool BundleAdjust::validateNetwork() {
536 outputBundleStatus(
"\nValidating network...");
538 int imagesWithInsufficientMeasures = 0;
539 QString msg =
"Images with one or less measures:\n";
540 int numObservations = m_bundleObservations.size();
541 for (
int i = 0; i < numObservations; i++) {
542 int numImages = m_bundleObservations.at(i)->size();
543 for (
int j = 0; j < numImages; j++) {
545 int numMeasures = m_controlNet->
546 GetNumberOfValidMeasuresInImage(bundleImage->serialNumber());
548 if (numMeasures > 1) {
552 imagesWithInsufficientMeasures++;
553 msg += bundleImage->fileName() +
": " +
toString(numMeasures) +
"\n";
557 if ( imagesWithInsufficientMeasures > 0 ) {
561 outputBundleStatus(
"\nValidation complete!...\n");
572 bool BundleAdjust::initializeCHOLMODLibraryVariables() {
577 m_cholmodTriplet = NULL;
579 cholmod_start(&m_cholmodCommon);
585 m_cholmodCommon.nmethods = 1;
586 m_cholmodCommon.method[0].ordering = CHOLMOD_AMD;
602 bool BundleAdjust::initializeNormalEquationsMatrix() {
604 int nBlockColumns = m_bundleObservations.size();
606 if (m_bundleSettings->solveTargetBody())
609 m_sparseNormals.setNumberOfColumns(nBlockColumns);
611 m_sparseNormals.at(0)->setStartColumn(0);
614 if (m_bundleSettings->solveTargetBody()) {
615 nParameters += m_bundleSettings->numberTargetBodyParameters();
616 m_sparseNormals.at(1)->setStartColumn(nParameters);
619 for (
int i = 2; i < nBlockColumns; i++) {
620 nParameters += m_bundleObservations.at(observation)->numberParameters();
621 m_sparseNormals.at(i)->setStartColumn(nParameters);
626 for (
int i = 0; i < nBlockColumns; i++) {
627 m_sparseNormals.at(i)->setStartColumn(nParameters);
628 nParameters += m_bundleObservations.at(i)->numberParameters();
644 bool BundleAdjust::freeCHOLMODLibraryVariables() {
646 cholmod_free_triplet(&m_cholmodTriplet, &m_cholmodCommon);
647 cholmod_free_sparse(&m_cholmodNormal, &m_cholmodCommon);
648 cholmod_free_factor(&m_L, &m_cholmodCommon);
650 cholmod_finish(&m_cholmodCommon);
667 return bundleSolveInformation();
675 void BundleAdjust::abortBundle() {
694 bool BundleAdjust::solveCholesky() {
695 emit(statusBarUpdate(
"Solving"));
713 m_controlNet->ComputeApriori();
717 if (m_bundleTargetBody && m_bundleTargetBody->solveMeanRadius()) {
718 int numControlPoints = m_bundleControlPoints.size();
719 for (
int i = 0; i < numControlPoints; i++) {
721 SurfacePoint surfacepoint = point->adjustedSurfacePoint();
725 point->setAdjustedSurfacePoint(surfacepoint);
730 if (m_bundleTargetBody && m_bundleTargetBody->solveTriaxialRadii()
731 && m_bundleSettings->controlPointCoordTypeBundle() == SurfacePoint::Latitudinal) {
732 int numControlPoints = m_bundleControlPoints.size();
733 for (
int i = 0; i < numControlPoints; i++) {
735 SurfacePoint surfacepoint = point->adjustedSurfacePoint();
741 point->setAdjustedSurfacePoint(surfacepoint);
748 double previousSigma0 = 0.0;
751 clock_t solveStartClock = clock();
755 emit iterationUpdate(m_iteration);
759 m_bundleResults.setConverged(
false);
760 emit statusUpdate(
"\n aborting...");
766 emit statusUpdate( QString(
"starting iteration %1\n").arg(m_iteration) );
768 clock_t iterationStartClock = clock();
771 if (m_iteration != 1) {
772 m_sparseNormals.zeroBlocks();
776 if (!formNormalEquations()) {
777 m_bundleResults.setConverged(
false);
783 m_bundleResults.setConverged(
false);
784 emit statusUpdate(
"\n aborting...");
791 if (!solveSystem()) {
792 outputBundleStatus(
"\nsolve failed!");
793 m_bundleResults.setConverged(
false);
799 m_bundleResults.setConverged(
false);
800 emit statusUpdate(
"\n aborting...");
807 applyParameterCorrections();
811 m_bundleResults.setConverged(
false);
812 emit statusUpdate(
"\n aborting...");
819 vtpv = computeResiduals();
822 if ( m_bundleSettings->outlierRejection() ) {
823 computeRejectionLimit();
829 m_bundleResults.setConverged(
false);
830 emit statusUpdate(
"\n aborting...");
837 m_bundleResults.computeSigma0(vtpv, m_bundleSettings->convergenceCriteria());
844 emit statusUpdate(QString(
"Iteration: %1 \n")
846 emit statusUpdate(QString(
"Sigma0: %1 \n")
847 .arg(m_bundleResults.sigma0(),
851 emit statusUpdate(QString(
"Observations: %1 \n")
852 .arg(m_bundleResults.numberObservations()));
853 emit statusUpdate(QString(
"Constrained Parameters:%1 \n")
854 .arg(m_bundleResults.numberConstrainedPointParameters()));
855 emit statusUpdate(QString(
"Unknowns: %1 \n")
856 .arg(m_bundleResults.numberUnknownParameters()));
857 emit statusUpdate(QString(
"Degrees of Freedom: %1 \n")
858 .arg(m_bundleResults.degreesOfFreedom()));
859 emit iterationUpdate(m_iteration);
862 if (m_bundleSettings->convergenceCriteria() == BundleSettings::Sigma0) {
863 if (fabs(previousSigma0 - m_bundleResults.sigma0())
864 <= m_bundleSettings->convergenceCriteriaThreshold()) {
869 if (m_bundleResults.maximumLikelihoodModelIndex()
870 < m_bundleResults.numberMaximumLikelihoodModels() - 1
871 && m_bundleResults.maximumLikelihoodModelIndex()
875 if (m_bundleResults.numberMaximumLikelihoodModels()
876 > m_bundleResults.maximumLikelihoodModelIndex() + 1) {
879 m_bundleResults.incrementMaximumLikelihoodModelIndex();
883 m_bundleResults.setConverged(
true);
884 emit statusUpdate(
"Bundle has converged\n");
885 emit statusBarUpdate(
"Converged");
892 int numConvergedParams = 0;
893 int numImgParams = m_imageSolution.size();
894 for (
int ij = 0; ij < numImgParams; ij++) {
895 if (fabs(m_imageSolution(ij)) > m_bundleSettings->convergenceCriteriaThreshold()) {
899 numConvergedParams++;
902 if ( numConvergedParams == numImgParams ) {
903 m_bundleResults.setConverged(
true);
904 emit statusUpdate(
"Bundle has converged\n");
905 emit statusBarUpdate(
"Converged");
910 m_bundleResults.printMaximumLikelihoodTierInformation();
911 clock_t iterationStopClock = clock();
912 double iterationTime = (iterationStopClock - iterationStartClock)
913 / (
double)CLOCKS_PER_SEC;
914 emit statusUpdate( QString(
"End of Iteration %1 \n").arg(m_iteration) );
915 emit statusUpdate( QString(
"Elapsed Time: %1 \n").arg(iterationTime,
921 if (m_iteration >= m_bundleSettings->convergenceCriteriaMaximumIterations()) {
922 emit(statusBarUpdate(
"Max Iterations Reached"));
928 if (!m_bundleResults.converged()) {
929 m_bundleResults.initializeResidualsProbabilityDistribution(101);
936 if (!m_bundleResults.converged() || !m_bundleSettings->errorPropagation()) {
937 cholmod_free_factor(&m_L, &m_cholmodCommon);
945 previousSigma0 = m_bundleResults.sigma0();
948 if (m_bundleResults.converged() && m_bundleSettings->errorPropagation()) {
949 clock_t errorPropStartClock = clock();
951 outputBundleStatus(
"\nStarting Error Propagation");
954 emit statusUpdate(
"\n\nError Propagation Complete\n");
955 clock_t errorPropStopClock = clock();
956 m_bundleResults.setElapsedTimeErrorProp((errorPropStopClock - errorPropStartClock)
957 / (
double)CLOCKS_PER_SEC);
960 clock_t solveStopClock = clock();
961 m_bundleResults.setElapsedTime((solveStopClock - solveStartClock)
962 / (
double)CLOCKS_PER_SEC);
966 m_bundleResults.setIterations(m_iteration);
967 m_bundleResults.setObservations(m_bundleObservations);
968 m_bundleResults.setBundleControlPoints(m_bundleControlPoints);
970 emit resultsReady(bundleSolveInformation());
972 emit statusUpdate(
"\nBundle Complete\n");
977 m_bundleResults.setConverged(
false);
978 emit statusUpdate(
"\n aborting...");
979 emit statusBarUpdate(
"Failed to Converge");
981 QString msg =
"Could not solve bundle adjust.";
1004 return bundleSolutionInfo;
1019 bool BundleAdjust::formNormalEquations() {
1020 emit(statusBarUpdate(
"Forming Normal Equations"));
1021 bool status =
false;
1023 m_bundleResults.setNumberObservations(0);
1024 m_bundleResults.resetNumberConstrainedPointParameters();
1031 static boost::numeric::ublas::symmetric_matrix<double, upper> N22(3);
1034 boost::numeric::ublas::compressed_vector<double> n1(m_rank);
1036 m_RHS.resize(m_rank);
1040 if (m_bundleSettings->solveTargetBody()) {
1041 int numTargetBodyParameters = m_bundleSettings->numberTargetBodyParameters();
1043 coeffTarget.resize(2,numTargetBodyParameters);
1052 coeffPoint3D.clear();
1058 int numGood3DPoints = 0;
1059 int numRejected3DPoints = 0;
1061 int num3DPoints = m_bundleControlPoints.size();
1063 outputBundleStatus(
"\n\n");
1065 for (
int i = 0; i < num3DPoints; i++) {
1066 emit(pointUpdate(i+1));
1069 if (point->isRejected()) {
1070 numRejected3DPoints++;
1083 int numMeasures = point->size();
1084 for (
int j = 0; j < numMeasures; j++) {
1089 if (measure->isRejected()) {
1093 status = computePartials(coeffTarget, coeffImage, coeffPoint3D, coeffRHS, *measure,
1103 int numObs = m_bundleResults.numberObservations();
1104 m_bundleResults.setNumberObservations(numObs + 2);
1106 formMeasureNormals(N22, N12, n1, n2, coeffTarget, coeffImage, coeffPoint3D, coeffRHS,
1107 measure->observationIndex());
1111 formPointNormals(N22, N12, n2, m_RHS, point);
1120 formWeightedNormals(n1, m_RHS);
1123 m_bundleResults.setNumberUnknownParameters(m_rank + 3 * numGood3DPoints);
1148 bool BundleAdjust::formMeasureNormals(symmetric_matrix<double, upper>&N22,
1150 compressed_vector<double> &n1,
1152 matrix<double> &coeffTarget,
1153 matrix<double> &coeffImage,
1154 matrix<double> &coeffPoint3D,
1155 vector<double> &coeffRHS,
1156 int observationIndex) {
1158 static symmetric_matrix<double, upper> N11;
1159 static matrix<double> N11TargetImage;
1161 int blockIndex = observationIndex;
1164 int numTargetPartials = coeffTarget.size2();
1165 if (m_bundleSettings->solveTargetBody()) {
1168 static vector<double> n1Target(numTargetPartials);
1169 n1Target.resize(numTargetPartials);
1173 N11.resize(numTargetPartials);
1176 N11 = prod(trans(coeffTarget), coeffTarget);
1179 m_sparseNormals.insertMatrixBlock(0, 0, numTargetPartials, numTargetPartials);
1181 (*(*m_sparseNormals[0])[0]) += N11;
1184 N11TargetImage.resize(numTargetPartials, coeffImage.size2());
1185 N11TargetImage.clear();
1186 N11TargetImage = prod(trans(coeffTarget),coeffImage);
1188 m_sparseNormals.insertMatrixBlock(blockIndex, 0,
1189 numTargetPartials, coeffImage.size2());
1190 (*(*m_sparseNormals[blockIndex])[0]) += N11TargetImage;
1193 static matrix<double> N12Target(numTargetPartials, 3);
1196 N12Target = prod(trans(coeffTarget), coeffPoint3D);
1200 *N12[0] += N12Target;
1203 n1Target = prod(trans(coeffTarget), coeffRHS);
1206 for (
int i = 0; i < numTargetPartials; i++) {
1207 n1(i) += n1Target(i);
1216 int numImagePartials = coeffImage.size2();
1219 n1Image.resize(numImagePartials);
1223 N11.resize(numImagePartials);
1226 N11 = prod(trans(coeffImage), coeffImage);
1228 int t = m_sparseNormals.at(blockIndex)->startColumn();
1231 m_sparseNormals.insertMatrixBlock(blockIndex, blockIndex,
1232 numImagePartials, numImagePartials);
1234 (*(*m_sparseNormals[blockIndex])[blockIndex]) += N11;
1237 static matrix<double> N12Image(numImagePartials, 3);
1238 N12Image.resize(numImagePartials, 3);
1241 N12Image = prod(trans(coeffImage), coeffPoint3D);
1245 *N12[blockIndex] += N12Image;
1248 n1Image = prod(trans(coeffImage), coeffRHS);
1253 for (
int i = 0; i < numImagePartials; i++) {
1254 n1(i + t) += n1Image(i);
1258 N22 += prod(trans(coeffPoint3D), coeffPoint3D);
1261 n2 += prod(trans(coeffPoint3D), coeffRHS);
1284 bool BundleAdjust::formPointNormals(symmetric_matrix<double, upper>&N22,
1290 boost::numeric::ublas::bounded_vector<double, 3> &NIC = bundleControlPoint->nicVector();
1298 boost::numeric::ublas::bounded_vector<double, 3> &weights
1299 = bundleControlPoint->weights();
1300 boost::numeric::ublas::bounded_vector<double, 3> &corrections
1301 = bundleControlPoint->corrections();
1303 if (weights(0) > 0.0) {
1304 N22(0,0) += weights(0);
1305 n2(0) += (-weights(0) * corrections(0));
1306 m_bundleResults.incrementNumberConstrainedPointParameters(1);
1309 if (weights(1) > 0.0) {
1310 N22(1,1) += weights(1);
1311 n2(1) += (-weights(1) * corrections(1));
1312 m_bundleResults.incrementNumberConstrainedPointParameters(1);
1315 if (weights(2) > 0.0) {
1316 N22(2,2) += weights(2);
1317 n2(2) += (-weights(2) * corrections(2));
1318 m_bundleResults.incrementNumberConstrainedPointParameters(1);
1327 bundleControlPoint->setAdjustedSurfacePoint(
SurfacePoint);
1330 productATransB(N22, N12, Q);
1333 NIC = prod(N22, n2);
1339 accumProductAlphaAB(-1.0, Q, n2, nj);
1356 bool BundleAdjust::formWeightedNormals(compressed_vector<double> &n1,
1357 vector<double> &nj) {
1359 m_bundleResults.resetNumberConstrainedImageParameters();
1363 for (
int i = 0; i < m_sparseNormals.size(); i++) {
1365 if ( !diagonalBlock )
1368 if (m_bundleSettings->solveTargetBody() && i == 0) {
1369 m_bundleResults.resetNumberConstrainedTargetParameters();
1372 vector<double> weights = m_bundleTargetBody->parameterWeights();
1373 vector<double> corrections = m_bundleTargetBody->parameterCorrections();
1375 int blockSize = diagonalBlock->size1();
1376 for (
int j = 0; j < blockSize; j++) {
1377 if (weights[j] > 0.0) {
1378 (*diagonalBlock)(j,j) += weights[j];
1379 nj[n] -= weights[j] * corrections(j);
1380 m_bundleResults.incrementNumberConstrainedTargetParameters(1);
1389 if (m_bundleSettings->solveTargetBody()) {
1390 observation = m_bundleObservations.at(i-1);
1393 observation = m_bundleObservations.at(i);
1399 int blockSize = diagonalBlock->size1();
1400 for (
int j = 0; j < blockSize; j++) {
1401 if (weights(j) > 0.0) {
1402 (*diagonalBlock)(j,j) += weights(j);
1403 nj[n] -= weights(j) * corrections(j);
1404 m_bundleResults.incrementNumberConstrainedImageParameters(1);
1427 bool BundleAdjust::productATransB(symmetric_matrix <double,upper> &N22,
1431 QMapIterator< int, LinearAlgebra::Matrix * > N12it(N12);
1433 while ( N12it.hasNext() ) {
1436 int rowIndex = N12it.key();
1441 *(Q[rowIndex]) = prod(N22,trans(*(N12it.value())));
1460 QMapIterator<int, LinearAlgebra::Matrix*> N12it(N12);
1461 QMapIterator<int, LinearAlgebra::Matrix*> Qit(Q);
1464 while ( N12it.hasNext() ) {
1467 int rowIndex = N12it.key();
1470 while ( Qit.hasNext() ) {
1473 int columnIndex = Qit.key();
1475 if ( rowIndex > columnIndex ) {
1482 m_sparseNormals.insertMatrixBlock(columnIndex, rowIndex,
1483 N12block->size1(), Qblock->size2());
1485 (*(*m_sparseNormals[columnIndex])[rowIndex]) -= prod(*N12block,*Qblock);
1502 void BundleAdjust::accumProductAlphaAB(
double alpha,
1505 vector<double> &nj) {
1513 QMapIterator<int, LinearAlgebra::Matrix*> Qit(Q);
1515 while ( Qit.hasNext() ) {
1518 int columnIndex = Qit.key();
1523 numParams = m_sparseNormals.at(columnIndex)->startColumn();
1525 for (
unsigned i = 0; i < blockProduct.size(); i++) {
1526 nj(numParams+i) += alpha*blockProduct(i);
1541 bool BundleAdjust::solveSystem() {
1544 if ( !loadCholmodTriplet() ) {
1545 QString msg =
"CHOLMOD: Failed to load Triplet matrix";
1550 m_cholmodNormal = cholmod_triplet_to_sparse(m_cholmodTriplet,
1551 m_cholmodTriplet->nnz,
1556 m_L = cholmod_analyze(m_cholmodNormal, &m_cholmodCommon);
1560 cholmod_factorize(m_cholmodNormal, m_L, &m_cholmodCommon);
1563 if (m_cholmodCommon.status == CHOLMOD_NOT_POSDEF) {
1564 QString msg =
"Matrix NOT positive-definite: failure at column " +
toString((
int) m_L->minor);
1572 cholmod_dense *x, *b;
1575 b = cholmod_zeros(m_cholmodNormal->nrow, 1, m_cholmodNormal->xtype, &m_cholmodCommon);
1578 double *px = (
double*)b->x;
1579 for (
int i = 0; i < m_rank; i++) {
1584 x = cholmod_solve(CHOLMOD_A, m_L, b, &m_cholmodCommon);
1587 double *sx = (
double*)x->x;
1588 for (
int i = 0; i < m_rank; i++) {
1589 m_imageSolution[i] = sx[i];
1593 cholmod_free_sparse(&m_cholmodNormal, &m_cholmodCommon);
1594 cholmod_free_dense(&b, &m_cholmodCommon);
1595 cholmod_free_dense(&x, &m_cholmodCommon);
1612 bool BundleAdjust::loadCholmodTriplet() {
1614 if ( m_iteration == 1 ) {
1615 int numElements = m_sparseNormals.numberOfElements();
1616 m_cholmodTriplet = cholmod_allocate_triplet(m_rank, m_rank, numElements,
1617 -1, CHOLMOD_REAL, &m_cholmodCommon);
1619 if ( !m_cholmodTriplet ) {
1620 outputBundleStatus(
"\nTriplet allocation failure\n");
1624 m_cholmodTriplet->nnz = 0;
1627 int *tripletColumns = (
int*) m_cholmodTriplet->i;
1628 int *tripletRows = (
int*) m_cholmodTriplet->j;
1629 double *tripletValues = (
double*)m_cholmodTriplet->x;
1635 int numBlockcolumns = m_sparseNormals.size();
1636 for (
int columnIndex = 0; columnIndex < numBlockcolumns; columnIndex++) {
1640 if ( !normalsColumn ) {
1641 QString status =
"\nSparseBlockColumnMatrix retrieval failure at column " +
1642 QString::number(columnIndex);
1643 outputBundleStatus(status);
1647 int numLeadingColumns = normalsColumn->
startColumn();
1649 QMapIterator< int, LinearAlgebra::Matrix * > it(*normalsColumn);
1651 while ( it.hasNext() ) {
1654 int rowIndex = it.key();
1658 int numLeadingRows = m_sparseNormals.at(rowIndex)->startColumn();
1661 if ( !normalsBlock ) {
1662 QString status =
"\nmatrix block retrieval failure at column ";
1663 status.append(columnIndex);
1664 status.append(
", row ");
1665 status.append(rowIndex);
1666 outputBundleStatus(status);
1667 status =
"Total # of block columns: " + QString::number(numBlockcolumns);
1668 outputBundleStatus(status);
1669 status =
"Total # of blocks: " + QString::number(m_sparseNormals.numberOfBlocks());
1670 outputBundleStatus(status);
1674 if ( columnIndex == rowIndex ) {
1675 for (
unsigned ii = 0; ii < normalsBlock->size1(); ii++) {
1676 for (
unsigned jj = ii; jj < normalsBlock->size2(); jj++) {
1677 entryValue = normalsBlock->at_element(ii,jj);
1678 int entryColumnIndex = jj + numLeadingColumns;
1679 int entryRowIndex = ii + numLeadingRows;
1681 if ( m_iteration == 1 ) {
1682 tripletColumns[numEntries] = entryColumnIndex;
1683 tripletRows[numEntries] = entryRowIndex;
1684 m_cholmodTriplet->nnz++;
1687 tripletValues[numEntries] = entryValue;
1694 for (
unsigned ii = 0; ii < normalsBlock->size1(); ii++) {
1695 for (
unsigned jj = 0; jj < normalsBlock->size2(); jj++) {
1696 entryValue = normalsBlock->at_element(ii,jj);
1697 int entryColumnIndex = jj + numLeadingColumns;
1698 int entryRowIndex = ii + numLeadingRows;
1700 if ( m_iteration ==1 ) {
1701 tripletColumns[numEntries] = entryRowIndex;
1702 tripletRows[numEntries] = entryColumnIndex;
1703 m_cholmodTriplet->nnz++;
1706 tripletValues[numEntries] = entryValue;
1727 bool BundleAdjust::cholmodInverse() {
1731 m_normalInverse.resize(m_rank);
1736 b = cholmod_zeros ( m_rank, 1, CHOLMOD_REAL, &m_cholmodCommon ) ;
1737 double *pb = (
double*)b->x;
1741 for (i = 0; i < m_rank; i++) {
1747 x = cholmod_solve ( CHOLMOD_A, m_L, b, &m_cholmodCommon ) ;
1751 for (j = 0; j <= i; j++) {
1752 m_normalInverse(j, i) = px[j];
1755 cholmod_free_dense(&x,&m_cholmodCommon);
1758 cholmod_free_dense(&b,&m_cholmodCommon);
1776 bool BundleAdjust::invert3x3(symmetric_matrix<double, upper> &m) {
1780 boost::numeric::ublas::symmetric_matrix< double, upper > c = m;
1782 den = m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1))
1783 - m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0))
1784 + m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0));
1787 if (fabs(den) < 1.0e-100) {
1793 m(0, 0) = (c(1, 1) * c(2, 2) - c(1, 2) * c(2, 1)) * det;
1794 m(0, 1) = (c(0, 2) * c(2, 1) - c(0, 1) * c(2, 2)) * det;
1795 m(0, 2) = (c(0, 1) * c(1, 2) - c(0, 2) * c(1, 1)) * det;
1796 m(1, 1) = (c(0, 0) * c(2, 2) - c(0, 2) * c(2, 0)) * det;
1797 m(1, 2) = (c(0, 2) * c(1, 0) - c(0, 0) * c(1, 2)) * det;
1798 m(2, 2) = (c(0, 0) * c(1, 1) - c(0, 1) * c(1, 0)) * det;
1823 bool BundleAdjust::computePartials(matrix<double> &coeffTarget,
1824 matrix<double> &coeffImage,
1825 matrix<double> &coeffPoint3D,
1826 vector<double> &coeffRHS,
1832 std::vector<double> lookBWRTCoord1;
1833 std::vector<double> lookBWRTCoord2;
1834 std::vector<double> lookBWRTCoord3;
1836 Camera *measureCamera = NULL;
1838 double measuredX, computedX, measuredY, computedY;
1839 double deltaX, deltaY;
1840 double observationSigma;
1841 double observationWeight;
1843 measureCamera = measure.
camera();
1849 int numImagePartials = observation->numberParameters();
1854 if (numImagePartials != m_previousNumberImagePartials) {
1855 coeffImage.resize(2,numImagePartials);
1856 m_previousNumberImagePartials = numImagePartials;
1860 if (m_bundleSettings->solveTargetBody()) {
1861 coeffTarget.clear();
1865 coeffPoint3D.clear();
1885 &computedX, &computedY,
false))) {
1886 QString msg =
"Unable to map apriori surface point for measure ";
1899 if (m_bundleSettings->solveTargetBody() && m_bundleSettings->solvePoleRA()) {
1901 &coeffTarget(0, index),
1902 &coeffTarget(1, index));
1906 if (m_bundleSettings->solveTargetBody() && m_bundleSettings->solvePoleRAVelocity()) {
1908 &coeffTarget(0, index),
1909 &coeffTarget(1, index));
1913 if (m_bundleSettings->solveTargetBody() && m_bundleSettings->solvePoleDec()) {
1915 &coeffTarget(0, index),
1916 &coeffTarget(1, index));
1920 if (m_bundleSettings->solveTargetBody() && m_bundleSettings->solvePoleDecVelocity()) {
1922 &coeffTarget(0, index),
1923 &coeffTarget(1, index));
1927 if (m_bundleSettings->solveTargetBody() && m_bundleSettings->solvePM()) {
1929 &coeffTarget(0, index),
1930 &coeffTarget(1, index));
1934 if (m_bundleSettings->solveTargetBody() && m_bundleSettings->solvePMVelocity()) {
1936 &coeffTarget(0, index),
1937 &coeffTarget(1, index));
1941 if (m_bundleSettings->solveTargetBody() && m_bundleTargetBody->solveMeanRadius()) {
1942 std::vector<double> lookBWRTMeanRadius =
1944 m_bundleTargetBody->meanRadius());
1947 &coeffTarget(1, index));
1951 if (m_bundleSettings->solveTargetBody() && m_bundleTargetBody->solveTriaxialRadii()) {
1953 std::vector<double> lookBWRTRadiusA =
1955 CameraGroundMap::WRT_MajorAxis);
1958 &coeffTarget(1, index));
1961 std::vector<double> lookBWRTRadiusB =
1963 CameraGroundMap::WRT_MinorAxis);
1966 &coeffTarget(1, index));
1969 std::vector<double> lookBWRTRadiusC =
1971 CameraGroundMap::WRT_PolarAxis);
1974 &coeffTarget(1, index));
1980 if (observationSolveSettings->instrumentPositionSolveOption() !=
1981 BundleObservationSolveSettings::NoPositionFactors) {
1983 int numCamPositionCoefficients =
1984 observationSolveSettings->numberCameraPositionCoefficientsSolved();
1988 for (
int cameraCoef = 0; cameraCoef < numCamPositionCoefficients; cameraCoef++) {
1990 &coeffImage(0, index),
1991 &coeffImage(1, index));
1996 for (
int cameraCoef = 0; cameraCoef < numCamPositionCoefficients; cameraCoef++) {
1998 &coeffImage(0, index),
1999 &coeffImage(1, index));
2004 for (
int cameraCoef = 0; cameraCoef < numCamPositionCoefficients; cameraCoef++) {
2006 &coeffImage(0, index),
2007 &coeffImage(1, index));
2013 if (observationSolveSettings->instrumentPointingSolveOption() !=
2014 BundleObservationSolveSettings::NoPointingFactors) {
2016 int numCamAngleCoefficients =
2017 observationSolveSettings->numberCameraAngleCoefficientsSolved();
2020 for (
int cameraCoef = 0; cameraCoef < numCamAngleCoefficients; cameraCoef++) {
2022 cameraCoef, &coeffImage(0, index),
2023 &coeffImage(1, index));
2028 for (
int cameraCoef = 0; cameraCoef < numCamAngleCoefficients; cameraCoef++) {
2030 cameraCoef, &coeffImage(0, index),
2031 &coeffImage(1, index));
2036 if (observationSolveSettings->solveTwist()) {
2037 for (
int cameraCoef = 0; cameraCoef < numCamAngleCoefficients; cameraCoef++) {
2039 cameraCoef, &coeffImage(0, index),
2040 &coeffImage(1, index));
2048 &coeffPoint3D(0, 0),
2049 &coeffPoint3D(1, 0));
2051 &coeffPoint3D(0, 1),
2052 &coeffPoint3D(1, 1));
2054 &coeffPoint3D(0, 2),
2055 &coeffPoint3D(1, 2));
2061 deltaX = measuredX - computedX;
2062 deltaY = measuredY - computedY;
2064 coeffRHS(0) = deltaX;
2065 coeffRHS(1) = deltaY;
2068 double obsValue = deltaX / measureCamera->
PixelPitch();
2069 m_bundleResults.addResidualsProbabilityDistributionObservation(obsValue);
2071 obsValue = deltaY / measureCamera->
PixelPitch();
2072 m_bundleResults.addResidualsProbabilityDistributionObservation(obsValue);
2074 observationSigma = 1.4 * measureCamera->
PixelPitch();
2075 observationWeight = 1.0 / observationSigma;
2077 if (m_bundleResults.numberMaximumLikelihoodModels()
2078 > m_bundleResults.maximumLikelihoodModelIndex()) {
2080 double residualR2ZScore
2081 = sqrt(deltaX * deltaX + deltaY * deltaY) / observationSigma / sqrt(2.0);
2083 m_bundleResults.addProbabilityDistributionObservation(residualR2ZScore);
2084 int currentModelIndex = m_bundleResults.maximumLikelihoodModelIndex();
2085 observationWeight *= m_bundleResults.maximumLikelihoodModelWFunc(currentModelIndex)
2086 .sqrtWeightScaler(residualR2ZScore);
2090 coeffImage *= observationWeight;
2091 coeffPoint3D *= observationWeight;
2092 coeffRHS *= observationWeight;
2094 if (m_bundleSettings->solveTargetBody()) {
2095 coeffTarget *= observationWeight;
2105 void BundleAdjust::applyParameterCorrections() {
2106 emit(statusBarUpdate(
"Updating Parameters"));
2111 if (m_bundleSettings->solveTargetBody()) {
2112 int numTargetBodyParameters = m_bundleTargetBody->numberParameters();
2114 m_bundleTargetBody->applyParameterCorrections(subrange(m_imageSolution,0,
2115 numTargetBodyParameters));
2117 t += numTargetBodyParameters;
2121 int numObservations = m_bundleObservations.size();
2122 for (
int i = 0; i < numObservations; i++) {
2125 int numParameters = observation->numberParameters();
2127 observation->applyParameterCorrections(subrange(m_imageSolution,t,t+numParameters));
2129 if (m_bundleSettings->solveTargetBody()) {
2130 observation->updateBodyRotation();
2139 int numControlPoints = m_bundleControlPoints.size();
2141 for (
int i = 0; i < numControlPoints; i++) {
2144 if (point->isRejected()) {
2149 point->applyParameterCorrections(m_imageSolution, m_sparseNormals,
2150 m_bundleTargetBody);
2168 double BundleAdjust::computeResiduals() {
2169 emit(statusBarUpdate(
"Computing Residuals"));
2171 double vtpvControl = 0.0;
2172 double vtpvImage = 0.0;
2177 m_xResiduals.Reset();
2178 m_yResiduals.Reset();
2179 m_xyResiduals.Reset();
2182 int numObjectPoints = m_bundleControlPoints.size();
2184 for (
int i = 0; i < numObjectPoints; i++) {
2188 point->computeResiduals();
2190 int numMeasures = point->numberOfMeasures();
2191 for (
int j = 0; j < numMeasures; j++) {
2194 weight = 1.4 * (measure->camera())->PixelPitch();
2195 weight = 1.0 / weight;
2198 vx = measure->focalPlaneMeasuredX() - measure->focalPlaneComputedX();
2199 vy = measure->focalPlaneMeasuredY() - measure->focalPlaneComputedY();
2202 if (measure->isRejected()) {
2206 m_xResiduals.AddData(vx);
2207 m_yResiduals.AddData(vy);
2208 m_xyResiduals.AddData(vx);
2209 m_xyResiduals.AddData(vy);
2211 vtpv += vx * vx * weight + vy * vy * weight;
2217 for (
int i = 0; i < numObjectPoints; i++) {
2221 boost::numeric::ublas::bounded_vector<double, 3> weights = bundleControlPoint->weights();
2222 boost::numeric::ublas::bounded_vector<double, 3> corrections =
2223 bundleControlPoint->corrections();
2225 if ( weights(0) > 0.0 ) {
2226 vtpvControl += corrections(0) * corrections(0) * weights(0);
2228 if ( weights(1) > 0.0 ) {
2229 vtpvControl += corrections(1) * corrections(1) * weights(1);
2231 if ( weights(2) > 0.0 ) {
2232 vtpvControl += corrections(2) * corrections(2) * weights(2);
2239 for (
int i = 0; i < m_bundleObservations.size(); i++) {
2246 for (
int j = 0; j < (int)corrections.size(); j++) {
2247 if (weights[j] > 0.0) {
2249 vtpvImage += v * v * weights[j];
2255 double vtpvTargetBody = 0.0;
2256 if ( m_bundleTargetBody) {
2257 vtpvTargetBody = m_bundleTargetBody->vtpv();
2260 vtpv = vtpv + vtpvControl + vtpvImage + vtpvTargetBody;
2264 m_bundleResults.setRmsXYResiduals(m_xResiduals.Rms(), m_yResiduals.Rms(), m_xyResiduals.Rms());
2276 bool BundleAdjust::wrapUp() {
2280 for (
int i = 0; i < m_bundleControlPoints.size(); i++) {
2282 point->computeResiduals();
2285 computeBundleStatistics();
2305 bool BundleAdjust::computeRejectionLimit() {
2308 int numResiduals = m_bundleResults.numberObservations() / 2;
2310 std::vector<double> residuals;
2312 residuals.resize(numResiduals);
2315 int residualIndex = 0;
2316 int numObjectPoints = m_bundleControlPoints.size();
2317 for (
int i = 0; i < numObjectPoints; i++) {
2321 if ( point->isRejected() ) {
2325 int numMeasures = point->numberOfMeasures();
2326 for (
int j = 0; j < numMeasures; j++) {
2330 if ( measure->isRejected() ) {
2334 vx = measure->sampleResidual();
2335 vy = measure->lineResidual();
2337 residuals[residualIndex] = sqrt(vx*vx + vy*vy);
2344 std::sort(residuals.begin(), residuals.end());
2350 int midpointIndex = numResiduals / 2;
2352 if ( numResiduals % 2 == 0 ) {
2353 median = (residuals[midpointIndex - 1] + residuals[midpointIndex]) / 2;
2356 median = residuals[midpointIndex];
2360 for (
int i = 0; i < numResiduals; i++) {
2361 residuals[i] = fabs(residuals[i] - median);
2364 std::sort(residuals.begin(), residuals.end());
2366 if ( numResiduals % 2 == 0 ) {
2367 medianDev = (residuals[midpointIndex - 1] + residuals[midpointIndex]) / 2;
2370 medianDev = residuals[midpointIndex];
2373 QString status =
"\nmedian deviation: ";
2374 status.append(QString(
"%1").arg(medianDev));
2375 status.append(
"\n");
2376 outputBundleStatus(status);
2378 mad = 1.4826 * medianDev;
2381 status.append(QString(
"%1").arg(mad));
2382 status.append(
"\n");
2383 outputBundleStatus(status);
2385 m_bundleResults.setRejectionLimit(median
2386 + m_bundleSettings->outlierRejectionMultiplier() * mad);
2388 status =
"\nRejection Limit: ";
2389 status.append(QString(
"%1").arg(m_bundleResults.rejectionLimit()));
2390 status.append(
"\n");
2391 outputBundleStatus(status);
2404 bool BundleAdjust::flagOutliers() {
2407 int totalNumRejected = 0;
2409 int maxResidualIndex;
2412 double usedRejectionLimit = m_bundleResults.rejectionLimit();
2416 int numComingBack = 0;
2418 int numObjectPoints = m_bundleControlPoints.size();
2420 outputBundleStatus(
"\n");
2421 for (
int i = 0; i < numObjectPoints; i++) {
2424 point->zeroNumberOfRejectedMeasures();
2427 maxResidualIndex = -1;
2430 int numMeasures = point->numberOfMeasures();
2431 for (
int j = 0; j < numMeasures; j++) {
2435 vx = measure->sampleResidual();
2436 vy = measure->lineResidual();
2438 sumSquares = sqrt(vx*vx + vy*vy);
2441 if ( sumSquares <= usedRejectionLimit ) {
2444 if ( measure->isRejected() ) {
2445 QString status =
"Coming back in: ";
2446 status.append(QString(
"%1").arg(point->id().toLatin1().data()));
2447 status.append(
"\r");
2448 outputBundleStatus(status);
2450 m_controlNet->DecrementNumberOfRejectedMeasuresInImage(measure->cubeSerialNumber());
2453 measure->setRejected(
false);
2458 if ( measure->isRejected() ) {
2464 if ( sumSquares > maxResidual ) {
2465 maxResidual = sumSquares;
2466 maxResidualIndex = j;
2471 if ( maxResidual == -1.0 || maxResidual <= usedRejectionLimit ) {
2472 point->setNumberOfRejectedMeasures(numRejected);
2478 if ((numMeasures - (numRejected + 1)) < 2) {
2479 point->setNumberOfRejectedMeasures(numRejected);
2488 rejected->setRejected(
true);
2490 point->setNumberOfRejectedMeasures(numRejected);
2491 m_controlNet->IncrementNumberOfRejectedMeasuresInImage(rejected->cubeSerialNumber());
2495 if ( ( numMeasures-numRejected ) < 2 ) {
2496 point->setRejected(
true);
2497 QString status =
"Rejecting Entire Point: ";
2498 status.append(QString(
"%1").arg(point->id().toLatin1().data()));
2499 status.append(
"\r");
2500 outputBundleStatus(status);
2503 point->setRejected(
false);
2507 int numberRejectedObservations = 2*totalNumRejected;
2509 QString status =
"\nRejected Observations:";
2510 status.append(QString(
"%1").arg(numberRejectedObservations));
2511 status.append(
" (Rejection Limit:");
2512 status.append(QString(
"%1").arg(usedRejectionLimit));
2513 status.append(
")\n");
2514 outputBundleStatus(status);
2516 m_bundleResults.setNumberRejectedObservations(numberRejectedObservations);
2518 status =
"\nMeasures that came back: ";
2519 status.append(QString(
"%1").arg(numComingBack));
2520 status.append(
"\n");
2521 outputBundleStatus(status);
2536 if (m_imageLists.count() > 0) {
2537 return m_imageLists;
2539 else if (m_serialNumberList->size() > 0) {
2542 for (
int i = 0; i < m_serialNumberList->size(); i++) {
2543 Image *image =
new Image(m_serialNumberList->fileName(i));
2547 m_imageLists.append(imgList);
2550 QString msg =
"Invalid image in serial number list\n";
2555 QString msg =
"No images used in bundle adjust\n";
2559 return m_imageLists;
2583 bool BundleAdjust::errorPropagation() {
2584 emit(statusBarUpdate(
"Error Propagation"));
2586 cholmod_free_triplet(&m_cholmodTriplet, &m_cholmodCommon);
2587 cholmod_free_sparse(&m_cholmodNormal, &m_cholmodCommon);
2593 double sigma0Squared = m_bundleResults.sigma0() * m_bundleResults.sigma0();
2595 int numObjectPoints = m_bundleControlPoints.size();
2597 std::string currentTime = iTime::CurrentLocalTime().toLatin1().data();
2599 QString status =
" Time: ";
2600 status.append(currentTime.c_str());
2601 status.append(
"\n\n");
2602 outputBundleStatus(status);
2605 std::vector< symmetric_matrix<double> > pointCovariances(numObjectPoints,
2606 symmetric_matrix<double>(3));
2607 for (
int d = 0; d < numObjectPoints; d++) {
2608 pointCovariances[d].clear();
2614 b = cholmod_zeros ( m_rank, 1, CHOLMOD_REAL, &m_cholmodCommon );
2615 double *pb = (
double*)b->x;
2622 FileName matrixFile(m_bundleSettings->outputFilePrefix() +
"inverseMatrix.dat");
2626 QFile matrixOutput(matrixFile.expanded());
2629 if (m_bundleSettings->createInverseMatrix()) {
2631 matrixOutput.open(QIODevice::WriteOnly);
2633 QDataStream outStream(&matrixOutput);
2636 int columnIndex = 0;
2638 int numBlockColumns = m_sparseNormals.size();
2639 for (i = 0; i < numBlockColumns; i++) {
2646 inverseMatrix.insertMatrixBlock(i, numRows, numColumns);
2647 inverseMatrix.zeroBlocks();
2652 inverseMatrix.insertMatrixBlock(i, numRows, numColumns);
2653 inverseMatrix.zeroBlocks();
2659 inverseMatrix.wipe();
2662 for (j = 0; j < (i+1); j++) {
2666 inverseMatrix.insertMatrixBlock(j, numRows, numColumns);
2674 for (j = 0; j < numColumns; j++) {
2675 if ( columnIndex > 0 ) {
2676 pb[columnIndex - 1] = 0.0;
2678 pb[columnIndex] = 1.0;
2680 x = cholmod_solve ( CHOLMOD_A, m_L, b, &m_cholmodCommon );
2685 for (k = 0; k < inverseMatrix.size(); k++) {
2688 int sz1 = matrix->size1();
2690 for (
int ii = 0; ii < sz1; ii++) {
2691 (*matrix)(ii,localCol) = px[ii + rp];
2693 rp += matrix->size1();
2699 cholmod_free_dense(&x,&m_cholmodCommon);
2703 if (m_bundleSettings->solveTargetBody() && i == 0) {
2704 vector< double > &adjustedSigmas = m_bundleTargetBody->adjustedSigmas();
2705 matrix< double > *targetCovMatrix = inverseMatrix.value(i);
2707 for (
int z = 0; z < numColumns; z++)
2708 adjustedSigmas[z] = sqrt((*targetCovMatrix)(z,z))*m_bundleResults.sigma0();
2713 if (m_bundleSettings->solveTargetBody()) {
2714 observation = m_bundleObservations.at(i-1);
2717 observation = m_bundleObservations.at(i);
2719 vector< double > &adjustedSigmas = observation->adjustedSigmas();
2720 matrix< double > *imageCovMatrix = inverseMatrix.value(i);
2721 for (
int z = 0; z < numColumns; z++) {
2722 adjustedSigmas[z] = sqrt((*imageCovMatrix)(z,z))*m_bundleResults.sigma0();
2727 if (m_bundleSettings->createInverseMatrix()) {
2728 outStream << inverseMatrix;
2733 for (j = 0; j < numObjectPoints; j++) {
2734 emit(pointUpdate(j+1));
2736 if ( point->isRejected() ) {
2742 QString status =
"\rError Propagation: Inverse Block ";
2743 status.append(QString::number(i+1));
2744 status.append(
" of ");
2745 status.append(QString::number(numBlockColumns));
2746 status.append(
"; Point ");
2747 status.append(QString::number(j+1));
2748 status.append(
" of ");
2749 status.append(QString::number(numObjectPoints));
2750 outputBundleStatus(status);
2761 boost::numeric::ublas::symmetric_matrix<double> &covariance = pointCovariances[pointIndex];
2772 QMapIterator< int, LinearAlgebra::Matrix * > it(Q);
2773 while ( it.hasNext() ) {
2776 int nKey = it.key();
2784 if ( !secondQBlock ) {
2790 if ( !inverseBlock ) {
2794 T = prod(*inverseBlock, trans(*firstQBlock));
2795 T = prod(*secondQBlock,T);
2805 catch (std::exception &e) {
2806 outputBundleStatus(
"\n\n");
2807 QString msg =
"Input data and settings are not sufficiently stable " 2808 "for error propagation.";
2816 if (m_bundleSettings->createInverseMatrix()) {
2818 matrixOutput.close();
2820 m_bundleResults.setCorrMatCovFileName(matrixFile);
2824 m_sparseNormals.wipe();
2827 cholmod_free_dense(&b,&m_cholmodCommon);
2829 outputBundleStatus(
"\n\n");
2833 status =
"\rFilling point covariance matrices: Time ";
2834 status.append(currentTime.c_str());
2835 outputBundleStatus(status);
2836 outputBundleStatus(
"\n\n");
2841 for (j = 0; j < numObjectPoints; j++) {
2845 if ( point->isRejected() ) {
2850 status =
"\rError Propagation: Filling point covariance matrices ";
2851 status.append(QString(
"%1").arg(j+1));
2852 status.append(
" of ");
2853 status.append(QString(
"%1").arg(numObjectPoints));
2854 status.append(
"\r");
2855 outputBundleStatus(status);
2859 boost::numeric::ublas::symmetric_matrix<double> &covariance = pointCovariances[pointIndex];
2867 boost::numeric::ublas::symmetric_matrix <double,boost::numeric::ublas::upper> pCovar;
2869 if (m_bundleSettings->controlPointCoordTypeBundle() == SurfacePoint::Latitudinal) {
2870 pCovar =
SurfacePoint.GetSphericalMatrix(SurfacePoint::Kilometers);
2874 pCovar =
SurfacePoint.GetRectangularMatrix(SurfacePoint::Kilometers);
2876 pCovar += covariance;
2877 pCovar *= sigma0Squared;
2932 return m_controlNet;
2942 return m_serialNumberList;
2951 int BundleAdjust::numberOfImages()
const {
2952 return m_serialNumberList->
size();
2964 QString BundleAdjust::fileName(
int i) {
2965 return m_serialNumberList->fileName(i);
2974 double BundleAdjust::iteration()
const {
2987 return m_controlNet->Camera(i)->instrumentRotation()->Cache(
"InstrumentPointing");
2999 return m_controlNet->Camera(i)->instrumentPosition()->Cache(
"InstrumentPosition");
3011 void BundleAdjust::iterationSummary() {
3012 QString iterationNumber;
3014 if ( m_bundleResults.converged() ) {
3015 iterationNumber =
"Iteration" +
toString(m_iteration) +
": Final";
3018 iterationNumber =
"Iteration" +
toString(m_iteration);
3021 PvlGroup summaryGroup(iterationNumber);
3024 toString( m_bundleResults.sigma0() ) );
3026 toString( m_bundleResults.numberObservations() ) );
3027 summaryGroup +=
PvlKeyword(
"Constrained_Point_Parameters",
3028 toString( m_bundleResults.numberConstrainedPointParameters() ) );
3029 summaryGroup +=
PvlKeyword(
"Constrained_Image_Parameters",
3030 toString( m_bundleResults.numberConstrainedImageParameters() ) );
3031 if (m_bundleSettings->bundleTargetBody()) {
3032 summaryGroup +=
PvlKeyword(
"Constrained_Target_Parameters",
3033 toString( m_bundleResults.numberConstrainedTargetParameters() ) );
3035 summaryGroup +=
PvlKeyword(
"Unknown_Parameters",
3036 toString( m_bundleResults.numberUnknownParameters() ) );
3037 summaryGroup +=
PvlKeyword(
"Degrees_of_Freedom",
3038 toString( m_bundleResults.degreesOfFreedom() ) );
3039 summaryGroup +=
PvlKeyword(
"Rejected_Measures",
3040 toString( m_bundleResults.numberRejectedObservations()/2) );
3042 if ( m_bundleResults.numberMaximumLikelihoodModels() >
3043 m_bundleResults.maximumLikelihoodModelIndex() ) {
3046 summaryGroup +=
PvlKeyword(
"Maximum_Likelihood_Tier: ",
3047 toString( m_bundleResults.maximumLikelihoodModelIndex() ) );
3048 summaryGroup +=
PvlKeyword(
"Median_of_R^2_residuals: ",
3049 toString( m_bundleResults.maximumLikelihoodMedianR2Residuals() ) );
3052 if ( m_bundleResults.converged() ) {
3053 summaryGroup +=
PvlKeyword(
"Converged",
"TRUE");
3054 summaryGroup +=
PvlKeyword(
"TotalElapsedTime",
toString( m_bundleResults.elapsedTime() ) );
3056 if (m_bundleSettings->errorPropagation()) {
3057 summaryGroup +=
PvlKeyword(
"ErrorPropagationElapsedTime",
3058 toString( m_bundleResults.elapsedTimeErrorProp() ) );
3062 std::ostringstream ostr;
3063 ostr << summaryGroup << std::endl;
3064 m_iterationSummary += QString::fromStdString( ostr.str() );
3065 if (m_printSummary) {
3066 Application::Log(summaryGroup);
3076 bool BundleAdjust::isConverged() {
3077 return m_bundleResults.converged();
3086 bool BundleAdjust::isAborted() {
3098 QString BundleAdjust::iterationSummaryGroup()
const {
3099 return m_iterationSummary;
3112 void BundleAdjust::outputBundleStatus(QString status) {
3113 if (QCoreApplication::applicationName() !=
"ipce") {
3114 printf(
"%s", status.toStdString().c_str());
3155 bool BundleAdjust::computeBundleStatistics() {
3160 int numberImages = m_serialNumberList->size();
3165 int numObjectPoints = m_bundleControlPoints.size();
3166 for (
int i = 0; i < numObjectPoints; i++) {
3170 if (point->isRejected()) {
3174 int numMeasures = point->numberOfMeasures();
3175 for (
int j = 0; j < numMeasures; j++) {
3179 if (measure->isRejected()) {
3183 double sampleResidual = fabs(measure->sampleResidual());
3184 double lineResidual = fabs(measure->lineResidual());
3187 int imageIndex = m_serialNumberList->serialNumberIndex(measure->cubeSerialNumber());
3190 rmsImageSampleResiduals[imageIndex].AddData(sampleResidual);
3191 rmsImageLineResiduals[imageIndex].AddData(lineResidual);
3192 rmsImageResiduals[imageIndex].AddData(lineResidual);
3193 rmsImageResiduals[imageIndex].AddData(sampleResidual);
3198 if (m_bundleSettings->errorPropagation()) {
3204 QString minSigmaCoord1PointId =
"";
3207 QString maxSigmaCoord1PointId =
"";
3211 QString minSigmaCoord2PointId =
"";
3214 QString maxSigmaCoord2PointId =
"";
3218 QString minSigmaCoord3PointId =
"";
3221 QString maxSigmaCoord3PointId =
"";
3228 Distance sigmaCoord1Dist, sigmaCoord2Dist, sigmaCoord3Dist;
3231 int numPoints = m_bundleControlPoints.size();
3233 for (
int i = 0; i < numPoints; i++) {
3237 maxSigmaCoord1Dist = point->adjustedSurfacePoint().GetSigmaDistance(type,
3239 minSigmaCoord1Dist = maxSigmaCoord1Dist;
3241 maxSigmaCoord2Dist = point->adjustedSurfacePoint().GetSigmaDistance(type,
3243 minSigmaCoord2Dist = maxSigmaCoord2Dist;
3245 maxSigmaCoord1PointId = point->id();
3246 maxSigmaCoord2PointId = maxSigmaCoord1PointId;
3247 minSigmaCoord1PointId = maxSigmaCoord1PointId;
3248 minSigmaCoord2PointId = maxSigmaCoord1PointId;
3251 if (m_bundleSettings->solveRadius() || type == SurfacePoint::Rectangular) {
3252 maxSigmaCoord3Dist = point->adjustedSurfacePoint().GetSigmaDistance(type,
3253 SurfacePoint::Three);
3254 minSigmaCoord3Dist = maxSigmaCoord3Dist;
3256 maxSigmaCoord3PointId = maxSigmaCoord1PointId;
3257 minSigmaCoord3PointId = maxSigmaCoord1PointId;
3262 for (
int i = 0; i < numPoints; i++) {
3266 sigmaCoord1Dist = point->adjustedSurfacePoint().GetSigmaDistance(type,
3268 sigmaCoord2Dist = point->adjustedSurfacePoint().GetSigmaDistance(type,
3270 sigmaCoord3Dist = point->adjustedSurfacePoint().GetSigmaDistance(type,
3271 SurfacePoint::Three);
3277 if (sigmaCoord1Dist > maxSigmaCoord1Dist) {
3278 maxSigmaCoord1Dist = sigmaCoord1Dist;
3279 maxSigmaCoord1PointId = point->id();
3281 if (sigmaCoord2Dist > maxSigmaCoord2Dist) {
3282 maxSigmaCoord2Dist = sigmaCoord2Dist;
3283 maxSigmaCoord2PointId = point->id();
3285 if (m_bundleSettings->solveRadius() || type == SurfacePoint::Rectangular) {
3286 if (sigmaCoord3Dist > maxSigmaCoord3Dist) {
3287 maxSigmaCoord3Dist = sigmaCoord3Dist;
3288 maxSigmaCoord3PointId = point->id();
3291 if (sigmaCoord1Dist < minSigmaCoord1Dist) {
3292 minSigmaCoord1Dist = sigmaCoord1Dist;
3293 minSigmaCoord1PointId = point->id();
3295 if (sigmaCoord2Dist < minSigmaCoord2Dist) {
3296 minSigmaCoord2Dist = sigmaCoord2Dist;
3297 minSigmaCoord2PointId = point->id();
3299 if (m_bundleSettings->solveRadius() || type == SurfacePoint::Rectangular) {
3300 if (sigmaCoord3Dist < minSigmaCoord3Dist) {
3301 minSigmaCoord3Dist = sigmaCoord3Dist;
3302 minSigmaCoord3PointId = point->id();
3308 m_bundleResults.resizeSigmaStatisticsVectors(numberImages);
3310 m_bundleResults.setSigmaCoord1Range(minSigmaCoord1Dist, maxSigmaCoord1Dist,
3311 minSigmaCoord1PointId, maxSigmaCoord1PointId);
3313 m_bundleResults.setSigmaCoord2Range(minSigmaCoord2Dist, maxSigmaCoord2Dist,
3314 minSigmaCoord2PointId, maxSigmaCoord2PointId);
3316 m_bundleResults.setSigmaCoord3Range(minSigmaCoord3Dist, maxSigmaCoord3Dist,
3317 minSigmaCoord3PointId, maxSigmaCoord3PointId);
3319 m_bundleResults.setRmsFromSigmaStatistics(sigmaCoord1Stats.
Rms(),
3320 sigmaCoord2Stats.
Rms(),
3321 sigmaCoord3Stats.
Rms());
3323 m_bundleResults.setRmsImageResidualLists(rmsImageLineResiduals.toList(),
3324 rmsImageSampleResiduals.toList(),
3325 rmsImageResiduals.toList());
This class defines a body-fixed surface point.
This represents an ISIS control net in a project-based GUI interface.
Camera * camera() const
Accesses the associated camera for this bundle measure.
void setRunTime(QString runTime)
Sets the run time, and the name if a name is not already set.
double meters() const
Get the distance in meters.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
virtual CameraType GetCameraType() const =0
Returns the type of camera that was created.
std::vector< double > EllipsoidPartial(SurfacePoint spoint, PartialType raxis)
Compute derivative of focal plane coordinate w/r to one of the ellipsoidal radii (a, b, or c)
Internalizes a list of images and allows for operations on the entire list.
static QString CurrentLocalTime()
Returns the current local time This time is taken directly from the system clock, so if the system cl...
File name manipulation and expansion.
QSharedPointer< ControlNet > ControlNetQsp
This typedef is for future implementation of target body.
double focalPlaneMeasuredY() const
Accesses the measured focal plane y value for this control measure //TODO verify? ...
QSharedPointer< BundleObservation > parentBundleObservation()
Accesses the parent BundleObservation for this bundle measure.
Container class for BundleAdjustment results.
Camera(Cube &cube)
Constructs the Camera object.
void add(const QString &filename, bool def2filename=false)
Adds a new filename / serial number pair to the SerialNumberList.
static void cholmodErrorHandler(int nStatus, const char *file, int nLineNo, const char *message)
Custom error handler for CHOLMOD.
virtual bool GetdXYdTOrientation(const SpiceRotation::PartialType varType, int coefIndex, double *cudx, double *cudy)
Compute derivative of focal plane coordinate w/r to target body using current state.
void zeroBlocks()
Sets all elements of all matrix blocks to zero.
double line() const
Accesses the current line measurement for this control measure.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
A container class for a ControlMeasure.
void ResetLocalRadius(const Distance &radius)
This method resets the local radius of a SurfacePoint.
boost::numeric::ublas::matrix< double > Matrix
Definition for an Isis::LinearAlgebra::Matrix of doubles.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
Distance measurement, usually in meters.
Latitude GetLatitude() const
Return the body-fixed latitude for the surface point.
void wipe()
Deletes all pointer elements and removes them from the map.
bool SetImage(const double sample, const double line)
Sets the sample/line values of the image to get the lat/lon values.
This class is used to accumulate statistics on double arrays.
This class hold image information that BundleAdjust needs to run correctly.Definition for a BundleIma...
boost::numeric::ublas::vector< double > Vector
Definition for an Isis::LinearAlgebra::Vector of doubles.
Program progress reporter.
int numberOfRows()
Returns total number of rows in map (this needs to be clarified and maybe rewritten).
std::vector< double > MeanRadiusPartial(SurfacePoint spoint, Distance meanRadius)
Compute derivative of focal plane coordinate w/r to mean of the ellipsoidal radii (a...
std::vector< double > Partial(CoordinateType type, CoordIndex index)
Compute partial derivative of conversion from body-fixed coordinates to the specified.
CameraGroundMap * GroundMap()
Returns a pointer to the CameraGroundMap object.
virtual bool GetdXYdPosition(const SpicePosition::PartialType varType, int coefIndex, double *cudx, double *cudy)
Compute derivative w/r to position of focal plane coordinate from ground position using current Spice...
Contains multiple PvlContainers.
double sample() const
Accesses the current sample measurement for this control measure.
bool insertMatrixBlock(int nRowBlock, int nRows, int nCols)
Inserts a "newed" LinearAlgebra::Matrix pointer of size (nRows, nCols) into the map with the block ro...
#define _FILEINFO_
Macro for the filename and line number.
A single keyword-value pair.
This class holds information about a control point that BundleAdjust needs to run correctly...
virtual bool GetXY(const SurfacePoint &spoint, double *cudx, double *cudy, bool test=true)
Compute undistorted focal plane coordinate from ground position using current Spice from SetImage cal...
This represents a cube in a project-based GUI interface.
double PixelPitch() const
Returns the pixel pitch.
void SetMatrix(CoordinateType type, const boost::numeric::ublas::symmetric_matrix< double, boost::numeric::ublas::upper > &covar)
Set the covariance matrix.
double Rms() const
Computes and returns the rms.
double focalPlaneMeasuredX() const
Accesses the measured focal plane x value for this control measure //TODO verify? ...
void append(Image *const &value)
Appends an image to the image list.
const QSharedPointer< BundleObservationSolveSettings > observationSolveSettings()
Accesses the parent observation's solve settings.
CoordinateType
Defines the coordinate typ, units, and coordinate index for some of the output methods.
int size() const
How many serial number / filename combos are in the list.
virtual bool GetdXYdOrientation(const SpiceRotation::PartialType varType, int coefIndex, double *cudx, double *cudy)
Compute derivative of focal plane coordinate w/r to instrument using current state from SetImage call...
int numberOfColumns()
Returns total number of columns in map (NOTE: NOT the number of matrix blocks).
QString cubeSerialNumber() const
Accesses the serial number of the cube containing this control measure.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
SurfacePoint adjustedSurfacePoint() const
Accesses the adjusted SurfacePoint associated with this BundleControlPoint.
Longitude GetLongitude() const
Return the body-fixed longitude for the surface point.
ErrorType errorType() const
Returns the source of the error for this exception.
Class for storing Table blobs information.
QString id() const
Accesses the Point ID associated with this BundleControlPoint.
Namespace for ISIS/Bullet specific routines.
bool insertMatrixBlock(int nColumnBlock, int nRows, int nCols)
Inserts a "newed" LinearAlgebra::Matrix pointer of size (nRows, nCols) into the map with the block co...
int startColumn() const
Sets starting column for block in full matrix.
void AddData(const double *data, const unsigned int count)
Add an array of doubles to the accumulators and counters.
Serial Number list generator.
QString fileName() const
Access the name of the control network file associated with this Control.
void closeCube()
Cleans up the Cube pointer.
QString fileName() const
Get the file name of the cube that this image represents.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
virtual bool GetdXYdPoint(std::vector< double > d_pB, double *dx, double *dy)
Compute derivative of focal plane coordinate w/r to ground point using current state.