00001
00028 #include <boost/foreach.hpp>
00029 #include "PTOptimizer.h"
00030
00031 #include "ImageGraph.h"
00032 #include "panodata/StandardImageVariableGroups.h"
00033 #include <panotools/PanoToolsOptimizerWrapper.h>
00034 #include <panotools/PanoToolsInterface.h>
00035 #include <algorithms/basic/CalculateCPStatistics.h>
00036 #include <algorithms/nona/CenterHorizontally.h>
00037 #include <algorithms/nona/CalculateFOV.h>
00038 #include <vigra_ext/ransac.h>
00039
00040 #if DEBUG
00041 #include <fstream>
00042 #include <boost/graph/graphviz.hpp>
00043 #endif
00044
00045 namespace HuginBase {
00046
00047 using namespace hugin_utils;
00048
00049 bool PTOptimizer::runAlgorithm()
00050 {
00051 PTools::optimize(o_panorama);
00052 return true;
00053 }
00054
00055
00056 class OptVarSpec
00057 {
00058 public:
00059 OptVarSpec(int img, std::string name)
00060 : m_img(img), m_name(name)
00061 {
00062 }
00063
00064 double get(PanoramaData & pano) const
00065 {
00066 return pano.getImage(m_img).getVar(m_name);
00067 }
00068 void set(PanoramaData & pano, double x) const
00069 {
00070 pano.updateVariable(m_img,Variable(m_name,x));
00071 }
00072 int m_img;
00073 std::string m_name;
00074 };
00075
00077 class PTOptEstimator
00078 {
00079
00080 public:
00081
00082 PTOptEstimator(PanoramaData & pano, int i1, int i2, double maxError,
00083 bool optHFOV, bool optB)
00084 {
00085 m_maxError = maxError;
00086
00087 UIntSet imgs;
00088 imgs.insert(i1);
00089 imgs.insert(i2);
00090 m_localPano = (pano.getNewSubset(imgs));
00091 m_li1 = (i1 < i2) ? 0 : 1;
00092 m_li2 = (i1 < i2) ? 1 : 0;
00093
00094 m_cps = m_localPano->getCtrlPoints();
00095
00096 BOOST_FOREACH(ControlPoint & kp, m_cps) {
00097 if (kp.mode == ControlPoint::X_Y) {
00098 m_xy_cps.push_back(kp);
00099 }
00100 }
00101
00102 if (optHFOV)
00103 m_optvars.push_back(OptVarSpec(0,std::string("v")));
00104 if (optB)
00105 m_optvars.push_back(OptVarSpec(0,std::string("b")));
00106 m_optvars.push_back(OptVarSpec(m_li2,"r"));
00107 m_optvars.push_back(OptVarSpec(m_li2,"p"));
00108 m_optvars.push_back(OptVarSpec(m_li2,"y"));
00109 if (optHFOV)
00110 m_optvars.push_back(OptVarSpec(0,"v"));
00111 if (optB)
00112 m_optvars.push_back(OptVarSpec(0,"b"));
00113
00115 m_opt_first_pass.resize(2);
00116 m_opt_first_pass[1].insert("r");
00117 m_opt_first_pass[1].insert("p");
00118 m_opt_first_pass[1].insert("y");
00119
00121 if (optHFOV || optB) {
00122 m_opt_second_pass = m_opt_first_pass;
00123 if (optHFOV)
00124 m_opt_second_pass[0].insert("v");
00125 if (optB)
00126 m_opt_second_pass[0].insert("b");
00127 }
00128
00129
00130 m_numForEstimate = (m_optvars.size()+1)/2;
00131
00132
00133 m_initParams.resize(m_optvars.size());
00134 int i=0;
00135 BOOST_FOREACH(OptVarSpec & v, m_optvars) {
00136 m_initParams[i] = v.get(*m_localPano);
00137 DEBUG_DEBUG("get init var: " << v.m_name << ", " << v.m_img << ": " << m_initParams[i]);
00138 i++;
00139 }
00140 }
00141
00142
00143
00149 bool estimate(const std::vector<const ControlPoint *> & points, std::vector<double> & p) const
00150 {
00151
00152 p.resize(m_initParams.size());
00153 std::copy(m_initParams.begin(), m_initParams.end(), p.begin());
00154
00155 return leastSquaresEstimate(points, p);
00156 }
00157
00158
00159
00160 bool leastSquaresEstimate(const std::vector<const ControlPoint *> & points, std::vector<double> & p) const
00161 {
00162
00163 CPVector cpoints(points.size());
00164 for (int i=0; i < points.size(); i++) {
00165 cpoints[i] = *points[i];
00166 }
00167
00168 m_localPano->setCtrlPoints(cpoints);
00169
00170 PanoramaData * pano = const_cast<PanoramaData *>(m_localPano);
00171
00172 int i=0;
00173 BOOST_FOREACH(const OptVarSpec & v, m_optvars) {
00174 v.set(*pano, p[i]);
00175 DEBUG_DEBUG("Initial " << v.m_name << ": i1:" << pano->getImage(m_li1).getVar(v.m_name) << ", i2: " << pano->getImage(m_li2).getVar(v.m_name));
00176 i++;
00177 }
00178
00179 m_localPano->setOptimizeVector(m_opt_first_pass);
00180
00181 UIntSet imgs;
00182 imgs.insert(0);
00183 imgs.insert(1);
00184
00185
00186 PTools::optimize(*pano);
00187
00188
00189
00190 if (m_opt_second_pass.size() > 0) {
00191 m_localPano->setOptimizeVector(m_opt_second_pass);
00192
00193
00194 PTools::optimize(*pano);
00195
00196
00197 }
00198
00199
00200 i=0;
00201 BOOST_FOREACH(const OptVarSpec & v, m_optvars) {
00202 p[i] = v.get(*pano);
00203 DEBUG_DEBUG("Optimized " << v.m_name << ": i1:" << pano->getImage(m_li1).getVar(v.m_name) << ", i2: " << pano->getImage(m_li2).getVar(v.m_name));
00204 i++;
00205 }
00206 return true;
00207 }
00208
00209
00210 bool agree(std::vector<double> &p, const ControlPoint & cp) const
00211 {
00212 PanoramaData * pano = const_cast<PanoramaData *>(m_localPano);
00213
00214 int i=0;
00215 BOOST_FOREACH(const OptVarSpec & v, m_optvars) {
00216 v.set(*pano, p[i]);
00217 i++;
00218 }
00219
00220
00221 PTools::Transform trafo_i1_to_pano;
00222 trafo_i1_to_pano.createInvTransform(m_localPano->getImage(m_li1),m_localPano->getOptions());
00223 PTools::Transform trafo_pano_to_i2;
00224 trafo_pano_to_i2.createTransform(m_localPano->getImage(m_li2),m_localPano->getOptions());
00225
00226 double x1,y1,x2,y2,xt,yt,x2t,y2t;
00227 if (cp.image1Nr == m_li1) {
00228 x1 = cp.x1;
00229 y1 = cp.y1;
00230 x2 = cp.x2;
00231 y2 = cp.y2;
00232 } else {
00233 x1 = cp.x2;
00234 y1 = cp.y2;
00235 x2 = cp.x1;
00236 y2 = cp.y1;
00237 }
00238 trafo_i1_to_pano.transformImgCoord(xt, yt, x1, y1);
00239 trafo_pano_to_i2.transformImgCoord(x2t, y2t, xt, yt);
00240 DEBUG_DEBUG("Trafo i1 (0 " << x1 << " " << y1 << ") -> ("<< xt <<" "<< yt<<") -> i2 (1 "<<x2t<<", "<<y2t<<"), real ("<<x2<<", "<<y2<<")")
00241
00242 x2t -= x2;
00243 y2t -= y2;
00244 double e = hypot(x2t,y2t);
00245 DEBUG_DEBUG("Error ("<<x2t<<", "<<y2t<<"), " << e)
00246 return e < m_maxError;
00247 }
00248
00249 ~PTOptEstimator()
00250 {
00251 delete m_localPano;
00252 }
00253
00254 int numForEstimate() const
00255 {
00256 return m_numForEstimate;
00257 }
00258
00259 public:
00260 CPVector m_xy_cps;
00261 std::vector<double> m_initParams;
00262 std::vector<OptVarSpec> m_optvars;
00263
00264 private:
00265 int m_li1, m_li2;
00266 double m_maxError;
00267 PanoramaData * m_localPano;
00268 CPVector m_cps;
00269 std::vector<std::set<std::string> > m_opt_first_pass;
00270 std::vector<std::set<std::string> > m_opt_second_pass;
00271 int m_numForEstimate;
00272 };
00273
00274
00275 std::vector<int> RANSACOptimizer::findInliers(PanoramaData & pano, int i1, int i2, double maxError, Mode rmode)
00276 {
00277 bool optHFOV = false;
00278 bool optB = false;
00279 switch (rmode) {
00280 case HOMOGRAPHY:
00281 case RPYV:
00282 optHFOV = true;
00283 break;
00284 case RPYVB:
00285 optHFOV = true;
00286 optB = true;
00287 case AUTO:
00288 case RPY:
00289 break;
00290 }
00291
00292 DEBUG_DEBUG("Optimizing HFOV:" << optHFOV << " b:" << optB)
00293 PTOptEstimator estimator(pano, i1, i2, maxError, optHFOV, optB);
00294
00295 std::vector<double> parameters(estimator.m_initParams.size());
00296 std::copy(estimator.m_initParams.begin(),estimator.m_initParams.end(), parameters.begin());
00297 std::vector<int> inlier_idx;
00298 DEBUG_DEBUG("Number of control points: " << estimator.m_xy_cps.size() << " Initial parameter[0]" << parameters[0]);
00299 std::vector<const ControlPoint *> inliers = Ransac::compute(parameters, inlier_idx, estimator, estimator.m_xy_cps, 0.999, 0.3);
00300 DEBUG_DEBUG("Number of inliers:" << inliers.size() << "optimized parameter[0]" << parameters[0]);
00301
00302
00303 int i=0;
00304 BOOST_FOREACH(const OptVarSpec & v, estimator.m_optvars) {
00305
00306 pano.updateVariable(i2, Variable(v.m_name, parameters[i]));
00307 i++;
00308 }
00309
00310
00311
00312 return inlier_idx;
00313 }
00314
00315
00316 bool RANSACOptimizer::runAlgorithm()
00317 {
00318 o_inliers = findInliers(o_panorama, o_i1, o_i2, o_maxError, o_mode);
00319 return true;
00320 }
00321
00322
00323 void AutoOptimise::autoOptimise(PanoramaData& pano, bool optRoll)
00324 {
00325
00326
00327
00328 CPGraph graph;
00329 createCPGraph(pano,graph);
00330
00331 #if DEBUG
00332 {
00333 std::ofstream gfile("cp_graph.dot");
00334
00335 boost::write_graphviz(gfile, graph);
00336 }
00337 #endif
00338 std::set<std::string> optvars;
00339 if(optRoll)
00340 {
00341 optvars.insert("r");
00342 };
00343 optvars.insert("p");
00344 optvars.insert("y");
00345
00346 unsigned int startImg = pano.getOptions().optimizeReferenceImage;
00347
00348
00349
00350
00351 OptimiseVisitor optVisitor(pano, optvars);
00352
00353 boost::queue<boost::graph_traits<CPGraph>::vertex_descriptor> qu;
00354 boost::breadth_first_search(graph, startImg,
00355 color_map(get(boost::vertex_color, graph)).
00356 visitor(optVisitor));
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 }
00380
00381
00382 void SmartOptimise::smartOptimize(PanoramaData& optPano)
00383 {
00384
00385 PanoramaOptions opts = optPano.getOptions();
00386 double oldSigma = opts.huberSigma;
00387 opts.huberSigma = 2;
00388 optPano.setOptions(opts);
00389
00390
00391 CPVector cps = optPano.getCtrlPoints();
00392 CPVector newCP;
00393 for (CPVector::const_iterator it = cps.begin(); it != cps.end(); it++) {
00394 if (it->mode == ControlPoint::X_Y)
00395 {
00396 newCP.push_back(*it);
00397 }
00398 }
00399 optPano.setCtrlPoints(newCP);
00400 AutoOptimise::autoOptimise(optPano);
00401
00402
00403 optPano.setCtrlPoints(cps);
00404 OptimizeVector optvars = createOptVars(optPano, OPT_POS, optPano.getOptions().optimizeReferenceImage);
00405 optPano.setOptimizeVector(optvars);
00406 PTools::optimize(optPano);
00407
00408
00409 StandardImageVariableGroups variable_groups(optPano);
00410
00411
00412
00413
00414 double origLensPar[5];
00415 origLensPar[0] = const_map_get(optPano.getImageVariables(0),"a").getValue();
00416 origLensPar[1] = const_map_get(optPano.getImageVariables(0),"b").getValue();
00417 origLensPar[2] = const_map_get(optPano.getImageVariables(0),"c").getValue();
00418 origLensPar[3] = const_map_get(optPano.getImageVariables(0),"d").getValue();
00419 origLensPar[4] = const_map_get(optPano.getImageVariables(0),"e").getValue();
00420 bool alreadyCalibrated = false;
00421 for (int i = 0; i < 5; i++) {
00422 if (origLensPar[i] != 0) {
00423 alreadyCalibrated = true;
00424 break;
00425 }
00426 }
00427
00428
00429 if (!alreadyCalibrated) {
00430
00431
00432
00433
00434 for (unsigned i=0; i< variable_groups.getLenses().getNumberOfParts(); i++)
00435 {
00436 variable_groups.getLenses().linkVariablePart(ImageVariableGroup::IVE_RadialDistortion, i);
00437 variable_groups.getLenses().linkVariablePart(ImageVariableGroup::IVE_RadialDistortionCenterShift, i);
00438 }
00439
00440 int optmode = OPT_POS;
00441 double origHFOV = const_map_get(optPano.getImageVariables(0),"v").getValue();
00442
00443
00444 double rmin, rmax, rmean, rvar, rq10, rq90;
00445 CalculateCPStatisticsRadial::calcCtrlPntsRadiStats(optPano, rmin, rmax, rmean, rvar, rq10, rq90);
00446
00447 DEBUG_DEBUG("Ctrl Point radi statistics: min:" << rmin << " max:" << rmax << " mean:" << rmean << " var:" << rvar << " q10:" << rq10 << " q90:" << rq90);
00448
00449 if (origHFOV > 60) {
00450
00451 optmode |= OPT_DE;
00452 }
00453
00454
00455 if ( (rq90 - rq10) >= 1.2) {
00456
00457
00458 optmode |= OPT_AC | OPT_B;
00459 } else if ( (rq90 - rq10) > 1.0) {
00460 optmode |= OPT_AC | OPT_B;
00461 } else {
00462 optmode |= OPT_B;
00463 }
00464
00465
00466 CenterHorizontally(optPano).run();
00467
00468 FDiff2D fov = CalculateFOV::calcFOV(optPano);
00469
00470 if (fov.x >= 359) {
00471
00472 optmode |= OPT_HFOV;
00473 }
00474
00475 DEBUG_DEBUG("second optimization: " << optmode);
00476
00477
00478 VariableMapVector oldVars = optPano.getVariables();
00479 DEBUG_DEBUG("oldVars[0].b: " << const_map_get(oldVars[0],"b").getValue());
00480 optvars = createOptVars(optPano, optmode, optPano.getOptions().optimizeReferenceImage);
00481 optPano.setOptimizeVector(optvars);
00482
00483 DEBUG_DEBUG("before opt 1: newVars[0].b: " << const_map_get(optPano.getVariables()[0],"b").getValue());
00484 PTools::optimize(optPano);
00485
00486
00487
00488 bool smallHFOV = false;
00489 bool highDist = false;
00490 bool highShift = false;
00491 const VariableMapVector & vars = optPano.getVariables();
00492 DEBUG_DEBUG("after opt 1: newVars[0].b: " << const_map_get(vars[0],"b").getValue());
00493 DEBUG_DEBUG("after opt 1: oldVars[0].b: " << const_map_get(oldVars[0],"b").getValue());
00494 for (VariableMapVector::const_iterator it = vars.begin() ; it != vars.end(); it++)
00495 {
00496 if (const_map_get(*it,"v").getValue() < 1.0) smallHFOV = true;
00497 if (fabs(const_map_get(*it,"a").getValue()) > 0.8) highDist = true;
00498 if (fabs(const_map_get(*it,"b").getValue()) > 0.8) highDist = true;
00499 if (fabs(const_map_get(*it,"c").getValue()) > 0.8) highDist = true;
00500 if (fabs(const_map_get(*it,"d").getValue()) > 2000) highShift = true;
00501 if (fabs(const_map_get(*it,"e").getValue()) > 2000) highShift = true;
00502 }
00503
00504 if (smallHFOV || highDist || highShift) {
00505 DEBUG_DEBUG("Optimization with strange result. status: HFOV: " << smallHFOV << " dist:" << highDist << " shift:" << highShift);
00506
00507 if (smallHFOV) {
00508
00509 optmode &= ~OPT_HFOV;
00510 }
00511 if (highDist) {
00512 optmode &= ~OPT_AC;
00513 }
00514 if (highShift) {
00515 optmode &= ~OPT_DE;
00516 }
00517
00518
00519 DEBUG_DEBUG("oldVars[0].b: " << const_map_get(oldVars[0],"b").getValue());
00520 optPano.updateVariables(oldVars);
00521 DEBUG_DEBUG("before opt 2: newVars[0].b: " << const_map_get(optPano.getVariables()[0],"b").getValue());
00522 optvars = createOptVars(optPano, optmode, optPano.getOptions().optimizeReferenceImage);
00523 optPano.setOptimizeVector(optvars);
00524 DEBUG_DEBUG("recover optimisation: " << optmode);
00525
00526 PTools::optimize(optPano);
00527
00528
00529 bool highDist = false;
00530 const VariableMapVector & vars = optPano.getVariables();
00531 DEBUG_DEBUG("after opt 2: newVars[0].b: " << const_map_get(vars[0],"b").getValue());
00532 DEBUG_DEBUG("after opt 2: oldVars[0].b: " << const_map_get(oldVars[0],"b").getValue());
00533 for (VariableMapVector::const_iterator it = vars.begin() ; it != vars.end(); it++)
00534 {
00535 if (fabs(const_map_get(*it,"b").getValue()) > 0.8) highDist = true;
00536 }
00537 if (highDist) {
00538 optmode &= ~OPT_B;
00539 DEBUG_DEBUG("recover optimisation (2): " << optmode);
00540
00541 optPano.updateVariables(oldVars);
00542 DEBUG_DEBUG("before opt 3: newVars[0].b: " << const_map_get(optPano.getVariables()[0],"b").getValue());
00543 optvars = createOptVars(optPano, optmode, optPano.getOptions().optimizeReferenceImage);
00544 optPano.setOptimizeVector(optvars);
00545
00546 PTools::optimize(optPano);
00547 const VariableMapVector & vars = optPano.getVariables();
00548 DEBUG_DEBUG("after opt 3: newVars[0].b: " << const_map_get(vars[0],"b").getValue());
00549 DEBUG_DEBUG("after opt 3: oldVars[0].b: " << const_map_get(oldVars[0],"b").getValue());
00550
00551 }
00552 }
00553 }
00554 opts.huberSigma = oldSigma;
00555 optPano.setOptions(opts);
00556 }
00557
00558 OptimizeVector SmartOptimizerStub::createOptVars(const PanoramaData& optPano, int mode, unsigned anchorImg)
00559 {
00560 OptimizeVector optvars;
00561 const SrcPanoImage & anchorImage = optPano.getImage(anchorImg);
00562 for (unsigned i=0; i < optPano.getNrOfImages(); i++) {
00563 std::set<std::string> imgopt;
00564
00565 const SrcPanoImage & iImage = optPano.getImage(i);
00566 if (!iImage.RollisLinkedWith(anchorImage) &&
00567 !iImage.PitchisLinkedWith(anchorImage) &&
00568 !iImage.YawisLinkedWith(anchorImage))
00569 {
00570 if (mode & OPT_POS) {
00571 imgopt.insert("r");
00572 imgopt.insert("p");
00573 imgopt.insert("y");
00574 }
00575 }
00576
00577
00578 if((i==anchorImg) && (mode & OPT_POS))
00579 {
00580 imgopt.insert("r");
00581 imgopt.insert("p");
00582 };
00583
00584 if (i!=anchorImg)
00585 {
00586 if (mode & OPT_EXP) {
00587 imgopt.insert("Eev");
00588 }
00589 if (mode & OPT_WB) {
00590 imgopt.insert("Er");
00591 imgopt.insert("Eb");
00592 }
00593 }
00594 if (mode & OPT_HFOV) {
00595 imgopt.insert("v");
00596 }
00597 if (mode & OPT_B)
00598 imgopt.insert("b");
00599 if (mode & OPT_AC) {
00600 imgopt.insert("a");
00601 imgopt.insert("c");
00602 }
00603 if (mode & OPT_DE) {
00604 imgopt.insert("d");
00605 imgopt.insert("e");
00606 }
00607 if (mode & OPT_GT) {
00608 imgopt.insert("g");
00609 imgopt.insert("t");
00610 }
00611 if (mode & OPT_VIG) {
00612 imgopt.insert("Vb");
00613 imgopt.insert("Vc");
00614 imgopt.insert("Vd");
00615 }
00616 if (mode & OPT_VIGCENTRE) {
00617 imgopt.insert("Vx");
00618 imgopt.insert("Vy");
00619 }
00620 if (mode & OPT_RESP) {
00621 imgopt.insert("Ra");
00622 imgopt.insert("Rb");
00623 imgopt.insert("Rc");
00624 imgopt.insert("Rd");
00625 imgopt.insert("Re");
00626 }
00627 optvars.push_back(imgopt);
00628 }
00629
00630 return optvars;
00631 }
00632
00633 }