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