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();
247 destExposure.setPhotoCalib(srcExposure.getPhotoCalib());
248 destExposure.setFilter(srcExposure.getFilter());
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) {
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);
Angle abs(Angle const &a)
std::string toString(std::string const &="") const override
Return string representation.
double indexToPosition(double ind)
Convert image index to image position.
afw::table::Key< std::string > warpingKernelName
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.
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)
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.
void swap(CameraSys &a, CameraSys &b)
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.
Implementation of the Photometric Calibration class.
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)