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

Generated on 4 Aug 2015 for Hugintrunk by  doxygen 1.4.7