Hugin trunk 0.1
Loading...
Searching...
No Matches
RemappedPanoImage.h
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
27#ifndef _NONA_REMAPPEDPANOIMAGE_H
28#define _NONA_REMAPPEDPANOIMAGE_H
29
30#include <vigra/imageinfo.hxx>
31#include <vigra/initimage.hxx>
32#include <vigra/copyimage.hxx>
33#include <vigra/flatmorphology.hxx>
34#include <vigra_ext/ROIImage.h>
36
39
41#include <panodata/Mask.h>
44
45// default values for exposure cutoff
46#define NONA_DEFAULT_EXPOSURE_LOWER_CUTOFF 1/255.0f
47#define NONA_DEFAULT_EXPOSURE_UPPER_CUTOFF 250/255.0f
48
49
50namespace HuginBase {
51namespace Nona {
52
53
60template <class TRANSFORM>
62 const PanoramaOptions & dest,
64 vigra::Rect2D & imgRect);
65
67template <class TRANSFORM>
69 const PanoramaOptions & dest,
71 vigra::Rect2D & imgRect,
72 vigra::BImage & alpha,
73 double & scale);
74
75
79template <class RemapImage, class AlphaImage>
80class RemappedPanoImage : public vigra_ext::ROIImage<RemapImage, AlphaImage>
81{
82
84
85 public:
86 // typedefs for the children types
87 typedef typename RemapImage::value_type image_value_type;
88 typedef typename RemapImage::traverser image_traverser;
89 typedef typename RemapImage::const_traverser const_image_traverser;
90 typedef typename RemapImage::Accessor ImageAccessor;
91 typedef typename RemapImage::ConstAccessor ConstImageAccessor;
92
93 typedef typename AlphaImage::value_type mask_value_type;
94 typedef typename AlphaImage::traverser mask_traverser;
95 typedef typename AlphaImage::const_traverser const_mask_traverser;
96 typedef typename AlphaImage::Accessor MaskAccessor;
97 typedef typename AlphaImage::ConstAccessor ConstMaskAccessor;
98
100
101
102 public:
109
110
111 public:
114 const PanoramaOptions & dest,
115 vigra::Rect2D roi);
120
121 public:
126 template<class DistImgType>
128
137 void calcAlpha();
138
140 template <class ImgIter, class ImgAccessor>
141 void remapImage(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
144
145
147 template <class ImgIter, class ImgAccessor,
148 class AlphaIter, class AlphaAccessor>
149 void remapImage(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
150 std::pair<AlphaIter, AlphaAccessor> alphaImg,
153
154
155 public:
157 vigra::ImageImportInfo::ICCProfile m_ICCProfile;
158
159 protected:
164
165};
166
167
168
171template <class SrcImgType, class FlatImgType, class DestImgType, class MaskImgType>
173 const MaskImgType & srcAlpha,
174 const FlatImgType & srcFlat,
175 const SrcPanoImage & src,
176 const PanoramaOptions & dest,
177 vigra::Rect2D outputRect,
180
181
182} // namespace
183} // namespace
184
185
186
187//==============================================================================
188// templated implementations
189
190
194
195// #define DEBUG_REMAP 1
196
197#ifdef DEBUG_REMAP
198#include <vigra/impex.hxx> // for vigra::exportImage()
199#ifdef _WIN32
200#define DEBUG_FILE_PREFIX "C:/temp/"
201#else
202#define DEBUG_FILE_PREFIX "/tmp/"
203#endif
204#endif
205
206
207namespace HuginBase {
208namespace Nona {
209
210
211template <class RemapImage, class AlphaImage>
213 const PanoramaOptions & dest, vigra::Rect2D roi)
214{
215 // restrict to panorama size
216 m_srcImg = src;
217 m_destImg = dest;
218
219 if (m_destImg.remapUsingGPU) {
220 // Make width multiple of 8 for fast GPU transfers.
221 const int r = roi.width() % 8;
222 if (r != 0) roi.addSize(vigra::Size2D(8 - r, 0));
223 }
224
225 Base::resize(roi);
226 m_transf.createTransform(src, dest);
227
228 DEBUG_DEBUG("after resize: " << Base::m_region);
229 DEBUG_DEBUG("m_srcImg size: " << m_srcImg.getSize());
230}
231
232
233#if 0
240template <class RemapImage, class AlphaImage>
242 const PanoCommand::VariableMap & srcVars,
243 PanoCommand::Lens::LensProjectionFormat srcProj,
244 const PanoCommand::PanoImage & img,
245 const vigra::Diff2D &destSize,
247 double destHFOV)
248{
250 m_srcOrigSize.x = img.getWidth();
251 m_srcOrigSize.y = img.getHeight();
253
254
255 m_srcPanoImg = img;
258 // create transforms
259 // SpaceTransform t;
260 // SpaceTransform invT;
261 /*
262 m_invTransf.createInvTransform(srcSize, srcVars, srcProj,
263 destSize, destProj, destHFOV,
264 m_srcOrigSize);
265 */
266 // calculate ROI for this image.
267 m_transf.createTransform(srcSize, srcVars, srcProj,
270
271 ImageOptions imgOpts = img.getOptions();
272
273 // todo: resize crop!
274 bool circCrop = srcProj == Lens::CIRCULAR_FISHEYE;
276 imgOpts.docrop, imgOpts.cropRect, circCrop,
277 m_transf,
278 imageRect);
279
280 m_warparound = (destProj == PanoramaOptions::EQUIRECTANGULAR && m_destHFOV == 360);
281
282
283}
284
285template <class RemapImage, class AlphaImage>
287 vigra::Size2D srcSize, const HuginBase::PanoramaOptions & opts)
288{
289 const PanoCommand::PanoImage & img = pano.getImage(imgNr);
290
292 m_srcOrigSize.x = img.getWidth();
293 m_srcOrigSize.y = img.getHeight();
294 m_srcProj = pano.getLens(pano.getImage(imgNr).getLensNr()).getProjection();
295
296 m_destProj = opts.getProjection();
297 m_destHFOV = opts.getHFOV();
298 m_warparound = (opts.getProjection() == PanoramaOptions::EQUIRECTANGULAR && opts.getHFOV() == 360);
299
300 // create transforms
301 // SpaceTransform t;
302 // SpaceTransform invT;
303
304// m_invTransf.createInvTransform(pano, imgNr, opts, m_srcSize);
305 m_transf.createTransform(pano, imgNr, opts, m_srcSize);
306
307 // calculate ROI for this image.
308 m_srcPanoImg = pano.getImage(imgNr);
309 ImageOptions imgOpts = pano.getImage(imgNr).getOptions();
310 vigra::Rect2D imageRect;
311 // todo: resize crop!
312 bool circCrop = pano.getLens(pano.getImage(imgNr).getLensNr()).getProjection() == Lens::CIRCULAR_FISHEYE;
313 estimateImageRect(vigra::Size2D(opts.getWidth(), opts.getHeight()), srcSize,
314 imgOpts.docrop, imgOpts.cropRect, circCrop,
315 m_transf,
316 imageRect);
317
318
319 // restrict to panorama size
320 Base::resize(imageRect);
321 DEBUG_DEBUG("after resize: " << Base::m_region);
322}
323#endif
324
325
330template<class RemapImage, class AlphaImage>
331template<class DistImgType>
333{
334 if (Base::boundingBox().isEmpty()) return;
335 imgX.resize(Base::boundingBox().size().width(), Base::boundingBox().size().height(), vigra::NumericTraits<typename DistImgType::value_type>::max());
336 imgY.resize(Base::boundingBox().size().width(), Base::boundingBox().size().height(), vigra::NumericTraits<typename DistImgType::value_type>::max());
337 // calculate the alpha channel,
338 int xstart = Base::boundingBox().left();
339 int xend = Base::boundingBox().right();
340 int ystart = Base::boundingBox().top();
341 int yend = Base::boundingBox().bottom();
342
343 // create dist y iterator
344 typename DistImgType::Iterator yImgX(imgX.upperLeft());
345 typename DistImgType::Iterator yImgY(imgY.upperLeft());
346 typename DistImgType::Accessor accX = imgX.accessor();
347 typename DistImgType::Accessor accY = imgY.accessor();
348 // loop over the image and transform
349 for(int y=ystart; y < yend; ++y, ++yImgX.y, ++yImgY.y)
350 {
351 // create x iterators
352 typename DistImgType::Iterator xImgX(yImgX);
353 typename DistImgType::Iterator xImgY(yImgY);
354 for(int x=xstart; x < xend; ++x, ++xImgY.x, ++xImgX.x)
355 {
356 double sx,sy;
357 if (m_transf.transformImgCoord(sx, sy, x, y))
358 {
359 if (m_srcImg.isInside(vigra::Point2D(hugin_utils::roundi(sx), hugin_utils::roundi(sy))))
360 {
361 accX.set(sx, xImgX);
362 accY.set(sy, xImgY);
363 };
364 };
365 }
366 }
367}
368
377template<class RemapImage, class AlphaImage>
379{
380 if (Base::boundingBox().isEmpty())
381 return;
382
383 Base::m_mask.resize(Base::boundingBox().size());
384 // calculate the alpha channel,
385 int xstart = Base::boundingBox().left();
386 int xend = Base::boundingBox().right();
387 int ystart = Base::boundingBox().top();
388 int yend = Base::boundingBox().bottom();
389
390 // loop over the image and transform
391#pragma omp parallel for schedule(dynamic, 10)
392 for(int y=ystart; y < yend; ++y)
393 {
394 // create dist y iterator
395 typename AlphaImage::Iterator yalpha(Base::m_mask.upperLeft());
396 yalpha.y += y - ystart;
397 // create x iterators
398 typename AlphaImage::Iterator xalpha(yalpha);
399 for(int x=xstart; x < xend; ++x, ++xalpha.x)
400 {
401 double sx,sy;
402 if(m_transf.transformImgCoord(sx,sy,x,y))
403 {
404 if (m_srcImg.isInside(vigra::Point2D(hugin_utils::roundi(sx),hugin_utils::roundi(sy))))
405 {
406 *xalpha = 255;
407 }
408 else
409 {
410 *xalpha = 0;
411 };
412 }
413 else
414 {
415 *xalpha = 0;
416 };
417 }
418 }
419}
420
422template <class ImageType>
423ImageType CopyImageNewSize(const ImageType& image, const vigra::Size2D& newSize)
424{
426 vigra::omp::copyImage(vigra::srcImageRange(image, vigra::Rect2D(newSize)), vigra::destImage(newImage));
427 return newImage;
428};
429
431template<class RemapImage, class AlphaImage>
432template<class ImgIter, class ImgAccessor>
433void RemappedPanoImage<RemapImage,AlphaImage>::remapImage(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
436{
437
438 // std::ostringstream msg;
439 // msg <<"remapping image " << imgNr;
440 // progress.setMessage(msg.str().c_str());
441
442 const bool useGPU = m_destImg.remapUsingGPU;
443
444 if (Base::boundingBox().isEmpty())
445 return;
446
447 vigra::Diff2D srcImgSize = srcImg.second - srcImg.first;
448
449 vigra::Size2D expectedSize = m_srcImg.getSize();
450 if (useGPU)
451 {
452 const int r = expectedSize.width() % 8;
453 if (r != 0) expectedSize += vigra::Diff2D(8 - r, 0);
454 }
455
456 DEBUG_DEBUG("srcImgSize: " << srcImgSize << " m_srcImgSize: " << m_srcImg.getSize());
458 "RemappedPanoImage<RemapImage,AlphaImage>::remapImage(): image unexpectedly changed dimensions.");
459
460 typedef typename ImgAccessor::value_type input_value_type;
462
463 // setup photometric transform for this image type
464 // this corrects for response curve, white balance, exposure and
465 // radial vignetting
467 invResponse.enforceMonotonicity();
468 if (m_destImg.outputMode == PanoramaOptions::OUTPUT_LDR) {
469 // select exposure and response curve for LDR output
470 std::vector<double> outLut;
471 if (!m_destImg.outputEMoRParams.empty())
472 {
473 vigra_ext::EMoR::createEMoRLUT(m_destImg.outputEMoRParams, outLut);
474 };
476 if (!m_destImg.outputPixelType.empty()) {
477 maxVal = vigra_ext::getMaxValForPixelType(m_destImg.outputPixelType);
478 }
479
480 invResponse.setOutput(1.0/pow(2.0,m_destImg.outputExposureValue), outLut,
481 maxVal, m_destImg.outputRangeCompression);
482 } else {
483 invResponse.setHDROutput(true,1.0/pow(2.0,m_destImg.outputExposureValue));
484 }
485
486 if ((m_srcImg.hasActiveMasks()) || (m_srcImg.getCropMode() != SrcPanoImage::NO_CROP) || Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false))
487 {
488 // need to create and additional alpha image for the crop mask...
489 // not very efficient during the remapping phase, but works.
490 vigra::BImage alpha(srcImgSize.x, srcImgSize.y);
491
492 switch (m_srcImg.getCropMode()) {
494 {
495 if (useGPU) {
496 if (srcImgSize != m_srcImg.getSize()) {
497 // src image with was increased for alignment reasons.
498 // Need to make an alpha image to mask off the extended region.
499 initImage(vigra::destImageRange(alpha),0);
500 initImage(alpha.upperLeft(),
501 alpha.upperLeft()+m_srcImg.getSize(),
502 alpha.accessor(),255);
503 }
504 else
505 initImage(vigra::destImageRange(alpha),255);
506 }
507 else
508 initImage(vigra::destImageRange(alpha),255);
509 break;
510 }
512 {
513 vigra::Rect2D cR = m_srcImg.getCropRect();
514 hugin_utils::FDiff2D m( (cR.left() + cR.width()/2.0),
515 (cR.top() + cR.height()/2.0) );
516
517 double radius = std::min(cR.width(), cR.height())/2.0;
518 // Default the entire alpha channel to opaque..
519 initImage(vigra::destImageRange(alpha),255);
520 //..crop everything outside the circle
521 vigra_ext::circularCrop(vigra::destImageRange(alpha), m, radius);
522 break;
523 }
525 {
526 vigra::Rect2D cR = m_srcImg.getCropRect();
527 // Default the entire alpha channel to transparent..
528 initImage(vigra::destImageRange(alpha),0);
529 // Make sure crop is inside the image..
530 cR &= vigra::Rect2D(0,0, srcImgSize.x, srcImgSize.y);
531 // Opaque only the area within the crop rectangle..
532 initImage(alpha.upperLeft()+cR.upperLeft(),
533 alpha.upperLeft()+cR.lowerRight(),
534 alpha.accessor(),255);
535 break;
536 }
537 default:
538 break;
539 }
540 if(m_srcImg.hasActiveMasks())
541 vigra_ext::applyMask(vigra::destImageRange(alpha), m_srcImg.getActiveMasks());
542 if (Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false))
543 {
544 const float lowerCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureLowerCutoff", NONA_DEFAULT_EXPOSURE_LOWER_CUTOFF);
545 const float upperCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureUpperCutoff", NONA_DEFAULT_EXPOSURE_UPPER_CUTOFF);
546 vigra_ext::applyExposureClipMask(srcImg, vigra::destImageRange(alpha), lowerCutoff, upperCutoff);
547 };
548 if (useGPU) {
549 transformImageAlphaGPU(srcImg,
550 vigra::srcImage(alpha),
551 destImageRange(Base::m_image),
552 destImage(Base::m_mask),
553 Base::boundingBox().upperLeft(),
554 m_transf,
556 m_srcImg.horizontalWarpNeeded(),
557 interpol,
558 progress);
559 if (Base::boundingBox().right() > m_destImg.getROI().right())
560 {
561 // dest image was enlarged for GPU alignment issue
562 // delete the pixels outside
563 vigra::Rect2D newBoundingBox = Base::boundingBox() & m_destImg.getROI();
564 Base::m_image = CopyImageNewSize(Base::m_image, newBoundingBox.size());
565 Base::m_mask = CopyImageNewSize(Base::m_mask, newBoundingBox.size());
566 Base::m_region = newBoundingBox;
567 };
568 } else {
569 transformImageAlpha(srcImg,
570 vigra::srcImage(alpha),
571 destImageRange(Base::m_image),
572 destImage(Base::m_mask),
573 Base::boundingBox().upperLeft(),
574 m_transf,
576 m_srcImg.horizontalWarpNeeded(),
577 interpol,
578 progress,
580 }
581 } else {
582 if (useGPU) {
583 if (srcImgSize != m_srcImg.getSize()) {
584 // src image with was increased for alignment reasons.
585 // Need to make an alpha image to mask off the extended region.
586 vigra::BImage alpha(srcImgSize.x, srcImgSize.y, vigra::UInt8(0));
587 initImage(alpha.upperLeft(),
588 alpha.upperLeft()+m_srcImg.getSize(),
589 alpha.accessor(),255);
590 transformImageAlphaGPU(srcImg,
591 vigra::srcImage(alpha),
592 destImageRange(Base::m_image),
593 destImage(Base::m_mask),
594 Base::boundingBox().upperLeft(),
595 m_transf,
597 m_srcImg.horizontalWarpNeeded(),
598 interpol,
599 progress);
600
601 }
602 else {
603 transformImageGPU(srcImg,
604 destImageRange(Base::m_image),
605 destImage(Base::m_mask),
606 Base::boundingBox().upperLeft(),
607 m_transf,
609 m_srcImg.horizontalWarpNeeded(),
610 interpol,
611 progress);
612 }
613 if (Base::boundingBox().right() > m_destImg.getROI().right())
614 {
615 // dest image was enlarged for GPU alignment issue
616 // delete the pixels outside
617 vigra::Rect2D newBoundingBox = Base::boundingBox() & m_destImg.getROI();
618 Base::m_image = CopyImageNewSize(Base::m_image, newBoundingBox.size());
619 Base::m_mask = CopyImageNewSize(Base::m_mask, newBoundingBox.size());
620 Base::m_region = newBoundingBox;
621 };
622 } else {
623 transformImage(srcImg,
624 destImageRange(Base::m_image),
625 destImage(Base::m_mask),
626 Base::boundingBox().upperLeft(),
627 m_transf,
629 m_srcImg.horizontalWarpNeeded(),
630 interpol,
631 progress,
633 }
634 }
635}
636
637
638
640template<class RemapImage, class AlphaImage>
641template<class ImgIter, class ImgAccessor,
642 class AlphaIter, class AlphaAccessor>
643void RemappedPanoImage<RemapImage,AlphaImage>::remapImage(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
644 std::pair<AlphaIter, AlphaAccessor> alphaImg,
647{
648 const bool useGPU = m_destImg.remapUsingGPU;
649
650 if (Base::boundingBox().isEmpty())
651 return;
652
653 progress->setMessage("remapping", hugin_utils::stripPath(m_srcImg.getFilename()));
654
655 vigra::Diff2D srcImgSize = srcImg.second - srcImg.first;
656
657 vigra::Size2D expectedSize = m_srcImg.getSize();
658 if (useGPU)
659 {
660 const int r = expectedSize.width() % 8;
661 if (r != 0) expectedSize += vigra::Diff2D(8 - r, 0);
662 }
664 "RemappedPanoImage<RemapImage,AlphaImage>::remapImage(): image unexpectedly changed dimensions.");
665
666 typedef typename ImgAccessor::value_type input_value_type;
668
669 // setup photometric transform for this image type
670 // this corrects for response curve, white balance, exposure and
671 // radial vignetting
673 if (m_destImg.outputMode == PanoramaOptions::OUTPUT_LDR) {
674 // select exposure and response curve for LDR output
675 std::vector<double> outLut;
676 // scale up to desired output format
678 if (!m_destImg.outputPixelType.empty()) {
679 maxVal = vigra_ext::getMaxValForPixelType(m_destImg.outputPixelType);
680 }
681 if (!m_destImg.outputEMoRParams.empty())
682 {
683 vigra_ext::EMoR::createEMoRLUT(m_destImg.outputEMoRParams, outLut);
685 };
686 invResponse.setOutput(1.0/pow(2.0,m_destImg.outputExposureValue), outLut,
687 maxVal, m_destImg.outputRangeCompression);
688 } else {
689 invResponse.setHDROutput(true,1.0/pow(2.0,m_destImg.outputExposureValue));
690 }
691
692 if ((m_srcImg.hasActiveMasks()) || (m_srcImg.getCropMode() != SrcPanoImage::NO_CROP) || Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false)) {
693 vigra::BImage alpha(srcImgSize);
694 vigra::Rect2D cR = m_srcImg.getCropRect();
695 switch (m_srcImg.getCropMode()) {
697 {
698 // Just copy the source alpha channel and crop it down.
699 vigra::copyImage(vigra::make_triple(alphaImg.first,
700 alphaImg.first + srcImgSize, alphaImg.second),
701 vigra::destImage(alpha));
702 break;
703 }
705 {
706 // Just copy the source alpha channel and crop it down.
707 vigra::copyImage(vigra::make_triple(alphaImg.first,
708 alphaImg.first + srcImgSize, alphaImg.second),
709 vigra::destImage(alpha));
710 hugin_utils::FDiff2D m( (cR.left() + cR.width()/2.0),
711 (cR.top() + cR.height()/2.0) );
712 double radius = std::min(cR.width(), cR.height())/2.0;
713 vigra_ext::circularCrop(vigra::destImageRange(alpha), m, radius);
714 break;
715 }
717 {
718 // Intersect the cropping rectangle with the one from the base
719 // image to ensure it fits inside.
720 cR &= vigra::Rect2D(0,0, srcImgSize.x, srcImgSize.y);
721
722 // Start with a blank alpha channel for the destination
723 initImage(vigra::destImageRange(alpha),0);
724
725 // Copy in only the area inside the rectangle
726 vigra::copyImage(alphaImg.first + cR.upperLeft(),
727 alphaImg.first + cR.lowerRight(),
728 alphaImg.second,
729 alpha.upperLeft() + cR.upperLeft(),alpha.accessor());
730 break;
731 }
732 default:
733 break;
734 }
735 if(m_srcImg.hasActiveMasks())
736 vigra_ext::applyMask(vigra::destImageRange(alpha), m_srcImg.getActiveMasks());
737 if (Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false))
738 {
739 const float lowerCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureLowerCutoff", NONA_DEFAULT_EXPOSURE_LOWER_CUTOFF);
740 const float upperCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureUpperCutoff", NONA_DEFAULT_EXPOSURE_UPPER_CUTOFF);
741 vigra_ext::applyExposureClipMask(srcImg, vigra::destImageRange(alpha), lowerCutoff, upperCutoff);
742 };
743 if (useGPU) {
745 vigra::srcImage(alpha),
746 destImageRange(Base::m_image),
747 destImage(Base::m_mask),
748 Base::boundingBox().upperLeft(),
749 m_transf,
751 m_srcImg.horizontalWarpNeeded(),
752 interp,
753 progress);
754 if (Base::boundingBox().right() > m_destImg.getROI().right())
755 {
756 // dest image was enlarged for GPU alignment issue
757 // delete the pixels outside
758 vigra::Rect2D newBoundingBox = Base::boundingBox() & m_destImg.getROI();
759 Base::m_image = CopyImageNewSize(Base::m_image, newBoundingBox.size());
760 Base::m_mask = CopyImageNewSize(Base::m_mask, newBoundingBox.size());
761 Base::m_region = newBoundingBox;
762 };
763 } else {
765 vigra::srcImage(alpha),
766 destImageRange(Base::m_image),
767 destImage(Base::m_mask),
768 Base::boundingBox().upperLeft(),
769 m_transf,
771 m_srcImg.horizontalWarpNeeded(),
772 interp,
773 progress,
775 }
776 } else {
777 if (useGPU) {
778 // extended region (if any) should already be cleared since ImportImageAlpha shouldn't have touched it.
780 alphaImg,
781 destImageRange(Base::m_image),
782 destImage(Base::m_mask),
783 Base::boundingBox().upperLeft(),
784 m_transf,
786 m_srcImg.horizontalWarpNeeded(),
787 interp,
788 progress);
789 if (Base::boundingBox().right() > m_destImg.getROI().right())
790 {
791 // dest image was enlarged for GPU alignment issue
792 // delete the pixels outside
793 vigra::Rect2D newBoundingBox = Base::boundingBox() & m_destImg.getROI();
794 Base::m_image = CopyImageNewSize(Base::m_image, newBoundingBox.size());
795 Base::m_mask = CopyImageNewSize(Base::m_mask, newBoundingBox.size());
796 Base::m_region = newBoundingBox;
797 };
798 } else {
800 alphaImg,
801 destImageRange(Base::m_image),
802 destImage(Base::m_mask),
803 Base::boundingBox().upperLeft(),
804 m_transf,
806 m_srcImg.horizontalWarpNeeded(),
807 interp,
808 progress,
810 }
811 }
812}
813
814
815
816
817
818
821template <class SrcImgType, class FlatImgType, class DestImgType, class MaskImgType>
823 const MaskImgType & srcAlpha,
824 const FlatImgType & srcFlat,
825 const SrcPanoImage & src,
826 const PanoramaOptions & dest,
827 vigra::Rect2D outputROI,
828// vigra_ext::Interpolator interpolator,
831{
832#ifdef DEBUG_REMAP
833 {
834 vigra::ImageExportInfo exi( DEBUG_FILE_PREFIX "hugin03_BeforeRemap.tif");
835 vigra::exportImage(vigra::srcImageRange(srcImg), exi);
836 }
837 {
838 if (srcAlpha.width() > 0) {
839 vigra::ImageExportInfo exi(DEBUG_FILE_PREFIX "hugin04_BeforeRemapAlpha.tif");
840 vigra::exportImage(vigra::srcImageRange(srcAlpha), exi);
841 }
842 }
843#endif
844
845 progress->setMessage("remapping", hugin_utils::stripPath(src.getFilename()));
846 // set pano image
847 DEBUG_DEBUG("setting src image with size: " << src.getSize());
848 remapped.setPanoImage(src, dest, outputROI);
849 // TODO: add provide support for flatfield images.
850 if (srcAlpha.size().x > 0) {
851 remapped.remapImage(vigra::srcImageRange(srcImg),
852 vigra::srcImage(srcAlpha), dest.interpolator,
853 progress);
854 } else {
855 remapped.remapImage(vigra::srcImageRange(srcImg), dest.interpolator, progress);
856 }
857
858#ifdef DEBUG_REMAP
859 {
860 vigra::ImageExportInfo exi( DEBUG_FILE_PREFIX "hugin04_AfterRemap.tif");
861 vigra::exportImage(vigra::srcImageRange(remapped.m_image), exi);
862 }
863 {
864 vigra::ImageExportInfo exi(DEBUG_FILE_PREFIX "hugin04_AfterRemapAlpha.tif");
865 vigra::exportImage(vigra::srcImageRange(remapped.m_mask), exi);
866 }
867#endif
868}
869
870
871} //namespace
872} //namespace
873
874#endif // _H
Contains functions to transform whole images.
Contains functions to transform whole images.
declaration of classes to work with mask
#define NONA_DEFAULT_EXPOSURE_LOWER_CUTOFF
#define NONA_DEFAULT_EXPOSURE_UPPER_CUTOFF
Helper class for storing different options.
struct to hold a image state for stitching
RemapImage::value_type image_value_type
RemapImage::ConstAccessor ConstImageAccessor
void remapImage(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, std::pair< AlphaIter, AlphaAccessor > alphaImg, vigra_ext::Interpolator interp, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
remap a image, with alpha channel
void setPanoImage(const SrcPanoImage &src, const PanoramaOptions &dest, vigra::Rect2D roi)
vigra_ext::ValueTypeTraits< image_value_type >::value_type component_type
void setAdvancedOptions(const AdvancedOptions &advancedOptions)
AlphaImage::value_type mask_value_type
AlphaImage::const_traverser const_mask_traverser
void calcSrcCoordImgs(DistImgType &imgX, DistImgType &imgY)
calculate distance map.
void calcAlpha()
calculate only the alpha channel.
AlphaImage::ConstAccessor ConstMaskAccessor
vigra::ImageImportInfo::ICCProfile m_ICCProfile
void remapImage(vigra::triple< ImgIter, ImgIter, ImgAccessor > srcImg, vigra_ext::Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
remap a image without alpha channel
RemapImage::const_traverser const_image_traverser
RemappedPanoImage()
create a remapped pano image
vigra_ext::ROIImage< RemapImage, AlphaImage > Base
Holds transformations for Image -> Pano and the other way.
Panorama image options.
unsigned int getWidth() const
PanoramaOptions::ProjectionFormat getProjection() const
ProjectionFormat
Projection of final panorama.
unsigned int getHeight() const
get panorama height
Model for a panorama.
Definition Panorama.h:153
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition Panorama.h:211
radiometric transformation, includes exposure, vignetting and white balance
All variables of a source image.
int getWidth() const
Get the width of the image in pixels.
brief description.
Definition ROIImage.h:86
vigra::FRGBImage ImageType
#define DEBUG_DEBUG(msg)
Definition utils.h:68
std::map< std::string, std::string > AdvancedOptions
void estimateImageAlpha(const SrcPanoImage &src, const PanoramaOptions &dest, TRANSFORM &transf, vigra::Rect2D &imgRect, vigra::BImage &alpha, double &scale)
ImageType CopyImageNewSize(const ImageType &image, const vigra::Size2D &newSize)
copies image into new image with changed size
void remapImage(SrcImgType &srcImg, const MaskImgType &srcAlpha, const FlatImgType &srcFlat, const SrcPanoImage &src, const PanoramaOptions &dest, vigra::Rect2D outputRect, RemappedPanoImage< DestImgType, MaskImgType > &remapped, AppBase::ProgressDisplay *progress)
remap a single image
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 estimateImageRect(const SrcPanoImage &src, const PanoramaOptions &dest, TRANSFORM &transf, vigra::Rect2D &imgRect)
calculate the outline of the image
mainly consists of wrapper around the pano tools library, to assist in ressource management and to pr...
Definition wxcms.cpp:39
int roundi(T x)
Definition hugin_math.h:73
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 copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
void createEMoRLUT(const std::vector< float > &params, VECTOR &lut)
Definition emor.h:44
void transformImageAlpha(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, std::pair< SrcAlphaIterator, SrcAlphaAccessor > srcAlpha, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, vigra::Diff2D destUL, TRANSFORM &transform, PixelTransform &pixelTransform, bool warparound, Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
Transform image, and respect a possible alpha channel.
void applyMask(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > img, HuginBase::MaskPolygonVector masks)
Definition Mask.h:163
double getMaxValForPixelType(const std::string &v)
Definition utils.h:89
Interpolator
enum with all interpolation methods
void applyExposureClipMask(vigra::triple< ImgIter, ImgIter, ImgAccessor > image, vigra::triple< AlphaIter, AlphaIter, AlphaAccessor > mask, double lowerLimit, double upperLimit)
Definition utils.h:370
void transformImageAlphaGPU(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, std::pair< SrcAlphaIterator, SrcAlphaAccessor > srcAlpha, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, vigra::Diff2D destUL, TRANSFORM &transform, PixelTransform &pixelTransform, bool warparound, Interpolator interpol, AppBase::ProgressDisplay *progress)
Transform image, and respect a possible alpha channel.
void enforceMonotonicity(LUT &lut)
enforce monotonicity of an array (mostly used for lookup tables)
Definition lut.h:87
void circularCrop(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > img, hugin_utils::FDiff2D middle, double radius)
Apply a circular crop to img.
Definition utils.h:495
T1::value_type value_type
Definition utils.h:153
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