40 #include "boost/pointer_cast.hpp"
41 #include "boost/regex.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);
163 boost::cmatch matches;
164 static const boost::regex LanczosRE(
"lanczos(\\d+)");
165 if (
name ==
"bilinear") {
167 }
else if (boost::regex_match(
name.c_str(), matches, LanczosRE)) {
172 }
else if (
name ==
"nearest") {
180 if (_warpingKernelPtr->getCacheSize() != _cacheSize) {
181 _warpingKernelPtr->computeCache(_cacheSize);
183 return _warpingKernelPtr;
188 setWarpingKernel(*warpingKernelPtr);
192 if (_maskWarpingKernelPtr) {
193 _testWarpingKernels(warpingKernel, *_maskWarpingKernelPtr);
196 std::static_pointer_cast<SeparableKernel>(warpingKernel.
clone()));
197 _warpingKernelPtr = warpingKernelPtr;
201 if (_maskWarpingKernelPtr) {
202 if (_maskWarpingKernelPtr->getCacheSize() != _cacheSize) {
203 _maskWarpingKernelPtr->computeCache(_cacheSize);
206 return _maskWarpingKernelPtr;
210 if (!maskWarpingKernelName.
empty()) {
212 setMaskWarpingKernel(*maskWarpingKernelPtr);
214 _maskWarpingKernelPtr.reset();
219 _testWarpingKernels(*_warpingKernelPtr, maskWarpingKernel);
220 _maskWarpingKernelPtr = std::static_pointer_cast<SeparableKernel>(maskWarpingKernel.
clone());
223 void WarpingControl::_testWarpingKernels(
SeparableKernel const &warpingKernel,
231 if (!kernelBBox.
contains(maskKernelBBox)) {
233 "warping kernel is smaller than mask warping kernel");
237 template <
typename DestExposureT,
typename SrcExposureT>
239 typename DestExposureT::MaskedImageT::SinglePixel padValue) {
240 if (!destExposure.hasWcs()) {
243 if (!srcExposure.hasWcs()) {
246 typename DestExposureT::MaskedImageT mi = destExposure.getMaskedImage();
247 destExposure.setPhotoCalib(srcExposure.getPhotoCalib());
248 destExposure.setFilterLabel(srcExposure.getFilterLabel());
249 destExposure.getInfo()->setVisitInfo(srcExposure.getInfo()->getVisitInfo());
250 return warpImage(mi, *destExposure.getWcs(), srcExposure.getMaskedImage(), *srcExposure.getWcs(), control,
260 geom::SkyWcs
const &destWcs,
261 geom::SkyWcs
const &srcWcs)
265 return srcWcs.skyToPixel(destWcs.pixelToSky(destPix));
268 inline double computeRelativeArea(
277 return std::abs(dSrcA.getX() * dSrcB.getY() - dSrcA.getY() * dSrcB.getX());
282 template <
typename DestImageT,
typename SrcImageT>
283 int warpImage(DestImageT &destImage, geom::SkyWcs
const &destWcs, SrcImageT
const &srcImage,
285 typename DestImageT::SinglePixel padValue) {
287 return warpImage(destImage, srcImage, *srcToDest, control, padValue);
290 template <
typename DestImageT,
typename SrcImageT>
291 int warpImage(DestImageT &destImage, SrcImageT
const &srcImage,
293 typename DestImageT::SinglePixel padValue) {
303 warpingKernelPtr->shrinkBBox(srcImage.getBBox(
image::LOCAL));
305 for (
int y = 0, height = destImage.getHeight();
y < height; ++
y) {
306 for (
typename DestImageT::x_iterator destPtr = destImage.row_begin(
y),
end = destImage.row_end(
y);
307 destPtr !=
end; ++destPtr) {
316 std::dynamic_pointer_cast<LanczosWarpingKernel>(warpingKernelPtr);
318 int numGoodPixels = 0;
321 auto const parentDestToParentSrc = srcToDest.inverted();
322 std::vector<double> const localDestToParentDestVec = {
static_cast<double>(destImage.getX0()),
323 static_cast<double>(destImage.getY0())};
325 auto const localDestToParentSrc = localDestToParentDest.then(*parentDestToParentSrc);
328 int const srcWidth = srcImage.getWidth();
329 int const srcHeight = srcImage.getHeight();
330 LOGL_DEBUG(
"TRACE2.afw.math.warp",
"source image width=%d; height=%d", srcWidth, srcHeight);
332 int const destWidth = destImage.getWidth();
333 int const destHeight = destImage.getHeight();
334 LOGL_DEBUG(
"TRACE2.afw.math.warp",
"remap image width=%d; height=%d", destWidth, destHeight);
337 LOGL_DEBUG(
"TRACE3.afw.math.warp",
"Remapping masked image");
339 int const maxCol = destWidth - 1;
340 int const maxRow = destHeight - 1;
344 if (interpLength > 0) {
349 int const numColEdges = 2 + ((destWidth - 1) / interpLength);
354 edgeColList.
reserve(numColEdges);
359 invWidthList.
reserve(numColEdges);
364 for (
int prevEndCol = -1; prevEndCol < maxCol; prevEndCol += interpLength) {
365 int endCol = prevEndCol + interpLength;
366 if (endCol > maxCol) {
370 assert(endCol - prevEndCol > 0);
371 invWidthList.
push_back(1.0 /
static_cast<double>(endCol - prevEndCol));
373 assert(edgeColList.
back() == maxCol);
388 endColPosList.
reserve(numColEdges);
391 for (
int colBand = 0, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
392 int const endCol = edgeColList[colBand];
395 auto rightSrcPosList = localDestToParentSrc->applyForward(endColPosList);
396 srcPosView[-1] = rightSrcPosList[0];
397 for (
int colBand = 1, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
398 int const prevEndCol = edgeColList[colBand - 1];
399 int const endCol = edgeColList[colBand];
403 (rightSrcPosList[colBand] - leftSrcPos) * invWidthList[colBand];
405 for (
int col = prevEndCol + 1;
col <= endCol; ++
col) {
406 srcPosView[
col] = srcPosView[
col - 1] + xDeltaSrcPos;
411 while (endRow < maxRow) {
414 int prevEndRow = endRow;
415 endRow = prevEndRow + interpLength;
416 if (endRow > maxRow) {
419 assert(endRow - prevEndRow > 0);
420 double interpInvHeight = 1.0 /
static_cast<double>(endRow - prevEndRow);
425 for (
int colBand = 0, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
426 int endCol = edgeColList[colBand];
429 auto bottomSrcPosList = localDestToParentSrc->applyForward(destRowPosList);
430 for (
int colBand = 0, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
431 int endCol = edgeColList[colBand];
432 yDeltaSrcPosList[colBand] =
433 (bottomSrcPosList[colBand] - srcPosView[endCol]) * interpInvHeight;
436 for (
int row = prevEndRow + 1;
row <= endRow; ++
row) {
437 typename DestImageT::x_iterator destXIter = destImage.row_begin(
row);
438 srcPosView[-1] += yDeltaSrcPosList[0];
439 for (
int colBand = 1, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
442 int const prevEndCol = edgeColList[colBand - 1];
443 int const endCol = edgeColList[colBand];
452 for (
int col = prevEndCol + 1;
col <= endCol; ++
col, ++destXIter) {
455 double relativeArea = computeRelativeArea(srcPos, leftSrcPos, srcPosView[
col]);
457 srcPosView[
col] = srcPos;
460 destXIter, srcPos, relativeArea,
475 destPosList.
reserve(1 + destWidth);
476 for (
int col = -1;
col < destWidth; ++
col) {
479 auto prevSrcPosList = localDestToParentSrc->applyForward(destPosList);
481 for (
int row = 0;
row < destHeight; ++
row) {
483 for (
int col = -1;
col < destWidth; ++
col) {
486 auto srcPosList = localDestToParentSrc->applyForward(destPosList);
488 typename DestImageT::x_iterator destXIter = destImage.row_begin(
row);
489 for (
int col = 0;
col < destWidth; ++
col, ++destXIter) {
491 auto srcPos = srcPosList[
col + 1];
492 double relativeArea =
493 computeRelativeArea(srcPos, prevSrcPosList[
col], prevSrcPosList[
col + 1]);
495 if (warpAtOnePoint(destXIter, srcPos, relativeArea,
502 swap(srcPosList, prevSrcPosList);
506 return numGoodPixels;
509 template <
typename DestImageT,
typename SrcImageT>
513 typename DestImageT::SinglePixel padValue) {
515 if ((destImage.getWidth() != srcImage.getWidth()) || (destImage.getHeight() != srcImage.getHeight()) ||
516 (destImage.getXY0() != srcImage.getXY0())) {
518 errStream <<
"src and dest images must have same size and xy0.";
523 SrcImageT srcImageCopy(srcImage,
true);
524 srcImageCopy.setXY0(0, 0);
525 destImage.setXY0(0, 0);
537 static float t = 0.0;
538 float t_before = 1.0*clock()/CLOCKS_PER_SEC;
539 int n =
warpImage(destImage, srcImageCopy, affTran, control, padValue);
540 float t_after = 1.0*clock()/CLOCKS_PER_SEC;
541 float dt = t_after - t_before;
543 std::cout <<srcImage.getWidth()<<
"x"<<srcImage.getHeight()<<
": "<< dt <<
" "<< t <<
std::endl;
545 int n =
warpImage(destImage, srcImageCopy, *affineTransform22, control, padValue);
549 destImage.setXY0(srcImage.getXY0());
559 #define EXPOSURE(PIXTYPE) image::Exposure<PIXTYPE, image::MaskPixel, image::VariancePixel>
560 #define MASKEDIMAGE(PIXTYPE) image::MaskedImage<PIXTYPE, image::MaskPixel, image::VariancePixel>
561 #define IMAGE(PIXTYPE) image::Image<PIXTYPE>
564 #define INSTANTIATE(DESTIMAGEPIXELT, SRCIMAGEPIXELT) \
565 template int warpCenteredImage( \
566 IMAGE(DESTIMAGEPIXELT) & destImage, IMAGE(SRCIMAGEPIXELT) const &srcImage, \
567 lsst::geom::LinearTransform const &linearTransform, lsst::geom::Point2D const ¢erPosition, \
568 WarpingControl const &control, IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
569 NL template int warpCenteredImage( \
570 MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
571 lsst::geom::LinearTransform const &linearTransform, lsst::geom::Point2D const ¢erPosition, \
572 WarpingControl const &control, MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
573 NL template int warpImage(IMAGE(DESTIMAGEPIXELT) & destImage, IMAGE(SRCIMAGEPIXELT) const &srcImage, \
574 geom::TransformPoint2ToPoint2 const &srcToDest, WarpingControl const &control, \
575 IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
576 NL template int warpImage(MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, \
577 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
578 geom::TransformPoint2ToPoint2 const &srcToDest, WarpingControl const &control, \
579 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
580 NL template int warpImage(IMAGE(DESTIMAGEPIXELT) & destImage, geom::SkyWcs const &destWcs, \
581 IMAGE(SRCIMAGEPIXELT) const &srcImage, geom::SkyWcs const &srcWcs, \
582 WarpingControl const &control, IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
583 NL template int warpImage(MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, geom::SkyWcs const &destWcs, \
584 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, geom::SkyWcs const &srcWcs, \
585 WarpingControl const &control, \
586 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \
587 NL template int warpExposure(EXPOSURE(DESTIMAGEPIXELT) & destExposure, \
588 EXPOSURE(SRCIMAGEPIXELT) const &srcExposure, WarpingControl const &control, \
589 EXPOSURE(DESTIMAGEPIXELT)::MaskedImageT::SinglePixel padValue);
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
LSST DM logging module built on log4cxx.
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Implementation of the Photometric Calibration class.
ShiftMap is a linear Mapping which shifts each axis by a specified constant value.
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.
An integer coordinate rectangle.
bool contains(Point2I const &point) const noexcept
Return true if the box contains the point.
Reports invalid arguments.
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
Angle abs(Angle const &a)
A base class for image defects.
#define INSTANTIATE(FROMSYS, TOSYS)
afw::table::Key< std::string > warpingKernelName
ImageT::image_category image_category