|
Isis 3.0 Object Programmers' Reference |
Home |
00001 #include "BundleAdjust.h" 00002 00003 #include <iomanip> 00004 00005 #include "SpecialPixel.h" 00006 #include "BasisFunction.h" 00007 #include "LeastSquares.h" 00008 #include "CameraDetectorMap.h" 00009 #include "CameraDistortionMap.h" 00010 #include "ControlPoint.h" 00011 #include "SpicePosition.h" 00012 #include "SpicePosition.h" 00013 #include "Application.h" 00014 00015 namespace Isis { 00016 BundleAdjust::BundleAdjust(const std::string &cnetFile, 00017 const std::string &cubeList, 00018 bool printSummary) { 00019 // Get control net and serial number list 00020 p_cleanUp = true; 00021 Progress progress; 00022 p_cnet = new Isis::ControlNet(cnetFile, &progress); 00023 p_snlist = new Isis::SerialNumberList(cubeList); 00024 p_printSummary = printSummary; 00025 p_heldsnlist = NULL; 00026 p_observationMode = false; 00027 p_solutionMethod = "SVD"; 00028 p_onlist = NULL; 00029 00030 Init( &progress ); 00031 } 00032 00033 BundleAdjust::BundleAdjust(const std::string &cnetFile, 00034 const std::string &cubeList, 00035 const std::string &heldList, 00036 bool printSummary) { 00037 // Get control net, serial number list, and held serial number list 00038 p_cleanUp = true; 00039 Progress progress; 00040 p_cnet = new Isis::ControlNet(cnetFile, &progress); 00041 p_snlist = new Isis::SerialNumberList(cubeList); 00042 p_heldsnlist = new Isis::SerialNumberList(heldList); 00043 p_printSummary = printSummary; 00044 p_observationMode = false; 00045 p_solutionMethod = "SVD"; 00046 p_onlist = NULL; 00047 00048 Init( &progress ); 00049 } 00050 00051 BundleAdjust::BundleAdjust(Isis::ControlNet &cnet, 00052 Isis::SerialNumberList &snlist, 00053 bool printSummary) { 00054 // Get control net and serial number list 00055 p_cleanUp = false; 00056 p_cnet = &cnet; 00057 p_snlist = &snlist; 00058 p_printSummary = printSummary; 00059 p_heldsnlist = NULL; 00060 p_observationMode = false; 00061 p_solutionMethod = "SVD"; 00062 p_onlist = NULL; 00063 00064 Init(); 00065 } 00066 00067 BundleAdjust::BundleAdjust(Isis::ControlNet &cnet, 00068 Isis::SerialNumberList &snlist, 00069 Isis::SerialNumberList &heldsnlist, 00070 bool printSummary) { 00071 // Get control net, image serial number list and hold image serial number list 00072 p_cleanUp = false; 00073 p_cnet = &cnet; 00074 p_snlist = &snlist; 00075 p_heldsnlist = &heldsnlist; 00076 p_printSummary = printSummary; 00077 p_observationMode = false; 00078 p_solutionMethod = "SVD"; 00079 p_onlist = NULL; 00080 00081 Init(); 00082 } 00083 00084 BundleAdjust::~BundleAdjust() { 00085 if (p_cleanUp) { 00086 delete p_cnet; 00087 delete p_snlist; 00088 if (p_heldImages > 0) delete p_heldsnlist; 00089 if (p_observationMode) delete p_onlist; 00090 } 00091 } 00092 00093 00094 void BundleAdjust::Init(Progress *progress) { 00095 // Get the cameras set up for all images 00096 p_cnet->SetImages(*p_snlist, progress); 00097 00098 p_heldImages = 0; 00099 int count; 00100 00101 if (p_heldsnlist != NULL) { 00102 //Check to make sure held images are in the control net 00103 CheckHeldList(); 00104 // Set all points on held images to held, using measurement on held image 00105 // to get lat/lon/radius of point 00106 ApplyHeldList(); 00107 00108 // Create a lookup table of held images 00109 count = 0; 00110 for (int i=0; i<p_snlist->Size(); i++) { 00111 if (p_heldsnlist->HasSerialNumber(p_snlist->SerialNumber(i))) { 00112 p_imageIndexMap.push_back(-1); 00113 p_heldImages++; 00114 } else { 00115 p_imageIndexMap.push_back(count); 00116 count++; 00117 } 00118 } 00119 } 00120 else { 00121 for (int i=0; i<p_snlist->Size(); i++) p_imageIndexMap.push_back(i); 00122 } 00123 00124 00125 // Create a lookup table of ignored, held, and ground points 00126 p_heldPoints = p_groundPoints = p_ignoredPoints = 0; 00127 count = 0; 00128 for (int i=0; i<p_cnet->Size(); i++) { 00129 if ((*p_cnet)[i].Held()) { 00130 p_pointIndexMap.push_back(-1); 00131 p_heldPoints++; 00132 } 00133 else if ((*p_cnet)[i].Ignore()) { 00134 p_pointIndexMap.push_back(-1); 00135 p_ignoredPoints++; 00136 } 00137 else if ((*p_cnet)[i].Type() == ControlPoint::Ground) { 00138 p_pointIndexMap.push_back(-1); 00139 p_groundPoints++; 00140 } 00141 else { 00142 p_pointIndexMap.push_back(count); 00143 count++; 00144 } 00145 } 00146 00147 // Set default variables to solve for 00148 p_solveTwist = true; 00149 p_solveRadii = false; 00150 p_cmatrixSolveType = AnglesOnly; 00151 p_spacecraftPositionSolveType = Nothing; 00152 p_ckDegree = 2; 00153 p_solveCamDegree = p_ckDegree; 00154 p_numberCameraCoefSolved = 1; 00155 00156 ComputeNumberPartials(); 00157 00158 // TODO: Need to have some validation code to make sure everything is 00159 // on the up-and-up with the control network. Add checks for multiple 00160 // networks, images without any points, and points on images removed from 00161 // the control net (when we start adding software to remove points with high 00162 // residuals) and ?. 00163 } 00164 00170 void BundleAdjust::CheckHeldList () { 00171 for (int ih=0; ih < p_heldsnlist->Size(); ih++) { 00172 if (!(p_snlist->HasSerialNumber(p_heldsnlist->SerialNumber(ih)))) { 00173 std::string msg = "Held image [" + p_heldsnlist->SerialNumber(ih) 00174 + "not in FROMLIST"; 00175 throw iException::Message(iException::User,msg,_FILEINFO_); 00176 } 00177 } 00178 } 00179 00180 00186 void BundleAdjust::ApplyHeldList () { 00187 double lat,lon,rad; 00188 // TODO Check for points already held ie) case where user has a point on 2 00189 // or more held images 00190 00191 for (int i=0; i<p_cnet->Size(); i++) { 00192 ControlPoint &pt = (*p_cnet)[i]; 00193 if (pt.Ignore()) continue; 00194 00195 for (int j=0; j<pt.Size(); j++) { 00196 ControlMeasure &m = pt[j]; 00197 if (m.Ignore()) continue; 00198 00199 if (p_heldsnlist->HasSerialNumber(m.CubeSerialNumber())) { 00200 Camera *cam=m.Camera(); 00201 if (cam->SetImage(m.Sample(), m.Line())) { 00202 lat = cam->UniversalLatitude(); 00203 lon = cam->UniversalLongitude(); 00204 rad = cam->LocalRadius(); //meters 00205 } 00206 else { 00207 std::string msg = "Cannot compute lat/lon for control point [" + 00208 pt.Id() + "], measure [" + m.CubeSerialNumber() + "]"; 00209 throw iException::Message(iException::User,msg,_FILEINFO_); 00210 } 00211 pt.SetUniversalGround (lat, lon, rad); 00212 pt.SetHeld (true); 00213 } 00214 } 00215 } 00216 } 00217 00224 void BundleAdjust::ComputeNumberPartials() { 00225 p_numImagePartials = 0; 00226 00227 if (p_cmatrixSolveType != None) { 00228 // Solve for ra/dec always 00229 p_numImagePartials = 2; 00230 00231 // Do we solve for twist 00232 if (p_solveTwist) { 00233 p_numImagePartials++; 00234 } 00235 00236 // Do we solve for angles only, +velocity, or +velocity and acceleration, or all coefficients 00237 p_numImagePartials *= p_numberCameraCoefSolved; 00238 /* if (p_cmatrixSolveType == AnglesVelocity) { 00239 p_numImagePartials *= 2; 00240 } 00241 else if (p_cmatrixSolveType == AnglesVelocityAcceleration) { 00242 p_numImagePartials *= 3; 00243 }*/ 00244 } 00245 00246 if (p_spacecraftPositionSolveType != Nothing) { 00247 // Solve for position always. 00248 p_numImagePartials += 3; 00249 00250 // Do we solve for position and velocity, position, velocity and acceleration, or position only 00251 if (p_spacecraftPositionSolveType == PositionVelocity) { 00252 p_numImagePartials += 3; 00253 } 00254 else if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { 00255 p_numImagePartials += 6; 00256 } 00257 } 00258 00259 // Solve for lat/lon always 00260 p_numPointPartials = 2; 00261 00262 // Do we solve for radii 00263 if (p_solveRadii) { 00264 p_numPointPartials++; 00265 } 00266 } 00267 00273 void BundleAdjust::SetObservationMode ( bool observationMode ) { 00274 p_observationMode = observationMode; 00275 00276 if (p_observationMode) { 00277 // Create the observation number list 00278 p_onlist = new Isis::ObservationNumberList(p_snlist); 00279 if (p_heldImages != 0) { 00280 p_onlist->Remove(p_heldsnlist); 00281 } 00282 00283 if (p_heldsnlist != NULL) { 00284 //Make sure ALL images in an observation are held if any are 00285 for (int ih=0; ih < p_heldsnlist->Size(); ih++) { 00286 for (int isn=0; isn < p_snlist->Size(); isn++) { 00287 if (p_heldsnlist->ObservationNumber(ih) == p_snlist->ObservationNumber(isn)) { 00288 if (!(p_heldsnlist->HasSerialNumber(p_snlist->SerialNumber(isn)))) { 00289 std::string msg = "Cube file " + p_snlist->Filename(isn) 00290 + " must be held since it is on the same observation as held cube " 00291 + p_heldsnlist->Filename(ih); 00292 throw iException::Message(iException::User,msg,_FILEINFO_); 00293 } 00294 } 00295 } 00296 } 00297 } 00298 } 00299 } 00300 00301 00302 00303 00307 void BundleAdjust::SetSolveTwist(bool solve) { 00308 p_solveTwist = solve; 00309 ComputeNumberPartials(); 00310 } 00311 00315 void BundleAdjust::SetSolveRadii(bool solve) { 00316 p_solveRadii = solve; 00317 ComputeNumberPartials(); 00318 } 00319 00323 void BundleAdjust::SetSolveCmatrix(CmatrixSolveType type) { 00324 p_cmatrixSolveType = type; 00325 00326 switch (type) { 00327 case BundleAdjust::AnglesOnly: 00328 p_numberCameraCoefSolved = 1; 00329 break; 00330 case BundleAdjust::AnglesVelocity: 00331 p_numberCameraCoefSolved = 2; 00332 break; 00333 case BundleAdjust::AnglesVelocityAcceleration: 00334 p_numberCameraCoefSolved = 3; 00335 break; 00336 case BundleAdjust::All: 00337 p_numberCameraCoefSolved = p_solveCamDegree+1; 00338 break; 00339 default: 00340 p_numberCameraCoefSolved = 0; 00341 break; 00342 } 00343 00344 // Make sure the degree of the polynomial the user selected for 00345 // the camera angles fit is sufficient for the selected CAMSOLVE 00346 if (p_numberCameraCoefSolved > p_solveCamDegree+1 ) { 00347 std::string msg = "Selected SolveCameraDegree " + iString(p_solveCamDegree) 00348 + " is not sufficient for the CAMSOLVE"; 00349 throw iException::Message(iException::User,msg,_FILEINFO_); 00350 } 00351 ComputeNumberPartials(); 00352 } 00353 00357 void BundleAdjust::SetSolveSpacecraftPosition(SpacecraftPositionSolveType type) { 00358 p_spacecraftPositionSolveType = type; 00359 ComputeNumberPartials(); 00360 } 00361 00367 int BundleAdjust::BasisColumns() const { 00368 int imageColumns = Observations() * p_numImagePartials; 00369 00370 // imageColumns -= p_heldImages * p_numImagePartials; 00371 00372 int pointColumns = p_cnet->Size() * p_numPointPartials; 00373 00374 pointColumns -= p_groundPoints * p_numPointPartials; 00375 pointColumns -= p_heldPoints * p_numPointPartials; 00376 pointColumns -= p_ignoredPoints * p_numPointPartials; 00377 00378 return imageColumns + pointColumns; 00379 } 00380 00395 double BundleAdjust::Solve(double tol, int maxIterations) { 00396 double mmPerPixel = DBL_MAX; 00397 double averageError; 00398 std::vector<int> observationInitialValueIndex; // Index of image to use for observation inital values 00399 int iIndex = -1; //Index of the image to use for initial spice for an observation 00400 int oIndex = -1; // Index of current observation 00401 00402 if (p_observationMode) { 00403 observationInitialValueIndex.assign( p_onlist->ObservationSize(), -1); 00404 } 00405 00406 for (int i=0; i<Images(); i++) { 00407 if (p_heldImages > 0) { 00408 if ((p_heldsnlist->HasSerialNumber(p_snlist->SerialNumber(i)))) continue; 00409 } 00410 Camera *cam = p_cnet->Camera(i); 00411 00412 if (p_observationMode) { 00413 oIndex = i; 00414 oIndex = p_onlist->ObservationNumberMapIndex(oIndex); // Get the observation index for this image 00415 iIndex = observationInitialValueIndex[oIndex]; // Get the index of the image to use for initial values // being used for the observation 00416 } 00417 if (p_cmatrixSolveType != None) { 00418 // For observations, find the index of the first image and use its polynomial for the observation 00419 // initial coefficient values. Initialize indeces to -1 00420 00421 // Fit the camera pointing to an equation 00422 SpiceRotation *rot = cam->InstrumentRotation(); 00423 00424 if (!p_observationMode ) { 00425 rot->SetPolynomialDegree( p_ckDegree ); // Set the ck polynomial fit degree 00426 rot->SetPolynomial(); 00427 rot->SetPolynomialDegree( p_solveCamDegree ); // Update to the solve polynomial fit degree 00428 } 00429 else { 00430 // Index of image to use for initial values is set already so set polynomial to initial values 00431 if (iIndex >= 0) { 00432 SpiceRotation *orot = p_cnet->Camera(iIndex)->InstrumentRotation(); //Observation rotation 00433 std::vector<double> anglePoly1, anglePoly2, anglePoly3; 00434 orot->GetPolynomial( anglePoly1, anglePoly2, anglePoly3); 00435 double baseTime = orot->GetBaseTime(); 00436 double timeScale = orot->GetTimeScale(); 00437 rot->SetPolynomialDegree( p_solveCamDegree ); // Update to the solve polynomial fit degree 00438 rot->SetOverrideBaseTime( baseTime, timeScale ); 00439 rot->SetPolynomial( anglePoly1, anglePoly2, anglePoly3); 00440 } 00441 else { 00442 // Index of image to use for inital observation values has not been assigned yet so use this image 00443 rot->SetPolynomialDegree( p_ckDegree ); 00444 rot->SetPolynomial(); 00445 rot->SetPolynomialDegree( p_solveCamDegree ); // Update to the solve polynomial fit degree 00446 observationInitialValueIndex[oIndex] = i; 00447 } 00448 } 00449 } 00450 if (p_spacecraftPositionSolveType != Nothing) { 00451 // Set the spacecraft position to an equation 00452 SpicePosition *pos = cam->InstrumentPosition(); 00453 00454 if (!p_observationMode ) { 00455 pos->SetPolynomial(); 00456 } 00457 else { 00458 // Index of image to use for initial values is set already so set polynomial to initial values 00459 if (iIndex >= 0) { 00460 SpicePosition *opos = p_cnet->Camera(iIndex)->InstrumentPosition(); //Observation position 00461 std::vector<double> posPoly1, posPoly2, posPoly3; 00462 opos->GetPolynomial( posPoly1, posPoly2, posPoly3); 00463 double baseTime = opos->GetBaseTime(); 00464 pos->SetOverrideBaseTime( baseTime ); 00465 pos->SetPolynomial( posPoly1, posPoly2, posPoly3); 00466 } 00467 else { 00468 // Index of image to use for inital observation values has not been assigned yet so use this image 00469 pos->SetPolynomial(); 00470 observationInitialValueIndex[oIndex] = i; 00471 } 00472 } 00473 } 00474 if (cam->PixelPitch() < mmPerPixel) { 00475 mmPerPixel = cam->PixelPitch(); 00476 } 00477 } 00478 00479 // Compute the apriori lat/lons for each nonheld point 00480 p_error = DBL_MAX; 00481 p_cnet->ComputeApriori(); 00482 00483 // Initialize solution parameters 00484 double sigmaXY, sigmaHat, sigmaX, sigmaY; 00485 sigmaXY = sigmaHat = sigmaX = sigmaY = 0.; 00486 p_iteration = 0; 00487 00488 while (p_iteration < maxIterations) { 00489 p_iteration++; 00490 p_cnet->ComputeErrors(); 00491 p_error = p_cnet->MaximumError(); 00492 averageError = p_cnet->AverageError(); 00493 if (p_printSummary) { 00494 IterationSummary(averageError,sigmaXY,sigmaHat,sigmaX,sigmaY); 00495 } 00496 p_statx.Reset(); 00497 p_staty.Reset(); 00498 00499 if (p_error <= tol) return p_error; 00500 00501 // Create the basis function and prep for a least squares solution 00502 BasisFunction basis("Bundle",BasisColumns(),BasisColumns()); 00503 LeastSquares *lsq; 00504 if (p_solutionMethod == "SPARSE") { 00505 lsq = new LeastSquares(basis,Isis::LeastSquares::SPARSE, 00506 p_cnet->NumValidMeasures()*2,BasisColumns()); 00507 } 00508 else { 00509 lsq = new LeastSquares(basis); 00510 } 00511 00512 // Loop through the control net and add the partials for each point 00513 for (int i=0; i<p_cnet->Size(); i++) { 00514 AddPartials(*lsq,i); 00515 } 00516 00517 // Try to solve the iteration 00518 try { 00519 if (p_solutionMethod == "SVD") { 00520 lsq->Solve(Isis::LeastSquares::SVD); 00521 00522 } else if (p_solutionMethod == "QRD") { 00523 lsq->Solve(Isis::LeastSquares::QRD); 00524 } 00525 else { 00526 int zeroColumn = lsq->Solve(Isis::LeastSquares::SPARSE); 00527 if (zeroColumn != 0) { 00528 std::string msg; 00529 int imageColumns = Observations() * p_numImagePartials; 00530 if (zeroColumn <= imageColumns) { 00531 msg = "Solution matrix has a column of zeros which probably "; 00532 msg += "indicates an image with no points. Running the program, "; 00533 msg += "cnetcheck, before jigsaw should catch these problems."; 00534 } 00535 else { 00536 msg = "Solution matrix has a column of zeros which probably "; 00537 msg += "indicates a point with no measures. Running the program, "; 00538 msg += "cnetcheck, before jigsaw should catch these problems."; 00539 } 00540 throw Isis::iException::Message(iException::Math,msg,_FILEINFO_); 00541 } 00542 } 00543 } 00544 catch (iException &e) { 00545 std::string msg = "Unable to solve in BundleAdjust, "; 00546 msg += "Iteration " + Isis::iString(p_iteration) + " of "; 00547 msg += Isis::iString(maxIterations) + ", Tolerance = "; 00548 msg += Isis::iString(tol); 00549 throw Isis::iException::Message(iException::Math,msg,_FILEINFO_); 00550 } 00551 00552 // Ok take the results and put them back into the camera blobs 00553 Update(basis); 00554 // return p_error; 00555 00556 //Compute sigmas 00557 sigmaXY = sqrt((p_statx.SumSquare() + p_staty.SumSquare())/lsq->Knowns()); 00558 sigmaHat = (lsq->Knowns() - BasisColumns()) ? 00559 (sqrt((p_statx.SumSquare() + p_staty.SumSquare())/ (lsq->Knowns() - BasisColumns()))) 00560 : 0.; 00561 sigmaX = p_statx.TotalPixels() ? 00562 sqrt(p_statx.SumSquare()/p_statx.TotalPixels()) : 0.; 00563 sigmaY = p_staty.TotalPixels() ? 00564 sqrt(p_staty.SumSquare()/p_staty.TotalPixels()) : 0.; 00565 } 00566 00567 std::string msg = "Did not converge to tolerance ["; 00568 msg += iString(tol) + "] in less than ["; 00569 msg += iString(maxIterations) + "] iterations"; 00570 throw iException::Message(iException::User,msg,_FILEINFO_); 00571 } 00572 00576 void BundleAdjust::AddPartials (LeastSquares &lsq, 00577 int pointIndex) { 00578 ControlPoint &point = (*p_cnet)[pointIndex]; 00579 if (point.Ignore()) return; // Ignore entire point 00580 00581 for (int i=0; i<point.Size(); i++) { 00582 if (point[i].Ignore()) continue; // Ignore this measure 00583 00584 if (p_heldImages) { 00585 if (p_heldsnlist->HasSerialNumber(point[i].CubeSerialNumber())) continue; 00586 } 00587 00588 Camera *cam = point[i].Camera(); 00589 // Get focal length with direction 00590 double fl = cam->DistortionMap()->UndistortedFocalPlaneZ(); 00591 // Map the control point lat/lon/radius into the camera through the Spice 00592 // at the measured point to correctly compute the partials for line scan 00593 // cameras. The camera SetUniversalGround method computes a time based 00594 // on the lat/lon/radius and uses the Spice for that time instead of the 00595 // measured point's time. 00596 cam->SetImage(point[i].Sample(),point[i].Line()); // Set the Spice to the measured point 00597 00598 // Compute the look vector in body-fixed coordinates 00599 double pB[3]; // Point on surface 00600 latrec_c( point.Radius() / 1000.0, 00601 (point.UniversalLongitude() * Isis::PI / 180.0), 00602 (point.UniversalLatitude() * Isis::PI / 180.0), 00603 pB); 00604 00605 // May need to do back of planet test here TODO 00606 std::vector<double> lookB(3); 00607 SpiceRotation *bodyRot = cam->BodyRotation(); 00608 std::vector<double> sB(3); // Spacecraft vector in bodyj-fixed coordinates 00609 sB = bodyRot->ReferenceVector(cam->InstrumentPosition()->Coordinate()); 00610 for (int ic=0; ic<3; ic++) lookB[ic] = pB[ic] - sB[ic]; 00611 00612 // if (!cam->SetUniversalGround(point.UniversalLatitude(), 00613 // point.UniversalLongitude(), 00614 // point.Radius())) { 00615 // std::string msg = "Point off image (lat/lon = "; 00616 // msg += "Isis::iString(point.UniversalLatitude()/"; 00617 // msg += "Isis::iString(point.UniversalLongitude() - point may be too "; 00618 // msg += "close to the edge on point Isis::iString(pointIndex) and "; 00619 // msg += "Measure Isis::iString(i)"; 00620 // throw iException::Message(iException::User,msg,_FILEINFO_); 00621 // exit(0); 00622 // } 00623 00624 // Create the known array to put in the least squares 00625 std::vector<double> xKnowns(BasisColumns(),0.0); 00626 std::vector<double> yKnowns(BasisColumns(),0.0); 00627 00628 // Get the look vector in the camera frame and the instrument rotation 00629 std::vector<double> lookC(3); 00630 std::vector<double> lookJ(3); 00631 lookJ = cam->BodyRotation()->J2000Vector( lookB ); 00632 SpiceRotation *instRot = cam->InstrumentRotation(); 00633 lookC = instRot->ReferenceVector( lookJ); 00634 00635 // cam->LookDirection(((double *)&lookC[0])); // From computed position 00636 00637 // Determine the image index for nonheld images 00638 bool useImage=false; 00639 if ( p_heldImages == 0) { 00640 useImage = true; 00641 } 00642 else if (p_heldImages > 0) { 00643 if ((!(p_heldsnlist->HasSerialNumber(point[i].CubeSerialNumber())))) 00644 useImage = true; 00645 } 00646 if (useImage) { 00647 int index = p_snlist->SerialNumberIndex(point[i].CubeSerialNumber()); 00648 index = ImageIndex(index); 00649 00650 if (p_spacecraftPositionSolveType != Nothing) { 00651 SpicePosition *instPos = cam->InstrumentPosition(); 00652 00653 // Add the partial for the x coordinate of the position (differentiating 00654 // point(x,y,z) - spacecraftPosition(x,y,z) in J2000 00655 std::vector<double> d_lookJ = instPos->CoordinatePartial (SpicePosition::WRT_X0); 00656 for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; 00657 std::vector<double> d_lookC_WRT_X0 = instRot->ReferenceVector(d_lookJ); 00658 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_X0,0); 00659 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_X0,1); 00660 index++; 00661 00662 if (p_spacecraftPositionSolveType > PositionOnly) { 00663 d_lookJ = instPos->CoordinatePartial (SpicePosition::WRT_X1); 00664 for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; 00665 std::vector<double> d_lookC_WRT_X1 = instRot->ReferenceVector(d_lookJ); 00666 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_X1,0); 00667 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_X1,1); index++; 00668 00669 if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { 00670 d_lookJ = instPos->CoordinatePartial (SpicePosition::WRT_X2); 00671 for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; 00672 std::vector<double> d_lookC_WRT_X2 = instRot->ReferenceVector(d_lookJ); 00673 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_X2,0); 00674 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_X2,1); index++; 00675 } 00676 } 00677 00678 // Add the partial for the y coordinate of the position 00679 d_lookJ = instPos->CoordinatePartial (SpicePosition::WRT_Y0); 00680 for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; 00681 std::vector<double> d_lookC_WRT_Y0 = instRot->ReferenceVector(d_lookJ); 00682 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Y0,0); 00683 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Y0,1); 00684 index++; 00685 00686 if (p_spacecraftPositionSolveType > PositionOnly) { 00687 d_lookJ = instPos->CoordinatePartial (SpicePosition::WRT_Y1); 00688 for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; 00689 std::vector<double> d_lookC_WRT_Y1 = instRot->ReferenceVector(d_lookJ); 00690 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Y1,0); 00691 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Y1,1); index++; 00692 00693 if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { 00694 d_lookJ = instPos->CoordinatePartial (SpicePosition::WRT_Y2); 00695 for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; 00696 std::vector<double> d_lookC_WRT_Y2 = instRot->ReferenceVector(d_lookJ); 00697 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Y2,0); 00698 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Y2,1); index++; 00699 } 00700 } 00701 00702 // Add the partial for the z coordinate of the position 00703 d_lookJ = instPos->CoordinatePartial (SpicePosition::WRT_Z0); 00704 for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; 00705 std::vector<double> d_lookC_WRT_Z0 = instRot->ReferenceVector(d_lookJ); 00706 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Z0,0); 00707 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Z0,1); 00708 index++; 00709 00710 if (p_spacecraftPositionSolveType > PositionOnly) { 00711 d_lookJ = instPos->CoordinatePartial (SpicePosition::WRT_Z1); 00712 for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; 00713 std::vector<double> d_lookC_WRT_Z1 = instRot->ReferenceVector(d_lookJ); 00714 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Z1,0); 00715 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Z1,1); index++; 00716 00717 if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { 00718 d_lookJ = instPos->CoordinatePartial (SpicePosition::WRT_Z2); 00719 for (int j=0; j<3; j++) d_lookJ[j] *= -1.0; 00720 std::vector<double> d_lookC_WRT_Z2 = instRot->ReferenceVector(d_lookJ); 00721 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Z2,0); 00722 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_Z1,1); index++; 00723 } 00724 } 00725 } 00726 if (p_cmatrixSolveType != None) { 00727 std::vector<double> d_lookC; 00728 00729 // Add the partials for ra 00730 for (int icoef=0; icoef<p_numberCameraCoefSolved; icoef++) { 00731 d_lookC = instRot->ToReferencePartial(lookJ,SpiceRotation::WRT_RightAscension, icoef); 00732 xKnowns[index] = fl * LowDHigh(lookC,d_lookC,0); 00733 yKnowns[index] = fl * LowDHigh(lookC,d_lookC,1); 00734 index++; 00735 } 00736 00737 // Add the partials for dec 00738 for (int icoef=0; icoef<p_numberCameraCoefSolved; icoef++) { 00739 d_lookC = instRot->ToReferencePartial(lookJ,SpiceRotation::WRT_Declination, icoef); 00740 xKnowns[index] = fl * LowDHigh(lookC,d_lookC,0); 00741 yKnowns[index] = fl * LowDHigh(lookC,d_lookC,1); 00742 index++; 00743 } 00744 00745 // Add the partial for twist if necessary 00746 if (p_solveTwist) { 00747 for (int icoef=0; icoef<p_numberCameraCoefSolved; icoef++) { 00748 d_lookC = instRot->ToReferencePartial(lookJ,SpiceRotation::WRT_Twist, icoef); 00749 xKnowns[index] = fl * LowDHigh(lookC,d_lookC,0); 00750 yKnowns[index] = fl * LowDHigh(lookC,d_lookC,1); index++; 00751 } 00752 } 00753 } 00754 } 00755 if ((!point.Held()) && (point.Type() != ControlPoint::Ground)) { 00756 std::vector<double> d_lookB_WRT_LAT = PointPartial(point,WRT_Latitude); 00757 std::vector<double> d_lookB_WRT_LON = PointPartial(point,WRT_Longitude); 00758 00759 SpiceRotation *bodyRot = cam->BodyRotation(); 00760 std::vector<double> d_lookJ_WRT_LAT = bodyRot->J2000Vector(d_lookB_WRT_LAT); 00761 std::vector<double> d_lookJ_WRT_LON = bodyRot->J2000Vector(d_lookB_WRT_LON); 00762 std::vector<double> d_lookC_WRT_LAT = instRot->ReferenceVector(d_lookJ_WRT_LAT); 00763 std::vector<double> d_lookC_WRT_LON = instRot->ReferenceVector(d_lookJ_WRT_LON); 00764 00765 int index = PointIndex(pointIndex); 00766 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_LAT,0); 00767 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_LAT,1); 00768 index++; 00769 00770 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_LON,0); 00771 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_LON,1); 00772 index++; 00773 00774 if (p_solveRadii) { 00775 std::vector<double> d_lookB_WRT_RAD = PointPartial(point,WRT_Radius); 00776 std::vector<double> d_lookJ_WRT_RAD = bodyRot->J2000Vector(d_lookB_WRT_RAD); 00777 std::vector<double> d_lookC_WRT_RAD = instRot->ReferenceVector(d_lookJ_WRT_RAD); 00778 xKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_RAD,0); 00779 yKnowns[index] = fl * LowDHigh(lookC,d_lookC_WRT_RAD,1); 00780 index++; 00781 } 00782 } 00783 00784 double mudx = point[i].FocalPlaneMeasuredX(); 00785 // double cudx = point[i].FocalPlaneComputedX(); 00786 double cudx = lookC[0] * fl / lookC[2]; 00787 double mudy = point[i].FocalPlaneMeasuredY(); 00788 // double cudy = point[i].FocalPlaneComputedY(); 00789 double cudy = lookC[1] * fl / lookC[2]; 00790 00791 double deltax = mudx - cudx; 00792 double deltay = mudy - cudy; 00793 00794 /* if (cam->DetectorMap()->LineRate() != 0.0) { 00795 if ( cam->DetectorMap()->IsYAxisTimeDependent() ) { 00796 deltay = point[i].MeasuredEphemerisTime() - point[i].ComputedEphemerisTime(); 00797 deltay = deltay / cam->DetectorMap()->LineRate(); // Convert to pixels 00798 deltay = deltay * cam->PixelPitch(); // convert to mm 00799 } 00800 if (cam->DetectorMap()->IsXAxisTimeDependent() ) { 00801 deltax = point[i].MeasuredEphemerisTime() - point[i].ComputedEphemerisTime(); 00802 deltax = deltax / cam->DetectorMap()->LineRate(); // Convert to pixels 00803 deltax = deltax * cam->PixelPitch(); // convert to mm 00804 } 00805 } 00806 00807 // deltay *= cam->DetectorMap()->YAxisDirection(); 00808 // deltax *= cam->DetectorMap()->XAxisDirection();*/ 00809 00810 lsq.AddKnown(xKnowns,deltax); 00811 lsq.AddKnown(yKnowns,deltay); 00812 p_statx.AddData(deltax); 00813 p_staty.AddData(deltay); 00814 } 00815 } 00816 00820 double BundleAdjust::LowDHigh(std::vector<double> &lookC, 00821 std::vector<double> &dlookC, 00822 int index) { 00823 return (lookC[2] * dlookC[index] - lookC[index] * dlookC[2]) / 00824 (lookC[2] * lookC[2]); 00825 } 00826 00827 00837 void BundleAdjust::Update (BasisFunction &basis) { 00838 // Update selected spice for each image 00839 for (int i=0; i<Images(); i++) { 00840 if (p_heldImages > 0) { 00841 if ((p_heldsnlist->HasSerialNumber(p_snlist->SerialNumber(i)))) continue; 00842 } 00843 00844 Camera *cam = p_cnet->Camera(i); 00845 int index = i; 00846 index = ImageIndex(index); 00847 if (p_spacecraftPositionSolveType != Nothing) { 00848 SpicePosition *pos = cam->InstrumentPosition(); 00849 std::vector<double> abcX(3),abcY(3),abcZ(3); 00850 pos->GetPolynomial(abcX,abcY,abcZ); 00851 00852 // Update the X coordinate coefficient(s) 00853 abcX[0] += basis.Coefficient(index); index++; 00854 if (p_spacecraftPositionSolveType > PositionOnly) { 00855 abcX[1] += basis.Coefficient(index); index++; 00856 if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { 00857 abcX[2] += basis.Coefficient(index); index++; 00858 } 00859 } 00860 00861 // Update the Y coordinate coefficient(s) 00862 abcY[0] += basis.Coefficient(index); index++; 00863 if (p_spacecraftPositionSolveType > PositionOnly) { 00864 abcY[1] += basis.Coefficient(index); index++; 00865 if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { 00866 abcY[2] += basis.Coefficient(index); index++; 00867 } 00868 } 00869 00870 // Update the Z coordinate cgoefficient(s) 00871 abcZ[0] += basis.Coefficient(index); index++; 00872 if (p_spacecraftPositionSolveType > PositionOnly) { 00873 abcZ[1] += basis.Coefficient(index); index++; 00874 if (p_spacecraftPositionSolveType == PositionVelocityAcceleration) { 00875 abcZ[2] += basis.Coefficient(index); index++; 00876 } 00877 } 00878 pos->SetPolynomial(abcX,abcY,abcZ); 00879 } 00880 00881 if (p_cmatrixSolveType != None) { 00882 SpiceRotation *rot = cam->InstrumentRotation(); 00883 std::vector<double> coefRA(p_numberCameraCoefSolved), 00884 coefDEC(p_numberCameraCoefSolved), 00885 coefTWI(p_numberCameraCoefSolved); 00886 rot->GetPolynomial(coefRA,coefDEC,coefTWI); 00887 00888 // Update right ascension coefficient(s) 00889 for (int icoef=0; icoef<p_numberCameraCoefSolved; icoef++) { 00890 coefRA[icoef] += basis.Coefficient(index); index++; 00891 } 00892 00893 // Update declination coefficient(s) 00894 for (int icoef=0; icoef<p_numberCameraCoefSolved; icoef++) { 00895 coefDEC[icoef] += basis.Coefficient(index); index++; 00896 } 00897 00898 if (p_solveTwist) { 00899 // Update twist coefficient(s) 00900 for (int icoef=0; icoef<p_numberCameraCoefSolved; icoef++) { 00901 coefTWI[icoef] += basis.Coefficient(index); index++; 00902 } 00903 } 00904 00905 rot->SetPolynomial(coefRA,coefDEC,coefTWI); 00906 } 00907 } 00908 00909 // Update lat/lon for each control point 00910 for (int i=0; i<p_cnet->Size(); i++) { 00911 if ((*p_cnet)[i].Held()) continue; 00912 if ((*p_cnet)[i].Ignore()) continue; 00913 if ((*p_cnet)[i].Type() == ControlPoint::Ground) continue; 00914 00915 double lat = (*p_cnet)[i].UniversalLatitude(); 00916 double lon = (*p_cnet)[i].UniversalLongitude(); 00917 double rad = (*p_cnet)[i].Radius(); 00918 int index = PointIndex(i); 00919 lat += (180.0 / Isis::PI) * (basis.Coefficient(index)); index++; 00920 lon += (180.0 / Isis::PI) * (basis.Coefficient(index)); index++; 00921 // Make sure updated values are still in valid range. 00922 // TODO What is the valid lon range? 00923 if (lat < -90.) { 00924 lat = -180. - lat; 00925 lon = lon + 180.; 00926 } 00927 if (lat > 90.) { 00928 lat = 180. - lat; 00929 lon = lon + 180.; 00930 } 00931 while (lon > 360.) lon = lon - 360.; 00932 while (lon < 0) lon = lon + 360.; 00933 00934 if (p_solveRadii) { 00935 rad += 1000.*basis.Coefficient(index); index++; 00936 } 00937 /* else { // Recompute radius to match updated lat/lon... Should this be removed? 00938 ControlMeasure &m = ((*p_cnet)[i])[0]; 00939 Camera *cam = m.Camera(); 00940 cam->SetUniversalGround(lat, lon); 00941 rad = cam->LocalRadius(); //meters 00942 }*/ 00943 (*p_cnet)[i].SetUniversalGround(lat,lon,rad); 00944 } 00945 } 00946 00948 int BundleAdjust::PointIndex (int i) const { 00949 int index; 00950 00951 if (!p_observationMode) { 00952 index = (Images() - p_heldImages) * p_numImagePartials; 00953 } 00954 else { 00955 index = Observations() * p_numImagePartials; 00956 } 00957 00958 index += p_pointIndexMap[i] * p_numPointPartials; 00959 return index; 00960 } 00961 00963 int BundleAdjust::ImageIndex (int i) const { 00964 if (!p_observationMode) { 00965 return p_imageIndexMap[i] * p_numImagePartials; 00966 } 00967 else { 00968 return p_onlist->ObservationNumberMapIndex(i) * p_numImagePartials; 00969 } 00970 } 00971 00972 00974 std::string BundleAdjust::Filename(int i) { 00975 // std::string serialNumber = (*p_snlist)[i]; 00976 // return p_snlist->Filename(serialNumber); 00977 return p_snlist->Filename(i); 00978 } 00979 00982 Table BundleAdjust::Cmatrix(int i) { 00983 return p_cnet->Camera(i)->InstrumentRotation()->Cache("InstrumentPointing"); 00984 } 00985 00988 Table BundleAdjust::SpVector(int i) { 00989 return p_cnet->Camera(i)->InstrumentPosition()->Cache("InstrumentPosition"); 00990 } 00991 00993 int BundleAdjust::Images () const { 00994 return p_snlist->Size(); 00995 } 00996 00998 int BundleAdjust::Observations () const { 00999 if ( !p_observationMode ) { 01000 return p_snlist->Size() - p_heldImages; 01001 } 01002 else { 01003 return p_onlist->ObservationSize(); 01004 } 01005 } 01006 01007 std::vector<double> BundleAdjust::PointPartial(Isis::ControlPoint &point, PartialDerivative wrt) { 01008 double lat = point.UniversalLatitude() * Isis::PI / 180.0; 01009 double lon = point.UniversalLongitude() * Isis::PI / 180.0; 01010 double sinLon = sin(lon); 01011 double cosLon = cos(lon); 01012 double sinLat = sin(lat); 01013 double cosLat = cos(lat); 01014 double radius = point.Radius() / 1000.0; 01015 01016 std::vector<double> v(3); 01017 if (wrt == WRT_Latitude) { 01018 v[0] = -radius * sinLat * cosLon; 01019 v[1] = -radius * sinLon * sinLat; 01020 v[2] = radius * cosLat; 01021 } 01022 else if (wrt == WRT_Longitude) { 01023 v[0] = -radius * cosLat * sinLon; 01024 v[1] = radius * cosLat * cosLon; 01025 v[2] = 0.0; 01026 } 01027 else { 01028 v[0] = cosLon * cosLat; 01029 v[1] = sinLon * cosLat; 01030 v[2] = sinLat; 01031 } 01032 01033 return v; 01034 } 01035 01036 01054 void BundleAdjust::IterationSummary(double avErr, double sigmaXY, double sigmaHat, 01055 double sigmaX, double sigmaY) { 01056 //Add this iteration to the summary pvl 01057 std::string itlog = "Iteration" + iString( p_iteration ); 01058 PvlGroup gp( itlog ); 01059 gp += PvlKeyword("MaximumError", p_error, "pixels"); 01060 gp += PvlKeyword("AverageError", avErr, "pixels"); 01061 gp += PvlKeyword("SigmaXY", sigmaXY, "mm"); 01062 gp += PvlKeyword("SigmaHat", sigmaHat, "mm"); 01063 gp += PvlKeyword("SigmaX", sigmaX, "mm"); 01064 gp += PvlKeyword("SigmaY", sigmaY, "mm"); 01065 01066 Application::Log( gp ); 01067 } 01068 01069 }