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         const int r = expectedSize.width() % 8;
00437         if (r != 0) expectedSize += vigra::Diff2D(8 - r, 0);
00438     }
00439 
00440     DEBUG_DEBUG("srcImgSize: " << srcImgSize << " m_srcImgSize: " << m_srcImg.getSize());
00441     vigra_precondition(srcImgSize == expectedSize, 
00442                        "RemappedPanoImage<RemapImage,AlphaImage>::remapImage(): image sizes not consistent");
00443 
00444     typedef typename ImgAccessor::value_type input_value_type;
00445     typedef typename vigra_ext::ValueTypeTraits<input_value_type>::value_type input_component_type;
00446 
00447     // setup photometric transform for this image type
00448     // this corrects for response curve, white balance, exposure and 
00449     // radial vignetting
00450     Photometric::InvResponseTransform<input_component_type, double> invResponse(m_srcImg);
00451     invResponse.enforceMonotonicity();
00452     if (m_destImg.outputMode == PanoramaOptions::OUTPUT_LDR) {
00453         // select exposure and response curve for LDR output
00454         std::vector<double> outLut;
00455         vigra_ext::EMoR::createEMoRLUT(m_destImg.outputEMoRParams, outLut);
00456         double maxVal = vigra_ext::LUTTraits<input_value_type>::max();
00457         if (m_destImg.outputPixelType.size() > 0) {
00458             maxVal = vigra_ext::getMaxValForPixelType(m_destImg.outputPixelType);
00459         }
00460 
00461         invResponse.setOutput(1.0/pow(2.0,m_destImg.outputExposureValue), outLut,
00462                               maxVal);
00463     } else {
00464         invResponse.setHDROutput(true,1.0/pow(2.0,m_destImg.outputExposureValue));
00465     }
00466 
00467     if ((m_srcImg.hasActiveMasks()) || (m_srcImg.getCropMode() != SrcPanoImage::NO_CROP) || Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false))
00468     {
00469         // need to create and additional alpha image for the crop mask...
00470         // not very efficient during the remapping phase, but works.
00471         vigra::BImage alpha(srcImgSize.x, srcImgSize.y);
00472 
00473         switch (m_srcImg.getCropMode()) {
00474         case SrcPanoImage::NO_CROP:
00475             {
00476                 if (useGPU) {
00477                     if (srcImgSize != m_srcImg.getSize()) {
00478                         // src image with was increased for alignment reasons.
00479                         // Need to make an alpha image to mask off the extended region.
00480                         initImage(vigra::destImageRange(alpha),0);
00481                         initImage(alpha.upperLeft(), 
00482                             alpha.upperLeft()+m_srcImg.getSize(),
00483                             alpha.accessor(),255);
00484                     }
00485                     else
00486                         initImage(vigra::destImageRange(alpha),255);
00487                 }
00488                 else
00489                     initImage(vigra::destImageRange(alpha),255);
00490                 break;
00491             }
00492         case SrcPanoImage::CROP_CIRCLE:
00493             {
00494                 vigra::Rect2D cR = m_srcImg.getCropRect();
00495                 hugin_utils::FDiff2D m( (cR.left() + cR.width()/2.0),
00496                         (cR.top() + cR.height()/2.0) );
00497 
00498                 double radius = std::min(cR.width(), cR.height())/2.0;
00499                 // Default the entire alpha channel to opaque..
00500                 initImage(vigra::destImageRange(alpha),255);
00501                 //..crop everything outside the circle
00502                 vigra_ext::circularCrop(vigra::destImageRange(alpha), m, radius);
00503                 break;
00504             }
00505         case SrcPanoImage::CROP_RECTANGLE:
00506             {
00507                 vigra::Rect2D cR = m_srcImg.getCropRect();
00508                 // Default the entire alpha channel to transparent..
00509                 initImage(vigra::destImageRange(alpha),0);
00510                 // Make sure crop is inside the image..
00511                 cR &= vigra::Rect2D(0,0, srcImgSize.x, srcImgSize.y);
00512                 // Opaque only the area within the crop rectangle..
00513                 initImage(alpha.upperLeft()+cR.upperLeft(), 
00514                           alpha.upperLeft()+cR.lowerRight(),
00515                           alpha.accessor(),255);
00516                 break;
00517             }
00518         default:
00519             break;
00520         }
00521         if(m_srcImg.hasActiveMasks())
00522             vigra_ext::applyMask(vigra::destImageRange(alpha), m_srcImg.getActiveMasks());
00523         if (Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false))
00524         {
00525             const float lowerCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureLowerCutoff", NONA_DEFAULT_EXPOSURE_LOWER_CUTOFF);
00526             const float upperCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureUpperCutoff", NONA_DEFAULT_EXPOSURE_UPPER_CUTOFF);
00527             vigra_ext::applyExposureClipMask(srcImg, vigra::destImageRange(alpha), lowerCutoff, upperCutoff);
00528         };
00529         if (useGPU) {
00530             transformImageAlphaGPU(srcImg,
00531                                    vigra::srcImage(alpha),
00532                                    destImageRange(Base::m_image),
00533                                    destImage(Base::m_mask),
00534                                    Base::boundingBox().upperLeft(),
00535                                    m_transf,
00536                                    invResponse,
00537                                    m_srcImg.horizontalWarpNeeded(),
00538                                    interpol,
00539                                    progress);
00540         } else {
00541             transformImageAlpha(srcImg,
00542                                 vigra::srcImage(alpha),
00543                                 destImageRange(Base::m_image),
00544                                 destImage(Base::m_mask),
00545                                 Base::boundingBox().upperLeft(),
00546                                 m_transf,
00547                                 invResponse,
00548                                 m_srcImg.horizontalWarpNeeded(),
00549                                 interpol,
00550                                 progress,
00551                                 singleThreaded);
00552         }
00553     } else {
00554         if (useGPU) {
00555             if (srcImgSize != m_srcImg.getSize()) {
00556                 // src image with was increased for alignment reasons.
00557                 // Need to make an alpha image to mask off the extended region.
00558                 vigra::BImage alpha(srcImgSize.x, srcImgSize.y, vigra::UInt8(0));
00559                 initImage(alpha.upperLeft(), 
00560                           alpha.upperLeft()+m_srcImg.getSize(),
00561                           alpha.accessor(),255);
00562                 transformImageAlphaGPU(srcImg,
00563                                        vigra::srcImage(alpha),
00564                                        destImageRange(Base::m_image),
00565                                        destImage(Base::m_mask),
00566                                        Base::boundingBox().upperLeft(),
00567                                        m_transf,
00568                                        invResponse,
00569                                        m_srcImg.horizontalWarpNeeded(),
00570                                        interpol,
00571                                        progress);
00572 
00573             }
00574             else {
00575                 transformImageGPU(srcImg,
00576                                   destImageRange(Base::m_image),
00577                                   destImage(Base::m_mask),
00578                                   Base::boundingBox().upperLeft(),
00579                                   m_transf,
00580                                   invResponse,
00581                                   m_srcImg.horizontalWarpNeeded(),
00582                                   interpol,
00583                                   progress);
00584             }
00585         } else {
00586             transformImage(srcImg,
00587                            destImageRange(Base::m_image),
00588                            destImage(Base::m_mask),
00589                            Base::boundingBox().upperLeft(),
00590                            m_transf,
00591                            invResponse,
00592                            m_srcImg.horizontalWarpNeeded(),
00593                            interpol,
00594                            progress,
00595                            singleThreaded);
00596         }
00597     }
00598 }
00599 
00600 
00601 
00603 template<class RemapImage, class AlphaImage>
00604 template<class ImgIter, class ImgAccessor,
00605          class AlphaIter, class AlphaAccessor>
00606 void RemappedPanoImage<RemapImage,AlphaImage>::remapImage(vigra::triple<ImgIter, ImgIter, ImgAccessor> srcImg,
00607                                                           std::pair<AlphaIter, AlphaAccessor> alphaImg,
00608                                                           vigra_ext::Interpolator interp,
00609                                                           AppBase::ProgressDisplay* progress, bool singleThreaded)
00610 {
00611     const bool useGPU = m_destImg.remapUsingGPU;
00612 
00613     if (Base::boundingBox().isEmpty())
00614         return;
00615 
00616     progress->setMessage("remapping", hugin_utils::stripPath(m_srcImg.getFilename()));
00617 
00618     vigra::Diff2D srcImgSize = srcImg.second - srcImg.first;
00619 
00620     vigra::Size2D expectedSize = m_srcImg.getSize();
00621     if (useGPU) {
00622         const int r = expectedSize.width() % 8;
00623         if (r != 0) expectedSize += vigra::Diff2D(8 - r, 0);
00624     }
00625 
00626     vigra_precondition(srcImgSize == expectedSize, 
00627                        "RemappedPanoImage<RemapImage,AlphaImage>::remapImage(): image sizes not consistent");
00628 
00629     typedef typename ImgAccessor::value_type input_value_type;
00630     typedef typename vigra_ext::ValueTypeTraits<input_value_type>::value_type input_component_type;
00631 
00632     // setup photometric transform for this image type
00633     // this corrects for response curve, white balance, exposure and 
00634     // radial vignetting
00635     Photometric::InvResponseTransform<input_component_type, double> invResponse(m_srcImg);
00636     if (m_destImg.outputMode == PanoramaOptions::OUTPUT_LDR) {
00637         // select exposure and response curve for LDR output
00638         std::vector<double> outLut;
00639         // scale up to desired output format
00640         double maxVal = vigra_ext::LUTTraits<input_value_type>::max();
00641         if (m_destImg.outputPixelType.size() > 0) {
00642             maxVal = vigra_ext::getMaxValForPixelType(m_destImg.outputPixelType);
00643         }
00644         vigra_ext::EMoR::createEMoRLUT(m_destImg.outputEMoRParams, outLut);
00645                 vigra_ext::enforceMonotonicity(outLut);
00646         invResponse.setOutput(1.0/pow(2.0,m_destImg.outputExposureValue), outLut,
00647                               maxVal);
00648     } else {
00649         invResponse.setHDROutput(true,1.0/pow(2.0,m_destImg.outputExposureValue));
00650     }
00651 
00652     if ((m_srcImg.hasActiveMasks()) || (m_srcImg.getCropMode() != SrcPanoImage::NO_CROP) || Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false)) {
00653         vigra::BImage alpha(srcImgSize);
00654         vigra::Rect2D cR = m_srcImg.getCropRect();
00655         switch (m_srcImg.getCropMode()) {
00656             case SrcPanoImage::NO_CROP:
00657             {
00658                 // Just copy the source alpha channel and crop it down.
00659                 vigra::copyImage(vigra::make_triple(alphaImg.first,
00660                         alphaImg.first + srcImgSize, alphaImg.second),
00661                         vigra::destImage(alpha));
00662                 break;
00663             }
00664             case SrcPanoImage::CROP_CIRCLE:
00665             {
00666                 // Just copy the source alpha channel and crop it down.
00667                 vigra::copyImage(vigra::make_triple(alphaImg.first,
00668                         alphaImg.first + srcImgSize, alphaImg.second),
00669                         vigra::destImage(alpha));
00670                 hugin_utils::FDiff2D m( (cR.left() + cR.width()/2.0),
00671                             (cR.top() + cR.height()/2.0) );
00672                 double radius = std::min(cR.width(), cR.height())/2.0;
00673                 vigra_ext::circularCrop(vigra::destImageRange(alpha), m, radius);
00674                 break;
00675             }
00676             case SrcPanoImage::CROP_RECTANGLE:
00677             {
00678                 // Intersect the cropping rectangle with the one from the base
00679                 // image to ensure it fits inside.
00680                 cR &= vigra::Rect2D(0,0, srcImgSize.x, srcImgSize.y);
00681 
00682                 // Start with a blank alpha channel for the destination
00683                 initImage(vigra::destImageRange(alpha),0);
00684 
00685                 // Copy in only the area inside the rectangle
00686                 vigra::copyImage(alphaImg.first + cR.upperLeft(),
00687                         alphaImg.first + cR.lowerRight(),
00688                         alphaImg.second,
00689                         alpha.upperLeft() + cR.upperLeft(),alpha.accessor());
00690                 break;
00691             }
00692             default:
00693                 break;
00694         }
00695         if(m_srcImg.hasActiveMasks())
00696             vigra_ext::applyMask(vigra::destImageRange(alpha), m_srcImg.getActiveMasks());
00697         if (Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposure", false))
00698         {
00699             const float lowerCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureLowerCutoff", NONA_DEFAULT_EXPOSURE_LOWER_CUTOFF);
00700             const float upperCutoff = Nona::GetAdvancedOption(m_advancedOptions, "maskClipExposureUpperCutoff", NONA_DEFAULT_EXPOSURE_UPPER_CUTOFF);
00701             vigra_ext::applyExposureClipMask(srcImg, vigra::destImageRange(alpha), lowerCutoff, upperCutoff);
00702         };
00703         if (useGPU) {
00704             vigra_ext::transformImageAlphaGPU(srcImg,
00705                                               vigra::srcImage(alpha),
00706                                               destImageRange(Base::m_image),
00707                                               destImage(Base::m_mask),
00708                                               Base::boundingBox().upperLeft(),
00709                                               m_transf,
00710                                               invResponse,
00711                                               m_srcImg.horizontalWarpNeeded(),
00712                                               interp,
00713                                               progress);
00714         } else {
00715             vigra_ext::transformImageAlpha(srcImg,
00716                                            vigra::srcImage(alpha),
00717                                            destImageRange(Base::m_image),
00718                                            destImage(Base::m_mask),
00719                                            Base::boundingBox().upperLeft(),
00720                                            m_transf,
00721                                            invResponse,
00722                                            m_srcImg.horizontalWarpNeeded(),
00723                                            interp,
00724                                            progress,
00725                                            singleThreaded);
00726         }
00727     } else {
00728         if (useGPU) {
00729             // extended region (if any) should already be cleared since ImportImageAlpha shouldn't have touched it.
00730             vigra_ext::transformImageAlphaGPU(srcImg,
00731                                               alphaImg,
00732                                               destImageRange(Base::m_image),
00733                                               destImage(Base::m_mask),
00734                                               Base::boundingBox().upperLeft(),
00735                                               m_transf,
00736                                               invResponse,
00737                                               m_srcImg.horizontalWarpNeeded(),
00738                                               interp,
00739                                               progress);
00740         } else {
00741             vigra_ext::transformImageAlpha(srcImg,
00742                                            alphaImg,
00743                                            destImageRange(Base::m_image),
00744                                            destImage(Base::m_mask),
00745                                            Base::boundingBox().upperLeft(),
00746                                            m_transf,
00747                                            invResponse,
00748                                            m_srcImg.horizontalWarpNeeded(),
00749                                            interp,
00750                                            progress,
00751                                            singleThreaded);
00752         }
00753     }
00754 }
00755 
00756 
00757 
00758 
00759 
00760 
00763 template <class SrcImgType, class FlatImgType, class DestImgType, class MaskImgType>
00764 void remapImage(SrcImgType & srcImg,
00765                 const MaskImgType & srcAlpha,
00766                 const FlatImgType & srcFlat,
00767                 const SrcPanoImage & src,
00768                 const PanoramaOptions & dest,
00769                 vigra::Rect2D outputROI,
00770 //                vigra_ext::Interpolator interpolator,
00771                 RemappedPanoImage<DestImgType, MaskImgType> & remapped,
00772                 AppBase::ProgressDisplay* progress)
00773 {
00774 #ifdef DEBUG_REMAP
00775     {
00776         vigra::ImageExportInfo exi( DEBUG_FILE_PREFIX "hugin03_BeforeRemap.tif");
00777                 vigra::exportImage(vigra::srcImageRange(srcImg), exi);
00778     }
00779     {
00780         if (srcAlpha.width() > 0) {
00781             vigra::ImageExportInfo exi(DEBUG_FILE_PREFIX "hugin04_BeforeRemapAlpha.tif");
00782                     vigra::exportImage(vigra::srcImageRange(srcAlpha), exi);
00783         }
00784     }
00785 #endif
00786 
00787     progress->setMessage("remapping", hugin_utils::stripPath(src.getFilename()));
00788     // set pano image
00789     DEBUG_DEBUG("setting src image with size: " << src.getSize());
00790     remapped.setPanoImage(src, dest, outputROI);
00791     // TODO: add provide support for flatfield images.
00792     if (srcAlpha.size().x > 0) {
00793         remapped.remapImage(vigra::srcImageRange(srcImg),
00794                             vigra::srcImage(srcAlpha), dest.interpolator,
00795                             progress);
00796     } else {
00797         remapped.remapImage(vigra::srcImageRange(srcImg), dest.interpolator, progress);
00798     }
00799 
00800 #ifdef DEBUG_REMAP
00801     {
00802         vigra::ImageExportInfo exi( DEBUG_FILE_PREFIX "hugin04_AfterRemap.tif"); 
00803                 vigra::exportImage(vigra::srcImageRange(remapped.m_image), exi); 
00804     }
00805     {
00806         vigra::ImageExportInfo exi(DEBUG_FILE_PREFIX "hugin04_AfterRemapAlpha.tif");
00807                 vigra::exportImage(vigra::srcImageRange(remapped.m_mask), exi);
00808     }
00809 #endif
00810 }
00811 
00812 
00813 } //namespace
00814 } //namespace
00815 
00816 #endif // _H

Generated on 29 Aug 2016 for Hugintrunk by  doxygen 1.4.7