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.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) {
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);