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

Generated on 24 Nov 2017 for Hugintrunk by  doxygen 1.4.7