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);
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();
248 destExposure.setCalib(calibCopy);
249 destExposure.setFilter(srcExposure.getFilter());
250 destExposure.getInfo()->setVisitInfo(srcExposure.getInfo()->getVisitInfo());
251 return warpImage(mi, *destExposure.getWcs(), srcExposure.getMaskedImage(), *srcExposure.getWcs(), control,
269 inline double computeRelativeArea(
278 return std::abs(dSrcA.getX() * dSrcB.getY() - dSrcA.getY() * dSrcB.getX());
283 template <
typename DestImageT,
typename SrcImageT>
286 typename DestImageT::SinglePixel padValue) {
288 return warpImage(destImage, srcImage, *srcToDest, control, padValue);
291 template <
typename DestImageT,
typename SrcImageT>
292 int warpImage(DestImageT &destImage, SrcImageT
const &srcImage,
294 typename DestImageT::SinglePixel padValue) {
304 warpingKernelPtr->shrinkBBox(srcImage.getBBox(
image::LOCAL));
306 for (
int y = 0, height = destImage.getHeight();
y < height; ++
y) {
307 for (
typename DestImageT::x_iterator destPtr = destImage.row_begin(
y),
end = destImage.row_end(
y);
308 destPtr !=
end; ++destPtr) {
319 int numGoodPixels = 0;
322 auto const parentDestToParentSrc = srcToDest.
inverted();
323 std::vector<double> const localDestToParentDestVec = {
static_cast<double>(destImage.getX0()),
324 static_cast<double>(destImage.getY0())};
326 auto const localDestToParentSrc = localDestToParentDest.then(*parentDestToParentSrc);
329 int const srcWidth = srcImage.getWidth();
330 int const srcHeight = srcImage.getHeight();
331 LOGL_DEBUG(
"TRACE2.afw.math.warp",
"source image width=%d; height=%d", srcWidth, srcHeight);
333 int const destWidth = destImage.getWidth();
334 int const destHeight = destImage.getHeight();
335 LOGL_DEBUG(
"TRACE2.afw.math.warp",
"remap image width=%d; height=%d", destWidth, destHeight);
338 LOGL_DEBUG(
"TRACE3.afw.math.warp",
"Remapping masked image");
340 int const maxCol = destWidth - 1;
341 int const maxRow = destHeight - 1;
345 if (interpLength > 0) {
350 int const numColEdges = 2 + ((destWidth - 1) / interpLength);
355 edgeColList.
reserve(numColEdges);
360 invWidthList.
reserve(numColEdges);
365 for (
int prevEndCol = -1; prevEndCol < maxCol; prevEndCol += interpLength) {
366 int endCol = prevEndCol + interpLength;
367 if (endCol > maxCol) {
371 assert(endCol - prevEndCol > 0);
372 invWidthList.
push_back(1.0 / static_cast<double>(endCol - prevEndCol));
374 assert(edgeColList.
back() == maxCol);
389 endColPosList.
reserve(numColEdges);
392 for (
int colBand = 0, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
393 int const endCol = edgeColList[colBand];
396 auto rightSrcPosList = localDestToParentSrc->applyForward(endColPosList);
397 srcPosView[-1] = rightSrcPosList[0];
398 for (
int colBand = 1, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
399 int const prevEndCol = edgeColList[colBand - 1];
400 int const endCol = edgeColList[colBand];
404 (rightSrcPosList[colBand] - leftSrcPos) * invWidthList[colBand];
406 for (
int col = prevEndCol + 1;
col <= endCol; ++
col) {
407 srcPosView[
col] = srcPosView[
col - 1] + xDeltaSrcPos;
412 while (endRow < maxRow) {
415 int prevEndRow = endRow;
416 endRow = prevEndRow + interpLength;
417 if (endRow > maxRow) {
420 assert(endRow - prevEndRow > 0);
421 double interpInvHeight = 1.0 /
static_cast<double>(endRow - prevEndRow);
426 for (
int colBand = 0, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
427 int endCol = edgeColList[colBand];
430 auto bottomSrcPosList = localDestToParentSrc->applyForward(destRowPosList);
431 for (
int colBand = 0, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
432 int endCol = edgeColList[colBand];
433 yDeltaSrcPosList[colBand] =
434 (bottomSrcPosList[colBand] - srcPosView[endCol]) * interpInvHeight;
437 for (
int row = prevEndRow + 1;
row <= endRow; ++
row) {
438 typename DestImageT::x_iterator destXIter = destImage.row_begin(
row);
439 srcPosView[-1] += yDeltaSrcPosList[0];
440 for (
int colBand = 1, endBand = edgeColList.
size(); colBand < endBand; ++colBand) {
443 int const prevEndCol = edgeColList[colBand - 1];
444 int const endCol = edgeColList[colBand];
453 for (
int col = prevEndCol + 1;
col <= endCol; ++
col, ++destXIter) {
456 double relativeArea = computeRelativeArea(srcPos, leftSrcPos, srcPosView[
col]);
458 srcPosView[
col] = srcPos;
461 destXIter, srcPos, relativeArea,
476 destPosList.
reserve(1 + destWidth);
477 for (
int col = -1;
col < destWidth; ++
col) {
480 auto prevSrcPosList = localDestToParentSrc->applyForward(destPosList);
482 for (
int row = 0;
row < destHeight; ++
row) {
484 for (
int col = -1;
col < destWidth; ++
col) {
487 auto srcPosList = localDestToParentSrc->applyForward(destPosList);
489 typename DestImageT::x_iterator destXIter = destImage.row_begin(
row);
490 for (
int col = 0;
col < destWidth; ++
col, ++destXIter) {
492 auto srcPos = srcPosList[
col + 1];
493 double relativeArea =
494 computeRelativeArea(srcPos, prevSrcPosList[
col], prevSrcPosList[col + 1]);
496 if (warpAtOnePoint(destXIter, srcPos, relativeArea,
503 swap(srcPosList, prevSrcPosList);
507 return numGoodPixels;
510 template <
typename DestImageT,
typename SrcImageT>
514 typename DestImageT::SinglePixel padValue) {
516 if ((destImage.getWidth() != srcImage.getWidth()) || (destImage.getHeight() != srcImage.getHeight()) ||
517 (destImage.getXY0() != srcImage.getXY0())) {
519 errStream <<
"src and dest images must have same size and xy0.";
524 SrcImageT srcImageCopy(srcImage,
true);
525 srcImageCopy.setXY0(0, 0);
526 destImage.setXY0(0, 0);
538 static float t = 0.0;
539 float t_before = 1.0*clock()/CLOCKS_PER_SEC;
540 int n =
warpImage(destImage, srcImageCopy, affTran, control, padValue);
541 float t_after = 1.0*clock()/CLOCKS_PER_SEC;
542 float dt = t_after - t_before;
544 std::cout <<srcImage.getWidth()<<
"x"<<srcImage.getHeight()<<
": "<< dt <<
" "<< t <<
std::endl;
546 int n =
warpImage(destImage, srcImageCopy, *affineTransform22, control, padValue);
550 destImage.setXY0(srcImage.getXY0());
560 #define EXPOSURE(PIXTYPE) image::Exposure<PIXTYPE, image::MaskPixel, image::VariancePixel> 561 #define MASKEDIMAGE(PIXTYPE) image::MaskedImage<PIXTYPE, image::MaskPixel, image::VariancePixel> 562 #define IMAGE(PIXTYPE) image::Image<PIXTYPE> 565 #define INSTANTIATE(DESTIMAGEPIXELT, SRCIMAGEPIXELT) \ 566 template int warpCenteredImage( \ 567 IMAGE(DESTIMAGEPIXELT) & destImage, IMAGE(SRCIMAGEPIXELT) const &srcImage, \ 568 lsst::geom::LinearTransform const &linearTransform, lsst::geom::Point2D const ¢erPosition, \ 569 WarpingControl const &control, IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \ 570 NL template int warpCenteredImage( \ 571 MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \ 572 lsst::geom::LinearTransform const &linearTransform, lsst::geom::Point2D const ¢erPosition, \ 573 WarpingControl const &control, MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \ 574 NL template int warpImage(IMAGE(DESTIMAGEPIXELT) & destImage, IMAGE(SRCIMAGEPIXELT) const &srcImage, \ 575 geom::TransformPoint2ToPoint2 const &srcToDest, WarpingControl const &control, \ 576 IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \ 577 NL template int warpImage(MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, \ 578 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \ 579 geom::TransformPoint2ToPoint2 const &srcToDest, WarpingControl const &control, \ 580 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \ 581 NL template int warpImage(IMAGE(DESTIMAGEPIXELT) & destImage, geom::SkyWcs const &destWcs, \ 582 IMAGE(SRCIMAGEPIXELT) const &srcImage, geom::SkyWcs const &srcWcs, \ 583 WarpingControl const &control, IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \ 584 NL template int warpImage(MASKEDIMAGE(DESTIMAGEPIXELT) & destImage, geom::SkyWcs const &destWcs, \ 585 MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, geom::SkyWcs const &srcWcs, \ 586 WarpingControl const &control, \ 587 MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); \ 588 NL template int warpExposure(EXPOSURE(DESTIMAGEPIXELT) & destExposure, \ 589 EXPOSURE(SRCIMAGEPIXELT) const &srcExposure, WarpingControl const &control, \ 590 EXPOSURE(DESTIMAGEPIXELT)::MaskedImageT::SinglePixel padValue);
Angle abs(Angle const &a)
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
std::string toString(std::string const &="") const override
Return string representation.
double indexToPosition(double ind)
Convert image index to image position.
lsst::geom::Point2D skyToPixel(lsst::geom::SpherePoint const &sky) const
Compute pixel position(s) from sky position(s)
afw::table::Key< std::string > warpingKernelName
lsst::geom::SpherePoint pixelToSky(lsst::geom::Point2D const &pixel) const
Compute sky position(s) from pixel position(s)
Kernel::Pixel operator()(double x) const override
Solve bilinear equation.
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)
void setWarpingKernelName(std::string const &warpingKernelName)
set the warping kernel by name
A functor that computes one warped pixel.
Parameters to control convolution.
LanczosWarpingKernel(int order)
std::shared_ptr< SeparableKernel > getWarpingKernel() const
get the warping kernel
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Describe an exposure's calibration.
std::shared_ptr< SeparableKernel > makeWarpingKernel(std::string name)
Return a warping kernel given its name.
void setMaskWarpingKernel(SeparableKernel const &maskWarpingKernel)
set the mask warping kernel
Transform< Point2Endpoint, Point2Endpoint > TransformPoint2ToPoint2
LSST DM logging module built on log4cxx.
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
Kernel::Pixel operator()(double x) const override
Solve nearest neighbor equation.
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.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
int getOrder() const
get the order of the kernel
A base class for image defects.
int getInterpLength() const
get the interpolation length (pixels)
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
void setMaskWarpingKernelName(std::string const &maskWarpingKernelName)
set or clear the mask warping kernel by name
void setWarpingKernel(SeparableKernel const &warpingKernel)
set the warping kernel
bool imagesOverlap(ImageBase< T1 > const &image1, ImageBase< T2 > const &image2)
Return true if the pixels for two images or masks overlap in memory.
lsst::geom::Point2I getCtr() const
Return index of kernel's center.
T static_pointer_cast(T... args)
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
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.
ShiftMap is a linear Mapping which shifts each axis by a specified constant value.
Bilinear warping: fast; good for undersampled data.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
int getWidth() const
Return the Kernel's width.
lsst::geom::Extent2I const getDimensions() const
Return the Kernel's dimensions (width, height)
void swap(Image< PixelT > &a, Image< PixelT > &b)
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
A Transform obtained by putting two SkyWcs objects "back to back".
std::shared_ptr< SeparableKernel > getMaskWarpingKernel() const
get the mask warping kernel
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
bool contains(Point2I const &point) const noexcept
Return true if the box contains the point.
Nearest neighbor warping: fast; good for undersampled data.
Reports invalid arguments.
Lanczos warping: accurate but slow and can introduce ringing artifacts.
ImageT::image_category image_category
Extent< double, 2 > Extent2D
An integer coordinate rectangle.
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.
std::string toString(std::string const &="") const override
Return string representation.
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
#define INSTANTIATE(FROMSYS, TOSYS)
std::shared_ptr< TransformPoint2ToPoint2 > makeTransform(lsst::geom::AffineTransform const &affine)
Wrap an lsst::geom::AffineTransform as a Transform.
T emplace_back(T... args)