44 #include "boost/pointer_cast.hpp"
45 #include "boost/regex.hpp"
62 namespace pexExcept = lsst::pex::exceptions;
64 namespace afwGeom = lsst::afw::geom;
65 namespace afwCoord = lsst::afw::coord;
66 namespace afwMath = lsst::afw::math;
84 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"bad ind argument in WarpingKernel::setKernelParameter()");
86 int ctr = p->
getCtr()[ind];
89 if (ctr == (size-1)/2) {
90 if (value < -1e-6 || value > 1+1e-6) {
91 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"bad coordinate in WarpingKernel::setKernelParameter()");
93 }
else if (ctr == (size+1)/2) {
94 if (value < -1-1e-6 || value > 1e-6) {
95 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"bad coordinate in WarpingKernel::setKernelParameter()");
98 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"bad ctr value in WarpingKernel::setKernelParameter()");
116 checkWarpingKernelParameter(
this, ind, value);
145 return 0.5 + (1.0 - (2.0 * fabs(this->_params[0]))) * (0.5 - fabs(x));
150 checkWarpingKernelParameter(
this, ind, value);
157 std::string afwMath::BilinearWarpingKernel::BilinearFunction1::toString(std::string
const& prefix)
const {
158 std::ostringstream os;
159 os <<
"_BilinearFunction1: ";
160 os << Function1<Kernel::Pixel>::toString(prefix);
177 return static_cast<double>((fabs(this->_params[0]) < 0.5) == (fabs(x) < 0.5));
182 checkWarpingKernelParameter(
this, ind, value);
189 std::string afwMath::NearestWarpingKernel::NearestFunction1::toString(std::string
const& prefix)
const {
190 std::ostringstream os;
191 os <<
"_NearestFunction1: ";
192 os << Function1<Kernel::Pixel>::toString(prefix);
197 typedef std::shared_ptr<afwMath::SeparableKernel> KernelPtr;
198 boost::cmatch matches;
199 static const boost::regex LanczosRE(
"lanczos(\\d+)");
200 if (name ==
"bilinear") {
202 }
else if (boost::regex_match(name.c_str(), matches, LanczosRE)) {
203 std::string orderStr(matches[1].first, matches[1].second);
205 std::istringstream(orderStr) >> order;
207 }
else if (name ==
"nearest") {
210 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
211 "unknown warping kernel name: \"" + name +
"\"");
216 if (_warpingKernelPtr->getCacheSize() != _cacheSize) {
217 _warpingKernelPtr->computeCache(_cacheSize);
219 return _warpingKernelPtr;
226 setWarpingKernel(*warpingKernelPtr);
232 if (_maskWarpingKernelPtr) {
233 _testWarpingKernels(warpingKernel, *_maskWarpingKernelPtr);
236 _testDevicePreference(_devicePreference, warpingKernelPtr);
237 _warpingKernelPtr = warpingKernelPtr;
242 if (_maskWarpingKernelPtr) {
243 if (_maskWarpingKernelPtr->getCacheSize() != _cacheSize) {
244 _maskWarpingKernelPtr->computeCache(_cacheSize);
247 return _maskWarpingKernelPtr;
251 std::string
const &maskWarpingKernelName
253 if (!maskWarpingKernelName.empty()) {
255 setMaskWarpingKernel(*maskWarpingKernelPtr);
257 _maskWarpingKernelPtr.reset();
264 _testWarpingKernels(*_warpingKernelPtr, maskWarpingKernel);
281 if (!kernelBBox.
contains(maskKernelBBox)) {
282 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
283 "warping kernel is smaller than mask warping kernel");
294 throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
295 "devicePreference = USE_GPU, but warping kernel not Lanczos");
301 template<
typename DestExposureT,
typename SrcExposureT>
303 DestExposureT &destExposure,
304 SrcExposureT
const &srcExposure,
306 typename DestExposureT::MaskedImageT::SinglePixel padValue
309 if (!destExposure.hasWcs()) {
310 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"destExposure has no Wcs");
312 if (!srcExposure.hasWcs()) {
313 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"srcExposure has no Wcs");
315 typename DestExposureT::MaskedImageT mi = destExposure.getMaskedImage();
316 std::shared_ptr<afwImage::Calib> calibCopy(
new afwImage::Calib(*srcExposure.getCalib()));
317 destExposure.setCalib(calibCopy);
318 destExposure.setFilter(srcExposure.getFilter());
319 return warpImage(mi, *destExposure.getWcs(), srcExposure.getMaskedImage(), *srcExposure.getWcs(),
342 inline double computeRelativeArea(
350 return std::abs(dSrcA.getX()*dSrcB.getY() - dSrcA.getY()*dSrcB.getX());
353 template<
typename DestImageT,
typename SrcImageT>
355 DestImageT &destImage,
356 SrcImageT
const &srcImage,
357 afwMath::detail::PositionFunctor
const &computeSrcPos,
360 typename DestImageT::SinglePixel padValue
363 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
364 "destImage is srcImage; cannot warp in place");
372 warpingKernelPtr->shrinkBBox(srcImage.getBBox(afwImage::
LOCAL));
374 for (
int y = 0, height = destImage.getHeight();
y < height; ++
y) {
375 for (
typename DestImageT::x_iterator destPtr = destImage.row_begin(
y), end = destImage.row_end(
y);
376 destPtr != end; ++destPtr) {
383 int interpLength = control.getInterpLength();
386 std::shared_ptr<afwMath::LanczosWarpingKernel const> const lanczosKernelPtr =
387 std::dynamic_pointer_cast<afwMath::LanczosWarpingKernel>(warpingKernelPtr);
390 if(!lanczosKernelPtr) {
392 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"Gpu can process only Lanczos kernels");
396 if (control.getMaskWarpingKernel() )
397 maskWarpingKernelPtr = control.getMaskWarpingKernel();
400 std::pair<int, afwMath::detail::WarpImageGpuStatus::ReturnCode> result =
402 *lanczosKernelPtr, *maskWarpingKernelPtr,
403 computeSrcPos, interpLength, padValue,
false);
406 catch(lsst::afw::gpu::GpuMemoryError) { }
407 catch(pexExcept::MemoryError) { }
408 catch(lsst::afw::gpu::GpuRuntimeError) { }
410 std::pair<int, afwMath::detail::WarpImageGpuStatus::ReturnCode> result =
412 *lanczosKernelPtr, *maskWarpingKernelPtr,
413 computeSrcPos, interpLength, padValue,
418 "Gpu cannot perform this warp (kernel too big?)");
424 int numGoodPixels = 0;
427 int const srcWidth = srcImage.getWidth();
428 int const srcHeight = srcImage.getHeight();
429 LOGL_DEBUG(
"TRACE2.afw.math.warp",
"source image width=%d; height=%d", srcWidth, srcHeight);
431 int const destWidth = destImage.getWidth();
432 int const destHeight = destImage.getHeight();
434 LOGL_DEBUG(
"TRACE2.afw.math.warp",
"remap image width=%d; height=%d", destWidth, destHeight);
437 LOGL_DEBUG(
"TRACE3.afw.math.warp",
"Remapping masked image");
446 std::vector<afwGeom::Point2D> _srcPosList(1 + destWidth);
447 std::vector<afwGeom::Point2D>::iterator
const srcPosView = _srcPosList.begin() + 1;
449 int const maxCol = destWidth - 1;
450 int const maxRow = destHeight - 1;
452 afwMath::detail::WarpAtOnePoint<DestImageT, SrcImageT> warpAtOnePoint(srcImage, control, padValue);
454 if (interpLength > 0) {
459 int const numColEdges = 2 + ((destWidth - 1) / interpLength);
463 std::vector<int> edgeColList;
464 edgeColList.reserve(numColEdges);
468 std::vector<double> invWidthList;
469 invWidthList.reserve(numColEdges);
472 edgeColList.push_back(-1);
473 invWidthList.push_back(0.0);
474 for (
int prevEndCol = -1; prevEndCol < maxCol; prevEndCol += interpLength) {
475 int endCol = prevEndCol + interpLength;
476 if (endCol > maxCol) {
479 edgeColList.push_back(endCol);
480 assert(endCol - prevEndCol > 0);
481 invWidthList.push_back(1.0 / static_cast<double>(endCol - prevEndCol));
483 assert(edgeColList.back() == maxCol);
486 std::vector<afwGeom::Extent2D> yDeltaSrcPosList(edgeColList.size());
490 srcPosView[-1] = computeSrcPos(-1, -1);
491 for (
int colBand = 1, endBand = edgeColList.size(); colBand < endBand; ++colBand) {
492 int const prevEndCol = edgeColList[colBand-1];
493 int const endCol = edgeColList[colBand];
496 afwGeom::Extent2D xDeltaSrcPos = (rightSrcPos - leftSrcPos) * invWidthList[colBand];
498 for (
int col = prevEndCol + 1; col <= endCol; ++
col) {
499 srcPosView[
col] = srcPosView[col-1] + xDeltaSrcPos;
504 while (endRow < maxRow) {
507 int prevEndRow = endRow;
508 endRow = prevEndRow + interpLength;
509 if (endRow > maxRow) {
512 assert(endRow - prevEndRow > 0);
513 double interpInvHeight = 1.0 /
static_cast<double>(endRow - prevEndRow);
516 for (
int colBand = 0, endBand = edgeColList.size(); colBand < endBand; ++colBand) {
517 int endCol = edgeColList[colBand];
519 yDeltaSrcPosList[colBand] = (bottomSrcPos - srcPosView[endCol]) * interpInvHeight;
522 for (
int row = prevEndRow + 1; row <= endRow; ++
row) {
523 typename DestImageT::x_iterator destXIter = destImage.row_begin(row);
524 srcPosView[-1] += yDeltaSrcPosList[0];
525 for (
int colBand = 1, endBand = edgeColList.size(); colBand < endBand; ++colBand) {
528 int const prevEndCol = edgeColList[colBand-1];
529 int const endCol = edgeColList[colBand];
535 afwGeom::Point2D rightSrcPos = srcPosView[endCol] + yDeltaSrcPosList[colBand];
536 afwGeom::Extent2D xDeltaSrcPos = (rightSrcPos - leftSrcPos) * invWidthList[colBand];
538 for (
int col = prevEndCol + 1; col <= endCol; ++
col, ++destXIter) {
541 double relativeArea = computeRelativeArea(srcPos, leftSrcPos, srcPosView[col]);
543 srcPosView[
col] = srcPos;
545 if (warpAtOnePoint(destXIter, srcPos, relativeArea,
560 std::vector<afwGeom::Point2D>::iterator srcPosView = _srcPosList.begin() + 1;
561 for (
int col = -1; col < destWidth; ++
col) {
562 srcPosView[
col] = computeSrcPos(col, -1);
565 for (
int row = 0; row < destHeight; ++
row) {
566 typename DestImageT::x_iterator destXIter = destImage.row_begin(row);
568 srcPosView[-1] = computeSrcPos(-1, row);
570 for (
int col = 0; col < destWidth; ++
col, ++destXIter) {
572 double relativeArea = computeRelativeArea(srcPos, srcPosView[col-1], srcPosView[col]);
573 srcPosView[
col] = srcPos;
575 if (warpAtOnePoint(destXIter, srcPos, relativeArea,
583 return numGoodPixels;
588 template<
typename DestImageT,
typename SrcImageT>
590 DestImageT &destImage,
592 SrcImageT
const &srcImage,
595 typename DestImageT::SinglePixel padValue
599 afwMath::detail::XYTransformPositionFunctor
const computeSrcPos{destXY0, xyTransform};
600 return doWarpImage(destImage, srcImage, computeSrcPos, control, padValue);
604 template<
typename DestImageT,
typename SrcImageT>
606 DestImageT &destImage,
607 SrcImageT
const &srcImage,
610 typename DestImageT::SinglePixel padValue
613 afwMath::detail::XYTransformPositionFunctor
const computeSrcPos(destXY0, xyTransform);
614 return doWarpImage(destImage, srcImage, computeSrcPos, control, padValue);
618 template<
typename DestImageT,
typename SrcImageT>
620 DestImageT &destImage,
621 SrcImageT
const &srcImage,
625 typename DestImageT::SinglePixel padValue
629 (destImage.getWidth() != srcImage.getWidth()) ||
630 (destImage.getHeight() != srcImage.getHeight()) ||
631 (destImage.getXY0() != srcImage.getXY0())
633 std::ostringstream errStream;
634 errStream <<
"src and dest images must have same size and xy0.";
635 throw LSST_EXCEPT(pexExcept::InvalidParameterError, errStream.str());
639 SrcImageT srcImageCopy(srcImage,
true);
640 srcImageCopy.setXY0(0, 0);
641 destImage.setXY0(0, 0);
652 static float t = 0.0;
653 float t_before = 1.0*clock()/CLOCKS_PER_SEC;
654 int n =
warpImage(destImage, srcImageCopy, affTran, control, padValue);
655 float t_after = 1.0*clock()/CLOCKS_PER_SEC;
656 float dt = t_after - t_before;
658 std::cout <<srcImage.getWidth()<<
"x"<<srcImage.getHeight()<<
": "<< dt <<
" "<< t <<std::endl;
660 int n =
warpImage(destImage, srcImageCopy, affXYTransform, control, padValue);
664 destImage.setXY0(srcImage.getXY0());
675 #define EXPOSURE(PIXTYPE) afwImage::Exposure<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
676 #define MASKEDIMAGE(PIXTYPE) afwImage::MaskedImage<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
677 #define IMAGE(PIXTYPE) afwImage::Image<PIXTYPE>
680 #define INSTANTIATE(DESTIMAGEPIXELT, SRCIMAGEPIXELT) \
681 template int afwMath::warpCenteredImage( \
682 IMAGE(DESTIMAGEPIXELT) &destImage, \
683 IMAGE(SRCIMAGEPIXELT) const &srcImage, \
684 afwGeom::LinearTransform const &linearTransform, \
685 afwGeom::Point2D const ¢erPosition, \
686 afwMath::WarpingControl const &control, \
687 IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
688 template int afwMath::warpCenteredImage( \
689 MASKEDIMAGE(DESTIMAGEPIXELT) &destImage, \
690 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
691 afwGeom::LinearTransform const &linearTransform, \
692 afwGeom::Point2D const ¢erPosition, \
693 afwMath::WarpingControl const &control, \
694 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
695 template int afwMath::warpImage( \
696 IMAGE(DESTIMAGEPIXELT) &destImage, \
697 IMAGE(SRCIMAGEPIXELT) const &srcImage, \
698 afwGeom::XYTransform const &xyTransform, \
699 afwMath::WarpingControl const &control, \
700 IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
701 template int afwMath::warpImage( \
702 MASKEDIMAGE(DESTIMAGEPIXELT) &destImage, \
703 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
704 afwGeom::XYTransform const &xyTransform, \
705 afwMath::WarpingControl const &control, \
706 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
707 template int afwMath::warpImage( \
708 IMAGE(DESTIMAGEPIXELT) &destImage, \
709 afwImage::Wcs const &destWcs, \
710 IMAGE(SRCIMAGEPIXELT) const &srcImage, \
711 afwImage::Wcs const &srcWcs, \
712 afwMath::WarpingControl const &control, \
713 IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
714 template int afwMath::warpImage( \
715 MASKEDIMAGE(DESTIMAGEPIXELT) &destImage, \
716 afwImage::Wcs const &destWcs, \
717 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
718 afwImage::Wcs const &srcWcs, \
719 afwMath::WarpingControl const &control, \
720 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
721 template int afwMath::warpExposure( \
722 EXPOSURE(DESTIMAGEPIXELT) &destExposure, \
723 EXPOSURE(SRCIMAGEPIXELT) const &srcExposure, \
724 afwMath::WarpingControl const &control,\
725 EXPOSURE(DESTIMAGEPIXELT)::MaskedImageT::SinglePixel padValue);
bool isGpuEnabled()
returns true if GPU acceleration is enabled
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
GPU accelerared image warping.
An include file to include the header files for lsst::afw::geom.
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
Declare the Kernel class and subclasses.
boost::shared_ptr< SeparableKernel > makeWarpingKernel(std::string name)
Return a warping kernel given its name.
geom::Extent2I const getDimensions() const
Return the Kernel's dimensions (width, height)
double indexToPosition(double ind)
Convert image index to image position.
table::Key< std::string > name
#define LOGL_DEBUG(logger, message...)
bool contains(Point2I const &point) const
Return true if the box contains the point.
additional GPU exceptions
geom::Point2D skyToPixel(geom::Angle sky1, geom::Angle sky2) const
Convert from sky coordinates (e.g. RA/dec) to pixel positions.
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
void setWarpingKernelName(std::string const &warpingKernelName)
set the warping kernel by name
void _testDevicePreference(lsst::afw::gpu::DevicePreference const &devicePreference, boost::shared_ptr< SeparableKernel const > const &warpingKernelPtr) const
test if GPU device preference and main warping kernel are compatible
Parameters to control convolution.
Implementation of the WCS standard for a any projection.
virtual Ptr clone(void) const
int warpCenteredImage(DestImageT &destImage, SrcImageT const &srcImage, lsst::afw::geom::LinearTransform const &linearTransform, lsst::afw::geom::Point2D const ¢erPosition, WarpingControl const &control, typename DestImageT::SinglePixel padValue=lsst::afw::math::edgePixel< DestImageT >(typename lsst::afw::image::detail::image_traits< DestImageT >::image_category()))
Warp an image with a LinearTranform about a specified point. This enables warping an image of e...
boost::shared_ptr< coord::Coord > pixelToSky(double pix1, double pix2) const
Convert from pixel position to sky coordinates (e.g. RA/dec)
DevicePreference
A type used to select whether to use CPU or GPU device.
void setMaskWarpingKernel(SeparableKernel const &maskWarpingKernel)
set the mask warping kernel
An integer coordinate rectangle.
int warpImage(DestImageT &destImage, lsst::afw::image::Wcs const &destWcs, SrcImageT const &srcImage, lsst::afw::image::Wcs const &srcWcs, WarpingControl const &control, typename DestImageT::SinglePixel padValue=lsst::afw::math::edgePixel< DestImageT >(typename lsst::afw::image::detail::image_traits< DestImageT >::image_category()))
Warp an Image or MaskedImage to a new Wcs. See also convenience function warpExposure() to warp an Ex...
table::Key< table::Array< Kernel::Pixel > > image
int getOrder() const
get the order of the kernel
int getWidth() const
Return the Kernel's width.
std::pair< int, WarpImageGpuStatus::ReturnCode > warpImageGPU(DestImageT &destImage, SrcImageT const &srcImage, afwMath::LanczosWarpingKernel const &lanczosKernel, lsst::afw::math::SeparableKernel const &maskWarpingKernel, PositionFunctor const &computeSrcPos, int const interpLength, typename DestImageT::SinglePixel padValue, const bool forceProcessing)
GPU accelerated image warping using Lanczos resampling.
int warpExposure(DestExposureT &destExposure, SrcExposureT const &srcExposure, WarpingControl const &control, typename DestExposureT::MaskedImageT::SinglePixel padValue=lsst::afw::math::edgePixel< typename DestExposureT::MaskedImageT >(typename lsst::afw::image::detail::image_traits< typename DestExposureT::MaskedImageT >::image_category()))
Warp (remap) one exposure to another.
void setMaskWarpingKernelName(std::string const &maskWarpingKernelName)
set or clear the mask warping kernel by name
bool isSameObject(A const &, B const &)
bool isGpuBuild()
Inline function which returns true only when GPU_BUILD macro is defined.
void setWarpingKernel(SeparableKernel const &warpingKernel)
set the warping kernel
if(width!=gim.getWidth()||height!=gim.getHeight()||x0!=gim.getX0()||y0!=gim.getY0())
Interface for CPU/GPU device selection.
lsst::afw::geom::Point2I getCtr() const
Return index of kernel's center.
Bilinear warping: fast; good for undersampled data.
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
#define LSST_EXCEPT(type,...)
tbl::Key< std::string > warpingKernelName
Support for warping an image to a new WCS.
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
Nearest neighbor warping: fast; good for undersampled data.
void _testWarpingKernels(SeparableKernel const &warpingKernel, SeparableKernel const &maskWarpingKernel) const
Throw an exception if the two kernels are not compatible in shape.
Lanczos warping: accurate but slow and can introduce ringing artifacts.
ImageT::image_category image_category
Extent< double, 2 > Extent2D
GPU accelerared image warping.
virtual boost::shared_ptr< Kernel > clone() const
Return a pointer to a deep copy of this kernel.
Include files required for standard LSST Exception handling.
Kernels are used for convolution with MaskedImages and (eventually) Images.
A function to determine whether compiling for GPU is enabled.
Functions to handle coordinates.