RemappedPanoImage.h

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00027 #ifndef _NONA_REMAPPEDPANOIMAGE_H
00028 #define _NONA_REMAPPEDPANOIMAGE_H
00029 
00030 #include <vigra/imageinfo.hxx>
00031 #include <vigra/initimage.hxx>
00032 #include <vigra/copyimage.hxx>
00033 #include <vigra/flatmorphology.hxx>
00034 #include <vigra_ext/ROIImage.h>
00035 
00036 #include <appbase/ProgressDisplay.h>
00037 #include <nona/StitcherOptions.h>
00038 
00039 #include <panodata/SrcPanoImage.h>
00040 #include <panodata/Mask.h>
00041 #include <panodata/PanoramaOptions.h>
00042 #include <panotools/PanoToolsInterface.h>
00043 
00044 // default values for exposure cutoff
00045 #define NONA_DEFAULT_EXPOSURE_LOWER_CUTOFF 1/255.0f
00046 #define NONA_DEFAULT_EXPOSURE_UPPER_CUTOFF 250/255.0f
00047 
00048 
00049 namespace HuginBase {
00050 namespace Nona {
00051 
00052 
00059 template <class TRANSFORM>
00060 void estimateImageRect(const SrcPanoImage & src,
00061                        const PanoramaOptions & dest,
00062                        TRANSFORM & transf,
00063                        vigra::Rect2D & imgRect);
00064 
00066 template <class TRANSFORM>
00067 void estimateImageAlpha(const SrcPanoImage & src,
00068                         const PanoramaOptions & dest,
00069                         TRANSFORM & transf,
00070                         vigra::Rect2D & imgRect,
00071                          vigra::BImage & alpha,
00072                          double & scale);
00073 
00074 
00078 template <class RemapImage, class AlphaImage>
00079 class RemappedPanoImage : public vigra_ext::ROIImage<RemapImage, AlphaImage>
00080 {
00081 
00082         typedef vigra_ext::ROIImage<RemapImage, AlphaImage> Base;
00083 
00084     public:
00085     // typedefs for the children types
00086         typedef typename RemapImage::value_type      image_value_type;
00087         typedef typename RemapImage::traverser       image_traverser;
00088         typedef typename RemapImage::const_traverser const_image_traverser;
00089         typedef typename RemapImage::Accessor        ImageAccessor;
00090         typedef typename RemapImage::ConstAccessor   ConstImageAccessor;
00091 
00092         typedef typename AlphaImage::value_type       mask_value_type;
00093         typedef typename AlphaImage::traverser        mask_traverser;
00094         typedef typename AlphaImage::const_traverser  const_mask_traverser;
00095         typedef typename AlphaImage::Accessor         MaskAccessor;
00096         typedef typename AlphaImage::ConstAccessor    ConstMaskAccessor;
00097 
00098         typedef typename vigra_ext::ValueTypeTraits<image_value_type>::value_type component_type;
00099 
00100         
00101     public:
00106         RemappedPanoImage() : m_advancedOptions()
00107         {};
00108 
00109         
00110     public:
00112         void setPanoImage(const SrcPanoImage & src,
00113                           const PanoramaOptions & dest,
00114                           vigra::Rect2D roi);
00115         void setAdvancedOptions(const AdvancedOptions& advancedOptions)
00116         {
00117             m_advancedOptions = advancedOptions;
00118         };
00119 
00120     public:
00125         template<class DistImgType>
00126             void calcSrcCoordImgs(DistImgType & imgX, DistImgType & imgY);
00127 
00136         void calcAlpha();
00137 
00139         template <class ImgIter, class ImgAccessor>
00140         void remapImage(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
00141                         vigra_ext::Interpolator interpol,
00142                         AppBase::ProgressDisplay* progress, bool singleThreaded = false);
00143 
00144 
00146         template <class ImgIter, class ImgAccessor,
00147                   class AlphaIter, class AlphaAccessor>
00148         void remapImage(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
00149                         std::pair<AlphaIter, AlphaAccessor> alphaImg,
00150                         vigra_ext::Interpolator interp,
00151                         AppBase::ProgressDisplay* progress, bool singleThreaded = false);
00152         
00153         
00154     public:
00156         vigra::ImageImportInfo::ICCProfile m_ICCProfile;
00157 
00158     protected:
00159         SrcPanoImage m_srcImg;
00160         PanoramaOptions m_destImg;
00161         PTools::Transform m_transf;
00162         AdvancedOptions m_advancedOptions;
00163 
00164 };
00165 
00166 
00167 
00170 template <class SrcImgType, class FlatImgType, class DestImgType, class MaskImgType>
00171 void remapImage(SrcImgType & srcImg,
00172                 const MaskImgType & srcAlpha,
00173                 const FlatImgType & srcFlat,
00174                 const SrcPanoImage & src,
00175                 const PanoramaOptions & dest,
00176                 vigra::Rect2D outputRect,
00177                 RemappedPanoImage<DestImgType, MaskImgType> & remapped,
00178                 AppBase::ProgressDisplay* progress);
00179 
00180 
00181 } // namespace
00182 } // namespace
00183 
00184 
00185 
00186 //==============================================================================
00187 // templated implementations
00188 
00189 
00190 #include <photometric/ResponseTransform.h>
00191 #include <vigra_ext/ImageTransforms.h>
00192 #include <vigra_ext/ImageTransformsGPU.h>
00193 
00194 // #define DEBUG_REMAP 1
00195 
00196 #ifdef DEBUG_REMAP
00197 #include <vigra/impex.hxx> // for vigra::exportImage()
00198 #ifdef _WIN32
00199 #define DEBUG_FILE_PREFIX "C:/temp/"
00200 #else
00201 #define DEBUG_FILE_PREFIX "/tmp/"
00202 #endif
00203 #endif
00204 
00205 
00206 namespace HuginBase {
00207 namespace Nona {
00208 
00209 
00210 template <class RemapImage, class AlphaImage>
00211 void RemappedPanoImage<RemapImage,AlphaImage>::setPanoImage(const SrcPanoImage & src,
00212                   const PanoramaOptions & dest, vigra::Rect2D roi)
00213 {
00214     // restrict to panorama size
00215     m_srcImg = src;
00216     m_destImg = dest;
00217 
00218     if (m_destImg.remapUsingGPU) {
00219         // Make width multiple of 8 for fast GPU transfers.
00220         const int r = roi.width() % 8;
00221         if (r != 0) roi.addSize(vigra::Size2D(8 - r, 0));
00222     }
00223 
00224     Base::resize(roi);
00225     m_transf.createTransform(src, dest);
00226 
00227     DEBUG_DEBUG("after resize: " << Base::m_region);
00228     DEBUG_DEBUG("m_srcImg size: " << m_srcImg.getSize());
00229 }
00230 
00231 
00232 #if 0
00233 
00239 template <class RemapImage, class AlphaImage>
00240 void RemappedPanoImage<RemapImage,AlphaImage>::setPanoImage(const vigra::Size2D & srcSize,
00241                   const PanoCommand::VariableMap & srcVars,
00242                   PanoCommand::Lens::LensProjectionFormat srcProj,
00243                   const PanoCommand::PanoImage & img,
00244                   const vigra::Diff2D &destSize,
00245                   HuginBase::PanoramaOptions::ProjectionFormat destProj,
00246                   double destHFOV)
00247 {
00248     m_srcSize = srcSize;
00249     m_srcOrigSize.x = img.getWidth();
00250     m_srcOrigSize.y = img.getHeight();
00251     m_srcProj = m_srcProj;
00252 
00253 
00254     m_srcPanoImg = img;
00255     m_destProj = destProj;
00256     m_destHFOV = destHFOV;
00257     // create transforms
00258     //    SpaceTransform t;
00259     //    SpaceTransform invT;
00260     /*
00261     m_invTransf.createInvTransform(srcSize, srcVars, srcProj,
00262                                    destSize, destProj, destHFOV,
00263                                    m_srcOrigSize);
00264     */
00265     // calculate ROI for this image.
00266     m_transf.createTransform(srcSize, srcVars, srcProj,
00267                              destSize, destProj, destHFOV,
00268                              m_srcOrigSize);
00269 
00270     ImageOptions imgOpts = img.getOptions();
00271 
00272     // todo: resize crop!
00273     bool circCrop = srcProj == Lens::CIRCULAR_FISHEYE;
00274     estimateImageRect(destSize, m_srcOrigSize,
00275                       imgOpts.docrop, imgOpts.cropRect, circCrop,
00276                       m_transf,
00277                       imageRect);
00278 
00279     m_warparound = (destProj == PanoramaOptions::EQUIRECTANGULAR && m_destHFOV == 360);
00280 
00281 
00282 }
00283 
00284 template <class RemapImage, class AlphaImage>
00285 void RemappedPanoImage<RemapImage,AlphaImage>::setPanoImage(const HuginBase::Panorama & pano, unsigned int imgNr,
00286                   vigra::Size2D srcSize, const HuginBase::PanoramaOptions & opts)
00287 {
00288     const PanoCommand::PanoImage & img = pano.getImage(imgNr);
00289 
00290     m_srcSize = srcSize;
00291     m_srcOrigSize.x = img.getWidth();
00292     m_srcOrigSize.y = img.getHeight();
00293     m_srcProj = pano.getLens(pano.getImage(imgNr).getLensNr()).getProjection();
00294 
00295     m_destProj = opts.getProjection();
00296     m_destHFOV = opts.getHFOV();
00297     m_warparound = (opts.getProjection() == PanoramaOptions::EQUIRECTANGULAR && opts.getHFOV() == 360);
00298 
00299     // create transforms
00300     //    SpaceTransform t;
00301     //    SpaceTransform invT;
00302 
00303 //        m_invTransf.createInvTransform(pano, imgNr, opts, m_srcSize);
00304     m_transf.createTransform(pano, imgNr, opts, m_srcSize);
00305 
00306     // calculate ROI for this image.
00307     m_srcPanoImg = pano.getImage(imgNr);
00308     ImageOptions imgOpts = pano.getImage(imgNr).getOptions();
00309     vigra::Rect2D imageRect;
00310     // todo: resize crop!
00311     bool circCrop = pano.getLens(pano.getImage(imgNr).getLensNr()).getProjection() == Lens::CIRCULAR_FISHEYE;
00312     estimateImageRect(vigra::Size2D(opts.getWidth(), opts.getHeight()), srcSize,
00313                       imgOpts.docrop, imgOpts.cropRect, circCrop,  
00314                       m_transf,
00315                       imageRect);
00316 
00317 
00318     // restrict to panorama size
00319     Base::resize(imageRect);
00320     DEBUG_DEBUG("after resize: " << Base::m_region);
00321 }
00322 #endif
00323 
00324 
00329 template<class RemapImage, class AlphaImage>
00330 template<class DistImgType>
00331 void RemappedPanoImage<RemapImage,AlphaImage>::calcSrcCoordImgs(DistImgType & imgX, DistImgType & imgY)
00332 {
00333     if (Base::boundingBox().isEmpty()) return;
00334     imgX.resize(Base::boundingBox().size());
00335     imgY.resize(Base::boundingBox().size());
00336     // calculate the alpha channel,
00337     int xstart = Base::boundingBox().left();
00338     int xend   = Base::boundingBox().right();
00339     int ystart = Base::boundingBox().top();
00340     int yend   = Base::boundingBox().bottom();
00341 
00342     // create dist y iterator
00343     typename DistImgType::Iterator yImgX(imgX.upperLeft());
00344     typename DistImgType::Iterator yImgY(imgY.upperLeft());
00345     typename DistImgType::Accessor accX = imgX.accessor();
00346     typename DistImgType::Accessor accY = imgY.accessor();
00347     // loop over the image and transform
00348     for(int y=ystart; y < yend; ++y, ++yImgX.y, ++yImgY.y)
00349     {
00350         // create x iterators
00351         typename DistImgType::Iterator xImgX(yImgX);
00352         typename DistImgType::Iterator xImgY(yImgY);
00353         for(int x=xstart; x < xend; ++x, ++xImgY.x, ++xImgX.x)
00354         {
00355             double sx,sy;
00356             m_transf.transformImgCoord(sx,sy,x,y);
00357             accX.set(sx, xImgX);
00358             accY.set(sy, xImgY);
00359         }
00360     }
00361 }
00362 
00371 template<class RemapImage, class AlphaImage>
00372 void RemappedPanoImage<RemapImage,AlphaImage>::calcAlpha()
00373 {
00374     if (Base::boundingBox().isEmpty())
00375         return;
00376 
00377     Base::m_mask.resize(Base::boundingBox().size());
00378     // calculate the alpha channel,
00379     int xstart = Base::boundingBox().left();
00380     int xend   = Base::boundingBox().right();
00381     int ystart = Base::boundingBox().top();
00382     int yend   = Base::boundingBox().bottom();
00383 
00384     // loop over the image and transform
00385 #pragma omp parallel for schedule(dynamic, 10)
00386     for(int y=ystart; y < yend; ++y)
00387     {
00388         // create dist y iterator
00389         typename AlphaImage::Iterator yalpha(Base::m_mask.upperLeft());
00390         yalpha.y += y - ystart;
00391         // create x iterators
00392         typename AlphaImage::Iterator xalpha(yalpha);
00393         for(int x=xstart; x < xend; ++x, ++xalpha.x)
00394         {
00395             double sx,sy;
00396             if(m_transf.transformImgCoord(sx,sy,x,y))
00397             {
00398                 if (m_srcImg.isInside(vigra::Point2D(hugin_utils::roundi(sx),hugin_utils::roundi(sy))))
00399                 {
00400                     *xalpha = 255;
00401                 }
00402                 else
00403                 {
00404                     *xalpha = 0;
00405                 };
00406             }
00407             else
00408             {
00409                 *xalpha = 0;
00410             };
00411         }
00412     }
00413 }
00414 
00416 template<class RemapImage, class AlphaImage>
00417 template<class ImgIter, class ImgAccessor>
00418 void RemappedPanoImage<RemapImage,AlphaImage>::remapImage(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
00419                                                           vigra_ext::Interpolator interpol,
00420                                                           AppBase::ProgressDisplay* progress, bool singleThreaded)
00421 {
00422 
00423     //        std::ostringstream msg;
00424     //        msg <<"remapping image "  << imgNr;
00425     //        progress.setMessage(msg.str().c_str());
00426 
00427     const bool useGPU = m_destImg.remapUsingGPU;
00428 
00429     if (Base::boundingBox().isEmpty())
00430         return;
00431 
00432     vigra::Diff2D srcImgSize = srcImg.second - srcImg.first;
00433 
00434     vigra::Size2D expectedSize = m_srcImg.getSize();
00435     if (useGPU)
00436     {
00437         const int r = expectedSize.width() % 8;
00438         if (r != 0) expectedSize += vigra::Diff2D(8 - r, 0);
00439     }
00440 
00441     DEBUG_DEBUG("srcImgSize: " << srcImgSize << " m_srcImgSize: " << m_srcImg.getSize());
00442     vigra_precondition(srcImgSize == expectedSize, 
00443                        "RemappedPanoImage<RemapImage,AlphaImage>::remapImage(): image unexpectedly changed dimensions.");
00444 
00445     typedef typename ImgAccessor::value_type input_value_type;
00446     typedef typename vigra_ext::ValueTypeTraits<input_value_type>::value_type input_component_type;
00447 
00448     // setup photometric transform for this image type
00449     // this corrects for response curve, white balance, exposure and 
00450     // radial vignetting
00451     Photometric::InvResponseTransform<input_component_type, double> invResponse(m_srcImg);
00452     invResponse.enforceMonotonicity();
00453     if (m_destImg.outputMode == PanoramaOptions::OUTPUT_LDR) {
00454         // select exposure and response curve for LDR output
00455         std::vector<double> outLut;
00456         if (!m_destImg.outputEMoRParams.empty())
00457         {
00458             vigra_ext::EMoR::createEMoRLUT(m_destImg.outputEMoRParams, outLut);
00459         };
00460         double maxVal = vigra_ext::LUTTraits<input_value_type>::max();
00461         if (m_destImg.outputPixelType.size() > 0) {
00462             maxVal = vigra_ext::getMaxValForPixelType(m_destImg.outputPixelType);
00463         }
00464 
00465         invResponse.setOutput(1.0/pow(2.0,m_destImg.outputExposureValue), outLut,
00466                               maxVal);
00467     } else {
00468         invResponse.setHDROutput(true,1.0/pow(2.0,m_destImg.outputExposureValue));
00469     }
00470 
00471     if ((m_srcImg.hasActiveMasks()) || (m_srcImg.getCropMode() != SrcPanoImage::NO_CROP) || Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false))
00472     {
00473         // need to create and additional alpha image for the crop mask...
00474         // not very efficient during the remapping phase, but works.
00475         vigra::BImage alpha(srcImgSize.x, srcImgSize.y);
00476 
00477         switch (m_srcImg.getCropMode()) {
00478         case SrcPanoImage::NO_CROP:
00479             {
00480                 if (useGPU) {
00481                     if (srcImgSize != m_srcImg.getSize()) {
00482                         // src image with was increased for alignment reasons.
00483                         // Need to make an alpha image to mask off the extended region.
00484                         initImage(vigra::destImageRange(alpha),0);
00485                         initImage(alpha.upperLeft(), 
00486                             alpha.upperLeft()+m_srcImg.getSize(),
00487                             alpha.accessor(),255);
00488                     }
00489                     else
00490                         initImage(vigra::destImageRange(alpha),255);
00491                 }
00492                 else
00493                     initImage(vigra::destImageRange(alpha),255);
00494                 break;
00495             }
00496         case SrcPanoImage::CROP_CIRCLE:
00497             {
00498                 vigra::Rect2D cR = m_srcImg.getCropRect();
00499                 hugin_utils::FDiff2D m( (cR.left() + cR.width()/2.0),
00500                         (cR.top() + cR.height()/2.0) );
00501 
00502                 double radius = std::min(cR.width(), cR.height())/2.0;
00503                 // Default the entire alpha channel to opaque..
00504                 initImage(vigra::destImageRange(alpha),255);
00505                 //..crop everything outside the circle
00506                 vigra_ext::circularCrop(vigra::destImageRange(alpha), m, radius);
00507                 break;
00508             }
00509         case SrcPanoImage::CROP_RECTANGLE:
00510             {
00511                 vigra::Rect2D cR = m_srcImg.getCropRect();
00512                 // Default the entire alpha channel to transparent..
00513                 initImage(vigra::destImageRange(alpha),0);
00514                 // Make sure crop is inside the image..
00515                 cR &= vigra::Rect2D(0,0, srcImgSize.x, srcImgSize.y);
00516                 // Opaque only the area within the crop rectangle..
00517                 initImage(alpha.upperLeft()+cR.upperLeft(), 
00518                           alpha.upperLeft()+cR.lowerRight(),
00519                           alpha.accessor(),255);
00520                 break;
00521             }
00522         default:
00523             break;
00524         }
00525         if(m_srcImg.hasActiveMasks())
00526             vigra_ext::applyMask(vigra::destImageRange(alpha), m_srcImg.getActiveMasks());
00527         if (Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false))
00528         {
00529             const float lowerCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureLowerCutoff", NONA_DEFAULT_EXPOSURE_LOWER_CUTOFF);
00530             const float upperCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureUpperCutoff", NONA_DEFAULT_EXPOSURE_UPPER_CUTOFF);
00531             vigra_ext::applyExposureClipMask(srcImg, vigra::destImageRange(alpha), lowerCutoff, upperCutoff);
00532         };
00533         if (useGPU) {
00534             transformImageAlphaGPU(srcImg,
00535                                    vigra::srcImage(alpha),
00536                                    destImageRange(Base::m_image),
00537                                    destImage(Base::m_mask),
00538                                    Base::boundingBox().upperLeft(),
00539                                    m_transf,
00540                                    invResponse,
00541                                    m_srcImg.horizontalWarpNeeded(),
00542                                    interpol,
00543                                    progress);
00544         } else {
00545             transformImageAlpha(srcImg,
00546                                 vigra::srcImage(alpha),
00547                                 destImageRange(Base::m_image),
00548                                 destImage(Base::m_mask),
00549                                 Base::boundingBox().upperLeft(),
00550                                 m_transf,
00551                                 invResponse,
00552                                 m_srcImg.horizontalWarpNeeded(),
00553                                 interpol,
00554                                 progress,
00555                                 singleThreaded);
00556         }
00557     } else {
00558         if (useGPU) {
00559             if (srcImgSize != m_srcImg.getSize()) {
00560                 // src image with was increased for alignment reasons.
00561                 // Need to make an alpha image to mask off the extended region.
00562                 vigra::BImage alpha(srcImgSize.x, srcImgSize.y, vigra::UInt8(0));
00563                 initImage(alpha.upperLeft(), 
00564                           alpha.upperLeft()+m_srcImg.getSize(),
00565                           alpha.accessor(),255);
00566                 transformImageAlphaGPU(srcImg,
00567                                        vigra::srcImage(alpha),
00568                                        destImageRange(Base::m_image),
00569                                        destImage(Base::m_mask),
00570                                        Base::boundingBox().upperLeft(),
00571                                        m_transf,
00572                                        invResponse,
00573                                        m_srcImg.horizontalWarpNeeded(),
00574                                        interpol,
00575                                        progress);
00576 
00577             }
00578             else {
00579                 transformImageGPU(srcImg,
00580                                   destImageRange(Base::m_image),
00581                                   destImage(Base::m_mask),
00582                                   Base::boundingBox().upperLeft(),
00583                                   m_transf,
00584                                   invResponse,
00585                                   m_srcImg.horizontalWarpNeeded(),
00586                                   interpol,
00587                                   progress);
00588             }
00589         } else {
00590             transformImage(srcImg,
00591                            destImageRange(Base::m_image),
00592                            destImage(Base::m_mask),
00593                            Base::boundingBox().upperLeft(),
00594                            m_transf,
00595                            invResponse,
00596                            m_srcImg.horizontalWarpNeeded(),
00597                            interpol,
00598                            progress,
00599                            singleThreaded);
00600         }
00601     }
00602 }
00603 
00604 
00605 
00607 template<class RemapImage, class AlphaImage>
00608 template<class ImgIter, class ImgAccessor,
00609          class AlphaIter, class AlphaAccessor>
00610 void RemappedPanoImage<RemapImage,AlphaImage>::remapImage(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
00611                                                           std::pair<AlphaIter, AlphaAccessor> alphaImg,
00612                                                           vigra_ext::Interpolator interp,
00613                                                           AppBase::ProgressDisplay* progress, bool singleThreaded)
00614 {
00615     const bool useGPU = m_destImg.remapUsingGPU;
00616 
00617     if (Base::boundingBox().isEmpty())
00618         return;
00619 
00620     progress->setMessage("remapping", hugin_utils::stripPath(m_srcImg.getFilename()));
00621 
00622     vigra::Diff2D srcImgSize = srcImg.second - srcImg.first;
00623 
00624     vigra::Size2D expectedSize = m_srcImg.getSize();
00625     if (useGPU)
00626     {
00627         const int r = expectedSize.width() % 8;
00628         if (r != 0) expectedSize += vigra::Diff2D(8 - r, 0);
00629     }
00630     vigra_precondition(srcImgSize == expectedSize,
00631                        "RemappedPanoImage<RemapImage,AlphaImage>::remapImage(): image unexpectedly changed dimensions.");
00632 
00633     typedef typename ImgAccessor::value_type input_value_type;
00634     typedef typename vigra_ext::ValueTypeTraits<input_value_type>::value_type input_component_type;
00635 
00636     // setup photometric transform for this image type
00637     // this corrects for response curve, white balance, exposure and 
00638     // radial vignetting
00639     Photometric::InvResponseTransform<input_component_type, double> invResponse(m_srcImg);
00640     if (m_destImg.outputMode == PanoramaOptions::OUTPUT_LDR) {
00641         // select exposure and response curve for LDR output
00642         std::vector<double> outLut;
00643         // scale up to desired output format
00644         double maxVal = vigra_ext::LUTTraits<input_value_type>::max();
00645         if (m_destImg.outputPixelType.size() > 0) {
00646             maxVal = vigra_ext::getMaxValForPixelType(m_destImg.outputPixelType);
00647         }
00648         if (!m_destImg.outputEMoRParams.empty())
00649         {
00650             vigra_ext::EMoR::createEMoRLUT(m_destImg.outputEMoRParams, outLut);
00651             vigra_ext::enforceMonotonicity(outLut);
00652         };
00653         invResponse.setOutput(1.0/pow(2.0,m_destImg.outputExposureValue), outLut,
00654                               maxVal);
00655     } else {
00656         invResponse.setHDROutput(true,1.0/pow(2.0,m_destImg.outputExposureValue));
00657     }
00658 
00659     if ((m_srcImg.hasActiveMasks()) || (m_srcImg.getCropMode() != SrcPanoImage::NO_CROP) || Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false)) {
00660         vigra::BImage alpha(srcImgSize);
00661         vigra::Rect2D cR = m_srcImg.getCropRect();
00662         switch (m_srcImg.getCropMode()) {
00663             case SrcPanoImage::NO_CROP:
00664             {
00665                 // Just copy the source alpha channel and crop it down.
00666                 vigra::copyImage(vigra::make_triple(alphaImg.first,
00667                         alphaImg.first + srcImgSize, alphaImg.second),
00668                         vigra::destImage(alpha));
00669                 break;
00670             }
00671             case SrcPanoImage::CROP_CIRCLE:
00672             {
00673                 // Just copy the source alpha channel and crop it down.
00674                 vigra::copyImage(vigra::make_triple(alphaImg.first,
00675                         alphaImg.first + srcImgSize, alphaImg.second),
00676                         vigra::destImage(alpha));
00677                 hugin_utils::FDiff2D m( (cR.left() + cR.width()/2.0),
00678                             (cR.top() + cR.height()/2.0) );
00679                 double radius = std::min(cR.width(), cR.height())/2.0;
00680                 vigra_ext::circularCrop(vigra::destImageRange(alpha), m, radius);
00681                 break;
00682             }
00683             case SrcPanoImage::CROP_RECTANGLE:
00684             {
00685                 // Intersect the cropping rectangle with the one from the base
00686                 // image to ensure it fits inside.
00687                 cR &= vigra::Rect2D(0,0, srcImgSize.x, srcImgSize.y);
00688 
00689                 // Start with a blank alpha channel for the destination
00690                 initImage(vigra::destImageRange(alpha),0);
00691 
00692                 // Copy in only the area inside the rectangle
00693                 vigra::copyImage(alphaImg.first + cR.upperLeft(),
00694                         alphaImg.first + cR.lowerRight(),
00695                         alphaImg.second,
00696                         alpha.upperLeft() + cR.upperLeft(),alpha.accessor());
00697                 break;
00698             }
00699             default:
00700                 break;
00701         }
00702         if(m_srcImg.hasActiveMasks())
00703             vigra_ext::applyMask(vigra::destImageRange(alpha), m_srcImg.getActiveMasks());
00704         if (Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false))
00705         {
00706             const float lowerCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureLowerCutoff", NONA_DEFAULT_EXPOSURE_LOWER_CUTOFF);
00707             const float upperCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureUpperCutoff", NONA_DEFAULT_EXPOSURE_UPPER_CUTOFF);
00708             vigra_ext::applyExposureClipMask(srcImg, vigra::destImageRange(alpha), lowerCutoff, upperCutoff);
00709         };
00710         if (useGPU) {
00711             vigra_ext::transformImageAlphaGPU(srcImg,
00712                                               vigra::srcImage(alpha),
00713                                               destImageRange(Base::m_image),
00714                                               destImage(Base::m_mask),
00715                                               Base::boundingBox().upperLeft(),
00716                                               m_transf,
00717                                               invResponse,
00718                                               m_srcImg.horizontalWarpNeeded(),
00719                                               interp,
00720                                               progress);
00721         } else {
00722             vigra_ext::transformImageAlpha(srcImg,
00723                                            vigra::srcImage(alpha),
00724                                            destImageRange(Base::m_image),
00725                                            destImage(Base::m_mask),
00726                                            Base::boundingBox().upperLeft(),
00727                                            m_transf,
00728                                            invResponse,
00729                                            m_srcImg.horizontalWarpNeeded(),
00730                                            interp,
00731                                            progress,
00732                                            singleThreaded);
00733         }
00734     } else {
00735         if (useGPU) {
00736             // extended region (if any) should already be cleared since ImportImageAlpha shouldn't have touched it.
00737             vigra_ext::transformImageAlphaGPU(srcImg,
00738                                               alphaImg,
00739                                               destImageRange(Base::m_image),
00740                                               destImage(Base::m_mask),
00741                                               Base::boundingBox().upperLeft(),
00742                                               m_transf,
00743                                               invResponse,
00744                                               m_srcImg.horizontalWarpNeeded(),
00745                                               interp,
00746                                               progress);
00747         } else {
00748             vigra_ext::transformImageAlpha(srcImg,
00749                                            alphaImg,
00750                                            destImageRange(Base::m_image),
00751                                            destImage(Base::m_mask),
00752                                            Base::boundingBox().upperLeft(),
00753                                            m_transf,
00754                                            invResponse,
00755                                            m_srcImg.horizontalWarpNeeded(),
00756                                            interp,
00757                                            progress,
00758                                            singleThreaded);
00759         }
00760     }
00761 }
00762 
00763 
00764 
00765 
00766 
00767 
00770 template <class SrcImgType, class FlatImgType, class DestImgType, class MaskImgType>
00771 void remapImage(SrcImgType & srcImg,
00772                 const MaskImgType & srcAlpha,
00773                 const FlatImgType & srcFlat,
00774                 const SrcPanoImage & src,
00775                 const PanoramaOptions & dest,
00776                 vigra::Rect2D outputROI,
00777 //                vigra_ext::Interpolator interpolator,
00778                 RemappedPanoImage<DestImgType, MaskImgType> & remapped,
00779                 AppBase::ProgressDisplay* progress)
00780 {
00781 #ifdef DEBUG_REMAP
00782     {
00783         vigra::ImageExportInfo exi( DEBUG_FILE_PREFIX "hugin03_BeforeRemap.tif");
00784                 vigra::exportImage(vigra::srcImageRange(srcImg), exi);
00785     }
00786     {
00787         if (srcAlpha.width() > 0) {
00788             vigra::ImageExportInfo exi(DEBUG_FILE_PREFIX "hugin04_BeforeRemapAlpha.tif");
00789                     vigra::exportImage(vigra::srcImageRange(srcAlpha), exi);
00790         }
00791     }
00792 #endif
00793 
00794     progress->setMessage("remapping", hugin_utils::stripPath(src.getFilename()));
00795     // set pano image
00796     DEBUG_DEBUG("setting src image with size: " << src.getSize());
00797     remapped.setPanoImage(src, dest, outputROI);
00798     // TODO: add provide support for flatfield images.
00799     if (srcAlpha.size().x > 0) {
00800         remapped.remapImage(vigra::srcImageRange(srcImg),
00801                             vigra::srcImage(srcAlpha), dest.interpolator,
00802                             progress);
00803     } else {
00804         remapped.remapImage(vigra::srcImageRange(srcImg), dest.interpolator, progress);
00805     }
00806 
00807 #ifdef DEBUG_REMAP
00808     {
00809         vigra::ImageExportInfo exi( DEBUG_FILE_PREFIX "hugin04_AfterRemap.tif"); 
00810                 vigra::exportImage(vigra::srcImageRange(remapped.m_image), exi); 
00811     }
00812     {
00813         vigra::ImageExportInfo exi(DEBUG_FILE_PREFIX "hugin04_AfterRemapAlpha.tif");
00814                 vigra::exportImage(vigra::srcImageRange(remapped.m_mask), exi);
00815     }
00816 #endif
00817 }
00818 
00819 
00820 } //namespace
00821 } //namespace
00822 
00823 #endif // _H

Generated on 29 Mar 2017 for Hugintrunk by  doxygen 1.4.7