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