1 // -*- c-basic-offset: 4 -*- 2 /** @file panodata/Panorama.h 3 * 4 * @author Pablo d'Angelo <pablo.dangelo@web.de> 5 * 6 * $Id$ 7 * 8 * This is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This software is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public 19 * License along with this software. If not, see 20 * <http://www.gnu.org/licenses/>. 21 * 22 */ 23 24 #ifndef _PANODATA_PANORAMA_H 25 #define _PANODATA_PANORAMA_H 26 27 // if this file is preprocessed for SWIG, we want to ignore 28 // all the header inclusions that follow: 29 30 #ifndef _HSI_IGNORE_SECTION 31 32 #include <hugin_shared.h> 33 #include <list> 34 #include <appbase/DocumentData.h> 35 #include <panodata/PanoramaData.h> 36 37 38 #endif // _HSI_IGNORE_SECTION 39 40 namespace HuginBase { 41 42 /** Memento class for a Panorama object 43 * 44 * Holds the internal state of a Panorama. 45 * Used when other objects need to get/set the state without 46 * knowing anything about the internals. 47 * 48 */ 49 class IMPEX PanoramaMemento : public PanoramaDataMemento 50 { 51 52 friend class Panorama; 53 54 public: PanoramaMemento()55 PanoramaMemento() 56 : PanoramaDataMemento(), optSwitch(0), optPhotoSwitch(0), needsOptimization(false) 57 {}; 58 59 /// copy ctor. 60 PanoramaMemento(const PanoramaMemento & o); 61 62 /// assignment operator 63 PanoramaMemento& operator=(const PanoramaMemento & o); 64 65 virtual ~PanoramaMemento(); 66 67 /** load a Hugin file 68 * 69 * initializes the PanoramaMemento from a script file 70 */ 71 bool loadPTScript(std::istream & i, int & ptoVersion, const std::string & prefix = ""); 72 73 private: 74 enum PTParseState { 75 P_NONE, 76 P_OUTPUT, 77 P_MODIFIER, 78 P_IMAGE, 79 P_OPTIMIZE, 80 P_CP 81 }; 82 83 /** The images inside the panorama. 84 * 85 * The image variables are stored inside. We use pointers to the real 86 * objects so that the memory addresses of them remain constant when we 87 * remove and swap the order of images. We should create and free images 88 * when necessary. 89 */ 90 std::vector<SrcPanoImage *> images; 91 /** description of the icc profile */ 92 std::string iccProfileDesc; 93 /** number of bands of first image (without alpha channel), 94 * currently we can't mix grayscale and RGB images */ 95 int bands = 0; 96 97 CPVector ctrlPoints; 98 99 PanoramaOptions options; 100 101 OptimizeVector optvec; 102 /** stores the optimizer switch, use OR of HuginBase::OptimizerSwitches */ 103 int optSwitch; 104 /** stores the photometric optimizer switch, use OR of HuginBase::OptimizerSwitches */ 105 int optPhotoSwitch; 106 107 // indicates that changes have been made to 108 // control points or lens parameters after the 109 // last optimisation 110 bool needsOptimization; 111 112 void deleteAllImages(); 113 }; 114 115 116 117 /** Model for a panorama. 118 * 119 * This class contains the properties of a panorama 120 * That is: 121 * - images 122 * - variables that can be optimized including links between them 123 * - control points 124 * - properites of the output panorama. 125 * 126 * view and controller classes can get information about these 127 * with the getXXX Functions. 128 * 129 * Images and Control points are numbered, and const references are 130 * handed out. this means that all interaction will be based on 131 * image/control point numbers. The references are not stable, 132 * they might disappear when other functions of this class are 133 * called, so its best to get a new reference whenever you need the object. 134 * 135 * This also means that the whole object is not threadsafe and concurrent 136 * access has to be synchronized from the outside. 137 * 138 * Changes should be made through command objects, not with direct calls. 139 * 140 * @todo should the changer call the report() functions? 141 * 142 * @todo should we add constraints for the simple / advanced functionality 143 * to the model? I have to think a bit more about that issue. maybe the 144 * contraints can be factored out into another class that corrects 145 * then when updating. or we could have different models.. 146 * SimplePanorama and AdvancedPanorama. 147 * 148 * also, it is useful to use the memento pattern for the internal 149 * state, so that redo/undo for complex interactions can be 150 * implemented without too much pain. 151 */ 152 class IMPEX Panorama : public ManagedPanoramaData, public AppBase::DocumentData 153 { 154 155 public: 156 157 /** ctor. 158 */ 159 Panorama(); 160 161 /** dtor. 162 */ 163 ~Panorama(); 164 165 166 // ====================== PanoramaData ========================================= 167 168 169 /** get a subset of the panorama 170 * 171 * This returns a panorama that contains only the images specified by \imgs 172 * Useful for operations on a subset of the panorama 173 */ 174 Panorama getSubset(const UIntSet & imgs) const; 175 176 /** duplicate the panorama 177 * 178 * returns a copy of the pano state, except for the listeners. 179 */ 180 Panorama duplicate() const; 181 182 /// getNewSubset(const UIntSet & imgs)183 PanoramaData* getNewSubset(const UIntSet& imgs) const 184 { 185 return new Panorama(this->getSubset(imgs)); 186 } 187 188 /// getNewCopy()189 PanoramaData* getNewCopy() const 190 { 191 return new Panorama(this->duplicate()); 192 } 193 194 /** get a panorama, which does not contain 195 * images linked with positions, the cps are moved to the first image 196 * of each linked stacked 197 * @param imageGroups contains a mapping of the initial images to the new images */ 198 PanoramaData* getUnlinkedSubset(UIntSetVector& imageGroups) const; 199 200 // -- Data Access -- 201 202 // = images = 203 204 /// number of images. getNrOfImages()205 std::size_t getNrOfImages() const 206 { 207 return state.images.size(); 208 }; 209 210 /// get a panorama image, counting starts with 0 getImage(std::size_t nr)211 inline const SrcPanoImage & getImage(std::size_t nr) const 212 { 213 assert(nr < state.images.size()); 214 return *state.images[nr]; 215 }; 216 217 /// set a panorama image, counting starts with 0 setImage(std::size_t nr,const SrcPanoImage & img)218 void setImage(std::size_t nr, const SrcPanoImage & img) 219 { 220 setSrcImage(nr, img); 221 }; 222 223 /// the the number for a specific image 224 // unsigned int getImageNr(const PanoImage * image) const; 225 226 /** add an Image to the panorama 227 */ 228 unsigned int addImage(const SrcPanoImage &img); 229 230 /** merges the panorama with the given pano */ 231 void mergePanorama(const Panorama &newPano); 232 233 /** creates an image, from filename, and a Lens, if needed */ 234 // int addImageAndLens(const std::string & filename); 235 236 /** add an Image to the panorama 237 * @return image number 238 */ 239 // unsigned int addImage(const std::string & filename); 240 241 /** remove an Image. 242 * 243 * also deletes/updates all associated control points 244 * and the Lens, if it was only used by this image. 245 */ 246 void removeImage(unsigned int nr); 247 248 /** swap images. 249 * 250 * swaps the images, image @p img1 becomes @p img2 and the other way round 251 */ 252 void swapImages(unsigned int img1, unsigned int img2); 253 254 /** moves images. 255 * 256 * moves the image from pos1 to pos2 257 */ 258 void moveImage(size_t img1, size_t img2); 259 260 /** get a description of a source image 261 * 262 * Notice the SrcPanoImage is a copy. This removes all references to the 263 * other images, which means you should use getImage instead if you 264 * would like to find out about the variable links. 265 * 266 * @warning Variable links cannot be accessed this way. 267 */ 268 SrcPanoImage getSrcImage(unsigned imgNr) const; 269 270 /** set input image parameters 271 * 272 * This sets the values of the image variables, but does not change the 273 * links. 274 * @warning Variable links cannot be set this way. 275 */ 276 void setSrcImage(unsigned int nr, const SrcPanoImage & img); 277 278 /** set a new image filename 279 * 280 * It is assumed that it is of the same size 281 * as the old image. 282 * 283 */ 284 void setImageFilename(unsigned int img, const std::string & fname); 285 286 /** mark an image as active or inactive. 287 * 288 * This is only a flag, that can be turned on or off. 289 * If an image is marked active, then it should 290 * be used for optimizing and stitching. 291 * 292 * However, this is not done automatically. One has 293 * to use getActiveImages() to get the numbers of the 294 * active images, and pass these to the respective 295 * functions that do the stitching or optimisation 296 */ 297 void activateImage(unsigned int imgNr, bool active=true); 298 299 /** get active images */ 300 UIntSet getActiveImages() const; 301 302 303 // = CPs = 304 305 /// number of control points getNrOfCtrlPoints()306 std::size_t getNrOfCtrlPoints() const 307 { 308 return state.ctrlPoints.size(); 309 }; 310 311 /// get a control point, counting starts with 0 getCtrlPoint(std::size_t nr)312 const ControlPoint & getCtrlPoint(std::size_t nr) const 313 { 314 assert(nr < state.ctrlPoints.size()); 315 return state.ctrlPoints[nr]; 316 }; 317 318 /// get all control point of this Panorama getCtrlPoints()319 const CPVector & getCtrlPoints() const 320 { return state.ctrlPoints; }; 321 322 /** return all control points for a given image. */ 323 std::vector<unsigned int> getCtrlPointsForImage(unsigned int imgNr) const; 324 325 /** return a vector of std::pairs with global ctrl point nr and ControlPoint 326 * In the class ControlPoint the image with imgNr is always image1 */ 327 CPointVector getCtrlPointsVectorForImage(unsigned int imgNr) const; 328 329 /** set all control points (Ippei: Is this supposed to be 'add' method?) */ 330 void setCtrlPoints(const CPVector & points); 331 332 /** add a new control point.*/ 333 unsigned int addCtrlPoint(const ControlPoint & point); 334 335 /** remove a control point. 336 */ 337 void removeCtrlPoint(unsigned int pNr); 338 339 /** removes duplicates control points 340 */ 341 void removeDuplicateCtrlPoints(); 342 343 /** change a control Point. 344 */ 345 void changeControlPoint(unsigned int pNr, const ControlPoint & point); 346 347 /// get the number of a control point 348 // unsigned int getCtrlPointNr(const ControlPoint * point) const; 349 350 /** get the next unused line number for t3, ... control point creation */ 351 int getNextCPTypeLineNumber() const; 352 353 /** assign new mode line numbers, if required */ 354 void updateLineCtrlPoints(); 355 356 357 /** update control points distances. 358 * 359 * updates control distances and position in final panorama 360 * usually used to set the changes from the optimization. 361 * The control points must be the same as in 362 */ 363 void updateCtrlPointErrors(const CPVector & controlPoints); 364 365 /** update control points for a subset of images. 366 * 367 * Usually, the control point subset is created using subset() 368 * The number and ordering and control points must not be changed 369 * between the call to subset() and this function. 370 */ 371 void updateCtrlPointErrors(const UIntSet & imgs, const CPVector & cps); 372 373 /** return description of icc profile used for pano */ 374 const std::string getICCProfileDesc() const; 375 /** sets the icc profile description for check of same profile */ 376 void setICCProfileDesc(const std::string& newDesc); 377 /** return number of bands of first image (without alpha channel) 378 * so it can be 1 for grayscale or 3 for rgb images */ 379 const int getNrOfBands() const; 380 /** sets the number of bands */ 381 void setNrOfBands(const int nrBands); 382 383 // = Variables = 384 385 /// get variables of this panorama 386 VariableMapVector getVariables() const; 387 388 /** Get the variables of an image 389 * 390 * Should not be used for most GUI stuff, use the getImage(imgNr).get* 391 * methods instead for each variable you want. 392 * 393 * @todo change things using this to use getImage(imgNr).get*() instead. 394 */ 395 const VariableMap getImageVariables(unsigned int imgNr) const; 396 397 /** Set the variables. 398 * 399 * Usually used when the optimizer results should be applied. 400 * 401 */ 402 virtual void updateVariables(const VariableMapVector & vars); 403 404 /** update variables for some specific images */ 405 virtual void updateVariables(const UIntSet & imgs, const VariableMapVector & var); 406 407 /** Set variables for a single picture. 408 * 409 */ 410 virtual void updateVariables(unsigned int imgNr, const VariableMap & var); 411 412 /** update a single variable 413 * 414 * It knows lenses etc and updates other images when the 415 * variable is linked 416 */ 417 virtual void updateVariable(unsigned int imgNr, const Variable &var); 418 419 /** updates the focal length by changing hfov */ 420 virtual void UpdateFocalLength(UIntSet imgs, double newFocalLength); 421 /** updates the crop factor, try to keep focal length constant */ 422 virtual void UpdateCropFactor(UIntSet imgs, double newCropFactor); 423 /* Link image variable functions. Used to group image variables which 424 * should share the same value. The initial value is the one kept by 425 * the image with number sourceImgNr. 426 */ 427 #define image_variable( name, type, default_value ) \ 428 virtual void linkImageVariable##name(unsigned int sourceImgNr, unsigned int destImgNr); 429 #include "image_variables.h" 430 #undef image_variable 431 432 /* Unlink image variable functions. Makes a image variable independant 433 * of the other images. 434 */ 435 #define image_variable( name, type, default_value ) \ 436 virtual void unlinkImageVariable##name(unsigned int imgNr); 437 #include "image_variables.h" 438 #undef image_variable 439 440 /** update the global white balace of the panorama by multiplying 441 * the red and blue factor of each image with given factors 442 */ 443 virtual void updateWhiteBalance(double redFactor, double blueFactor); 444 445 /** returns the maximum exposure value difference of all images in the project */ 446 const double getMaxExposureDifference() const; 447 /** return true, if the metadata indicates that the projects is a bracketet project */ 448 const bool hasPossibleStacks() const; 449 /** create automatically stacks as indicated by metadata */ 450 void linkPossibleStacks(bool linkPosition); 451 452 // = Optimise Vector = 453 /** return the optimize settings stored inside panorama */ getOptimizeVector()454 const OptimizeVector & getOptimizeVector() const 455 { return state.optvec; }; 456 457 /** set optimize setting */ 458 void setOptimizeVector(const OptimizeVector & optvec); 459 460 /** returns optimizer master switch */ getOptimizerSwitch()461 const int getOptimizerSwitch() const 462 { return state.optSwitch;}; 463 /** set optimizer master switch */ 464 void setOptimizerSwitch(const int newSwitch); 465 466 /** return the photometric optimizer master switch */ getPhotometricOptimizerSwitch()467 const int getPhotometricOptimizerSwitch() const 468 { return state.optPhotoSwitch; }; 469 /** sets the photometric optimizer master switch */ 470 void setPhotometricOptimizerSwitch(const int newSwitch); 471 472 /** @note Is this the most appropriate way to remember which variables 473 * need optimisation? Can we have optimisation information in 474 * ImageVariables instead now? 475 */ 476 477 478 // = Panorama options = 479 480 /** returns the options for this panorama */ getOptions()481 const PanoramaOptions & getOptions() const 482 { return state.options; }; 483 484 /** set new output settings 485 * This is not used directly for optimizing/stiching, but it can 486 * be feed into runOptimizer() and runStitcher(). 487 */ 488 void setOptions(const PanoramaOptions & opt); 489 490 491 492 // -- script interface -- 493 494 /** read after optimization, fills in control point errors. 495 * 496 * @param set of image numbers that where used during by 497 * printPanoramaScript(). 498 * @param vars will be set the the optimzied variables 499 * @param ctrlPoints will contain the controlpoints, with distance 500 * information 501 * 502 * @return false on error (could not read optimizer output, parse error) 503 */ 504 void parseOptimizerScript(std::istream & i, 505 const UIntSet & imgs, 506 VariableMapVector & imgVars, 507 CPVector & ctrlPoints) const; 508 509 /// create an optimizer script 510 void printPanoramaScript(std::ostream & o, 511 const OptimizeVector & optvars, 512 const PanoramaOptions & options, 513 const UIntSet & imgs, 514 bool forPTOptimizer, 515 const std::string & stripPrefix="") const; 516 517 /// create the stitcher script 518 void printStitcherScript(std::ostream & o, 519 const PanoramaOptions & target, 520 const UIntSet & imgs) const; 521 522 523 524 //=========== ManagedPanoramaData ============================================== 525 526 527 528 // -- Observing -- 529 530 /** add a panorama observer. 531 * 532 * It will recieve all change messages. 533 * An observer can only be added once. if its added twice, 534 * the second addObserver() will have no effect. 535 */ 536 void addObserver(PanoramaObserver *o); 537 538 /** remove a panorama observer. 539 * 540 * Observers must be removed before they are destroyed, 541 * else Panorama will try to notify them after they have been 542 * destroyed 543 * 544 * @return true if observer was known, false otherwise. 545 */ 546 bool removeObserver(PanoramaObserver *observer); 547 548 /** remove all panorama observers. 549 * 550 * @warning this is a hack. it must not be used on normal Panorama's. 551 */ 552 void clearObservers(); 553 554 /** return if the panorama class has pending changes 555 normally all controls listen to panoramaChanges notification and react only there, 556 but the fast preview window also reacts to changes in the Redraw procedure to handle 557 the tools like drag or crop, use this as workaround (it does not include all changes) 558 */ 559 const bool hasPendingChanges() const; 560 561 /** notify observers about changes in this class 562 * 563 * This needs to be called explicitly by somebody after 564 * changes have been made. 565 * Allows to compress multiple changes into one notification. 566 * 567 * @param keepDirty do not set dirty flag. useful for changing 568 * the dirty flag itself 569 */ 570 void changeFinished(bool keepDirty); 571 572 /** notify observers about changes in this class 573 * 574 * This needs to be called explicitly by somebody after 575 * changes have been made. 576 * Allows to compress multiple changes into one notification. 577 * 578 */ changeFinished()579 void changeFinished() 580 { changeFinished(false); } 581 582 /** mark image for change notification. 583 * 584 * Does not send the notification, this is left 585 * to changedFinished() 586 */ 587 void imageChanged(unsigned int imgNr); 588 589 /** set complete mask list for image with number */ 590 void updateMasksForImage(unsigned int imgNr, MaskPolygonVector newMasks); 591 /** updates all active masks 592 * 593 * this is necessary after variables of *one* image has changed, 594 * because positive masks have to be updated 595 */ 596 void updateMasks(bool convertPosMaskToNeg=false); 597 /** transfers given mask from image imgNr to all targetImgs 598 */ 599 void transferMask(MaskPolygon mask,unsigned int imgNr, const UIntSet& targetImgs); 600 /** updates the optimize vector according to master switches */ 601 void updateOptimizeVector(); 602 /** returns set of reference image and images linked with reference images */ 603 std::set<size_t> getRefImages(); 604 /** checks if yaw/pitch/roll of reference image can be check, 605 * it depends on number and type of control points */ 606 void checkRefOptStatus(bool& linkRefImgsYaw, bool& linkRefImgsPitch, bool& linkRefImgsRoll); 607 608 // -- Memento interface -- 609 610 /// get the internal state 611 virtual PanoramaDataMemento* getNewMemento() const; 612 613 /// set the internal state 614 virtual bool setMementoToCopyOf(const PanoramaDataMemento* const memento); 615 616 /// get the internal state getMemento()617 PanoramaMemento getMemento() const 618 { return state; } 619 620 /// set the internal state 621 void setMemento(const PanoramaMemento& memento); 622 623 624 // -- Optimization Status -- 625 626 /** true if control points or lens variables 627 * have been changed after the last optimisation 628 */ needsOptimization()629 bool needsOptimization() 630 { return state.needsOptimization; }; 631 632 /// 633 void markAsOptimized(bool optimized=true) 634 { state.needsOptimization = !optimized; }; 635 636 637 638 //=========== Document Data ==================================================== 639 640 public: 641 /** Reads data. You have to check with refered images after data is 642 * loaded as the file path is likely to be relative, and the image 643 * property might have been changed since the project is saved. 644 */ 645 ReadWriteError readData(std::istream& dataInput, std::string documentType = ""); 646 647 /// 648 ReadWriteError writeData(std::ostream& dataOutput, std::string documentType = ""); 649 650 /** true if there are unsaved changes */ isDirty()651 bool isDirty() const 652 { 653 if (dirty != AppBase::DocumentData::isDirty()) 654 DEBUG_WARN("modification status mismatch."); 655 656 return dirty; 657 } 658 659 /** clear dirty flag. call after save */ clearDirty()660 virtual void clearDirty() 661 { 662 AppBase::DocumentData::clearDirty(); 663 dirty = false; 664 } 665 666 protected: 667 void setDirty(const bool& dirty = true) 668 { 669 AppBase::DocumentData::setDirty(dirty); 670 671 this->dirty = dirty; 672 } 673 674 675 // == additional methods for documents == 676 677 public: 678 /// sets the path prefix of the images reffered with relative paths setFilePrefix(std::string prefix)679 void setFilePrefix(std::string prefix) 680 { imgFilePrefix = prefix; } 681 682 protected: getFilePrefix()683 std::string getFilePrefix() const 684 { return imgFilePrefix; } 685 686 //=========== Internal methods ================================================= 687 688 public: 689 /** clear the internal state. (public use deprecated) */ 690 void reset(); 691 692 protected: 693 /// adjust the links of the linked variables, must be called 694 /// when a lens has been changed. 695 void adjustVarLinks(); 696 private: 697 /** center the crop for given image and all linked images */ 698 void centerCrop(unsigned int imgNr); 699 /** return the centered crop for given image */ 700 vigra::Rect2D centerCropImage(unsigned int imgNr); 701 /** update the crop mode in dependence of crop rect and lens projection */ 702 void updateCropMode(unsigned int imgNr); 703 704 std::string imgFilePrefix; 705 706 /// this indicates that there are unsaved changes 707 bool dirty; 708 709 PanoramaMemento state; 710 std::list<PanoramaObserver *> observers; 711 /// the images that have been changed since the last changeFinished() 712 UIntSet changedImages; 713 714 bool m_forceImagesUpdate; 715 716 std::set<std::string> m_ptoptimizerVarNames; 717 }; 718 719 } // namespace 720 #endif // _PANORAMA_H 721