00001
00026 #include "Panorama.h"
00027
00028 #include "PTScriptParsing.h"
00029 #include "ImageVariableTranslate.h"
00030 #include "StandardImageVariableGroups.h"
00031 #include <panotools/PanoToolsInterface.h>
00032 #include <algorithms/basic/CalculateOverlap.h>
00033 #include <panodata/OptimizerSwitches.h>
00034
00035 #include <fstream>
00036 #include <typeinfo>
00037 #include <vigra/impex.hxx>
00038
00039
00040 namespace HuginBase {
00041
00042 using namespace hugin_utils;
00043
00044 Panorama::Panorama()
00045 :
00046
00047
00048
00049 dirty(false),
00050 m_forceImagesUpdate(false)
00051 {
00052
00053 m_ptoptimizerVarNames.insert("a");
00054 m_ptoptimizerVarNames.insert("b");
00055 m_ptoptimizerVarNames.insert("c");
00056 m_ptoptimizerVarNames.insert("d");
00057 m_ptoptimizerVarNames.insert("e");
00058 m_ptoptimizerVarNames.insert("g");
00059 m_ptoptimizerVarNames.insert("t");
00060 m_ptoptimizerVarNames.insert("v");
00061 m_ptoptimizerVarNames.insert("r");
00062 m_ptoptimizerVarNames.insert("p");
00063 m_ptoptimizerVarNames.insert("y");
00064 m_ptoptimizerVarNames.insert("TrX");
00065 m_ptoptimizerVarNames.insert("TrY");
00066 m_ptoptimizerVarNames.insert("TrZ");
00067 m_ptoptimizerVarNames.insert("Tpy");
00068 m_ptoptimizerVarNames.insert("Tpp");
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 }
00080
00081
00082 Panorama::~Panorama()
00083 {
00084 DEBUG_TRACE("dtor");
00085 reset();
00086 DEBUG_TRACE("dtor about to finish");
00087 }
00088
00089
00090 void Panorama::reset()
00091 {
00092
00093
00094
00095 state.ctrlPoints.clear();
00096 state.deleteAllImages();
00097 state.options.reset();
00098 state.optvec.clear();
00099 state.optSwitch=0;
00100 state.optPhotoSwitch=0;
00101 state.needsOptimization = false;
00102 AppBase::DocumentData::setDirty(false);
00103 dirty=false;
00104 }
00105
00106
00107 #if 0
00108 QDomElement Panorama::toXML(QDomDocument & doc)
00109 {
00110 QDomElement root = doc.createElement("panorama");
00111
00112 root.appendChild(options.toXML(doc));
00113
00114
00115 QDomElement images_ = doc.createElement("images");
00116 for (ImageVector::iterator it = images.begin(); it != images.end(); ++it) {
00117 images_.appendChild(it->toXML(doc));
00118 }
00119 root.appendChild(images_);
00120
00121
00122 QDomElement cps = doc.createElement("control_points");
00123 for (CPVector::iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
00124 cps.appendChild(it->toXML(doc));
00125 }
00126 root.appendChild(cps);
00127
00128
00129 QDomElement lenses_ = doc.createElement("lenses");
00130 for (std::vector<Lens>::iterator it = lenses.begin(); it != lenses.end(); ++it) {
00131 lenses_.appendChild(it->toXML(doc));
00132 }
00133 root.appendChild(lenses_);
00134
00135 return root;
00136 }
00137
00138 void Panorama::setFromXML(const QDomNode & elem)
00139 {
00140 DEBUG_DEBUG("Panorama::setFromXML");
00141 clear();
00142
00143 Q_ASSERT(elem.nodeName() == "panorama");
00144
00145 QDomNode n = elem.namedItem("output");
00146 Q_ASSERT(!n.isNull);
00147 options.setFromXML(n);
00148 n = elem.namedItem("images");
00149 Q_ASSERT(!n.isNull);
00150 n = n.firstChild();
00151 while( !n.isNull() ) {
00152 QDomElement e = n.toElement();
00153 Q_ASSERT((!e.isNull()) && e.tagName() == "image" );
00154 images.push_back(PanoImage(*this, e));
00155 reportAddedImage(images.size() -1);
00156 n = n.nextSibling();
00157 }
00158
00159
00160 n = elem.namedItem("control_points");
00161 Q_ASSERT(!n.isNull());
00162 n = n.firstChild();
00163 while( !n.isNull() ) {
00164 QDomElement e = n.toElement();
00165 Q_ASSERT((!e.isNull()) && e.tagName() == "control_point" );
00166 controlPoints.push_back(ControlPoint(*this, e));
00167 reportAddedCtrlPoint(controlPoints.size() -1);
00168 n = n.nextSibling();
00169 }
00170 }
00171
00172
00173 #endif
00174
00175
00176 std::vector<unsigned int> Panorama::getCtrlPointsForImage(unsigned int imgNr) const
00177 {
00178 std::vector<unsigned int> result;
00179 unsigned int i = 0;
00180 for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
00181 if ((it->image1Nr == imgNr) || (it->image2Nr == imgNr)) {
00182 result.push_back(i);
00183 }
00184 i++;
00185 }
00186 return result;
00187 }
00188
00189 CPointVector Panorama::getCtrlPointsVectorForImage(unsigned int imgNr) const
00190 {
00191 CPointVector result;
00192 for(unsigned int i=0;i<state.ctrlPoints.size();i++)
00193 {
00194 ControlPoint point=state.ctrlPoints[i];
00195 if(point.image1Nr==imgNr)
00196 {
00197 result.push_back(std::make_pair(i,point));
00198 }
00199 else
00200 {
00201 if(point.image2Nr==imgNr)
00202 {
00203 point.mirror();
00204 result.push_back(std::make_pair(i,point));
00205 };
00206 };
00207 };
00208 return result;
00209 };
00210
00211 VariableMapVector Panorama::getVariables() const
00212 {
00213 VariableMapVector map;
00214 for (size_t i = 0; i < state.images.size(); i++)
00215 {
00216 map.push_back(state.images[i]->getVariableMap());
00217 }
00218 return map;
00219 }
00220
00221 const VariableMap Panorama::getImageVariables(unsigned int imgNr) const
00222 {
00223 assert(imgNr < state.images.size());
00224 return state.images[imgNr]->getVariableMap();
00225 }
00226
00227
00228 void Panorama::updateCtrlPointErrors(const UIntSet & imgs, const CPVector & cps)
00229 {
00230 unsigned sc = 0;
00231 unsigned ic = 0;
00232 std::map<unsigned int, unsigned int> script2CPMap;
00233 for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
00234 if (set_contains(imgs, it->image1Nr) && set_contains(imgs, it->image2Nr)) {
00235 script2CPMap[sc] = ic;
00236 sc++;
00237 }
00238 ic++;
00239 }
00240
00241
00242 assert(cps.size() == script2CPMap.size());
00243 unsigned i=0;
00244 for (CPVector::const_iterator it = cps.begin(); it != cps.end(); ++it) {
00245 imageChanged(script2CPMap[it->image1Nr]);
00246 imageChanged(script2CPMap[it->image2Nr]);
00247 state.ctrlPoints[script2CPMap[i]].error = it->error;
00248 i++;
00249 }
00250 }
00251
00252
00253 void Panorama::updateCtrlPointErrors(const CPVector & cps)
00254 {
00255 assert(cps.size() == state.ctrlPoints.size());
00256 unsigned int nrp = cps.size();
00257 for (unsigned int i = 0; i < nrp ; i++) {
00258 imageChanged(state.ctrlPoints[i].image1Nr);
00259 imageChanged(state.ctrlPoints[i].image2Nr);
00260 state.ctrlPoints[i].error = cps[i].error;
00261 }
00262 }
00263
00264 void Panorama::updateVariables(const VariableMapVector & vars)
00265 {
00266 assert(vars.size() == state.images.size());
00267 unsigned int i = 0;
00268 for (VariableMapVector::const_iterator it = vars.begin(); it != vars.end(); ++it) {
00269 updateVariables(i, *it);
00270 i++;
00271 }
00272 }
00273
00274 void Panorama::updateVariables(const UIntSet & imgs, const VariableMapVector & vars)
00275 {
00276 VariableMapVector::const_iterator v_it = vars.begin();
00277 for (UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it) {
00278 assert(*it < state.images.size());
00279 updateVariables(*it, *v_it);
00280 ++v_it;
00281 }
00282 }
00283
00284 void Panorama::updateVariables(unsigned int imgNr, const VariableMap & var)
00285 {
00286 if (imgNr > state.images.size())
00287 return;
00288 for (VariableMap::const_iterator it = var.begin(); it != var.end() ; ++it) {
00289 updateVariable(imgNr,it->second);
00290 }
00291 }
00292
00293 void Panorama::updateVariable(unsigned int imgNr, const Variable &var)
00294 {
00295 if (imgNr > state.images.size())
00296 return;
00297
00298 state.images[imgNr]->setVar(var.getName(), var.getValue());
00299
00300 #define image_variable( name, type, default_value ) \
00301 if (PTOVariableConverterFor##name::checkApplicability(var.getName())) \
00302 {\
00303 for (std::size_t i = 0; i < getNrOfImages(); i++)\
00304 {\
00305 if (state.images[imgNr]->name##isLinkedWith(*state.images[i]))\
00306 {\
00307 imageChanged(i);\
00308 }\
00309 }\
00310 }\
00311 else
00312 #include "image_variables.h"
00313 #undef image_variable
00314 {
00315 DEBUG_ERROR("Unknown variable " << var.getName());
00316 }
00317 state.needsOptimization = true;
00318 }
00319
00320 void Panorama::UpdateFocalLength(UIntSet imgs, double newFocalLength)
00321 {
00322 for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++)
00323 {
00324 state.images[*it]->updateFocalLength(newFocalLength);
00325 imageChanged(*it);
00326 };
00327
00328 for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++)
00329 {
00330 SrcPanoImage *img=state.images[*it];
00331 if(state.images[*it]->HFOVisLinked())
00332 {
00333 for(unsigned int j=0;j<getNrOfImages();j++)
00334 {
00335 if(*it!=j)
00336 {
00337 if(state.images[*it]->HFOVisLinkedWith(*img))
00338 {
00339 imageChanged(j);
00340 };
00341 };
00342 };
00343 };
00344 };
00345 };
00346
00347 void Panorama::UpdateCropFactor(UIntSet imgs, double newCropFactor)
00348 {
00349
00350 std::vector<double> focalLengthVector(getNrOfImages(),0.0);
00351 for(unsigned i=0;i<getNrOfImages();i++)
00352 {
00353 focalLengthVector[i]=state.images[i]->calcFocalLength(state.images[i]->getProjection(),
00354 state.images[i]->getHFOV(),state.images[i]->getExifCropFactor(),state.images[i]->getSize());
00355 };
00356 for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++)
00357 {
00358 state.images[*it]->updateCropFactor(focalLengthVector[*it],newCropFactor);
00359 imageChanged(*it);
00360 };
00361 };
00362
00363
00364
00365
00366
00368 #define image_variable( name, type, default_value )\
00369 void Panorama::linkImageVariable##name(unsigned int sourceImgNr, unsigned int destImgNr)\
00370 {\
00371 state.images[destImgNr]->link##name(state.images[sourceImgNr]);\
00372 imageChanged(destImgNr);\
00373 imageChanged(sourceImgNr);\
00374 state.needsOptimization = true;\
00375 }
00376 #include "image_variables.h"
00377 #undef image_variable
00378
00380 #define image_variable( name, type, default_value )\
00381 void Panorama::unlinkImageVariable##name(unsigned int imgNr)\
00382 {\
00383 state.images[imgNr]->unlink##name();\
00384 imageChanged(imgNr);\
00385 state.needsOptimization = true;\
00386 }
00387 #include "image_variables.h"
00388 #undef image_variable
00389
00390 void Panorama::setOptimizeVector(const OptimizeVector & optvec)
00391 {
00392 DEBUG_ASSERT(optvec.size() == state.images.size());
00393 state.optvec = optvec;
00394 }
00395
00396 void Panorama::setOptimizerSwitch(const int newSwitch)
00397 {
00398 if(state.optSwitch!=newSwitch)
00399 {
00400 state.optSwitch=newSwitch;
00401 };
00402 };
00403
00404 void Panorama::setPhotometricOptimizerSwitch(const int newSwitch)
00405 {
00406 if(state.optPhotoSwitch!=newSwitch)
00407 {
00408 state.optPhotoSwitch=newSwitch;
00409 };
00410 };
00411
00412 unsigned int Panorama::addImage(const SrcPanoImage &img)
00413 {
00414 unsigned int nr = state.images.size();
00415 state.images.push_back(new SrcPanoImage(img));
00416
00417 state.optvec.push_back(std::set<std::string>());
00418 imageChanged(nr);
00419 return nr;
00420 }
00421
00422 void Panorama::removeImage(unsigned int imgNr)
00423 {
00424 DEBUG_DEBUG("Panorama::removeImage(" << imgNr << ")");
00425 assert(imgNr < state.images.size());
00426
00427
00428 CPVector::iterator it = state.ctrlPoints.begin();
00429 while (it != state.ctrlPoints.end()) {
00430 if ((it->image1Nr == imgNr) || (it->image2Nr == imgNr)) {
00431
00432 it = state.ctrlPoints.erase(it);
00433 } else {
00434
00435 if (it->image1Nr > imgNr) it->image1Nr--;
00436 if (it->image2Nr > imgNr) it->image2Nr--;
00437 ++it;
00438 }
00439 }
00440
00441 DEBUG_TRACE("Remove variables and image from panorama state")
00442 delete state.images[imgNr];
00443 state.images.erase(state.images.begin() + imgNr);
00444 state.optvec.erase(state.optvec.begin() + imgNr);
00445
00446
00447 if (state.options.optimizeReferenceImage >= state.images.size()) {
00448 state.options.optimizeReferenceImage = 0;
00449 imageChanged(state.options.optimizeReferenceImage);
00450 }
00451
00452 if (state.options.colorReferenceImage >= state.images.size()) {
00453 state.options.colorReferenceImage = 0;
00454 imageChanged(state.options.colorReferenceImage);
00455 }
00456
00457
00458 DEBUG_TRACE("flag moved images as dirty");
00459 for (unsigned int i=imgNr; i < state.images.size(); i++) {
00460 imageChanged(i);
00461 }
00462 m_forceImagesUpdate = true;
00463 }
00464
00465
00466 void Panorama::setImageFilename(unsigned int i, const std::string & fname)
00467 {
00468 DEBUG_ASSERT(i < state.images.size());
00469 state.images[i]->setFilename(fname);
00470 imageChanged(i);
00471 m_forceImagesUpdate = true;
00472 }
00473
00474 unsigned int Panorama::addCtrlPoint(const ControlPoint & point )
00475 {
00476 unsigned int nr = state.ctrlPoints.size();
00477 state.ctrlPoints.push_back(point);
00478 imageChanged(point.image1Nr);
00479 imageChanged(point.image2Nr);
00480 state.needsOptimization = true;
00481 return nr;
00482 }
00483
00484 void Panorama::removeCtrlPoint(unsigned int pNr)
00485 {
00486 DEBUG_ASSERT(pNr < state.ctrlPoints.size());
00487 ControlPoint & point = state.ctrlPoints[pNr];
00488 unsigned int i1 = point.image1Nr;
00489 unsigned int i2 = point.image2Nr;
00490 state.ctrlPoints.erase(state.ctrlPoints.begin() + pNr);
00491
00492
00493 updateLineCtrlPoints();
00494 imageChanged(i1);
00495 imageChanged(i2);
00496 state.needsOptimization = true;
00497 }
00498
00499 void Panorama::removeDuplicateCtrlPoints()
00500 {
00501 std::set<std::string> listOfCPs;
00502 std::set<unsigned int> duplicateCPs;
00503 for(unsigned int i=0; i<state.ctrlPoints.size();i++)
00504 {
00505 std::string s=state.ctrlPoints[i].getCPString();
00506 std::pair<std::set<std::string>::iterator,bool> it=listOfCPs.insert(s);
00507 if(it.second==false)
00508 {
00509 duplicateCPs.insert(i);
00510 };
00511 }
00512
00513 if(duplicateCPs.size()>0)
00514 {
00515 for(std::set<unsigned int>::reverse_iterator it=duplicateCPs.rbegin();it!=duplicateCPs.rend();it++)
00516 {
00517 ControlPoint cp=state.ctrlPoints[*it];
00518 imageChanged(cp.image1Nr);
00519 imageChanged(cp.image2Nr);
00520 removeCtrlPoint(*it);
00521 };
00522 };
00523 updateLineCtrlPoints();
00524 }
00525
00526
00527 void Panorama::changeControlPoint(unsigned int pNr, const ControlPoint & point)
00528 {
00529 assert(pNr < state.ctrlPoints.size());
00530
00531
00532 imageChanged(state.ctrlPoints[pNr].image1Nr);
00533 imageChanged(state.ctrlPoints[pNr].image2Nr);
00534 imageChanged(point.image1Nr);
00535 imageChanged(point.image2Nr);
00536 state.needsOptimization = true;
00537
00538 state.ctrlPoints[pNr] = point;
00539 updateLineCtrlPoints();
00540 }
00541
00542 void Panorama::setCtrlPoints(const CPVector & points)
00543 {
00544 for (CPVector::const_iterator it = state.ctrlPoints.begin();
00545 it != state.ctrlPoints.end(); it++)
00546 {
00547 imageChanged(it->image1Nr);
00548 imageChanged(it->image2Nr);
00549 }
00550
00551 state.ctrlPoints = points;
00552
00553 for (CPVector::const_iterator it = state.ctrlPoints.begin();
00554 it != state.ctrlPoints.end(); it++)
00555 {
00556 imageChanged(it->image1Nr);
00557 imageChanged(it->image2Nr);
00558 }
00559 state.needsOptimization = true;
00560 updateLineCtrlPoints();
00561 }
00562
00563
00564 void Panorama::updateLineCtrlPoints()
00565 {
00566
00567 std::map<int, int> lines;
00568 for (CPVector::const_iterator it = state.ctrlPoints.begin();
00569 it != state.ctrlPoints.end(); it++)
00570 {
00571 if (it->mode > 2)
00572 lines[it->mode] = 0;
00573 }
00574 int i=3;
00575 for (std::map<int,int >::iterator it = lines.begin(); it != lines.end(); ++it)
00576 {
00577 (*it).second = i;
00578 i++;
00579 }
00580
00581 for (CPVector::iterator it = state.ctrlPoints.begin();
00582 it != state.ctrlPoints.end(); it++)
00583 {
00584 if (it->mode > 2) {
00585 int newmode = lines[it->mode];
00586 if (it->mode != newmode) {
00587 it->mode = newmode;
00588 imageChanged(it->image1Nr);
00589 imageChanged(it->image2Nr);
00590 }
00591 }
00592 }
00593 }
00594
00595
00596 void Panorama::printPanoramaScript(std::ostream & o,
00597 const OptimizeVector & optvars,
00598 const PanoramaOptions & output,
00599 const UIntSet & imgs,
00600 bool forPTOptimizer,
00601 const std::string & stripPrefix) const
00602 {
00603 using namespace std;
00604
00605 #ifdef __unix__
00606
00607 char * t = setlocale(LC_NUMERIC,NULL);
00608 char * old_locale = (char*) malloc(strlen(t)+1);
00609 strcpy(old_locale, t);
00610 setlocale(LC_NUMERIC,"C");
00611 #endif
00612
00613 if (forPTOptimizer) {
00614 o << "# PTOptimizer script, written by hugin" << std::endl
00615 << std::endl;
00616 } else {
00617 o << "# hugin project file" << std::endl;
00618 o << "#hugin_ptoversion 2" << std::endl;
00619 }
00620
00621
00622 output.printScriptLine(o, forPTOptimizer);
00623
00624 std::map<unsigned int, unsigned int> linkAnchors;
00625
00626 std::map<unsigned int, unsigned int> imageNrMap;
00627 o << std::endl
00628 << "# image lines" << std::endl;
00629
00630
00631 std::stringstream vlines;
00632 std::stringstream masklines;
00633 unsigned int ic = 0;
00634 for (UIntSet::const_iterator imgNrIt = imgs.begin(); imgNrIt != imgs.end();
00635 ++imgNrIt)
00636 {
00637 unsigned int imgNr = *imgNrIt;
00638 imageNrMap[imgNr] = ic;
00639 const SrcPanoImage & img = *state.images[imgNr];
00640 VariableMap vars;
00641
00642
00643 o << "#-hugin ";
00644 if (img.getCropMode() != BaseSrcPanoImage::NO_CROP) {
00645 if (img.getAutoCenterCrop())
00646 o << " autoCenterCrop=1";
00647 }
00648 o << " cropFactor=" << img.getExifCropFactor() ;
00649 if (! img.getActive()) {
00650 o << " disabled";
00651 }
00652 o << std::endl;
00653
00654 o << "i w" << img.getSize().width() << " h" << img.getSize().height()
00655 <<" f" << img.getProjection() << " ";
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 #define image_variable( name, type, default_value )\
00668 PTOVariableConverterFor##name::addToVariableMap(state.images[imgNr]->get##name##IV(), vars);\
00669 if (!vars.empty())\
00670 {\
00671 bool linking = false;\
00672 std::size_t link_target;\
00673 if (ic!=0)\
00674 {\
00675 if (state.images[imgNr]->name##isLinked())\
00676 {\
00677 for (link_target = 0; link_target < imgNr; link_target++)\
00678 {\
00679 if (set_contains(imgs,link_target) && state.images[imgNr]->name##isLinkedWith(*state.images[link_target]))\
00680 {\
00681 linking = true;\
00682 break;\
00683 }\
00684 }\
00685 }\
00686 }\
00687 for (VariableMap::const_iterator vit = vars.begin();\
00688 vit != vars.end(); ++vit)\
00689 {\
00690 if (forPTOptimizer && !set_contains(m_ptoptimizerVarNames,vit->first))\
00691 continue;\
00692 else if (linking)\
00693 {\
00694 o << vit->first << "=" << imageNrMap[link_target] << " ";\
00695 } else {\
00696 if (set_contains(optvars[imgNr], vit->first))\
00697 {\
00698 vlines << "v " << vit->first << imageNrMap[imgNr] << std::endl;\
00699 }\
00700 if (((vit->first == "a" && set_contains(optvars[imgNr], "a") )|| \
00701 (vit->first == "b" && set_contains(optvars[imgNr], "b") )|| \
00702 (vit->first == "c" && set_contains(optvars[imgNr], "c") )|| \
00703 (vit->first == "TrX" && set_contains(optvars[imgNr], "TrX") )|| \
00704 (vit->first == "TrY" && set_contains(optvars[imgNr], "TrY") )|| \
00705 (vit->first == "TrZ" && set_contains(optvars[imgNr], "TrZ") )|| \
00706 (vit->first == "Tpy" && set_contains(optvars[imgNr], "Tpy") )|| \
00707 (vit->first == "Tpp" && set_contains(optvars[imgNr], "Tpp") )\
00708 )\
00709 && forPTOptimizer && vit->second.getValue() == 0.0) \
00710 {\
00711 o << vit->first << 1e-5 << " ";\
00712 } else if (( (vit->first == "r" && set_contains(optvars[imgNr], "r") ) || \
00713 (vit->first == "p" && set_contains(optvars[imgNr], "p") ) || \
00714 (vit->first == "y" && set_contains(optvars[imgNr], "y") ) \
00715 )\
00716 && forPTOptimizer && fabs(vit->second.getValue()) < 1e-13)\
00717 {\
00718 o << vit->first << 0 << " ";\
00719 } else {\
00720 vit->second.print(o) << " ";\
00721 }\
00722 }\
00723 }\
00724 }\
00725 vars.clear();
00726 #include "image_variables.h"
00727 #undef image_variable
00728
00729 if (img.getCropMode()!=SrcPanoImage::NO_CROP) {
00730
00731 vigra::Rect2D c = img.getCropRect();
00732 o << " S" << c.left() << "," << c.right() << "," << c.top() << "," << c.bottom();
00733 }
00734
00735 if (!forPTOptimizer) {
00736
00737 if (img.getVigCorrMode() != SrcPanoImage::VIGCORR_NONE) {
00738 o << " Vm" << img.getVigCorrMode();
00739 }
00740
00741 if (img.getFlatfieldFilename().size() > 0) {
00742 o << " Vf\"" << img.getFlatfieldFilename() << "\"";
00743 }
00744 if (img.getResponseType() > 0) {
00745 o << " Rt" << img.getResponseType();
00746 }
00747
00748 if(img.hasMasks())
00749 img.printMaskLines(masklines,ic);
00750 }
00751
00752 #if 0
00753
00754 o << " u" << output.featherWidth
00755 << (img.getMorph() ? " o" : "");
00756 #endif
00757 std::string fname = img.getFilename();
00758 if (stripPrefix.size() > 0) {
00759
00760
00761 std::string tmp = fname.substr(0,stripPrefix.size());
00762 if (tmp.compare(stripPrefix) == 0) {
00763 DEBUG_DEBUG("striping " << stripPrefix << " from " << fname);
00764 fname = fname.erase(0,stripPrefix.size());
00765 DEBUG_DEBUG("after stripping: " << fname);
00766 } else {
00767 DEBUG_DEBUG(stripPrefix << " does not match " << fname);
00768 }
00769 }
00770 o << " n\"" << fname << "\"" << std::endl;
00771 ic++;
00772 }
00773
00774 o << std::endl << std::endl
00775 << "# specify variables that should be optimized" << std::endl
00776 << vlines.str()
00777 << "v" << std::endl;
00778
00779 o << std::endl << std::endl
00780 << "# control points" << std::endl;
00781 for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
00782 if (set_contains(imgs, it->image1Nr) && set_contains(imgs, it->image2Nr)) {
00783 o << "c n" << imageNrMap[it->image1Nr]
00784 << " N" << imageNrMap[it->image2Nr]
00785 << " x" << it->x1 << " y" << it->y1
00786 << " X" << it->x2 << " Y" << it->y2
00787 << " t" << it->mode << std::endl;
00788 }
00789 }
00790 o << std::endl;
00791
00792 if(masklines.str().length()>0)
00793 o << "# masks" << std::endl
00794 << masklines.str()
00795 << std::endl;
00796
00797
00798 o << "#hugin_optimizeReferenceImage " << output.optimizeReferenceImage << std::endl;
00799 o << "#hugin_blender ";
00800 switch (output.blendMode) {
00801 case PanoramaOptions::NO_BLEND:
00802 o << "none" << endl;
00803 break;
00804 case PanoramaOptions::PTBLENDER_BLEND:
00805 o << "PTblender" << endl;
00806 break;
00807 case PanoramaOptions::SMARTBLEND_BLEND:
00808 o << "smartblend" << endl;
00809 break;
00810 case PanoramaOptions::PTMASKER_BLEND:
00811 o << "PTmasker" << endl;
00812 break;
00813 default:
00814 case PanoramaOptions::ENBLEND_BLEND:
00815 o << "enblend" << endl;
00816 break;
00817 }
00818
00819 o << "#hugin_remapper ";
00820 switch (output.remapper) {
00821 case PanoramaOptions::PTMENDER:
00822 o << "PTmender" << endl;
00823 break;
00824 default:
00825 case PanoramaOptions::NONA:
00826 o << "nona" << endl;
00827 break;
00828 }
00829
00830 o << "#hugin_enblendOptions " << output.enblendOptions << endl;
00831 o << "#hugin_enfuseOptions " << output.enfuseOptions << endl;
00832 o << "#hugin_hdrmergeOptions " << output.hdrmergeOptions << endl;
00833
00834 o << "#hugin_outputLDRBlended " << (output.outputLDRBlended ? "true" : "false") << endl;
00835 o << "#hugin_outputLDRLayers " << (output.outputLDRLayers ? "true" : "false") << endl;
00836 o << "#hugin_outputLDRExposureRemapped " << (output.outputLDRExposureRemapped ? "true" : "false") << endl;
00837 o << "#hugin_outputLDRExposureLayers " << (output.outputLDRExposureLayers ? "true" : "false") << endl;
00838 o << "#hugin_outputLDRExposureBlended " << (output.outputLDRExposureBlended ? "true" : "false") << endl;
00839 o << "#hugin_outputLDRStacks " << (output.outputLDRStacks ? "true" : "false") << endl;
00840 o << "#hugin_outputLDRExposureLayersFused " << (output.outputLDRExposureLayersFused ? "true" : "false") << endl;
00841 o << "#hugin_outputHDRBlended " << (output.outputHDRBlended ? "true" : "false") << endl;
00842 o << "#hugin_outputHDRLayers " << (output.outputHDRLayers ? "true" : "false") << endl;
00843 o << "#hugin_outputHDRStacks " << (output.outputHDRStacks ? "true" : "false") << endl;
00844
00845 o << "#hugin_outputLayersCompression " << output.outputLayersCompression << endl;
00846 o << "#hugin_outputImageType " << output.outputImageType << endl;
00847 o << "#hugin_outputImageTypeCompression " << output.outputImageTypeCompression << endl;
00848 o << "#hugin_outputJPEGQuality " << output.quality << endl;
00849 o << "#hugin_outputImageTypeHDR " << output.outputImageTypeHDR << endl;
00850 o << "#hugin_outputImageTypeHDRCompression " << output.outputImageTypeHDRCompression << endl;
00851
00852 o << "#hugin_outputStacksMinOverlap " << setprecision(3) << output.outputStacksMinOverlap << endl;
00853 o << "#hugin_outputLayersExposureDiff " << setprecision(2) << output.outputLayersExposureDiff << endl;
00854
00855 if(optvars==getOptimizeVector())
00856 {
00857 o << "#hugin_optimizerMasterSwitch " << getOptimizerSwitch() << endl;
00858 o << "#hugin_optimizerPhotoMasterSwitch " << getPhotometricOptimizerSwitch() << endl;
00859 }
00860 else
00861 {
00862 o << "#hugin_optimizerMasterSwitch 0" << endl;
00863 o << "#hugin_optimizerPhotoMasterSwitch 0" << endl;
00864 };
00865
00866 #ifdef __unix__
00867
00868 setlocale(LC_NUMERIC,old_locale);
00869 free(old_locale);
00870 #endif
00871 }
00872
00873
00874 void Panorama::printStitcherScript(std::ostream & o,
00875 const PanoramaOptions & target,
00876 const UIntSet & imgs) const
00877 {
00878 #ifdef __unix__
00879
00880 char * t = setlocale(LC_NUMERIC,NULL);
00881 char * old_locale = (char*) malloc(strlen(t)+1);
00882 strcpy(old_locale, t);
00883 setlocale(LC_NUMERIC,"C");
00884 #endif
00885
00886 o << "# PTStitcher script, written by hugin" << std::endl
00887 << std::endl;
00888
00889 target.printScriptLine(o, true);
00890 o << std::endl
00891 << "# output image lines" << std::endl;
00892 for (UIntSet::const_iterator imgNrIt = imgs.begin(); imgNrIt != imgs.end(); ++imgNrIt) {
00893 unsigned int imgNr = *imgNrIt;
00894 const SrcPanoImage & img = *state.images[imgNr];
00895
00896
00897 const VariableMap & vars = state.images[imgNr]->getVariableMap();
00898
00899 o << "o w" << img.getSize().width() << " h" << img.getSize().height()
00900 <<" f" << img.getProjection() << " ";
00901
00902 VariableMap::const_iterator vit;
00903 for(vit = vars.begin(); vit != vars.end(); ++vit)
00904 {
00905 if (!set_contains(m_ptoptimizerVarNames,vit->first)) {
00906 continue;
00907 }
00908 vit->second.print(o) << " ";
00909 }
00910 #if 0
00911
00912 o << " u" << img.getFeatureWidth()
00913 << (img.getMorph() ? " o" : "");
00914 #endif
00915 o << " n\"" << img.getFilename() << "\"";
00916 if (img.getCropMode()!=SrcPanoImage::NO_CROP) {
00917
00918 vigra::Rect2D c = img.getCropRect();
00919 o << " S" << c.left() << "," << c.right() << "," << c.top() << "," << c.bottom();
00920 }
00921 o << std::endl;
00922 }
00923 o << std::endl;
00924 #ifdef __unix__
00925
00926 setlocale(LC_NUMERIC,old_locale);
00927 free(old_locale);
00928 #endif
00929
00930 }
00931
00932 void Panorama::parseOptimizerScript(std::istream & i, const UIntSet & imgs,
00933 VariableMapVector & imgVars, CPVector & CPs) const
00934 {
00935 using namespace std;
00936 using namespace PTScriptParsing;
00937
00938 DEBUG_TRACE("");
00939 #ifdef __unix__
00940
00941 char * t = setlocale(LC_NUMERIC,NULL);
00942 char * old_locale = (char*) malloc(strlen(t)+1);
00943 strcpy(old_locale, t);
00944 setlocale(LC_NUMERIC,"C");
00945 #endif
00946
00947 unsigned int ic=0;
00948 std::map<unsigned int, unsigned int> script2ImgMap;
00949 for (UIntSet::const_iterator imgNrIt = imgs.begin(); imgNrIt != imgs.end();
00950 ++imgNrIt)
00951 {
00952 unsigned int imgNr = *imgNrIt;
00953 script2ImgMap[ic] = imgNr;
00954 ic++;
00955 }
00956 ic = 0;
00957 unsigned int sc = 0;
00958 std::map<unsigned int, unsigned int> script2CPMap;
00959 for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
00960 if (set_contains(imgs, it->image1Nr) && set_contains(imgs, it->image2Nr)) {
00961 script2CPMap[sc] = ic;
00962 sc++;
00963 }
00964 ic++;
00965 }
00966
00967
00968
00969
00970 int state = 0;
00971 string line;
00972 unsigned int lineNr = 0;
00973 unsigned int scriptImgCounter = 0;
00974 unsigned int scriptCPCounter = 0;
00975
00976
00977
00978
00979
00980
00981 while (!i.eof()) {
00982 std::getline(i, line);
00983 lineNr++;
00984 switch (state) {
00985 case 0:
00986 {
00987
00988
00989 if ((line.compare("# Control Points: Distance between desired and fitted Position") == 0 )
00990 || (line.compare("# Control Points: Distance between desired and fitted Position (in Pixels)") == 0 )
00991 || (line.compare("# Control Points: Distance between desired and fitted Position (in \"Pixels\")") == 0 )) {
00992
00993
00994 if (scriptImgCounter != imgs.size()) {
00995 DEBUG_ERROR("Read only " << scriptImgCounter << " images from PTOptimizer file");
00996 }
00997 DEBUG_DEBUG("Changing state to read control point distances");
00998 state = 1;
00999 break;
01000 }
01001 if (line[0] != 'o') continue;
01002
01003 VariableMap & var = imgVars[script2ImgMap[scriptImgCounter]];
01004 DEBUG_DEBUG("reading image variables for image:" << scriptImgCounter);
01005
01006 int link;
01007 readVar(map_get(var, "r"), link, line);
01008 DEBUG_ASSERT(link == -1);
01009 readVar(map_get(var, "p"), link, line);
01010 DEBUG_ASSERT(link == -1);
01011 readVar(map_get(var, "y"), link, line);
01012 DEBUG_ASSERT(link == -1);
01013
01014 DEBUG_DEBUG("yaw: " << map_get(var, "y").getValue()
01015 << " pitch " << map_get(var, "p").getValue()
01016 << " roll " << map_get(var, "r").getValue());
01017
01018
01019 readVar(map_get(var, "TrX"), link, line);
01020 DEBUG_ASSERT(link == -1);
01021 readVar(map_get(var, "TrY"), link, line);
01022 DEBUG_ASSERT(link == -1);
01023 readVar(map_get(var, "TrZ"), link, line);
01024 DEBUG_ASSERT(link == -1);
01025 readVar(map_get(var, "Tpy"), link, line);
01026 DEBUG_ASSERT(link == -1);
01027 readVar(map_get(var, "Tpp"), link, line);
01028 DEBUG_ASSERT(link == -1);
01029
01030 DEBUG_DEBUG("X: " << map_get(var, "TrX").getValue()
01031 << " Y " << map_get(var, "TrY").getValue()
01032 << " Z " << map_get(var, "TrZ").getValue());
01033
01034
01035
01036 for (const char **c = Lens::variableNames; *c != 0; ++c) {
01037 Variable & curVar = map_get(var, *c);
01038 if (!readVar(curVar, link, line)) {
01039 DEBUG_ERROR("Could not read "<< *c << " at script line " << lineNr);
01040 }
01041
01042 DEBUG_ASSERT(link == -1);
01043 }
01044 scriptImgCounter++;
01045 break;
01046 }
01047 case 1:
01048 {
01049
01050
01051 if (line[0] == 'C') {
01052
01053 state = 2;
01054 break;
01055 }
01056 if (line.find("# Control Point No") != 0) continue;
01057 DEBUG_DEBUG("reading cp dist line: " << line);
01058 string::size_type p;
01059 if ((p=line.find(':')) == string::npos) assert(0);
01060 p++;
01061 DEBUG_DEBUG("parsing point " << scriptCPCounter << " (idx:" << p << "): " << line.substr(p));
01062 double err = -1;
01063
01064 hugin_utils::stringToDouble(line.substr(p), err);
01065 CPs[script2CPMap[scriptCPCounter]].error = err;
01066 DEBUG_DEBUG("read CP distance " << err);
01067 scriptCPCounter++;
01068 break;
01069 }
01070 default:
01071
01072 break;
01073 }
01074 }
01075 #ifdef __unix__
01076
01077 setlocale(LC_NUMERIC,old_locale);
01078 free(old_locale);
01079 #endif
01080
01081 }
01082
01083 void Panorama::changeFinished(bool keepDirty)
01084 {
01085 if (state.images.size() == 0) {
01086
01087
01088 DEBUG_DEBUG("forcing images update, with no images");
01089 m_forceImagesUpdate = true;
01090 }
01091
01092 UIntSet::iterator uB = changedImages.lower_bound(state.images.size());
01093 changedImages.erase(uB,changedImages.end());
01094
01095 std::stringstream t;
01096 copy(changedImages.begin(), changedImages.end(),
01097 std::ostream_iterator<unsigned int>(t, " "));
01098 DEBUG_TRACE("changed image(s) " << t.str() << " begin");
01099
01100 if(changedImages.size()>0)
01101 {
01102 for(UIntSet::iterator it=changedImages.begin();it!=changedImages.end();it++)
01103 {
01104
01105 updateCropMode(*it);
01106
01107 if(state.images[*it]->getAutoCenterCrop())
01108 {
01109 centerCrop(*it);
01110 };
01111 };
01112 };
01113
01114 updateMasks();
01115 updateOptimizeVector();
01116 std::list<PanoramaObserver *>::iterator it;
01117 for(it = observers.begin(); it != observers.end(); ++it) {
01118 DEBUG_TRACE("notifying listener");
01119 if (changedImages.size() > 0 || m_forceImagesUpdate) {
01120 (*it)->panoramaImagesChanged(*this, changedImages);
01121 }
01122 (*it)->panoramaChanged(*this);
01123 }
01124
01125 changedImages.clear();
01126 m_forceImagesUpdate = false;
01127 if (!keepDirty) {
01128 dirty = true;
01129 AppBase::DocumentData::setDirty(dirty);
01130 }
01131 DEBUG_TRACE("end");
01132 }
01133
01134 void Panorama::updateMasksForImage(unsigned int imgNr, MaskPolygonVector newMasks)
01135 {
01136 DEBUG_ASSERT(imgNr < state.images.size());
01137 state.images[imgNr]->setMasks(newMasks);
01138 imageChanged(imgNr);
01139 m_forceImagesUpdate = true;
01140 };
01141
01142 void Panorama::transferMask(MaskPolygon mask,unsigned int imgNr, const UIntSet targetImgs)
01143 {
01144 if(targetImgs.size()==0)
01145 {
01146 return;
01147 };
01148 MaskPolygon transformedMask=mask;
01149
01150 vigra::Rect2D clipRect=vigra::Rect2D(0,0,state.images[imgNr]->getWidth(),state.images[imgNr]->getHeight());
01151 if(mask.isPositive())
01152 {
01153
01154 switch(state.images[imgNr]->getCropMode())
01155 {
01156 case BaseSrcPanoImage::CROP_RECTANGLE:
01157 clipRect=clipRect & state.images[imgNr]->getCropRect();
01158 if(clipRect.isEmpty())
01159 {
01160 return;
01161 };
01162 if(clipRect.width()>10 && clipRect.height()>10)
01163 {
01164 clipRect.addBorder(-2);
01165 };
01166 break;
01167 case BaseSrcPanoImage::CROP_CIRCLE:
01168 {
01169 vigra::Rect2D cropRect=state.images[imgNr]->getCropRect();
01170 FDiff2D center=FDiff2D((cropRect.left()+cropRect.right())/2.0,(cropRect.top()+cropRect.bottom())/2.0);
01171 double radius=((cropRect.width()<cropRect.height())?cropRect.width():cropRect.height())/2.0;
01172 if(radius>10)
01173 {
01174 radius-=2;
01175 };
01176 if(!transformedMask.clipPolygon(center,radius))
01177 {
01178 return;
01179 };
01180 };
01181 break;
01182 default:
01183 if(clipRect.width()>10 && clipRect.height()>10)
01184 {
01185 clipRect.addBorder(-2);
01186 };
01187 break;
01188 };
01189 };
01190 int origWindingNumber=transformedMask.getTotalWindingNumber();
01191 if(transformedMask.clipPolygon(clipRect))
01192 {
01193
01194
01195 transformedMask.subSample(20);
01196
01197 HuginBase::PTools::Transform trans;
01198 trans.createInvTransform(getImage(imgNr),getOptions());
01199 transformedMask.transformPolygon(trans);
01200 for(UIntSet::const_iterator it=targetImgs.begin();it!=targetImgs.end();it++)
01201 {
01202 if(imgNr==(*it))
01203 {
01204 continue;
01205 };
01206 MaskPolygon targetMask;
01207 if(state.images[imgNr]->YawisLinkedWith(*(state.images[*it])))
01208 {
01209
01210 targetMask=mask;
01211 }
01212 else
01213 {
01214 targetMask=transformedMask;
01215 PTools::Transform targetTrans;
01216 targetTrans.createTransform(getImage(*it),getOptions());
01217 targetMask.transformPolygon(targetTrans);
01218
01219 if(targetMask.getMaskPolygon().size()<3)
01220 {
01221 continue;
01222 };
01223
01224
01225 int newWindingNumber=targetMask.getTotalWindingNumber();
01226 targetMask.setInverted(origWindingNumber * newWindingNumber < 0);
01227 };
01228
01229 if(targetMask.clipPolygon(vigra::Rect2D(-maskOffset,-maskOffset,
01230 state.images[*it]->getWidth()+maskOffset,state.images[*it]->getHeight()+maskOffset)))
01231 {
01232 targetMask.setMaskType(MaskPolygon::Mask_negative);
01233 targetMask.setImgNr(*it);
01234 state.images[*it]->addActiveMask(targetMask);
01235 };
01236 };
01237 };
01238 };
01239
01240 void Panorama::updateMasks(bool convertPosMaskToNeg)
01241 {
01242
01243 UIntSet imgWithPosMasks;
01244 for(unsigned int i=0;i<state.images.size();i++)
01245 {
01246 state.images[i]->clearActiveMasks();
01247 if(state.images[i]->hasPositiveMasks())
01248 {
01249 imgWithPosMasks.insert(i);
01250 };
01251 };
01252 CalculateImageOverlap overlap(this);
01253 overlap.limitToImages(imgWithPosMasks);
01254 overlap.calculate(10);
01255 ConstStandardImageVariableGroups variable_groups(*this);
01256 ConstImageVariableGroup & lenses = variable_groups.getLenses();
01257 for(unsigned int i=0;i<state.images.size();i++)
01258 {
01259 if(state.images[i]->hasMasks())
01260 {
01261 MaskPolygonVector masks=state.images[i]->getMasks();
01262 for(unsigned int j=0;j<masks.size();j++)
01263 {
01264 if(convertPosMaskToNeg)
01265 {
01266
01267
01268
01269 switch(masks[j].getMaskType())
01270 {
01271 case MaskPolygon::Mask_negative:
01272 case MaskPolygon::Mask_positive:
01273 masks[j].setImgNr(i);
01274 masks[j].setMaskType(MaskPolygon::Mask_negative);
01275 state.images[i]->addActiveMask(masks[j]);
01276 break;
01277 case MaskPolygon::Mask_Stack_negative:
01278 case MaskPolygon::Mask_Stack_positive:
01279 {
01280
01281 UIntSet imgStack;
01282 for(unsigned int k=0;k<getNrOfImages();k++)
01283 {
01284 if(i!=k)
01285 {
01286 if(state.images[i]->StackisLinkedWith(*(state.images[k])))
01287 {
01288 imgStack.insert(k);
01289 };
01290 };
01291 };
01292 masks[j].setImgNr(i);
01293 masks[j].setMaskType(MaskPolygon::Mask_negative);
01294 state.images[i]->addActiveMask(masks[j]);
01295 transferMask(masks[j],i,imgStack);
01296 };
01297 break;
01298 case MaskPolygon::Mask_negative_lens:
01299 {
01300 unsigned int lensNr=lenses.getPartNumber(i);
01301
01302 UIntSet imgLens;
01303 for(unsigned int k=0;k<getNrOfImages();k++)
01304 {
01305 if(lenses.getPartNumber(k)==lensNr)
01306 {
01307 masks[j].setImgNr(k);
01308 masks[j].setMaskType(MaskPolygon::Mask_negative_lens);
01309 state.images[k]->addActiveMask(masks[j]);
01310 };
01311 };
01312 };
01313 break;
01314 };
01315 }
01316 else
01317 {
01318 switch(masks[j].getMaskType())
01319 {
01320 case MaskPolygon::Mask_negative:
01321
01322 masks[j].setImgNr(i);
01323 state.images[i]->addActiveMask(masks[j]);
01324 break;
01325 case MaskPolygon::Mask_positive:
01326
01327 if(state.images[i]->getActive())
01328 {
01329 UIntSet overlapImgs=overlap.getOverlapForImage(i);
01330 transferMask(masks[j],i,overlapImgs);
01331 };
01332 break;
01333 case MaskPolygon::Mask_Stack_negative:
01334 {
01335
01336 UIntSet imgStack;
01337 for(unsigned int k=0;k<getNrOfImages();k++)
01338 {
01339 if(i!=k)
01340 {
01341 if(state.images[i]->StackisLinkedWith(*(state.images[k])))
01342 {
01343 imgStack.insert(k);
01344 };
01345 };
01346 };
01347
01348 masks[j].setImgNr(i);
01349 masks[j].setMaskType(MaskPolygon::Mask_negative);
01350 state.images[i]->addActiveMask(masks[j]);
01351 transferMask(masks[j],i,imgStack);
01352 };
01353 break;
01354 case MaskPolygon::Mask_Stack_positive:
01355 {
01356
01357 UIntSet imgStack;
01358 fill_set(imgStack,0,getNrOfImages()-1);
01359 imgStack.erase(i);
01360 for(unsigned int k=0;k<getNrOfImages();k++)
01361 {
01362 if(i!=k)
01363 {
01364 if(state.images[i]->StackisLinkedWith(*(state.images[k])))
01365 {
01366 imgStack.erase(k);
01367 };
01368 };
01369 };
01370
01371 UIntSet imgOverlap=overlap.getOverlapForImage(i);
01372 UIntSet imgs;
01373 std::set_intersection(imgStack.begin(),imgStack.end(),imgOverlap.begin(),imgOverlap.end(),inserter(imgs,imgs.begin()));
01374
01375 transferMask(masks[j],i,imgs);
01376 };
01377 break;
01378 case MaskPolygon::Mask_negative_lens:
01379 {
01380 unsigned int lensNr=lenses.getPartNumber(i);
01381
01382 UIntSet imgLens;
01383 for(unsigned int k=0;k<getNrOfImages();k++)
01384 {
01385 if(lenses.getPartNumber(k)==lensNr)
01386 {
01387 masks[j].setImgNr(k);
01388 masks[j].setMaskType(MaskPolygon::Mask_negative_lens);
01389 state.images[k]->addActiveMask(masks[j]);
01390 };
01391 };
01392 };
01393 break;
01394 };
01395 };
01396 };
01397 };
01398 };
01399 };
01400
01401 void Panorama::updateCropMode(unsigned int imgNr)
01402 {
01403 vigra::Rect2D r=state.images[imgNr]->getCropRect();
01404 if(r.isEmpty() || r==vigra::Rect2D(state.images[imgNr]->getSize()))
01405 {
01406 state.images[imgNr]->setCropMode(SrcPanoImage::NO_CROP);
01407 }
01408 else
01409 {
01410 if (state.images[imgNr]->isCircularCrop())
01411 {
01412 state.images[imgNr]->setCropMode(SrcPanoImage::CROP_CIRCLE);
01413 }
01414 else
01415 {
01416 state.images[imgNr]->setCropMode(SrcPanoImage::CROP_RECTANGLE);
01417 };
01418 };
01419 };
01420
01421 vigra::Rect2D Panorama::centerCropImage(unsigned int imgNr)
01422 {
01423 vigra::Rect2D cropRect;
01424 if(state.images[imgNr]->getCropMode()==SrcPanoImage::NO_CROP)
01425 {
01426 return cropRect;
01427 };
01428 int dx = roundi(state.images[imgNr]->getRadialDistortionCenterShift().x);
01429 int dy = roundi(state.images[imgNr]->getRadialDistortionCenterShift().y);
01430 vigra::Point2D center = vigra::Point2D(state.images[imgNr]->getSize().width()/2 + dx, state.images[imgNr]->getSize().height()/2 + dy);
01431
01432 vigra::Diff2D d(state.images[imgNr]->getCropRect().width() / 2, state.images[imgNr]->getCropRect().height() / 2);
01433 cropRect.setUpperLeft( center - d);
01434 cropRect.setLowerRight( center + d);
01435 return cropRect;
01436 };
01437
01438 void Panorama::centerCrop(unsigned int imgNr)
01439 {
01440 vigra::Rect2D cropRect;
01441 if( state.images[imgNr]->getCropMode()!=SrcPanoImage::NO_CROP &&
01442 state.images[imgNr]->getAutoCenterCrop() &&
01443 !(state.images[imgNr]->getCropRect().isEmpty())
01444 )
01445 {
01446 cropRect=centerCropImage(imgNr);
01447 if(!cropRect.isEmpty())
01448 {
01449 state.images[imgNr]->setCropRect(cropRect);
01450 imageChanged(imgNr);
01451 };
01452 };
01453 for (std::size_t i = 0; i < getNrOfImages(); i++)
01454 {
01455 if(i==imgNr)
01456 {
01457 continue;
01458 };
01459 if (state.images[imgNr]->RadialDistortionCenterShiftisLinkedWith(*state.images[i]))
01460 {
01461 if( state.images[i]->getCropMode()!=SrcPanoImage::NO_CROP &&
01462 state.images[i]->getAutoCenterCrop() &&
01463 !(state.images[i]->getCropRect().isEmpty())
01464 )
01465 {
01466 cropRect=centerCropImage(i);
01467 if(!cropRect.isEmpty())
01468 {
01469 state.images[i]->setCropRect(cropRect);
01470 imageChanged(i);
01471 };
01472 };
01473 };
01474 };
01475 };
01476
01477 void UpdateOptVectorSet(std::set<std::string>& imgVar, const std::string var, const bool opt)
01478 {
01479 if(opt)
01480 {
01481 imgVar.insert(var);
01482 }
01483 else
01484 {
01485 imgVar.erase(var);
01486 };
01487 };
01488
01489 std::set<size_t> Panorama::getRefImages()
01490 {
01491 unsigned int refImg = getOptions().optimizeReferenceImage;
01492 std::set<size_t> refImgs;
01493 refImgs.insert(refImg);
01494 const HuginBase::SrcPanoImage & refImage = getImage(refImg);
01495 for (size_t imgNr = 0; imgNr < getNrOfImages(); imgNr++)
01496 {
01497 if(imgNr!=refImg)
01498 {
01499 const HuginBase::SrcPanoImage & compImage = getImage(imgNr);
01500 if (refImage.YawisLinkedWith(compImage))
01501 {
01502 refImgs.insert(imgNr);
01503 };
01504 };
01505 };
01506 return refImgs;
01507 };
01508
01509 void Panorama::checkRefOptStatus(bool& linkRefImgsYaw, bool& linkRefImgsPitch, bool& linkRefImgsRoll)
01510 {
01511
01512 int nHCP = 0;
01513 int nVCP = 0;
01514 const CPVector & cps = getCtrlPoints();
01515 for (CPVector::const_iterator it = cps.begin(); it != cps.end(); it++)
01516 {
01517
01518 if (it->mode == ControlPoint::X)
01519 {
01520 nVCP++;
01521 }
01522 else
01523 {
01524 if (it->mode == ControlPoint::Y)
01525 {
01526 nHCP++;
01527 }
01528 };
01529 };
01530
01531
01532
01533 linkRefImgsYaw=false;
01534 linkRefImgsPitch=false;
01535 linkRefImgsRoll=false;
01536 switch (getOptions().getProjection())
01537 {
01538 case PanoramaOptions::RECTILINEAR:
01539 linkRefImgsRoll = nVCP + nHCP >= 1;
01540 linkRefImgsYaw = nVCP + nHCP >= 3 && nVCP >= 1 && nHCP >= 1;
01541 linkRefImgsPitch = nVCP + nHCP >= 2;
01542 break;
01543 case PanoramaOptions::CYLINDRICAL:
01544 case PanoramaOptions::EQUIRECTANGULAR:
01545 linkRefImgsPitch = nHCP + nVCP > 1;
01546 linkRefImgsRoll = nHCP + nVCP >= 1;
01547 break;
01548 default:
01549 break;
01550 };
01551 };
01552
01553 void Panorama::updateOptimizeVector()
01554 {
01555 if(state.images.size()==0)
01556 {
01557 return;
01558 };
01559 if(state.optSwitch!=0)
01560 {
01561 std::set<size_t> refImgs=getRefImages();
01562 bool linkRefImgsYaw=false;
01563 bool linkRefImgsPitch=false;
01564 bool linkRefImgsRoll=false;
01565 checkRefOptStatus(linkRefImgsYaw, linkRefImgsPitch, linkRefImgsRoll);
01566
01567 for(size_t i=0;i<getNrOfImages();i++)
01568 {
01569 if(state.optSwitch & OPT_PAIR || state.optSwitch & OPT_POSITION || state.optSwitch & OPT_ALL)
01570 {
01571 if(set_contains(refImgs,i))
01572 {
01573 UpdateOptVectorSet(state.optvec[i],"y",linkRefImgsYaw);
01574 UpdateOptVectorSet(state.optvec[i],"p",linkRefImgsPitch);
01575 UpdateOptVectorSet(state.optvec[i],"r",linkRefImgsRoll);
01576
01577 UpdateOptVectorSet(state.optvec[i],"TrX",false);
01578 UpdateOptVectorSet(state.optvec[i],"TrY",false);
01579 UpdateOptVectorSet(state.optvec[i],"TrZ",false);
01580 }
01581 else
01582 {
01583 UpdateOptVectorSet(state.optvec[i],"y",true);
01584 UpdateOptVectorSet(state.optvec[i],"p",true);
01585 UpdateOptVectorSet(state.optvec[i],"r",true);
01586 UpdateOptVectorSet(state.optvec[i],"TrX",(state.optSwitch & OPT_TRANSLATION)>0);
01587 UpdateOptVectorSet(state.optvec[i],"TrY",(state.optSwitch & OPT_TRANSLATION)>0);
01588 UpdateOptVectorSet(state.optvec[i],"TrZ",(state.optSwitch & OPT_TRANSLATION)>0);
01589 };
01590 }
01591 else
01592 {
01593 UpdateOptVectorSet(state.optvec[i],"y",false);
01594 UpdateOptVectorSet(state.optvec[i],"p",false);
01595 UpdateOptVectorSet(state.optvec[i],"r",false);
01596 UpdateOptVectorSet(state.optvec[i],"Trx",false);
01597 UpdateOptVectorSet(state.optvec[i],"Try",false);
01598 UpdateOptVectorSet(state.optvec[i],"Trz",false);
01599 };
01600 UpdateOptVectorSet(state.optvec[i],"v",state.optSwitch & OPT_VIEW || state.optSwitch & OPT_ALL);
01601 UpdateOptVectorSet(state.optvec[i],"a",(state.optSwitch & OPT_ALL)>0);
01602 UpdateOptVectorSet(state.optvec[i],"b",state.optSwitch & OPT_BARREL || state.optSwitch & OPT_ALL);
01603 UpdateOptVectorSet(state.optvec[i],"c",(state.optSwitch & OPT_ALL)>0);
01604 UpdateOptVectorSet(state.optvec[i],"d",(state.optSwitch & OPT_ALL)>0);
01605 UpdateOptVectorSet(state.optvec[i],"e",(state.optSwitch & OPT_ALL)>0);
01606
01607 UpdateOptVectorSet(state.optvec[i],"g",false);
01608 UpdateOptVectorSet(state.optvec[i],"t",false);
01609 UpdateOptVectorSet(state.optvec[i],"Tpy", false);
01610 UpdateOptVectorSet(state.optvec[i],"Tpp", false);
01611 };
01612 };
01613 if(state.optPhotoSwitch!=0)
01614 {
01615 for(size_t i=0;i<getNrOfImages();i++)
01616 {
01617 UpdateOptVectorSet(state.optvec[i],"Eev",state.optPhotoSwitch & OPT_EXPOSURE && i!=state.options.colorReferenceImage);
01618 UpdateOptVectorSet(state.optvec[i],"Er", state.optPhotoSwitch & OPT_WHITEBALANCE && i!=state.options.colorReferenceImage);
01619 UpdateOptVectorSet(state.optvec[i],"Eb", state.optPhotoSwitch & OPT_WHITEBALANCE && i!=state.options.colorReferenceImage);
01620 UpdateOptVectorSet(state.optvec[i],"Vb", (state.optPhotoSwitch & OPT_VIGNETTING)>0);
01621 UpdateOptVectorSet(state.optvec[i],"Vc", (state.optPhotoSwitch & OPT_VIGNETTING)>0);
01622 UpdateOptVectorSet(state.optvec[i],"Vd", (state.optPhotoSwitch & OPT_VIGNETTING)>0);
01623 UpdateOptVectorSet(state.optvec[i],"Vx", (state.optPhotoSwitch & OPT_VIGNETTING_CENTER)>0);
01624 UpdateOptVectorSet(state.optvec[i],"Vy", (state.optPhotoSwitch & OPT_VIGNETTING_CENTER)>0);
01625 UpdateOptVectorSet(state.optvec[i],"Ra", (state.optPhotoSwitch & OPT_RESPONSE)>0);
01626 UpdateOptVectorSet(state.optvec[i],"Rb", (state.optPhotoSwitch & OPT_RESPONSE)>0);
01627 UpdateOptVectorSet(state.optvec[i],"Rc", (state.optPhotoSwitch & OPT_RESPONSE)>0);
01628 UpdateOptVectorSet(state.optvec[i],"Rd", (state.optPhotoSwitch & OPT_RESPONSE)>0);
01629 UpdateOptVectorSet(state.optvec[i],"Re", (state.optPhotoSwitch & OPT_RESPONSE)>0);
01630 };
01631 };
01632 };
01633
01634 void Panorama::swapImages(unsigned int img1, unsigned int img2)
01635 {
01636 DEBUG_TRACE("swapping images " << img1 << ", " << img2);
01637 DEBUG_ASSERT(img1 < state.images.size());
01638 DEBUG_ASSERT(img2 < state.images.size());
01639
01640
01641 SrcPanoImage * pimg1 = state.images[img1];
01642 state.images[img1] = state.images[img2];
01643 state.images[img2] = pimg1;
01644
01645
01646 for (CPVector::iterator it=state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
01647 int n1 = (*it).image1Nr;
01648 int n2 = (*it).image2Nr;
01649 if ((*it).image1Nr == img1) {
01650 n1 = img2;
01651 } else if ((*it).image1Nr == img2) {
01652 n1 = img1;
01653 }
01654 if ((*it).image2Nr == img1) {
01655 n2 = img2;
01656 } else if ((*it).image2Nr == img2) {
01657 n2 = img1;
01658 }
01659 (*it).image1Nr = n1;
01660 (*it).image2Nr = n2;
01661 }
01662
01663
01664 if (state.options.colorReferenceImage == img1) {
01665 state.options.colorReferenceImage = img2;
01666 } else if (state.options.colorReferenceImage == img2) {
01667 state.options.colorReferenceImage = img1;
01668 }
01669 if (state.options.optimizeReferenceImage == img1) {
01670 state.options.optimizeReferenceImage = img2;
01671 } else if (state.options.optimizeReferenceImage == img2) {
01672 state.options.optimizeReferenceImage = img1;
01673 }
01674 imageChanged(img1);
01675 imageChanged(img2);
01676 }
01677
01678 void Panorama::moveImage(size_t img1, size_t img2)
01679 {
01680
01681 std::vector<size_t> imgList(getNrOfImages(),-1);
01682 for(size_t i=0; i<getNrOfImages(); i++)
01683 {
01684 imgList[i]=i;
01685 };
01686 imgList.erase(imgList.begin()+img1);
01687 if(img2<imgList.size())
01688 {
01689 imgList.insert(imgList.begin()+img2, img1);
01690 }
01691 else
01692 {
01693 imgList.push_back(img1);
01694 };
01695
01696 std::map<size_t,size_t> imgMap;
01697 for(size_t i=0; i<imgList.size(); i++)
01698 {
01699 imgMap[imgList[i]]=i;
01700 };
01701
01702 std::vector<SrcPanoImage *> new_images(getNrOfImages());
01703 for(size_t i=0; i<imgList.size(); i++)
01704 {
01705 new_images[i]=state.images[imgList[i]];
01706 if(i!=imgList[i])
01707 {
01708 imageChanged(imgList[i]);
01709 };
01710 };
01711 state.images=new_images;
01712
01713
01714 OptimizeVector newOptVec;
01715 for(size_t i=0; i<state.optvec.size(); i++)
01716 {
01717 newOptVec.push_back(state.optvec[imgList[i]]);
01718 };
01719 state.optvec=newOptVec;
01720
01721
01722 for (CPVector::iterator it=state.ctrlPoints.begin(); it != state.ctrlPoints.end(); it++)
01723 {
01724 (*it).image1Nr = imgMap[(*it).image1Nr];
01725 (*it).image2Nr = imgMap[(*it).image2Nr];
01726 }
01727
01728
01729 state.options.colorReferenceImage=imgMap[state.options.colorReferenceImage];
01730 state.options.optimizeReferenceImage=imgMap[state.options.optimizeReferenceImage];
01731 };
01732
01733 bool Panorama::setMementoToCopyOf(const PanoramaDataMemento* memento)
01734 {
01735 if(memento==NULL)
01736 return false;
01737
01738 const PanoramaMemento* mymemento;
01739
01740 try {
01741
01742 mymemento = dynamic_cast<const PanoramaMemento*>(memento);
01743
01744 } catch (std::bad_cast e) {
01745
01746 DEBUG_DEBUG("Incompatible memento type.");
01747 return false;
01748 }
01749
01750 setMemento(PanoramaMemento(*mymemento));
01751 return true;
01752 }
01753
01754
01756 void Panorama::setMemento(const PanoramaMemento& memento)
01757 {
01758 DEBUG_TRACE("");
01759
01760
01761 reset();
01762 DEBUG_DEBUG("nr of images in memento:" << memento.images.size());
01763
01764 state = memento;
01765 updateMasks();
01766 unsigned int nNewImages = state.images.size();
01767 DEBUG_DEBUG("nNewImages:" << nNewImages);
01768
01769
01770 for (unsigned int i = 0; i < nNewImages; i++) {
01771 imageChanged(i);
01772 }
01773 }
01774
01775 PanoramaDataMemento* Panorama::getNewMemento() const
01776 {
01777 return new PanoramaMemento(getMemento());
01778 }
01779
01780 void Panorama::setOptions(const PanoramaOptions & opt)
01781 {
01782 if (state.options.optimizeReferenceImage != opt.optimizeReferenceImage) {
01783 imageChanged(opt.optimizeReferenceImage);
01784 imageChanged(state.options.optimizeReferenceImage);
01785 }
01786
01787 if (state.options.colorReferenceImage != opt.colorReferenceImage) {
01788 imageChanged(opt.colorReferenceImage);
01789 imageChanged(state.options.colorReferenceImage);
01790 }
01791
01792 state.options = opt;
01793 }
01794
01795 void Panorama::addObserver(PanoramaObserver * o)
01796 {
01797 observers.push_back(o);
01798 }
01799
01800 bool Panorama::removeObserver(PanoramaObserver * o)
01801 {
01802 size_t oldCount=observers.size();
01803 observers.remove(o);
01804 return observers.size()!=oldCount;
01805 }
01806
01807 void Panorama::clearObservers()
01808 {
01809 observers.clear();
01810 }
01811
01812 void Panorama::imageChanged(unsigned int imgNr)
01813 {
01814
01815 changedImages.insert(imgNr);
01816 assert(changedImages.find(imgNr) != changedImages.end());
01817 }
01818
01819 void Panorama::activateImage(unsigned int imgNr, bool active)
01820 {
01821 assert(imgNr < state.images.size());
01822 if (state.images[imgNr]->getActive() != active)
01823 {
01824 state.images[imgNr]->setActive(active);
01825 imageChanged(imgNr);
01826 }
01827 }
01828
01829 UIntSet Panorama::getActiveImages() const
01830 {
01831 UIntSet activeImgs;
01832
01833 for (unsigned int i = 0; i < state.images.size(); i++) {
01834 if (state.images[i]->getActive())
01835 {
01836 activeImgs.insert(i);
01837 }
01838 }
01839 return activeImgs;
01840 }
01841
01842
01843
01844 SrcPanoImage Panorama::getSrcImage(unsigned imgNr) const
01845 {
01846 DEBUG_ASSERT(imgNr < state.images.size());
01847 return *state.images[imgNr];
01848 }
01849
01850 void Panorama::setSrcImage(unsigned int imgNr, const SrcPanoImage & img)
01851 {
01852 DEBUG_ASSERT(imgNr < state.images.size());
01853
01854
01855
01856
01857 SrcPanoImage *dest = state.images[imgNr];
01858 #define image_variable( name, type, default_value ) \
01859 dest->set##name (img.get##name());
01860 #include "image_variables.h"
01861 #undef image_variable
01862
01863
01864 #define image_variable( name, type, default_value ) \
01865 for (std::size_t i = 0; i < getNrOfImages(); i++)\
01866 {\
01867 if(state.images[imgNr]->name##isLinkedWith(*state.images[i]))\
01868 {\
01869 imageChanged(i);\
01870 }\
01871 }
01872 #include "image_variables.h"
01873 #undef image_variable
01874 }
01875
01876
01877 Panorama Panorama::duplicate() const
01878 {
01879 Panorama pano(*this);
01880 pano.observers.clear();
01881 return pano;
01882 }
01883
01884 Panorama Panorama::getSubset(const UIntSet & imgs) const
01885 {
01886 Panorama subset;
01887
01888
01889
01890 subset.imgFilePrefix = imgFilePrefix;
01891 subset.dirty = dirty;
01892 subset.state.options = state.options;
01893 subset.state.optSwitch=0;
01894 subset.state.optPhotoSwitch=0;
01895 subset.state.needsOptimization = state.needsOptimization;
01896 subset.changedImages = changedImages;
01897 subset.m_forceImagesUpdate = m_forceImagesUpdate;
01898 subset.m_ptoptimizerVarNames = m_ptoptimizerVarNames;
01899
01900
01901 std::map<unsigned int, unsigned int> imageNrMap;
01902
01903
01904 unsigned int ic = 0;
01905 for (UIntSet::const_iterator imgNrIt = imgs.begin(); imgNrIt != imgs.end();
01906 ++imgNrIt)
01907 {
01908 subset.state.images.push_back(new SrcPanoImage(*state.images[*imgNrIt]));
01909 subset.state.optvec.push_back(state.optvec[*imgNrIt]);
01910 imageNrMap[*imgNrIt] = ic;
01911 ic++;
01912 }
01913
01914
01915 ic = 0;
01916 for (UIntSet::const_iterator i = imgs.begin(); i != imgs.end(); ++i)
01917 {
01918 unsigned int jc = ic + 1;
01919 UIntSet::const_iterator j = i;
01920 for (++j; j != imgs.end(); ++j)
01921 {
01926 #define image_variable( name, type, default_value )\
01927 if (state.images[*i]->name##isLinkedWith(*state.images[*j]))\
01928 {\
01929 subset.state.images[ic]->link##name(subset.state.images[jc]);\
01930 }
01931 #include "image_variables.h"
01932 #undef image_variable
01933 jc++;
01934 }
01935 ic++;
01936 }
01937
01938
01939 subset.state.ctrlPoints.clear();
01940 for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it) {
01941 if (set_contains(imgs, it->image1Nr) && set_contains(imgs, it->image2Nr)) {
01942 ControlPoint pnt = *it;
01943 pnt.image1Nr = imageNrMap[pnt.image1Nr];
01944 pnt.image2Nr = imageNrMap[pnt.image2Nr];
01945 subset.state.ctrlPoints.push_back(pnt);
01946 }
01947 }
01948
01949
01950 unsigned int newRefImg=0;
01951 std::map<unsigned int, unsigned int>::iterator it=imageNrMap.find(state.options.optimizeReferenceImage);
01952 if(it!=imageNrMap.end())
01953 {
01954 newRefImg=it->second;
01955 };
01956 it=imageNrMap.find(state.options.colorReferenceImage);
01957 subset.state.options.optimizeReferenceImage=newRefImg;
01958 newRefImg=0;
01959 if(it!=imageNrMap.end())
01960 {
01961 newRefImg=it->second;
01962 }
01963 subset.state.options.colorReferenceImage=newRefImg;
01964 return subset;
01965 }
01966
01967 void Panorama::mergePanorama(const Panorama &newPano)
01968 {
01969 if(newPano.getNrOfImages()>0)
01970 {
01971 std::vector<unsigned int> new_image_nr(newPano.getNrOfImages());
01972 unsigned int oldNrOfImage=getNrOfImages();
01973 HuginBase::OptimizeVector optVec=getOptimizeVector();
01974 HuginBase::OptimizeVector optVecNew=newPano.getOptimizeVector();
01975
01976 for(unsigned int i=0;i<newPano.getNrOfImages();i++)
01977 {
01978 std::string filename=newPano.getImage(i).getFilename();
01979 bool found=false;
01980 for(unsigned int j=0;j<getNrOfImages();j++)
01981 {
01982 if(getImage(j).getFilename()==filename)
01983 {
01984
01985 found=true;
01986 new_image_nr[i]=j;
01987
01988 HuginBase::MaskPolygonVector masksOld=getImage(j).getMasks();
01989 HuginBase::MaskPolygonVector masksNew=newPano.getImage(i).getMasks();
01990 if(masksNew.size()>0)
01991 {
01992 for(unsigned int k=0;k<masksNew.size();k++)
01993 {
01994 bool usedMasks=false;
01995 unsigned int l=0;
01996 while((!usedMasks) && l<masksOld.size())
01997 {
01998 usedMasks=(masksNew[k]==masksOld[l]);
01999 l++;
02000 };
02001 if(!usedMasks)
02002 masksOld.push_back(masksNew[k]);
02003 };
02004 updateMasksForImage(j,masksOld);
02005 };
02006 break;
02007 };
02008 };
02009 if(!found)
02010 {
02011
02012 new_image_nr[i]=addImage(newPano.getImage(i));
02013
02014 optVec.push_back(optVecNew[i]);
02015 };
02016 };
02017 setOptimizeVector(optVec);
02018
02019 for (unsigned int i=0; i<newPano.getNrOfImages(); i++)
02020 {
02021 for(unsigned int j=i+1;j<newPano.getNrOfImages();j++)
02022 {
02023 const HuginBase::SrcPanoImage &img=newPano.getImage(i);
02024 #define image_variable( name, type, default_value )\
02025 if(img.name##isLinkedWith(newPano.getImage(j)))\
02026 {\
02027 linkImageVariable##name(new_image_nr[i],new_image_nr[j]);\
02028 };
02029 #include "panodata/image_variables.h"
02030 #undef image_variable
02031 }
02032 }
02033
02034 CPVector cps=newPano.getCtrlPoints();
02035 for(unsigned int i=0;i<cps.size();i++)
02036 {
02037 HuginBase::ControlPoint cp(new_image_nr[cps[i].image1Nr], cps[i].x1, cps[i].y1,
02038 new_image_nr[cps[i].image2Nr],cps[i].x2, cps[i].y2, cps[i].mode);
02039 addCtrlPoint(cp);
02040 };
02041 removeDuplicateCtrlPoints();
02042 };
02043 };
02044
02045 int Panorama::getNextCPTypeLineNumber() const
02046 {
02047 int t=0;
02048 for (CPVector::const_iterator it = state.ctrlPoints.begin(); it != state.ctrlPoints.end(); ++it)
02049 {
02050 t = std::max(t, it->mode);
02051 }
02052 if (t <= 2) {
02053 t=2;
02054 }
02055 return t+1;
02056 }
02057
02058
02059 Panorama::ReadWriteError Panorama::readData(std::istream& dataInput, std::string documentType)
02060 {
02061
02062
02063 if(!dataInput.good() || dataInput.eof())
02064 {
02065 DEBUG_WARN("Failed to read from dataInput.");
02066 return INVALID_DATA;
02067 }
02068
02069 PanoramaMemento newPano;
02070 int ptoVersion;
02071 if (newPano.loadPTScript(dataInput, ptoVersion, getFilePrefix())) {
02072
02073 this->setMemento(newPano);
02074 return SUCCESSFUL;
02075
02076 } else {
02077 DEBUG_FATAL("Could not parse the data input successfully.");
02078 return PARCER_ERROR;
02079 }
02080 }
02081
02083 Panorama::ReadWriteError Panorama::writeData(std::ostream& dataOutput, std::string documentType)
02084 {
02085 UIntSet all;
02086
02087 if (getNrOfImages() > 0)
02088 fill_set(all, 0, getNrOfImages()-1);
02089
02090 printPanoramaScript(dataOutput, getOptimizeVector(), getOptions(), all, false, getFilePrefix());
02091
02092 return SUCCESSFUL;
02093 }
02094
02095 void Panorama::updateWhiteBalance(double redFactor, double blueFactor)
02096 {
02097 UIntSet modified_images;
02098 for(unsigned int i=0;i<getNrOfImages();i++)
02099 {
02100 if(!set_contains(modified_images,i))
02101 {
02102 state.images[i]->setWhiteBalanceRed(redFactor * state.images[i]->getWhiteBalanceRed());
02103 state.images[i]->setWhiteBalanceBlue(blueFactor * state.images[i]->getWhiteBalanceBlue());
02104 modified_images.insert(i);
02105 imageChanged(i);
02106
02107 if(state.images[i]->WhiteBalanceRedisLinked())
02108 {
02109 if(i+1<getNrOfImages())
02110 {
02111 for(unsigned int j=i+1;j<getNrOfImages();j++)
02112 {
02113 if(state.images[i]->WhiteBalanceRedisLinkedWith(*(state.images[j])))
02114 {
02115 modified_images.insert(j);
02116 imageChanged(j);
02117 };
02118 };
02119 };
02120 };
02121 };
02122 };
02123 };
02124
02125 PanoramaMemento::PanoramaMemento(const PanoramaMemento & data)
02126 {
02127
02128 *this = data;
02129 }
02130
02131 PanoramaMemento & PanoramaMemento::operator=(const PanoramaMemento & data)
02132 {
02133
02134
02135
02136
02137 if (&data == this)
02138 {
02139 return *this;
02140 }
02141
02142
02143 deleteAllImages();
02144
02145 for (std::vector<SrcPanoImage *>::const_iterator it = data.images.begin();
02146 it != data.images.end(); it++)
02147 {
02148 images.push_back(new SrcPanoImage(*(*it)));
02149 }
02150
02151
02157 std::size_t num_imgs = images.size();
02158 for (std::size_t i = 0; i < num_imgs; i++)
02159 {
02160
02161
02162
02163 for (std::size_t j = i + 1; j < num_imgs; j++)
02164 {
02165 #define image_variable( name, type, default_value )\
02166 if (data.images[i]->name##isLinkedWith(*data.images[j]))\
02167 {\
02168 images[i]->link##name(images[j]);\
02169 }
02170 #include "image_variables.h"
02171 #undef image_variable
02172 }
02173 }
02174
02175 ctrlPoints = data.ctrlPoints;
02176
02177 options = data.options;
02178
02179 optSwitch = data.optSwitch;
02180 optPhotoSwitch = data.optPhotoSwitch;
02181 optvec = data.optvec;
02182
02183 needsOptimization = data.needsOptimization;
02184
02185 return *this;
02186 }
02187
02188 PanoramaMemento::~PanoramaMemento()
02189 {
02190 deleteAllImages();
02191 }
02192
02193 void PanoramaMemento::deleteAllImages()
02194 {
02195
02196 for (std::vector<SrcPanoImage *>::iterator it = images.begin();
02197 it != images.end(); it++)
02198 {
02199 delete *it;
02200 }
02201
02202 images.clear();
02203 }
02204
02205 bool PanoramaMemento::loadPTScript(std::istream &i, int & ptoVersion, const std::string &prefix)
02206 {
02207 using namespace std;
02208 using namespace PTScriptParsing;
02209
02210 DEBUG_TRACE("");
02211
02212 char * p = setlocale(LC_NUMERIC,NULL);
02213 char * old_locale = strdup(p);
02214 setlocale(LC_NUMERIC,"C");
02215 PTParseState state;
02216 string line;
02217
02218
02219 vector<ImgInfo> oImgInfo;
02220 vector<ImgInfo> iImgInfo;
02221
02222 vector<ImgInfo> cImgInfo;
02223
02224 vector<ImgInfo> huginImgInfo;
02225
02226 MaskPolygonVector ImgMasks;
02227
02228
02229 bool skipNextLine = false;
02230
02231 bool PTGUIScriptFile = false;
02232 int PTGUIScriptVersion = 0;
02233
02234 int ctrlPointsImgNrOffset = 0;
02235 bool PTGUILensLine = false;
02236
02237 bool PTGUILensLoaded = false;
02238 ImgInfo PTGUILens;
02239
02240
02241 options.reset();
02242 options.tiff_saveROI = false;
02243
02244 ptoVersion = 1;
02245
02246 bool firstOptVecParse = true;
02247 unsigned int lineNr = 0;
02248 while (i.good()) {
02249 std::getline(i, line);
02250 lineNr++;
02251 DEBUG_DEBUG(lineNr << ": " << line);
02252 if (skipNextLine) {
02253 skipNextLine = false;
02254 continue;
02255 }
02256
02257 if(line.empty())
02258 continue;
02259
02260 switch(line[0]) {
02261 case 'p':
02262 {
02263 DEBUG_DEBUG("p line: " << line);
02264 int i;
02265 if (getIntParam(i,line,"f"))
02266 options.setProjection( (PanoramaOptions::ProjectionFormat) i );
02267 unsigned int w;
02268 if (getIntParam(w, line, "w"))
02269 options.setWidth(w);
02270 double v;
02271 if (getDoubleParam(v, line, "v"))
02272 options.setHFOV(v, false);
02273 int height;
02274 if (getIntParam(height, line, "h"))
02275 options.setHeight(height);
02276
02277 double newE;
02278 if (getDoubleParam(newE, line, "E"))
02279 options.outputExposureValue = newE;
02280 int ar=0;
02281 if (getIntParam(ar, line, "R"))
02282 options.outputMode = (PanoramaOptions::OutputMode) ar;
02283
02284 string format;
02285 if (getPTParam(format,line,"T"))
02286 options.outputPixelType = format;
02287
02288 if ( getPTParam(format, line, "S") ) {
02289 int left, right, top, bottom;
02290 int n = sscanf(format.c_str(), "%d,%d,%d,%d", &left, &right, &top, &bottom);
02291 if (n == 4) {
02292 options.setROI(vigra::Rect2D(left, top, right, bottom));
02293 } else {
02294 DEBUG_WARN("Could not parse crop string: " << format);
02295 }
02296 }
02297
02298
02299 if (getPTParam(format,line,"P")) {
02300 char * tstr = strdup(format.c_str());
02301 std::vector<double> projParam;
02302 char * b = strtok(tstr, " \"");
02303 if (b != NULL) {
02304 while (b != NULL) {
02305 double tempDbl;
02306 if (sscanf(b, "%lf", &tempDbl) == 1) {
02307 projParam.push_back(tempDbl);
02308 b = strtok(NULL, " \"");
02309 }
02310 }
02311 }
02312 free(tstr);
02313
02314 if (projParam.size() == options.getProjectionParameters().size()) {
02315 options.setProjectionParameters(projParam);
02316 }
02317 }
02318
02319
02320
02321
02322 if (getPTParam(format,line,"n")) {
02323 int t = format.find(' ');
02324 options.outputFormat = options.getFormatFromName(format.substr(0,t));
02325
02326
02327 switch (options.outputFormat)
02328 {
02329 case PanoramaOptions::JPEG:
02330 {
02331
02332 int q;
02333 if (getIntParam(q, format, "q") ) {
02334 options.quality = (int) q;
02335 }
02336 }
02337 break;
02338 case PanoramaOptions::TIFF_m:
02339 {
02340 int coordImgs = 0;
02341 if (getIntParam(coordImgs, format, "p"))
02342 if (coordImgs)
02343 options.saveCoordImgs = true;
02344 }
02345 case PanoramaOptions::TIFF:
02346 case PanoramaOptions::TIFF_mask:
02347 case PanoramaOptions::TIFF_multilayer:
02348 case PanoramaOptions::TIFF_multilayer_mask:
02349 {
02350
02351 std::string comp;
02352 if (getPTParam(comp, format, "c:")) {
02353 if (comp == "NONE" || comp == "LZW" ||
02354 comp == "PACKBITS" || comp == "DEFLATE")
02355 {
02356 options.tiffCompression = comp;
02357 } else {
02358 DEBUG_WARN("No valid tiff compression found");
02359 }
02360 }
02361
02362 if (getPTParam(comp, format, "r:")) {
02363 if (comp == "CROP") {
02364 options.tiff_saveROI = true;
02365 } else {
02366 options.tiff_saveROI = false;
02367 }
02368 }
02369 }
02370 break;
02371 default:
02372 break;
02373 }
02374 }
02375
02376 int cRefImg = 0;
02377 if (getIntParam(cRefImg, line,"k")) {
02378 options.colorCorrection = PanoramaOptions::BRIGHTNESS_COLOR;
02379 } else if (getIntParam(cRefImg, line,"b")) {
02380 options.colorCorrection = PanoramaOptions::BRIGHTNESS;
02381 } else if (getIntParam(cRefImg, line,"d")) {
02382 options.colorCorrection = PanoramaOptions::COLOR;
02383 } else {
02384 options.colorCorrection = PanoramaOptions::NONE;
02385 }
02386 options.colorReferenceImage=cRefImg;
02387 break;
02388
02389 }
02390 case 'm':
02391 {
02392 DEBUG_DEBUG("m line: " << line);
02393
02394 int i;
02395 if (getIntParam(i,line,"i"))
02396 options.interpolator = (vigra_ext::Interpolator) i;
02397 (void)getDoubleParam(options.gamma,line,"g");
02398
02399 if (getIntParam(i,line,"f")) {
02400 switch(i) {
02401 case 0:
02402 options.remapAcceleration = PanoramaOptions::MAX_SPEEDUP;
02403 break;
02404 case 1:
02405 options.remapAcceleration = PanoramaOptions::MEDIUM_SPEEDUP;
02406 break;
02407 default:
02408 options.remapAcceleration = PanoramaOptions::NO_SPEEDUP;
02409 break;
02410 }
02411 } else {
02412 options.remapAcceleration = PanoramaOptions::NO_SPEEDUP;
02413 }
02414
02415 break;
02416 }
02417 case 'v':
02418 {
02419 DEBUG_DEBUG("v line: " << line);
02420 if (!PTGUIScriptFile) {
02421 if (firstOptVecParse) {
02422 int nImg = max(iImgInfo.size(), oImgInfo.size());
02423 DEBUG_DEBUG("nImg: " << nImg);
02424 optvec = OptimizeVector(nImg);
02425 firstOptVecParse = false;
02426 }
02427 std::stringstream optstream;
02428 optstream << line.substr(1);
02429 string var;
02430 while (!(optstream >> std::ws).eof()) {
02431 optstream >> var;
02432 if (var.length() == 1) {
02433
02434 var += "0";
02435 }
02436
02437 std::string::size_type np = var.find_first_of("0123456789");
02438 if (np == std::string::npos) {
02439
02440 continue;
02441 }
02442 std::string name=var.substr(0,np);
02443 std::string number = var.substr(np);
02444 unsigned int nr = hugin_utils::lexical_cast<unsigned int>(number);
02445 DEBUG_ASSERT(nr < optvec.size());
02446 if(nr < optvec.size())
02447 {
02448 optvec[nr].insert(name);
02449 DEBUG_DEBUG("parsing opt: >" << var << "< : var:" << name << " image:" << nr);
02450 };
02451 }
02452 }
02453 break;
02454 }
02455 case 'c':
02456 {
02457 DEBUG_DEBUG("c line: " << line);
02458 int t;
02459
02460 ControlPoint point;
02461
02462 getIntParam(point.image1Nr, line, "n");
02463 point.image1Nr += ctrlPointsImgNrOffset;
02464 getIntParam(point.image2Nr, line, "N");
02465 point.image2Nr += ctrlPointsImgNrOffset;
02466 getDoubleParam(point.x1, line, "x");
02467 getDoubleParam(point.x2, line, "X");
02468 getDoubleParam(point.y1, line, "y");
02469 getDoubleParam(point.y2, line, "Y");
02470 if (!getIntParam(t, line, "t") ){
02471 t = 0;
02472 }
02473
02474 point.mode = t;
02475 ctrlPoints.push_back(point);
02476 state = P_CP;
02477 break;
02478 }
02479
02480
02481
02482
02483 case 'i':
02484 {
02485 if (PTGUILensLine) {
02486 PTGUILensLine = false;
02487 PTGUILensLoaded = true;
02488 PTGUILens.parse(line);
02489 } else {
02490 iImgInfo.push_back(ImgInfo(line));
02491 }
02492 break;
02493 }
02494 case 'o':
02495 {
02496 if (PTGUILensLine) {
02497 PTGUILensLine = false;
02498 PTGUILensLoaded = true;
02499 PTGUILens.parse(line);
02500 } else {
02501 oImgInfo.push_back(ImgInfo(line));
02502 }
02503 break;
02504 }
02505
02506 case 'k':
02507 {
02508 unsigned int param;
02509 if (getIntParam(param,line,"i"))
02510 {
02511 MaskPolygon newPolygon;
02512 newPolygon.setImgNr(param);
02513 if (getIntParam(param,line,"t"))
02514 newPolygon.setMaskType((HuginBase::MaskPolygon::MaskType)param);
02515 std::string format;
02516 if (getPTParam(format,line,"p"))
02517 {
02518 if(newPolygon.parsePolygonString(format))
02519 ImgMasks.push_back(newPolygon);
02520 };
02521 };
02522 break;
02523 }
02524
02525 case '#':
02526 {
02527
02528 if (line.substr(0,20) == string("# ptGui project file")) {
02529 PTGUIScriptFile = true;
02530 }
02531 if (line.substr(0,12) == "#-dummyimage") {
02532 PTGUILensLine = true;
02533 }
02534 if (PTGUIScriptFile) {
02535
02536 if (sscanf(line.c_str(), "#-fileversion %d", &PTGUIScriptVersion) > 0) {
02537 DEBUG_DEBUG("Detected PTGUI script version: " << PTGUIScriptVersion);
02538 switch (PTGUIScriptVersion) {
02539 case 0:
02540 break;
02541 case 1:
02542 break;
02543 case 2:
02544 break;
02545 case 3:
02546 break;
02547 case 4:
02548 break;
02549 case 5:
02550 break;
02551 case 6:
02552 break;
02553 case 7:
02554 break;
02555 default:
02556 ctrlPointsImgNrOffset = -1;
02557
02558 break;
02559 }
02560 }
02561 }
02562
02563 if (line.substr(0,8) == "#-hugin ") {
02564
02565 ImgInfo info;
02566 info.autoCenterCrop = (line.find("autoCenterCrop=1") != std::string::npos);
02567 size_t pos = line.find("cropFactor=");
02568 if (pos > 0 && pos < line.length()) {
02569 double cropFactor=1;
02570 const char * s = line.c_str() + pos;
02571 sscanf(s,"cropFactor=%lf", & cropFactor);
02572 if(cropFactor<0.01 || cropFactor > 100)
02573 cropFactor=1;
02574 info.cropFactor = cropFactor;
02575 }
02576 pos = line.find("disabled");
02577 if (pos > 0 && pos < line.length()) {
02578 info.enabled = false;
02579 }
02580 huginImgInfo.push_back(info);
02581 }
02582
02583
02584
02585 if (line.substr(0,10) == "#-imgfile ") {
02586
02587
02588 int b = line.find_first_not_of(" ",9);
02589 int e = line.find_first_of(" ",b);
02590 DEBUG_DEBUG(" width:" << line.substr(b,e-b)<<":")
02591 int nextWidth = hugin_utils::lexical_cast<int,string>(line.substr(b,e-b));
02592 DEBUG_DEBUG("next width " << nextWidth);
02593 b = line.find_first_not_of(" ",e);
02594 e = line.find_first_of(" ",b);
02595 DEBUG_DEBUG(" height:" << line.substr(b,e-b)<<":")
02596 int nextHeight = hugin_utils::lexical_cast<int, string>(line.substr(b,e-b));
02597 DEBUG_DEBUG("next height " << nextHeight);
02598
02599 string nextFilename;
02600 try {
02601 b = line.find_first_not_of(" \"",e);
02602 e = line.find_first_of("\"",b);
02603 nextFilename = line.substr(b,e-b);
02604 } catch (std::out_of_range& e) {
02605 DEBUG_ERROR("ERROR PARSING INPUT FILE" << e.what( ));
02606 return false;
02607 }
02608 DEBUG_DEBUG("next filename " << nextFilename);
02609
02610 ImgInfo info;
02611 info.width = nextWidth;
02612 info.height = nextHeight;
02613 info.filename = nextFilename;
02614 cImgInfo.push_back(info);
02615 }
02616
02617
02618
02619 if (line.substr(0,7) == "#hugin_") {
02620 istringstream is(line);
02621 string var,value;
02622 is >> var >> value;
02623 if (!is.fail()) {
02624 if (var == "#hugin_ptoversion") {
02625 ptoVersion = atoi(value.c_str());
02626 }
02627
02628 if (var == "#hugin_optimizeReferenceImage") {
02629 options.optimizeReferenceImage = atoi(value.c_str());
02630 } else if (var == "#hugin_remapper") {
02631 if (value == "nona") {
02632 options.remapper = PanoramaOptions::NONA;
02633 } else if (value == "PTmender") {
02634 options.remapper = PanoramaOptions::PTMENDER;
02635 }
02636 } else if (var == "#hugin_blender") {
02637 if (value == "none") {
02638 options.blendMode = PanoramaOptions::NO_BLEND;
02639 } else if (value == "PTblender") {
02640 options.blendMode = PanoramaOptions::PTBLENDER_BLEND;
02641 } else if (value == "enblend") {
02642 options.blendMode = PanoramaOptions::ENBLEND_BLEND;
02643 } else if (value == "PTmasker") {
02644 options.blendMode = PanoramaOptions::PTMASKER_BLEND;
02645 } else if (value == "smartblend") {
02646 options.blendMode = PanoramaOptions::SMARTBLEND_BLEND;
02647 }
02648
02649 } else if (var == "#hugin_enblendOptions") {
02650 options.enblendOptions = value;
02651 while (!is.eof()) {
02652 is >> value;
02653 if (value.length() > 0) {
02654 options.enblendOptions += " ";
02655 options.enblendOptions += value;
02656 }
02657 }
02658 } else if (var == "#hugin_enfuseOptions") {
02659 options.enfuseOptions = value;
02660 while (!is.eof()) {
02661 is >> value;
02662 if (value.length() > 0) {
02663 options.enfuseOptions += " ";
02664 options.enfuseOptions += value;
02665 }
02666 }
02667 } else if (var == "#hugin_hdrmergeOptions") {
02668 options.hdrmergeOptions = value;
02669 while (!is.eof()) {
02670 is >> value;
02671 if (value.length() > 0) {
02672 options.hdrmergeOptions += " ";
02673 options.hdrmergeOptions += value;
02674 }
02675 }
02676
02677 } else if (var == "#hugin_outputLDRBlended") {
02678 options.outputLDRBlended = (value == "true");
02679 } else if (var == "#hugin_outputLDRLayers") {
02680 options.outputLDRLayers = (value == "true");
02681 } else if (var == "#hugin_outputLDRExposureRemapped") {
02682 options.outputLDRExposureRemapped = (value == "true");
02683 } else if (var == "#hugin_outputLDRExposureLayers") {
02684 options.outputLDRExposureLayers = (value == "true");
02685 } else if (var == "#hugin_outputLDRExposureBlended") {
02686 options.outputLDRExposureBlended = (value == "true");
02687 } else if (var == "#hugin_outputLDRExposureLayersFused") {
02688 options.outputLDRExposureLayersFused = (value == "true");
02689 } else if (var == "#hugin_outputLDRStacks") {
02690 options.outputLDRStacks = (value == "true");
02691 } else if (var == "#hugin_outputHDRBlended") {
02692 options.outputHDRBlended = (value == "true");
02693 } else if (var == "#hugin_outputHDRLayers") {
02694 options.outputHDRLayers = (value == "true");
02695 } else if (var == "#hugin_outputHDRStacks") {
02696 options.outputHDRStacks = (value == "true");
02697
02698 } else if (var == "#hugin_outputStacksMinOverlap") {
02699 double val=atof(value.c_str());
02700 if(val>0 && val <= 1)
02701 {
02702 options.outputStacksMinOverlap = val;
02703 };
02704 } else if (var == "#hugin_outputLayersExposureDiff") {
02705 double val=atof(value.c_str());
02706 if(val>0.01)
02707 {
02708 options.outputLayersExposureDiff = val;
02709 }
02710
02711 } else if (var == "#hugin_outputLayersCompression") {
02712 options.outputLayersCompression = value;
02713 } else if (var == "#hugin_outputImageType") {
02714 options.outputImageType = value;
02715 } else if (var == "#hugin_outputImageTypeCompression") {
02716 options.outputImageTypeCompression = value;
02717 } else if (var == "#hugin_outputJPEGQuality") {
02718 options.quality = atoi(value.c_str());
02719 } else if (var == "#hugin_outputImageTypeHDR") {
02720 options.outputImageTypeHDR = value;
02721 } else if (var == "#hugin_outputImageTypeHDRCompression") {
02722 options.outputImageTypeHDRCompression = value;
02723 } else if (var == "#hugin_optimizerMasterSwitch") {
02724 optSwitch = atoi(value.c_str());
02725 } else if (var == "#hugin_optimizerPhotoMasterSwitch") {
02726 optPhotoSwitch = atoi(value.c_str());
02727 };
02728
02729 }
02730 }
02731 break;
02732 }
02733
02734 }
02735 }
02736
02737
02738
02741 #if 0
02742
02743 if (PTGUILensLoaded) {
02744
02745 Lens l;
02746 for (const char **v = Lens::variableNames; *v != 0; v++) {
02747 map_get(l.variables, *v).setValue(PTGUILens.vars[*v]);
02748 }
02749 l.setImageSize(vigra::Size2D(PTGUILens.width, PTGUILens.height));
02750 l.setCropFactor(1);
02751 l.setProjection((Lens::LensProjectionFormat) PTGUILens.f);
02752 lenses.push_back(l);
02753 }
02754 #endif
02755
02756
02757
02758
02759
02760
02761
02762
02763
02764
02765
02766
02767
02768
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782
02783 int nImgs = iImgInfo.size();
02784 int nOLines = oImgInfo.size();
02785 int nCLines = cImgInfo.size();
02786
02787 if (nImgs < nOLines) {
02788
02789 DEBUG_DEBUG("throwing away " << nImgs << " i lines");
02790 iImgInfo = oImgInfo;
02791 nImgs = nOLines;
02792 }
02793 if (nOLines < nImgs) {
02794 oImgInfo = iImgInfo;
02795 }
02796
02797
02798 for (int i=0; i < nImgs; i++) {
02799
02800
02801
02802
02803
02804 for (const char ** v = ImgInfo::varnames; *v ; v++) {
02805
02806 if (iImgInfo[i].links[*v] == -2 && oImgInfo[i].links[*v] != -2 || iImgInfo[i].links[*v] == -1 && oImgInfo[i].links[*v] >=0) {
02807 DEBUG_DEBUG(*v << ": o -> i");
02808 iImgInfo[i].vars[*v] = oImgInfo[i].vars[*v];
02809 iImgInfo[i].links[*v] = oImgInfo[i].links[*v];
02810 }
02811 }
02812
02813 if (iImgInfo[i].filename == "" && oImgInfo[i].filename != "") {
02814 DEBUG_DEBUG("filename: o -> i");
02815 iImgInfo[i].filename = oImgInfo[i].filename;
02816 }
02817
02818 if (iImgInfo[i].crop.isEmpty() && !oImgInfo[i].crop.isEmpty()) {
02819 DEBUG_DEBUG("crop: o -> i");
02820 iImgInfo[i].crop = oImgInfo[i].crop;
02821 }
02822
02823 if (iImgInfo[i].width <= 0 && oImgInfo[i].width > 0) {
02824 DEBUG_DEBUG("width: o -> i");
02825 iImgInfo[i].width = oImgInfo[i].width;
02826 }
02827
02828 if (iImgInfo[i].height <= 0 && oImgInfo[i].height > 0) {
02829 DEBUG_DEBUG("height: o -> i");
02830 iImgInfo[i].height = oImgInfo[i].height;
02831 }
02832
02833 if (iImgInfo[i].f < 0 && oImgInfo[i].f > 0) {
02834 DEBUG_DEBUG("f: o -> i");
02835 iImgInfo[i].f = oImgInfo[i].f;
02836 }
02837
02838 if (nCLines == nImgs) {
02839
02840 if (cImgInfo[i].filename != "" && cImgInfo[i].width > 0) {
02841 DEBUG_DEBUG("filename, width, height: c -> i");
02842 iImgInfo[i].filename = cImgInfo[i].filename;
02843 iImgInfo[i].width = cImgInfo[i].width;
02844 iImgInfo[i].height = cImgInfo[i].height;
02845 }
02846 }
02847 if (huginImgInfo.size() == (size_t)nImgs) {
02848 iImgInfo[i].cropFactor = huginImgInfo[i].cropFactor;
02849 iImgInfo[i].autoCenterCrop = huginImgInfo[i].autoCenterCrop;
02850 iImgInfo[i].enabled= huginImgInfo[i].enabled;
02851 }
02852 }
02853
02854
02855 for (int i=0; i < nImgs; i++) {
02856
02857 DEBUG_DEBUG("i line: " << i);
02858
02859 VariableMap vars;
02860 int link = -2;
02861 fillVariableMap(vars);
02862
02863 for (const char ** v = ImgInfo::varnames; *v != 0; v++) {
02864 std::string name(*v);
02865 double val = iImgInfo[i].vars[*v];
02866 map_get(vars,name).setValue(val);
02867 if (iImgInfo[i].links[*v] >= 0) {
02868 link = iImgInfo[i].links[*v];
02869 }
02870 }
02871
02872 string file = iImgInfo[i].filename;
02873
02874 #ifdef WIN32
02875 bool absPath = ( (file[1]==':' && file[2]=='\\') || (file[1]==':' && file[2]=='/') || (file[0] == '\\' && file[1] == '\\'));
02876 #else
02877 bool absPath = file[0] == '/';
02878 #endif
02879 if (!absPath) {
02880 file.insert(0, prefix);
02881 }
02882 DEBUG_DEBUG("filename: " << file);
02883
02884
02885 SrcPanoImage * new_img_p = new SrcPanoImage();
02886 images.push_back(new_img_p);
02887
02888 SrcPanoImage & new_img = *new_img_p;
02889 new_img.setFilename(file);
02890 double focal=0;
02891 double crop=0;
02892 new_img.readEXIF(focal,crop,false,false);
02893 new_img.setSize(vigra::Size2D(iImgInfo[i].width, iImgInfo[i].height));
02894
02895
02896
02897 VariableMap vars_for_name;
02898
02899
02900 SrcPanoImage name_src;
02901
02902
02903
02904
02905
02906
02907
02908
02909
02910
02911
02912
02913
02914
02915
02916
02917
02921 #define RESET_LOCALE setlocale(LC_NUMERIC,old_locale); free(old_locale);
02922 #define image_variable( name, type, default_value )\
02923 PTOVariableConverterFor##name::addToVariableMap(name_src.get##name##IV(), vars_for_name);\
02924 for (VariableMap::iterator vit = vars_for_name.begin();\
02925 vit != vars_for_name.end(); vit++)\
02926 {\
02927 if (link >= 0 && iImgInfo[i].links[vit->first] >= 0)\
02928 {\
02929 if ( !(PTGUILensLoaded && link == 0)\
02930 && (int) images.size() < link && (!PTGUILensLoaded))\
02931 {\
02932 DEBUG_ERROR("variables must be linked to an image with a lower number" << endl\
02933 << "number links: " << link << " images: " << images.size() << endl\
02934 << "error on line " << lineNr << ":" << endl\
02935 << line);\
02936 RESET_LOCALE\
02937 return false;\
02938 }\
02939 DEBUG_DEBUG("anchored to image " << iImgInfo[i].links[vit->first]);\
02940 new_img.link##name(images[iImgInfo[i].links[vit->first]]);\
02941 } else {\
02942 double val = map_get(vars, vit->first).getValue();\
02943 new_img.setVar(vit->first, val);\
02944 }\
02945 }\
02946 vars_for_name.clear();
02947 #include "image_variables.h"
02948 #undef image_variable
02949 new_img.setProjection((SrcPanoImage::Projection) iImgInfo[i].f);
02950
02951
02952 #define check_stack_link(name) \
02953 if(!new_img.YawisLinked() && new_img.name##isLinked())\
02954 {\
02955 new_img.unlink##name();\
02956 };\
02957 if(new_img.YawisLinked() && !new_img.name##isLinked())\
02958 {\
02959 for(size_t j=0; j<i; j++)\
02960 {\
02961 if(new_img.YawisLinkedWith(*images[j]))\
02962 {\
02963 new_img.link##name(images[j]);\
02964 break;\
02965 };\
02966 };\
02967 }
02968 check_stack_link(Pitch);
02969 check_stack_link(Roll);
02970 check_stack_link(X);
02971 check_stack_link(Y);
02972 check_stack_link(Z);
02973 check_stack_link(TranslationPlaneYaw);
02974 check_stack_link(TranslationPlanePitch);
02975 #undef check_stack_link
02976
02977 #if 0
02978 new_img.setFeatherWidth((unsigned int) iImgInfo[i].blend_radius);
02979 #endif
02980
02981
02982 new_img.setExifCropFactor(iImgInfo[i].cropFactor);
02983 new_img.setVigCorrMode(iImgInfo[i].vigcorrMode);
02984 new_img.setFlatfieldFilename(iImgInfo[i].flatfieldname);
02985 new_img.setResponseType((SrcPanoImage::ResponseType)iImgInfo[i].responseType);
02986 new_img.setAutoCenterCrop(iImgInfo[i].autoCenterCrop);
02987 new_img.setActive(iImgInfo[i].enabled);
02988
02989 if (!iImgInfo[i].crop.isEmpty()) {
02990 if (new_img.isCircularCrop())
02991 {
02992 new_img.setCropMode(SrcPanoImage::CROP_CIRCLE);
02993 } else {
02994 new_img.setCropMode(SrcPanoImage::CROP_RECTANGLE);
02995 }
02996 new_img.setCropRect(iImgInfo[i].crop);
02997 }
02998
02999
03000 for(unsigned int j=0;j<ImgMasks.size();j++)
03001 if(ImgMasks[j].getImgNr()==i)
03002
03003 if(ImgMasks[j].clipPolygon(vigra::Rect2D(-0.9*maskOffset,-0.9*maskOffset,
03004 new_img.getWidth()+0.9*maskOffset,new_img.getHeight()+0.9*maskOffset)))
03005 {
03006 new_img.addMask(ImgMasks[j]);
03007 };
03008 }
03009
03010
03011 if (optvec.size() != images.size()) {
03012 optvec = OptimizeVector(images.size());
03013 }
03014
03015
03016 setlocale(LC_NUMERIC,old_locale);
03017 free(old_locale);
03018
03019 return true;
03020 }
03021
03022 }