[1fab1b]: src / hugin_base / panodata / Panorama.h Maximize Restore History

Download this file

Panorama.h    739 lines (566 with data), 24.9 kB

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