Hugin trunk 0.1
Loading...
Searching...
No Matches
Stitcher.h
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
26#ifndef _NONA_STITCHER_H
27#define _NONA_STITCHER_H
28
29// To avoid windows.h namespace pollution later on
30#include <vigra/windows.h>
31
32#include <sstream>
33#include <iomanip>
34#include <vector>
35#include <utility>
36#include <cctype>
37#include <algorithm>
38
39#include <vigra/stdimage.hxx>
40#include <vigra/rgbvalue.hxx>
41#include <vigra/tiff.hxx>
42
43#include <vigra/impex.hxx>
45#include <vigra/copyimage.hxx>
46
48#include <vigra_ext/tiffUtils.h>
50
54#include <nona/ImageRemapper.h>
57
58// somehow these are still
59#undef DIFFERENCE
60#undef min
61#undef max
62#undef MIN
63#undef MAX
64
65namespace HuginBase {
66namespace Nona {
67
69template <typename ImageType, typename AlphaType>
71{
72public:
78
79 virtual ~Stitcher() {};
80
85 virtual void stitch(const PanoramaOptions & opts,
86 const UIntSet & images, const std::string & file,
88 {
89 init(opts, images);
90 }
91
92 void init(const PanoramaOptions & opts, const UIntSet & images)
93 {
94 m_images=images;
95 calcOutputROIS(opts, images);
96 };
97
98
100 {
101 UIntSet ret;
102 assert(m_rois.size() == m_images.size());
103 std::vector<vigra::Rect2D>::iterator itr = m_rois.begin();
104 for(UIntSet::iterator it = m_images.begin(); it != m_images.end(); ++it) {
105 if (! itr->isEmpty()) {
106 ret.insert(*it);
107 }
108 }
109 return ret;
110 }
111
112protected:
113 // calculate ROI's if not already known
114 virtual void calcOutputROIS(const PanoramaOptions & opts, const UIntSet & images)
115 {
117 }
118
122 std::vector<vigra::Rect2D> m_rois;
123};
124
125namespace detail
126{
127 template<typename ImageType, typename AlphaType>
129 unsigned int imgNr, unsigned int nImg,
130 const PanoramaOptions & opts,
131 const std::string& basename,
132 const bool useBigTIFF,
134 {
135 ImageType * final_img = 0;
136 AlphaType * alpha_img = 0;
138 vigra::BImage alpha;
139
140 if (remapped.boundingBox().isEmpty())
141 // do not save empty files...
142 // TODO: need to tell other parts (enblend etc.) about it too!
143 return;
144
146 {
147 // export alpha channel as gray channel (original pixel weights)
148 std::ostringstream greyname;
149 greyname << basename << std::setfill('0') << std::setw(4) << imgNr << "_gray.pgm";
150 vigra::ImageExportInfo exinfo1(greyname.str().c_str());
151 if (!opts.tiff_saveROI)
152 {
153 alpha.resize(opts.getROI().size());
154 vigra::Rect2D newOutRect = remapped.boundingBox() & opts.getROI();
155 vigra::Rect2D newOutArea(newOutRect);
156 newOutRect.moveBy(-opts.getROI().upperLeft());
157 vigra::copyImage(vigra_ext::applyRect(newOutArea,
160 destImage(alpha)));
161 vigra::exportImage(srcImageRange(alpha), exinfo1);
162 }
163 else
164 {
165 exinfo1.setPosition(remapped.boundingBox().upperLeft());
166 exinfo1.setCanvasSize(vigra::Size2D(opts.getWidth(), opts.getHeight()));
167 vigra::exportImage(srcImageRange(remapped.m_mask), exinfo1);
168 }
169
170 // calculate real alpha for saving with the image
171 progress->setMessage("Calculating mask");
172 remapped.calcAlpha();
173 }
174
175 if (!opts.tiff_saveROI)
176 {
177 // FIXME: this is stupid. Should not require space for full image...
178 // but this would need a lower level interface in vigra impex
179 complete.resize(opts.getROI().size());
180 alpha.resize(opts.getROI().size());
181 vigra::Rect2D newOutRect = remapped.boundingBox() & opts.getROI();
182 vigra::Rect2D newOutArea(newOutRect);
183 newOutRect.moveBy(-opts.getROI().upperLeft());
184 vigra::copyImage(vigra_ext::applyRect(newOutArea,
187 destImage(complete)));
188
189 vigra::copyImage(vigra_ext::applyRect(newOutArea,
192 destImage(alpha)));
194 alpha_img = &alpha;
195 }
196 else
197 {
198 final_img = &remapped.m_image;
199 alpha_img = &remapped.m_mask;
200 }
201
202 std::string ext = opts.getOutputExtension();
203 std::ostringstream filename;
204 filename << basename << std::setfill('0') << std::setw(4) << imgNr << "." + ext;
205
206 progress->setMessage("saving", hugin_utils::stripPath(filename.str()));
207
208 vigra::ImageExportInfo exinfo(filename.str().c_str(), useBigTIFF ? "w8" : "w");
209 exinfo.setXResolution(150);
210 exinfo.setYResolution(150);
211 exinfo.setICCProfile(remapped.m_ICCProfile);
212 if (opts.tiff_saveROI)
213 {
214 exinfo.setPosition(remapped.boundingBox().upperLeft());
215 exinfo.setCanvasSize(vigra::Size2D(opts.getWidth(), opts.getHeight()));
216 }
217 else
218 {
219 exinfo.setPosition(opts.getROI().upperLeft());
220 exinfo.setCanvasSize(vigra::Size2D(opts.getWidth(), opts.getHeight()));
221 }
222 if (!opts.outputPixelType.empty())
223 {
224 exinfo.setPixelType(opts.outputPixelType.c_str());
225 }
226 bool supportsAlpha = true;
227 if (ext == "tif")
228 {
229 exinfo.setCompression(opts.tiffCompression.c_str());
230 }
231 else
232 {
233 if (ext == "jpg")
234 {
235 std::ostringstream quality;
236 quality << "JPEG QUALITY=" << opts.quality;
237 exinfo.setCompression(quality.str().c_str());
238 supportsAlpha = false;
239 };
240 }
241
242 if (supportsAlpha)
243 {
244 vigra::exportImageAlpha(srcImageRange(*final_img), srcImage(*alpha_img), exinfo);
245 }
246 else
247 {
248 vigra::exportImage(srcImageRange(*final_img), exinfo);
249 };
250 };
251} // namespace detail
252
254template <typename ImageType, typename AlphaType>
255class MultiImageRemapper : public Stitcher<ImageType, AlphaType>
256{
257public:
258
260
266
268 {
269 }
270
271 virtual void stitch(const PanoramaOptions & opts, const UIntSet & images,
272 const std::string & basename,
275 {
276 Base::stitch(opts, images, basename, remapper);
283
284 m_basename = basename;
285
286 // setup the output.
288
289 // remap each image and save
290 int i=0;
291 for (UIntSet::const_iterator it = images.begin();
292 it != images.end(); ++it)
293 {
294 // get a remapped image.
296 if (GetAdvancedOption(advOptions, "ignoreExposure", false))
297 {
298 modOptions.outputExposureValue = Base::m_pano.getImage(*it).getExposureValue();
299 modOptions.outputRangeCompression = 0.0;
300 };
304 try {
305 saveRemapped(*remapped, *it, Base::m_pano.getNrOfImages(), opts, advOptions);
306 } catch (vigra::PreconditionViolation & e) {
307 // this can be thrown, if an image
308 // is completely out of the pano
309 std::cerr << e.what();
310 }
311 // free remapped image
312 remapper.release(remapped);
313 i++;
314 }
315 finalizeOutputFile(opts);
317 }
318
321 {
322 Base::m_progress->setMessage("Multiple images output");
323 }
324
327 unsigned int imgNr, unsigned int nImg,
328 const PanoramaOptions & opts,
330 {
332
333 if (opts.saveCoordImgs) {
334 vigra::UInt16Image xImg;
335 vigra::UInt16Image yImg;
336
337 Base::m_progress->setMessage("creating coordinate images");
338
339 remapped.calcSrcCoordImgs(xImg, yImg);
340 vigra::UInt16Image dist;
341 if (! opts.tiff_saveROI) {
342 dist.resize(opts.getWidth(), opts.getHeight());
343 vigra::copyImage(srcImageRange(xImg),
344 vigra_ext::applyRect(remapped.boundingBox(),
345 destImage(dist)));
346 std::ostringstream filename2;
347 filename2 << m_basename << std::setfill('0') << std::setw(4) << imgNr << "_x.tif";
348
349 vigra::ImageExportInfo exinfo(filename2.str().c_str());
350 exinfo.setXResolution(150);
351 exinfo.setYResolution(150);
352 exinfo.setCompression(opts.tiffCompression.c_str());
353 vigra::exportImage(srcImageRange(dist), exinfo);
354
355
356 vigra::copyImage(srcImageRange(yImg),
357 vigra_ext::applyRect(remapped.boundingBox(),
358 destImage(dist)));
359 std::ostringstream filename3;
360 filename3 << m_basename << std::setfill('0') << std::setw(4) << imgNr << "_y.tif";
361
362 vigra::ImageExportInfo exinfo2(filename3.str().c_str());
363 exinfo2.setXResolution(150);
364 exinfo2.setYResolution(150);
365 exinfo2.setCompression(opts.tiffCompression.c_str());
366 vigra::exportImage(srcImageRange(dist), exinfo2);
367 } else {
368 std::ostringstream filename2;
369 filename2 << m_basename << std::setfill('0') << std::setw(4) << imgNr << "_x.tif";
370 vigra::ImageExportInfo exinfo(filename2.str().c_str());
371 exinfo.setXResolution(150);
372 exinfo.setYResolution(150);
373 exinfo.setCompression(opts.tiffCompression.c_str());
374 vigra::exportImage(srcImageRange(xImg), exinfo);
375 std::ostringstream filename3;
376 filename3 << m_basename << std::setfill('0') << std::setw(4) << imgNr << "_y.tif";
377 vigra::ImageExportInfo exinfo2(filename3.str().c_str());
378 exinfo2.setXResolution(150);
379 exinfo2.setYResolution(150);
380 exinfo2.setCompression(opts.tiffCompression.c_str());
381 vigra::exportImage(srcImageRange(yImg), exinfo2);
382 }
383 }
384 }
385
386 virtual void finalizeOutputFile(const PanoramaOptions & opts)
387 {
389 }
390
391protected:
392 std::string m_basename;
393};
394
395
396
398template <typename ImageType, typename AlphaImageType>
399class TiffMultiLayerRemapper : public MultiImageRemapper<ImageType, AlphaImageType>
400{
401public:
402
409
411 {
412 }
413
415 {
416 const std::string filename (Base::m_basename + ".tif");
417 DEBUG_DEBUG("Layering image into a multi image tif file " << filename);
418 Base::m_progress->setMessage("Multiple layer output");
419 m_tiff = TIFFOpen(filename.c_str(), GetAdvancedOption(advOptions, "useBigTIFF", false) ? "w8" : "w");
420 DEBUG_ASSERT(m_tiff && "could not open tiff output file");
421 }
422
425 unsigned int imgNr, unsigned int nImg,
426 const PanoramaOptions & opts,
428 {
429 if (remapped.boundingBox().isEmpty())
430 return;
431
432 DEBUG_DEBUG("Saving TIFF ROI");
434 Base::m_pano.getImage(imgNr).getFilename(),
436 opts.tiffCompression,
437 imgNr+1, nImg, remapped.boundingBox().upperLeft(),
438 opts.getROI().size(),
439 remapped.m_ICCProfile);
440 vigra_ext::createAlphaTiffImage(vigra::srcImageRange(remapped.m_image),
441 vigra::maskImage(remapped.m_mask),
442 m_tiff);
444 }
445
453
454
455protected:
456 vigra::TiffImage * m_tiff;
457};
458
459template <typename ImageType, typename AlphaType>
460class WeightedStitcher : public Stitcher<ImageType, AlphaType>
461{
462public:
463
470
471 virtual ~WeightedStitcher() {};
472
473 void stitch(const PanoramaOptions & opts, const UIntSet & imgSet,
474 const std::string & filename,
476 AlphaType& alpha,
479 {
480 const unsigned int nImg = imgSet.size();
481
482 Base::m_progress->setMessage("Remapping and stitching");
483
484 const bool wrap = (opts.getHFOV() == 360.0) && (opts.getWidth()==opts.getROI().width());
485 // remap each image and blend into main pano image
486 const bool hardSeam = GetAdvancedOption(advOptions, "hardSeam", true);
487 UIntVector images;
488 if(hardSeam)
489 {
490 std::copy(imgSet.begin(), imgSet.end(), std::back_inserter(images));
491 }
492 else
493 {
495 };
496 for (UIntVector::const_iterator it = images.begin(); it != images.end(); ++it)
497 {
498 // get a remapped image.
499 DEBUG_DEBUG("remapping image: " << *it);
501 if (GetAdvancedOption(advOptions, "ignoreExposure", false))
502 {
503 modOptions.outputExposureValue = Base::m_pano.getImage(*it).getExposureValue();
504 modOptions.outputRangeCompression = 0.0;
505 };
508 Base::m_rois[std::distance(imgSet.begin(), imgSet.find(*it))], Base::m_progress);
509 if(iccProfile.empty())
510 {
512 };
513 if (GetAdvancedOption(advOptions, "saveIntermediateImages", false))
514 {
515 modOptions.outputFormat = PanoramaOptions::TIFF_m;
516 modOptions.tiff_saveROI = true;
517 std::string finalFilename(GetAdvancedOption(advOptions, "basename", filename));
518 const std::string suffix(GetAdvancedOption(advOptions, "saveIntermediateImagesSuffix"));
519 if (!suffix.empty())
520 {
521 finalFilename.append(suffix);
522 };
524 }
525 Base::m_progress->setMessage("blending", hugin_utils::stripPath(Base::m_pano.getImage(*it).getFilename()));
526 // add image to pano and panoalpha, adjusts panoROI as well.
527 try {
528 vigra_ext::MergeImages<ImageType, AlphaType>(panoImage, alpha, remapped->m_image, remapped->m_mask, vigra::Diff2D(remapped->boundingBox().upperLeft()), wrap, hardSeam);
529 // update bounding box of the panorama
530 m_panoROI |= remapped->boundingBox();
531 } catch (vigra::PreconditionViolation & e) {
532 DEBUG_ERROR("exception during stitching" << e.what());
533 // this can be thrown, if an image
534 // is completely out of the pano
535 }
536 // free remapped image
537 remapper.release(remapped);
538 }
539 // check if our intermediate image covers whole canvas
540 // if not update m_panoROI
541 if (m_panoROI.width() < opts.getROI().width() || m_panoROI.height() < opts.getROI().height())
542 {
543 // update m_panoROI
544 m_panoROI = opts.getROI();
545 }
546 }
547
548 void stitch(const PanoramaOptions & opts, const UIntSet & imgSet,
549 const std::string & filename,
552 {
553 Base::stitch(opts, imgSet, filename, remapper);
554
555 std::string basename = filename;
556
557 // create panorama canvas
558 ImageType pano(opts.getWidth(), opts.getHeight());
559 AlphaType panoMask(opts.getWidth(), opts.getHeight());
560
561 stitch(opts, imgSet, filename, pano, panoMask, remapper, advOptions);
562
563 std::string ext = opts.getOutputExtension();
564 std::string cext = hugin_utils::tolower(hugin_utils::getExtension(basename));
565 std::transform(cext.begin(),cext.end(), cext.begin(), (int(*)(int))std::tolower);
566 // remove extension only if it specifies the same file type, otherwise
567 // its probably part of the filename.
568 if (cext == ext) {
569 basename = hugin_utils::stripExtension(basename);
570 }
571 std::string outputfile(basename);
572 // append suffix if given
573 const std::string suffix = GetAdvancedOption(advOptions, "saveFinalImageSuffix", std::string());
574 if (!suffix.empty())
575 {
576 outputfile.append(suffix);
577 };
578 outputfile.append("." + ext);
579
580 // save the remapped image
582 DEBUG_DEBUG("Saving panorama: " << outputfile);
583 vigra::ImageExportInfo exinfo(outputfile.c_str(), GetAdvancedOption(advOptions, "useBigTIFF", false) ? "w8" : "w");
584 exinfo.setXResolution(150);
585 exinfo.setYResolution(150);
586 exinfo.setICCProfile(iccProfile);
587 if (!opts.outputPixelType.empty()) {
588 exinfo.setPixelType(opts.outputPixelType.c_str());
589 }
590
591 // set compression quality for jpeg images.
593 std::ostringstream quality;
594 quality << "JPEG QUALITY=" << opts.quality;
595 exinfo.setCompression(quality.str().c_str());
596 // scale down to UInt8 if necessary
598 // force 8 bit depth for jpeg output
599 exinfo.setPixelType("UINT8");
600 vigra::exportImage(srcImageRange(pano, m_panoROI), exinfo);
601 } else if (opts.outputFormat == PanoramaOptions::TIFF) {
602 exinfo.setCompression(opts.tiffCompression.c_str());
603 exinfo.setCanvasSize(pano.size());
604 exinfo.setPosition(m_panoROI.upperLeft());
605 vigra::exportImageAlpha(srcImageRange(pano, m_panoROI),
606 srcImage(panoMask, m_panoROI.upperLeft()), exinfo);
607 } else if (opts.outputFormat == PanoramaOptions::HDR) {
608 exinfo.setPixelType("FLOAT");
609 vigra::exportImage(srcImageRange(pano), exinfo);
610 } else {
611 vigra::exportImageAlpha(srcImageRange(pano, m_panoROI),
612 srcImage(panoMask, m_panoROI.upperLeft()), exinfo);
613 }
614 /*
615#ifdef DEBUG
616 vigra::exportImage(srcImageRange(panoMask), vigra::ImageExportInfo("pano_alpha.tif"));
617#endif
618 */
619 }
620
621 vigra::Rect2D GetPanoROI() const
622 {
623 return m_panoROI;
624 }
625 vigra::ImageImportInfo::ICCProfile GetICCProfile() const
626 {
627 return iccProfile;
628 };
629protected:
630 vigra::ImageImportInfo::ICCProfile iccProfile;
631 vigra::Rect2D m_panoROI;
632};
633
634
636template<class VALUETYPE>
638{
641 typedef typename vigra::NumericTraits<argument_type> Traits;
642 typedef typename Traits::RealPromote float_type;
643
644
646 {
647 reset();
648 }
649
650 void reset()
651 {
652 sum = vigra::NumericTraits<float_type>::zero();
653 values.clear();
654 }
655
656 template<class T, class M>
657 void operator() (T const &v, M const &a)
658 {
659 if (a) {
660 values.push_back(v);
661 sum = sum + v;
662 }
663 }
664
667 {
668 typedef typename std::vector<float_type>::const_iterator Iter;
669 if (values.size() > 1) {
670 float_type mean = sum / values.size();
671 float_type error = vigra::NumericTraits<float_type>::zero();
672 for (Iter it= values.begin(); it != values.end(); ++it) {
673 error += vigra::abs(*it-mean);
674 }
675 return error;
676 } else {
677 return sum;
678 }
679 }
680 std::vector<float_type> values;
682};
683
688template <typename ImageType, typename AlphaType>
689class ReduceStitcher : public Stitcher<ImageType, AlphaType>
690{
692public:
698
700 {
701 }
702
703 template <class FUNCTOR>
704 void stitch(const PanoramaOptions & opts, const UIntSet & imgSet,
705 const std::string & filename,
707 FUNCTOR & reduce,
709 {
710 Base::stitch(opts, imgSet, filename, remapper);
711
712 std::string basename = filename;
713
714 // create panorama canvas
715 ImageType pano(opts.getWidth(), opts.getHeight());
716 AlphaType panoMask(opts.getWidth(), opts.getHeight());
717
718 stitch(opts, imgSet, vigra::destImageRange(pano), vigra::destImage(panoMask),
719 remapper, reduce);
720
721 std::string ext = opts.getOutputExtension();
722 std::string cext = hugin_utils::tolower(hugin_utils::getExtension(basename));
723 // remove extension only if it specifies the same file type, otherwise
724 // its probably part of the filename.
725 if (cext == ext) {
726 basename = hugin_utils::stripExtension(basename);
727 }
728 std::string outputfile = basename + "." + ext;
729
730// Base::m_progress.setMessage("saving result: " + hugin_utils::stripPath(outputfile));
731 DEBUG_DEBUG("Saving panorama: " << outputfile);
732 vigra::ImageExportInfo exinfo(outputfile.c_str(), GetAdvancedOption(advOptions, "useBigTIFF", false) ? "w8" : "w");
733 if (!opts.outputPixelType.empty()) {
734 exinfo.setPixelType(opts.outputPixelType.c_str());
735 }
736 exinfo.setXResolution(150);
737 exinfo.setYResolution(150);
738 exinfo.setICCProfile(iccProfile);
739 // set compression quality for jpeg images.
741 std::ostringstream quality;
742 quality << "JPEG QUALITY=" << opts.quality;
743 exinfo.setCompression(quality.str().c_str());
744 vigra::exportImage(srcImageRange(pano), exinfo);
745 } else if (opts.outputFormat == PanoramaOptions::TIFF) {
746 exinfo.setCompression(opts.tiffCompression.c_str());
747 vigra::exportImageAlpha(srcImageRange(pano),
748 srcImage(panoMask), exinfo);
749 } else if (opts.outputFormat == PanoramaOptions::HDR) {
750 vigra::exportImage(srcImageRange(pano), exinfo);
751 } else {
752 vigra::exportImageAlpha(srcImageRange(pano),
753 srcImage(panoMask), exinfo);
754 }
755 /*
756#ifdef DEBUG
757 vigra::exportImage(srcImageRange(panoMask), vigra::ImageExportInfo("pano_alpha.tif"));
758#endif
759 */
760 }
761
762
763 template<class ImgIter, class ImgAccessor,
764 class AlphaIter, class AlphaAccessor,
765 class FUNCTOR>
766 void stitch(const PanoramaOptions & opts, const UIntSet & imgSet,
767 vigra::triple<ImgIter, ImgIter, ImgAccessor> pano,
768 std::pair<AlphaIter, AlphaAccessor> alpha,
770 FUNCTOR & reduce)
771 {
772 typedef typename vigra::NumericTraits<typename ImageType::value_type> Traits;
773 typedef typename AlphaAccessor::value_type MaskType;
774
775 Base::stitch(opts, imgSet, "dummy", remapper);
776
777 // remap all images..
778 typedef std::vector<RemappedPanoImage<ImageType, AlphaType> *> RemappedVector;
779 unsigned int nImg = imgSet.size();
780
781 Base::m_progress->setMessage("Stitching");
782 // empty ROI
783 // vigra::Rect2D panoROI;
784 // remap all images..
786
787 int i=0;
788 // remap each image and blend into main pano image
789 for (UIntSet::const_iterator it = imgSet.begin();
790 it != imgSet.end(); ++it)
791 {
792 // get a copy of the remapped image.
793 // not very good, keeps all images in memory,
794 // but should be enought for the preview.
795 remapped[i] = remapper.getRemapped(Base::m_pano, opts, *it,
797 if(iccProfile.empty())
798 {
800 };
801 i++;
802 }
803 vigra::Diff2D size = pano.second - pano.first;
804 ImgIter output = pano.first;
805 // iterate over the whole image...
806 // calculate something on the pixels that belong together..
807 for (int y=0; y < size.y; y++) {
808 for (int x=0; x < size.x; x++) {
809 reduce.reset();
810 MaskType maskRes=0;
811 for (unsigned int i=0; i< nImg; i++) {
812 MaskType a = remapped[i]->getMask(x,y);
813 if (a) {
815 reduce(remapped[i]->operator()(x,y), a);
816 }
817 }
818 pano.third.set(Traits::fromRealPromote(reduce()), output, vigra::Diff2D(x,y));
819 alpha.second.set(maskRes, alpha.first, vigra::Diff2D(x,y));
820 }
821 }
822
823 for (typename RemappedVector::iterator it=remapped.begin();
824 it != remapped.end(); ++it)
825 {
826 remapper.release(*it);
827 }
828 }
829
830public:
831 vigra::ImageImportInfo::ICCProfile iccProfile;
832};
833
836template <typename ImageType, typename AlphaType>
837class SimpleStitcher : public Stitcher<ImageType, AlphaType>
838{
840public:
846
848 {
849 }
850
851 template<class ImgIter, class ImgAccessor,
852 class AlphaIter, class AlphaAccessor,
853 class BlendFunctor>
854 void stitch(const PanoramaOptions & opts, const UIntSet & imgSet,
855 vigra::triple<ImgIter, ImgIter, ImgAccessor> pano,
856 std::pair<AlphaIter, AlphaAccessor> alpha,
859 {
862
863 Base::m_progress->setMessage("Remapping and stitching with watershed algorithm");
864 // empty ROI
865 vigra::Rect2D panoROI;
866
867 unsigned i=0;
868 // remap each image and blend into main pano image
869 for (UIntSet::reverse_iterator it = imgSet.rbegin();
870 it != imgSet.rend(); ++it)
871 {
872 // get a remapped image.
874 remapped = remapper.getRemapped(Base::m_pano, opts, *it,
876 if (iccProfile.empty()) {
877 // try to extract icc profile.
879 }
880 Base::m_progress->setMessage("blending");
881 // add image to pano and panoalpha, adjusts panoROI as well.
882 try {
883 blend(*remapped, pano, alpha, panoROI);
884 // update bounding box of the panorama
885 panoROI = panoROI | remapped->boundingBox();
886 } catch (vigra::PreconditionViolation & e) {
887 // this can be thrown, if an image
888 // is completely out of the pano
889 std::cerr << e.what();
890 }
891 // free remapped image
892 remapper.release(remapped);
893 i++;
894 }
896 }
897
898 template <class BlendFunctor>
899 void stitch(const PanoramaOptions & opts, const UIntSet & imgSet,
900 const std::string & filename,
903 {
904 std::string basename = filename;
905
906 // create panorama canvas
907 ImageType pano(opts.getWidth(), opts.getHeight());
908 AlphaType panoMask(opts.getWidth(), opts.getHeight());
909
910 stitch(opts, imgSet, vigra::destImageRange(pano), vigra::destImage(panoMask), remapper, blend);
911
912 std::string ext = opts.getOutputExtension();
913 std::string cext = hugin_utils::tolower(hugin_utils::getExtension(basename));
914 // remove extension only if it specifies the same file type, otherwise
915 // its probably part of the filename.
916 if (cext == ext) {
917 basename = hugin_utils::stripExtension(basename);
918 }
919 std::string outputfile = basename + "." + ext;
920
922 DEBUG_DEBUG("Saving panorama: " << outputfile);
923 vigra::ImageExportInfo exinfo(outputfile.c_str());
924 exinfo.setXResolution(150);
925 exinfo.setYResolution(150);
926 exinfo.setICCProfile(iccProfile);
927 // set compression quality for jpeg images.
929 std::ostringstream quality;
930 quality << "JPEG QUALITY=" << opts.quality;
931 exinfo.setCompression(quality.str().c_str());
932 vigra::exportImage(srcImageRange(pano), exinfo);
933 } else if (opts.outputFormat == PanoramaOptions::TIFF) {
934 exinfo.setCompression("DEFLATE");
935 vigra::exportImageAlpha(srcImageRange(pano),
936 srcImage(panoMask), exinfo);
937 } else {
938 vigra::exportImageAlpha(srcImageRange(pano),
939 srcImage(panoMask), exinfo);
940 }
941 /*
942#ifdef DEBUG
943 vigra::exportImage(srcImageRange(panoMask), vigra::ImageExportInfo("pano_alpha.tif"));
944#endif
945 */
946 Base::m_progress.popTask();
947
948 }
949public:
950 vigra::ImageExportInfo::ICCProfile iccProfile;
951};
952
957{
958
959public:
964 template <typename ImageType, typename AlphaType,
965 typename PanoIter, typename PanoAccessor,
966 typename AlphaIter, typename AlphaAccessor>
968 vigra::triple<PanoIter, PanoIter, PanoAccessor> pano,
969 std::pair<AlphaIter, AlphaAccessor> alpha,
970 const vigra::Rect2D & panoROI)
971 {
972 DEBUG_DEBUG("pano roi: " << panoROI << " img roi: " << img.boundingBox());
973
974// DEBUG_DEBUG("no overlap, copying upper area. imgroi " << img.roi());
975// DEBUG_DEBUG("pano roi: " << panoROI.upperLeft() << " -> " << panoROI.lowerRight());
976 DEBUG_DEBUG("size of panorama: " << pano.second - pano.first);
977
978 // check if bounding box of image is outside of panorama...
979 vigra::Rect2D fullPano(vigra::Size2D(pano.second-pano.first));
980 // blend only the intersection (which is inside the pano..)
981 vigra::Rect2D overlap = fullPano & img.boundingBox();
982
983 vigra::copyImageIf(vigra_ext::applyRect(overlap, vigra_ext::srcImageRange(img)),
985 vigra_ext::applyRect(overlap, std::make_pair(pano.first, pano.third)));
986 // copy mask
987 vigra::copyImageIf(vigra_ext::applyRect(overlap, srcMaskRange(img)),
988 vigra_ext::applyRect(overlap, srcMask(img)),
990 }
991};
992
993template<typename ImageType, typename AlphaType>
994static void stitchPanoIntern(const PanoramaData & pano,
995 const PanoramaOptions & opts,
997 const std::string & basename,
998 UIntSet imgs,
1000{
1002 // determine stitching output
1003 switch (opts.outputFormat) {
1009 {
1013 stitcher.stitch(opts, imgs, basename, m, hdrmerge, advOptions);
1014 } else {
1017 stitcher.stitch(opts, imgs, basename, m, advOptions);
1018 }
1019 break;
1020 }
1026 {
1029 stitcher.stitch(opts, imgs, basename, m, advOptions);
1030 break;
1031 }
1033 {
1035 stitcher.stitch(opts, imgs, basename, m, advOptions);
1036 break;
1037 }
1040 DEBUG_ERROR("multi mask stitching not implemented!");
1041 break;
1042 default:
1043 DEBUG_ERROR("output format " << opts.getFormatName(opts.outputFormat) << "not supported");
1044 break;
1045 }
1046}
1047
1054IMPEX void stitchPanorama(const PanoramaData & pano,
1055 const PanoramaOptions & opts,
1057 const std::string & basename,
1058 const UIntSet & usedImgs,
1060
1061// the instantiations of the stitching functions have been divided into two .cpp
1062// files, because g++ will use too much memory otherwise (> 1.5 GB)
1063
1064void stitchPanoGray_8_16(const PanoramaData & pano,
1065 const PanoramaOptions & opts,
1067 const std::string & basename,
1068 const UIntSet & usedImgs,
1069 const char * pixelType,
1071
1072void stitchPanoGray_32_float(const PanoramaData & pano,
1073 const PanoramaOptions & opts,
1075 const std::string & basename,
1076 const UIntSet & usedImgs,
1077 const char * pixelType,
1079
1080
1081void stitchPanoRGB_8_16(const PanoramaData & pano,
1082 const PanoramaOptions & opts,
1084 const std::string & basename,
1085 const UIntSet & usedImgs,
1086 const char * pixelType,
1088
1089void stitchPanoRGB_32_float(const PanoramaData & pano,
1090 const PanoramaOptions & opts,
1092 const std::string & basename,
1093 const UIntSet & usedImgs,
1094 const char * pixelType,
1096
1097} // namespace
1098} // namespace
1099
1100#endif // _H
Contains functions to transform whole images.
declaration of functions to handle stacks and layers
Contains functions to transform whole images.
Helper class for storing different options.
void setMessage(const std::string &message, const std::string &filename="")
sets the message to given string
void taskFinished()
call when a task has finished and the status message should be cleared
static std::vector< vigra::Rect2D > computeROIS(const PanoramaData &panorama, const PanoramaOptions &opts, const UIntSet &images)
functor to create a remapped image, loads image from disk
remap a set of images, and store the individual remapped files.
Definition Stitcher.h:256
virtual void stitch(const PanoramaOptions &opts, const UIntSet &images, const std::string &basename, SingleImageRemapper< ImageType, AlphaType > &remapper, const AdvancedOptions &advOptions)
Definition Stitcher.h:271
virtual void finalizeOutputFile(const PanoramaOptions &opts)
Definition Stitcher.h:386
MultiImageRemapper(const PanoramaData &pano, AppBase::ProgressDisplay *progress)
Definition Stitcher.h:261
virtual void saveRemapped(RemappedPanoImage< ImageType, AlphaType > &remapped, unsigned int imgNr, unsigned int nImg, const PanoramaOptions &opts, const AdvancedOptions &advOptions)
save a remapped image, or layer
Definition Stitcher.h:326
Stitcher< ImageType, AlphaType > Base
Definition Stitcher.h:259
virtual void prepareOutputFile(const PanoramaOptions &opts, const AdvancedOptions &advOptions)
prepare the output file (setup file structures etc.)
Definition Stitcher.h:320
create a panorama using the reduce operation on all overlapping pixels.
Definition Stitcher.h:690
ReduceStitcher(const PanoramaData &pano, AppBase::ProgressDisplay *progress)
Definition Stitcher.h:693
Stitcher< ImageType, AlphaType > Base
Definition Stitcher.h:691
void stitch(const PanoramaOptions &opts, const UIntSet &imgSet, vigra::triple< ImgIter, ImgIter, ImgAccessor > pano, std::pair< AlphaIter, AlphaAccessor > alpha, SingleImageRemapper< ImageType, AlphaType > &remapper, FUNCTOR &reduce)
Definition Stitcher.h:766
vigra::ImageImportInfo::ICCProfile iccProfile
Definition Stitcher.h:831
void stitch(const PanoramaOptions &opts, const UIntSet &imgSet, const std::string &filename, SingleImageRemapper< ImageType, AlphaType > &remapper, FUNCTOR &reduce, const AdvancedOptions &advOptions)
Definition Stitcher.h:704
struct to hold a image state for stitching
vigra::ImageImportInfo::ICCProfile m_ICCProfile
A stitcher without seaming, just copies the images over each other.
Definition Stitcher.h:838
vigra::ImageExportInfo::ICCProfile iccProfile
Definition Stitcher.h:950
Stitcher< ImageType, AlphaType > Base
Definition Stitcher.h:839
SimpleStitcher(const PanoramaData &pano, AppBase::ProgressDisplay *progress)
Definition Stitcher.h:841
void stitch(const PanoramaOptions &opts, const UIntSet &imgSet, const std::string &filename, SingleImageRemapper< ImageType, AlphaType > &remapper, BlendFunctor &blend)
Definition Stitcher.h:899
void stitch(const PanoramaOptions &opts, const UIntSet &imgSet, vigra::triple< ImgIter, ImgIter, ImgAccessor > pano, std::pair< AlphaIter, AlphaAccessor > alpha, SingleImageRemapper< ImageType, AlphaType > &remapper, BlendFunctor &blend)
Definition Stitcher.h:854
functor to create a remapped image
void setAdvancedOptions(const HuginBase::Nona::AdvancedOptions advancedOptions)
virtual void release(RemappedPanoImage< ImageType, AlphaType > *d)=0
virtual RemappedPanoImage< ImageType, AlphaType > * getRemapped(const PanoramaData &pano, const PanoramaOptions &opts, unsigned int imgNr, vigra::Rect2D outputROI, AppBase::ProgressDisplay *progress)=0
create a remapped pano image.
implements a stitching algorithm
Definition Stitcher.h:71
std::vector< vigra::Rect2D > m_rois
Definition Stitcher.h:122
void init(const PanoramaOptions &opts, const UIntSet &images)
Definition Stitcher.h:92
Stitcher(const PanoramaData &pano, AppBase::ProgressDisplay *progress)
create a stitcher for the given panorama
Definition Stitcher.h:74
const PanoramaData & m_pano
Definition Stitcher.h:119
virtual void calcOutputROIS(const PanoramaOptions &opts, const UIntSet &images)
Definition Stitcher.h:114
virtual UIntSet getUsedImages()
Definition Stitcher.h:99
AppBase::ProgressDisplay * m_progress
Definition Stitcher.h:120
virtual void stitch(const PanoramaOptions &opts, const UIntSet &images, const std::string &file, SingleImageRemapper< ImageType, AlphaType > &remapper)
Stitch some images into a panorama file.
Definition Stitcher.h:85
TiffMultiLayerRemapper(const PanoramaData &pano, AppBase::ProgressDisplay *progress)
Definition Stitcher.h:404
virtual void finalizeOutputFile(const PanoramaOptions &opts)
close the tiff file
Definition Stitcher.h:447
MultiImageRemapper< ImageType, AlphaImageType > Base
Definition Stitcher.h:403
virtual void saveRemapped(RemappedPanoImage< ImageType, AlphaImageType > &remapped, unsigned int imgNr, unsigned int nImg, const PanoramaOptions &opts, const AdvancedOptions &advOptions)
save the remapped image in a partial tiff layer
Definition Stitcher.h:424
virtual void prepareOutputFile(const PanoramaOptions &opts, const AdvancedOptions &advOptions)
prepare the output file (setup file structures etc.)
Definition Stitcher.h:414
vigra::ImageImportInfo::ICCProfile GetICCProfile() const
Definition Stitcher.h:625
void stitch(const PanoramaOptions &opts, const UIntSet &imgSet, const std::string &filename, SingleImageRemapper< ImageType, AlphaType > &remapper, const AdvancedOptions &advOptions)
Definition Stitcher.h:548
WeightedStitcher(const PanoramaData &pano, AppBase::ProgressDisplay *progress)
Definition Stitcher.h:465
vigra::ImageImportInfo::ICCProfile iccProfile
Definition Stitcher.h:630
vigra::Rect2D GetPanoROI() const
Definition Stitcher.h:621
void stitch(const PanoramaOptions &opts, const UIntSet &imgSet, const std::string &filename, ImageType &panoImage, AlphaType &alpha, SingleImageRemapper< ImageType, AlphaType > &remapper, const AdvancedOptions &advOptions)
Definition Stitcher.h:473
Stitcher< ImageType, AlphaType > Base
Definition Stitcher.h:464
Model for a panorama.
virtual const SrcPanoImage & getImage(std::size_t nr) const =0
get a panorama image, counting starts with 0
Panorama image options.
static const std::string & getFormatName(FileFormat f)
return string name of output file format
const std::string & getOutputExtension() const
return the extension used by the current output format
const vigra::Rect2D & getROI() const
unsigned int getWidth() const
unsigned int getHeight() const
get panorama height
vigra::Rect2D & boundingBox()
Definition ROIImage.h:238
class AlphaIterator class AlphaAccessor inline void exportImageAlpha(ImageIterator image_upper_left, ImageIterator image_lower_right, ImageAccessor image_accessor, AlphaIterator alpha_upper_left, AlphaAccessor alpha_accessor, const ImageExportInfo &export_info)
vigra::FRGBImage ImageType
#define IMPEX
#define DEBUG_ERROR(msg)
Definition utils.h:76
#define DEBUG_ASSERT(cond)
Definition utils.h:80
#define DEBUG_DEBUG(msg)
Definition utils.h:68
void saveRemapped(RemappedPanoImage< ImageType, AlphaType > &remapped, unsigned int imgNr, unsigned int nImg, const PanoramaOptions &opts, const std::string &basename, const bool useBigTIFF, AppBase::ProgressDisplay *progress)
Definition Stitcher.h:128
void stitchPanoRGB_32_float(const PanoramaData &pano, const PanoramaOptions &opts, AppBase::ProgressDisplay *progress, const std::string &basename, const UIntSet &usedImgs, const char *pixelType, const AdvancedOptions &advOptions)
Definition Stitcher4.cpp:34
void stitchPanoGray_32_float(const PanoramaData &pano, const PanoramaOptions &opts, AppBase::ProgressDisplay *progress, const std::string &basename, const UIntSet &usedImgs, const char *pixelType, const AdvancedOptions &advOptions)
Definition Stitcher1.cpp:28
std::map< std::string, std::string > AdvancedOptions
void stitchPanorama(const PanoramaData &pano, const PanoramaOptions &opt, AppBase::ProgressDisplay *progress, const std::string &basename, const UIntSet &usedImgs, const AdvancedOptions &advOptions)
The main stitching function.
Definition Stitcher.cpp:40
void stitchPanoRGB_8_16(const PanoramaData &pano, const PanoramaOptions &opts, AppBase::ProgressDisplay *progress, const std::string &basename, const UIntSet &usedImgs, const char *pixelType, const AdvancedOptions &advOptions)
Definition Stitcher3.cpp:28
static void stitchPanoIntern(const PanoramaData &pano, const PanoramaOptions &opts, AppBase::ProgressDisplay *progress, const std::string &basename, UIntSet imgs, const AdvancedOptions &advOptions)
Definition Stitcher.h:994
bool GetAdvancedOption(const AdvancedOptions &opts, const std::string &name, const bool defaultValue)
check if given option is saved and return its boolean value, otherwise return defaultValue
void stitchPanoGray_8_16(const PanoramaData &pano, const PanoramaOptions &opts, AppBase::ProgressDisplay *progress, const std::string &basename, const UIntSet &usedImgs, const char *pixelType, const AdvancedOptions &advOptions)
Definition Stitcher2.cpp:28
mainly consists of wrapper around the pano tools library, to assist in ressource management and to pr...
Definition wxcms.cpp:39
std::vector< unsigned int > UIntVector
UIntVector getEstimatedBlendingOrder(const PanoramaData &pano, const UIntSet &images, const unsigned int referenceImage)
returns vector of image numbers for blending in approbiate order
std::set< unsigned int > UIntSet
std::string stripExtension(const std::string &basename2)
remove extension of a filename
Definition utils.cpp:130
std::string getExtension(const std::string &basename2)
Get extension of a filename.
Definition utils.cpp:99
std::string tolower(const std::string &s)
convert a string to lowercase
Definition stl_utils.h:49
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
Definition utils.cpp:160
void createTiffDirectory(vigra::TiffImage *tiff, const std::string &pagename, const std::string &documentname, const std::string comp, uint16_t page, uint16_t nImg, vigra::Diff2D offset, vigra::Size2D fullSize, const vigra::ImageExportInfo::ICCProfile &icc)
write a new Tiff directory, for a new layer
Definition tiffUtils.h:58
void createAlphaTiffImage(ImageIterator upperleft, ImageIterator lowerright, ImageAccessor a, AlphaIterator alphaUpperleft, AlphaAccessor alphaA, vigra::TiffImage *tiff)
Definition tiffUtils.h:522
void ConvertTo8Bit(ImageType &image)
converts to given image to fit into 0..255
Definition utils.h:757
vigra::pair< typename ROIImage< Image, Alpha >::mask_const_traverser, typename ROIImage< Image, Alpha >::MaskConstAccessor > srcMask(const ROIImage< Image, Alpha > &img)
Definition ROIImage.h:347
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
Definition ROIImage.h:287
vigra::triple< typename ROIImage< Image, Alpha >::mask_const_traverser, typename ROIImage< Image, Alpha >::mask_const_traverser, typename ROIImage< Image, Alpha >::MaskConstAccessor > srcMaskRange(const ROIImage< Image, Alpha > &img)
Definition ROIImage.h:335
vigra::triple< ImgIter, ImgIter, ImgAcc > applyRect(vigra::Rect2D &r, vigra::triple< ImgIter, ImgIter, ImgAcc > img)
apply a roi to an image area
Definition ROIImage.h:46
float_type operator()() const
return the result
Definition Stitcher.h:666
std::vector< float_type > values
Definition Stitcher.h:680
vigra::NumericTraits< argument_type > Traits
Definition Stitcher.h:641
blend images, by simply stacking them, without soft blending or boundary calculation
Definition Stitcher.h:957
void operator()(RemappedPanoImage< ImageType, AlphaType > &img, vigra::triple< PanoIter, PanoIter, PanoAccessor > pano, std::pair< AlphaIter, AlphaAccessor > alpha, const vigra::Rect2D &panoROI)
blend img into pano, using alpha mask and panoROI
Definition Stitcher.h:967
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41
Some functions to create tiff images with masks.