41 #include "boost/pointer_cast.hpp"
73 static inline void checkWarpingKernelParameter(
const SeparableKernel *p,
unsigned int ind,
double value) {
76 "bad ind argument in WarpingKernel::setKernelParameter()");
78 int ctr = p->getCtr()[ind];
79 int size = p->getDimensions()[ind];
81 if (ctr == (size - 1) / 2) {
82 if (value < -1e-6 || value > 1 + 1e-6) {
84 "bad coordinate in WarpingKernel::setKernelParameter()");
86 }
else if (ctr == (size + 1) / 2) {
87 if (value < -1 - 1e-6 || value > 1e-6) {
89 "bad coordinate in WarpingKernel::setKernelParameter()");
93 "bad ctr value in WarpingKernel::setKernelParameter()");
104 checkWarpingKernelParameter(
this, ind, value);
125 return 0.5 + (1.0 - (2.0 * fabs(this->
_params[0]))) * (0.5 - fabs(
x));
129 checkWarpingKernelParameter(
this, ind, value);
135 os <<
"_BilinearFunction1: ";
136 os << Function1<Kernel::Pixel>::toString(
prefix);
141 return std::make_shared<NearestWarpingKernel>();
146 return static_cast<double>((fabs(this->_params[0]) < 0.5) == (fabs(
x) < 0.5));
150 checkWarpingKernelParameter(
this, ind, value);
156 os <<
"_NearestFunction1: ";
157 os << Function1<Kernel::Pixel>::toString(
prefix);
164 static const std::regex LanczosRE(
"lanczos(\\d+)");
165 if (
name ==
"bilinear") {
171 }
else if (
name ==
"nearest") {
179 if (_warpingKernelPtr->getCacheSize() != _cacheSize) {
180 _warpingKernelPtr->computeCache(_cacheSize);
182 return _warpingKernelPtr;
187 setWarpingKernel(*warpingKernelPtr);
191 if (_maskWarpingKernelPtr) {
192 _testWarpingKernels(warpingKernel, *_maskWarpingKernelPtr);
195 std::static_pointer_cast<SeparableKernel>(warpingKernel.
clone()));
196 _warpingKernelPtr = warpingKernelPtr;
200 if (_maskWarpingKernelPtr) {
201 if (_maskWarpingKernelPtr->getCacheSize() != _cacheSize) {
202 _maskWarpingKernelPtr->computeCache(_cacheSize);
205 return _maskWarpingKernelPtr;
209 if (!maskWarpingKernelName.
empty()) {
211 setMaskWarpingKernel(*maskWarpingKernelPtr);
213 _maskWarpingKernelPtr.reset();
218 _testWarpingKernels(*_warpingKernelPtr, maskWarpingKernel);
219 _maskWarpingKernelPtr = std::static_pointer_cast<SeparableKernel>(maskWarpingKernel.
clone());
222 void WarpingControl::_testWarpingKernels(
SeparableKernel const &warpingKernel,
230 if (!kernelBBox.
contains(maskKernelBBox)) {
232 "warping kernel is smaller than mask warping kernel");
236 template <
typename DestExposureT,
typename SrcExposureT>
238 typename DestExposureT::MaskedImageT::SinglePixel padValue) {
239 if (!destExposure.hasWcs()) {
242 if (!srcExposure.hasWcs()) {
245 typename DestExposureT::MaskedImageT mi = destExposure.getMaskedImage();
246 destExposure.setPhotoCalib(srcExposure.getPhotoCalib());
247 destExposure.setFilterLabel(srcExposure.getFilterLabel());
248 destExposure.getInfo()->setVisitInfo(srcExposure.getInfo()->getVisitInfo());
249 return warpImage(mi, *destExposure.getWcs(), srcExposure.getMaskedImage(), *srcExposure.getWcs(), control,
267 inline double computeRelativeArea(
276 return std::abs(dSrcA.getX() * dSrcB.getY() - dSrcA.getY() * dSrcB.getX());
281 template <
typename DestImageT,
typename SrcImageT>
284 typename DestImageT::SinglePixel padValue) {
286 return warpImage(destImage, srcImage, *srcToDest, control, padValue);
289 template <
typename DestImageT,
typename SrcImageT>
290 int warpImage(DestImageT &destImage, SrcImageT
const &srcImage,
292 typename DestImageT::SinglePixel padValue) {
302 warpingKernelPtr->shrinkBBox(srcImage.getBBox(
image::LOCAL));
304 for (
int y = 0, height = destImage.getHeight();
y < height; ++
y) {
305 for (
typename DestImageT::x_iterator destPtr = destImage.row_begin(
y),
end = destImage.row_end(
y);
306 destPtr !=
end; ++destPtr) {
315 std::dynamic_pointer_cast<LanczosWarpingKernel>(warpingKernelPtr);
317 int numGoodPixels = 0;
320 auto const parentDestToParentSrc = srcToDest.
inverted();
321 std::vector<double> const localDestToParentDestVec = {
static_cast<double>(destImage.getX0()),
322 static_cast<double>(destImage.getY0())};
324 auto const localDestToParentSrc = localDestToParentDest.then(*parentDestToParentSrc);
327 int const srcWidth = srcImage.getWidth();
328 int const srcHeight = srcImage.getHeight();
329 LOGL_DEBUG(
"TRACE2.afw.math.warp",
"source image width=%d; height=%d", srcWidth, srcHeight);
331 int const destWidth = destImage.getWidth();
332 int const destHeight = destImage.getHeight();
333 LOGL_DEBUG(
"TRACE2.afw.math.warp",
"remap image width=%d; height=%d", destWidth, destHeight);
336 LOGL_DEBUG(
"TRACE3.afw.math.warp",
"Remapping masked image");
338 int const maxCol = destWidth - 1;
339 int const maxRow = destHeight - 1;
343 if (interpLength > 0) {
348 int const numColEdges = 2 + ((destWidth - 1) / interpLength);
353 edgeColList.
reserve(numColEdges);
358 invWidthList.
reserve(numColEdges);
363 for (
int prevEndCol = -1; prevEndCol < maxCol; prevEndCol += interpLength) {
364 int endCol = prevEndCol + interpLength;
365 if (endCol > maxCol) {
369 assert(endCol - prevEndCol > 0);
370 invWidthList.
push_back(1.0 /
static_cast<double>(endCol - prevEndCol));
372 assert(edgeColList.
back() == maxCol);
387 endColPosList.
reserve(numColEdges);
390 for (
int colBand = 0, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
391 int const endCol = edgeColList[colBand];
394 auto rightSrcPosList = localDestToParentSrc->applyForward(endColPosList);
395 srcPosView[-1] = rightSrcPosList[0];
396 for (
int colBand = 1, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
397 int const prevEndCol = edgeColList[colBand - 1];
398 int const endCol = edgeColList[colBand];
402 (rightSrcPosList[colBand] - leftSrcPos) * invWidthList[colBand];
404 for (
int col = prevEndCol + 1; col <= endCol; ++col) {
405 srcPosView[col] = srcPosView[col - 1] + xDeltaSrcPos;
410 while (endRow < maxRow) {
413 int prevEndRow = endRow;
414 endRow = prevEndRow + interpLength;
415 if (endRow > maxRow) {
418 assert(endRow - prevEndRow > 0);
419 double interpInvHeight = 1.0 /
static_cast<double>(endRow - prevEndRow);
424 for (
int colBand = 0, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
425 int endCol = edgeColList[colBand];
428 auto bottomSrcPosList = localDestToParentSrc->applyForward(destRowPosList);
429 for (
int colBand = 0, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
430 int endCol = edgeColList[colBand];
431 yDeltaSrcPosList[colBand] =
432 (bottomSrcPosList[colBand] - srcPosView[endCol]) * interpInvHeight;
435 for (
int row = prevEndRow + 1; row <= endRow; ++row) {
436 typename DestImageT::x_iterator destXIter = destImage.row_begin(row);
437 srcPosView[-1] += yDeltaSrcPosList[0];
438 for (
int colBand = 1, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
441 int const prevEndCol = edgeColList[colBand - 1];
442 int const endCol = edgeColList[colBand];
451 for (
int col = prevEndCol + 1; col <= endCol; ++col, ++destXIter) {
454 double relativeArea = computeRelativeArea(srcPos, leftSrcPos, srcPosView[col]);
456 srcPosView[col] = srcPos;
459 destXIter, srcPos, relativeArea,
474 destPosList.
reserve(1 + destWidth);
475 for (
int col = -1; col < destWidth; ++col) {
478 auto prevSrcPosList = localDestToParentSrc->applyForward(destPosList);
480 for (
int row = 0; row < destHeight; ++row) {
482 for (
int col = -1; col < destWidth; ++col) {
485 auto srcPosList = localDestToParentSrc->applyForward(destPosList);
487 typename DestImageT::x_iterator destXIter = destImage.row_begin(row);
488 for (
int col = 0; col < destWidth; ++col, ++destXIter) {
490 auto srcPos = srcPosList[col + 1];
491 double relativeArea =
492 computeRelativeArea(srcPos, prevSrcPosList[col], prevSrcPosList[col + 1]);
494 if (warpAtOnePoint(destXIter, srcPos, relativeArea,
501 swap(srcPosList, prevSrcPosList);
505 return numGoodPixels;
508 template <
typename DestImageT,
typename SrcImageT>
512 typename DestImageT::SinglePixel padValue) {
514 if ((destImage.getWidth() != srcImage.getWidth()) || (destImage.getHeight() != srcImage.getHeight()) ||
515 (destImage.getXY0() != srcImage.getXY0())) {
517 errStream <<
"src and dest images must have same size and xy0.";
522 SrcImageT srcImageCopy(srcImage,
true);
523 srcImageCopy.setXY0(0, 0);
524 destImage.setXY0(0, 0);
536 static float t = 0.0;
537 float t_before = 1.0*clock()/CLOCKS_PER_SEC;
538 int n =
warpImage(destImage, srcImageCopy, affTran, control, padValue);
539 float t_after = 1.0*clock()/CLOCKS_PER_SEC;
540 float dt = t_after - t_before;
542 std::cout <<srcImage.getWidth()<<
"x"<<srcImage.getHeight()<<
": "<< dt <<
" "<< t <<
std::endl;
544 int n =
warpImage(destImage, srcImageCopy, *affineTransform22, control, padValue);
548 destImage.setXY0(srcImage.getXY0());
558 #define EXPOSURE(PIXTYPE) image::Exposure<PIXTYPE, image::MaskPixel, image::VariancePixel>
559 #define MASKEDIMAGE(PIXTYPE) image::MaskedImage<PIXTYPE, image::MaskPixel, image::VariancePixel>
560 #define IMAGE(PIXTYPE) image::Image<PIXTYPE>
563 #define INSTANTIATE(DESTIMAGEPIXELT, SRCIMAGEPIXELT) \
564 template int warpCenteredImage( \
565 IMAGE(DESTIMAGEPIXELT) & destImage, IMAGE(SRCIMAGEPIXELT) const &srcImage, \
566 lsst::geom::LinearTransform const &linearTransform, lsst::geom::Point2D const ¢erPosition, \
567 WarpingControl const &control, IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
568 NL template int warpCenteredImage( \
569 MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
570 lsst::geom::LinearTransform const &linearTransform, lsst::geom::Point2D const ¢erPosition, \
571 WarpingControl const &control, MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
572 NL template int warpImage(IMAGE(DESTIMAGEPIXELT) & destImage, IMAGE(SRCIMAGEPIXELT) const &srcImage, \
573 geom::TransformPoint2ToPoint2 const &srcToDest, WarpingControl const &control, \
574 IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
575 NL template int warpImage(MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, \
576 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
577 geom::TransformPoint2ToPoint2 const &srcToDest, WarpingControl const &control, \
578 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
579 NL template int warpImage(IMAGE(DESTIMAGEPIXELT) & destImage, geom::SkyWcs const &destWcs, \
580 IMAGE(SRCIMAGEPIXELT) const &srcImage, geom::SkyWcs const &srcWcs, \
581 WarpingControl const &control, IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
582 NL template int warpImage(MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, geom::SkyWcs const &destWcs, \
583 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, geom::SkyWcs const &srcWcs, \
584 WarpingControl const &control, \
585 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
586 NL template int warpExposure(EXPOSURE(DESTIMAGEPIXELT) & destExposure, \
587 EXPOSURE(SRCIMAGEPIXELT) const &srcExposure, WarpingControl const &control, \
588 EXPOSURE(DESTIMAGEPIXELT)::MaskedImageT::SinglePixel padValue);
table::Key< std::string > name
#define INSTANTIATE(FROMSYS, TOSYS)
#define LSST_EXCEPT(type,...)
#define LOGL_DEBUG(logger, message...)
Implementation of the Photometric Calibration class.
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
lsst::geom::SpherePoint pixelToSky(lsst::geom::Point2D const &pixel) const
Compute sky position(s) from pixel position(s)
lsst::geom::Point2D skyToPixel(lsst::geom::SpherePoint const &sky) const
Compute pixel position(s) from sky position(s)
std::string toString(std::string const &="") const override
Return string representation.
Kernel::Pixel operator()(double x) const override
Solve bilinear equation.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
std::vector< double > _params
lsst::geom::Extent2I const getDimensions() const
Return the Kernel's dimensions (width, height)
lsst::geom::Point2I getCtr() const
Return index of kernel's center.
int getWidth() const
Return the Kernel's width.
Lanczos warping: accurate but slow and can introduce ringing artifacts.
int getOrder() const
get the order of the kernel
LanczosWarpingKernel(int order)
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
Kernel::Pixel operator()(double x) const override
Solve nearest neighbor equation.
std::string toString(std::string const &="") const override
Return string representation.
Nearest neighbor warping: fast; good for undersampled data.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
Parameters to control convolution.
void setWarpingKernel(SeparableKernel const &warpingKernel)
set the warping kernel
int getInterpLength() const
get the interpolation length (pixels)
void setWarpingKernelName(std::string const &warpingKernelName)
set the warping kernel by name
void setMaskWarpingKernelName(std::string const &maskWarpingKernelName)
set or clear the mask warping kernel by name
void setMaskWarpingKernel(SeparableKernel const &maskWarpingKernel)
set the mask warping kernel
std::shared_ptr< SeparableKernel > getWarpingKernel() const
get the warping kernel
std::shared_ptr< SeparableKernel > getMaskWarpingKernel() const
get the mask warping kernel
A functor that computes one warped pixel.
bool contains(Point2I const &point) const noexcept
T emplace_back(T... args)
void swap(CameraSys &a, CameraSys &b)
std::shared_ptr< TransformPoint2ToPoint2 > makeTransform(lsst::geom::AffineTransform const &affine)
Wrap an lsst::geom::AffineTransform as a Transform.
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
A Transform obtained by putting two SkyWcs objects "back to back".
Transform< Point2Endpoint, Point2Endpoint > TransformPoint2ToPoint2
double indexToPosition(double ind)
Convert image index to image position.
bool imagesOverlap(ImageBase< T1 > const &image1, ImageBase< T2 > const &image2)
Return true if the pixels for two images or masks overlap in memory.
std::shared_ptr< SeparableKernel > makeWarpingKernel(std::string name)
Return a warping kernel given its name.
int warpCenteredImage(DestImageT &destImage, SrcImageT const &srcImage, lsst::geom::LinearTransform const &linearTransform, lsst::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.
int warpImage(DestImageT &destImage, geom::SkyWcs const &destWcs, SrcImageT const &srcImage, geom::SkyWcs 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.
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.
Extent< double, 2 > Extent2D
A base class for image defects.
ImageT::image_category image_category