LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
warpExposure.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*- // fixed format comment for emacs
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
33 #include <cassert>
34 #include <cmath>
35 #include <limits>
36 #include <sstream>
37 #include <string>
38 #include <vector>
39 #include <utility>
40 #include <ctime>
41 
42 #include "boost/shared_ptr.hpp"
43 #include "boost/pointer_cast.hpp"
44 #include "boost/cstdint.hpp"
45 #include "boost/regex.hpp"
46 
47 #include "lsst/pex/logging/Trace.h"
48 #include "lsst/pex/exceptions.h"
50 #include "lsst/afw/geom.h"
51 #include "lsst/afw/math/Kernel.h"
52 #include "lsst/afw/coord/Coord.h"
53 #include "lsst/afw/image/Calib.h"
54 #include "lsst/afw/image/Wcs.h"
61 
62 namespace pexExcept = lsst::pex::exceptions;
63 namespace pexLog = lsst::pex::logging;
64 namespace afwImage = lsst::afw::image;
65 namespace afwGeom = lsst::afw::geom;
66 namespace afwCoord = lsst::afw::coord;
67 namespace afwMath = lsst::afw::math;
68 
69 
70 //
71 // A helper function for the warping kernels which provides error-checking:
72 // the warping kernels are designed to work in two cases
73 // 0 < x < 1 and ctrX=(size-1)/2
74 // -1 < x < 0 and ctrX=(size+1)/2
75 // (and analogously for y). Note that to get the second case, Kernel::setCtrX(1) must be
76 // called before calling Kernel::setKernelParameter(). [see afw::math::offsetImage() for
77 // an example]
78 //
79 // FIXME eventually the 3 warping kernels will inherit from a common base class WarpingKernel
80 // and this routine can be eliminated by putting the code in WarpingKernel::setKernelParameter()
81 //
82 static inline void checkWarpingKernelParameter(const afwMath::SeparableKernel *p, unsigned int ind, double value)
83 {
84  if (ind > 1) {
85  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "bad ind argument in WarpingKernel::setKernelParameter()");
86  }
87  int ctr = p->getCtr()[ind];
88  int size = p->getDimensions()[ind];
89 
90  if (ctr == (size-1)/2) {
91  if (value < -1e-6 || value > 1+1e-6) {
92  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "bad coordinate in WarpingKernel::setKernelParameter()");
93  }
94  } else if (ctr == (size+1)/2) {
95  if (value < -1-1e-6 || value > 1e-6) {
96  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "bad coordinate in WarpingKernel::setKernelParameter()");
97  }
98  } else {
99  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "bad ctr value in WarpingKernel::setKernelParameter()");
100  }
101 }
102 
103 
104 PTR(afwMath::Kernel) afwMath::LanczosWarpingKernel::clone() const {
105  return PTR(afwMath::Kernel)(new afwMath::LanczosWarpingKernel(this->getOrder()));
106 }
107 
112  return this->getWidth() / 2;
113 }
114 
115 void afwMath::LanczosWarpingKernel::setKernelParameter(unsigned int ind, double value) const
116 {
117  checkWarpingKernelParameter(this, ind, value);
119 }
120 
121 PTR(afwMath::Kernel) afwMath::BilinearWarpingKernel::clone() const {
123 }
124 
132 afwMath::Kernel::Pixel afwMath::BilinearWarpingKernel::BilinearFunction1::operator() (double x) const
133 {
134  //
135  // this->_params[0] = value of x where we want to interpolate the function
136  // x = integer value of x where we evaluate the function in the interpolation
137  //
138  // The following weird-looking expression has no if/else statements, is roundoff-tolerant,
139  // and works in the following two cases:
140  // 0 < this->_params[0] < 1, x \in {0,1}
141  // -1 < this->_params[0] < 0, x \in {-1,0}
142  //
143  // The checks in BilinearWarpingKernel::setKernelParameter() ensure that one of these
144  // conditions is satisfied
145  //
146  return 0.5 + (1.0 - (2.0 * fabs(this->_params[0]))) * (0.5 - fabs(x));
147 }
148 
149 void afwMath::BilinearWarpingKernel::setKernelParameter(unsigned int ind, double value) const
150 {
151  checkWarpingKernelParameter(this, ind, value);
153 }
154 
158 std::string afwMath::BilinearWarpingKernel::BilinearFunction1::toString(std::string const& prefix) const {
159  std::ostringstream os;
160  os << "_BilinearFunction1: ";
161  os << Function1<Kernel::Pixel>::toString(prefix);
162  return os.str();
163 }
164 
165 PTR(afwMath::Kernel) afwMath::NearestWarpingKernel::clone() const {
167 }
168 
176 afwMath::Kernel::Pixel afwMath::NearestWarpingKernel::NearestFunction1::operator() (double x) const {
177  // this expression is faster than using conditionals, but offers no sanity checking
178  return static_cast<double>((fabs(this->_params[0]) < 0.5) == (fabs(x) < 0.5));
179 }
180 
181 void afwMath::NearestWarpingKernel::setKernelParameter(unsigned int ind, double value) const
182 {
183  checkWarpingKernelParameter(this, ind, value);
185 }
186 
190 std::string afwMath::NearestWarpingKernel::NearestFunction1::toString(std::string const& prefix) const {
191  std::ostringstream os;
192  os << "_NearestFunction1: ";
193  os << Function1<Kernel::Pixel>::toString(prefix);
194  return os.str();
195 }
196 
197 boost::shared_ptr<afwMath::SeparableKernel> afwMath::makeWarpingKernel(std::string name) {
198  typedef boost::shared_ptr<afwMath::SeparableKernel> KernelPtr;
199  boost::cmatch matches;
200  static const boost::regex LanczosRE("lanczos(\\d+)");
201  if (name == "bilinear") {
202  return KernelPtr(new BilinearWarpingKernel());
203  } else if (boost::regex_match(name.c_str(), matches, LanczosRE)) {
204  std::string orderStr(matches[1].first, matches[1].second);
205  int order;
206  std::istringstream(orderStr) >> order;
207  return KernelPtr(new LanczosWarpingKernel(order));
208  } else if (name == "nearest") {
209  return KernelPtr(new NearestWarpingKernel());
210  } else {
211  throw LSST_EXCEPT(pexExcept::InvalidParameterError,
212  "unknown warping kernel name: \"" + name + "\"");
213  }
214 }
215 
216 PTR(afwMath::SeparableKernel) afwMath::WarpingControl::getWarpingKernel() const {
217  if (_warpingKernelPtr->getCacheSize() != _cacheSize) {
218  _warpingKernelPtr->computeCache(_cacheSize);
219  }
220  return _warpingKernelPtr;
221 };
222 
224  std::string const &warpingKernelName
225 ) {
226  PTR(SeparableKernel) warpingKernelPtr(makeWarpingKernel(warpingKernelName));
227  setWarpingKernel(*warpingKernelPtr);
228 }
229 
231  SeparableKernel const &warpingKernel
232 ) {
233  if (_maskWarpingKernelPtr) {
234  _testWarpingKernels(warpingKernel, *_maskWarpingKernelPtr);
235  }
236  PTR(SeparableKernel) warpingKernelPtr(boost::static_pointer_cast<SeparableKernel>(warpingKernel.clone()));
237  _testDevicePreference(_devicePreference, warpingKernelPtr);
238  _warpingKernelPtr = warpingKernelPtr;
239 }
240 
241 
242 PTR(afwMath::SeparableKernel) afwMath::WarpingControl::getMaskWarpingKernel() const {
243  if (_maskWarpingKernelPtr) { // lazily update kernel cache
244  if (_maskWarpingKernelPtr->getCacheSize() != _cacheSize) {
245  _maskWarpingKernelPtr->computeCache(_cacheSize);
246  }
247  }
248  return _maskWarpingKernelPtr;
249 }
250 
252  std::string const &maskWarpingKernelName
253 ) {
254  if (!maskWarpingKernelName.empty()) {
255  PTR(SeparableKernel) maskWarpingKernelPtr(makeWarpingKernel(maskWarpingKernelName));
256  setMaskWarpingKernel(*maskWarpingKernelPtr);
257  } else {
258  _maskWarpingKernelPtr.reset();
259  }
260 }
261 
263  SeparableKernel const & maskWarpingKernel
264 ) {
265  _testWarpingKernels(*_warpingKernelPtr, maskWarpingKernel);
266  _maskWarpingKernelPtr = boost::static_pointer_cast<SeparableKernel>(maskWarpingKernel.clone());
267 }
268 
269 
271  SeparableKernel const &warpingKernel,
272  SeparableKernel const &maskWarpingKernel
273 ) const {
276  warpingKernel.getDimensions()
277  );
279  lsst::afw::geom::Point2I(0, 0) - lsst::afw::geom::Extent2I(maskWarpingKernel.getCtr()),
280  maskWarpingKernel.getDimensions()
281  );
282  if (!kernelBBox.contains(maskKernelBBox)) {
283  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
284  "warping kernel is smaller than mask warping kernel");
285  }
286 }
287 
289  lsst::afw::gpu::DevicePreference const &devicePreference,
290  CONST_PTR(SeparableKernel) const &warpingKernelPtr
291 ) const {
292  CONST_PTR(LanczosWarpingKernel) const lanczosKernelPtr =
293  boost::dynamic_pointer_cast<const LanczosWarpingKernel>(warpingKernelPtr);
294  if (devicePreference == lsst::afw::gpu::USE_GPU && !lanczosKernelPtr) {
295  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
296  "devicePreference = USE_GPU, but warping kernel not Lanczos");
297  }
298 }
299 
300 
301 
302 template<typename DestExposureT, typename SrcExposureT>
304  DestExposureT &destExposure,
305  SrcExposureT const &srcExposure,
306  afwMath::WarpingControl const &control,
307  typename DestExposureT::MaskedImageT::SinglePixel padValue
308  )
309 {
310  if (!destExposure.hasWcs()) {
311  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "destExposure has no Wcs");
312  }
313  if (!srcExposure.hasWcs()) {
314  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "srcExposure has no Wcs");
315  }
316  typename DestExposureT::MaskedImageT mi = destExposure.getMaskedImage();
317  boost::shared_ptr<afwImage::Calib> calibCopy(new afwImage::Calib(*srcExposure.getCalib()));
318  destExposure.setCalib(calibCopy);
319  destExposure.setFilter(srcExposure.getFilter());
320  return warpImage(mi, *destExposure.getWcs(), srcExposure.getMaskedImage(), *srcExposure.getWcs(),
321  control, padValue);
322 }
323 
324 template<typename DestExposureT, typename SrcExposureT>
326  DestExposureT &destExposure,
327  SrcExposureT const &srcExposure,
328  afwMath::SeparableKernel &warpingKernel,
329  int const interpLength,
330  typename DestExposureT::MaskedImageT::SinglePixel padValue,
332  )
333 {
334  if (!destExposure.hasWcs()) {
335  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "destExposure has no Wcs");
336  }
337  if (!srcExposure.hasWcs()) {
338  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "srcExposure has no Wcs");
339  }
340  typename DestExposureT::MaskedImageT mi = destExposure.getMaskedImage();
341  boost::shared_ptr<afwImage::Calib> calibCopy(new afwImage::Calib(*srcExposure.getCalib()));
342  destExposure.setCalib(calibCopy);
343  destExposure.setFilter(srcExposure.getFilter());
344  return warpImage(mi, *destExposure.getWcs(),
345  srcExposure.getMaskedImage(), *srcExposure.getWcs(), warpingKernel, interpLength,
346  padValue, devPref);
347 }
348 
349 
350 /************************************************************************************************************/
351 namespace {
352 
353  inline afwGeom::Point2D computeSrcPos(
354  int destCol,
355  int destRow,
356  afwGeom::Point2D const &destXY0,
357  afwImage::Wcs const &destWcs,
358  afwImage::Wcs const &srcWcs)
359  {
360  double const col = afwImage::indexToPosition(destCol + destXY0[0]);
361  double const row = afwImage::indexToPosition(destRow + destXY0[1]);
362  afwGeom::Angle sky1, sky2;
363  destWcs.pixelToSky(col, row, sky1, sky2);
364  return srcWcs.skyToPixel(sky1, sky2);
365  }
366 
367 
368  inline double computeRelativeArea(
369  afwGeom::Point2D const &srcPos,
370  afwGeom::Point2D const &leftSrcPos,
371  afwGeom::Point2D const &upSrcPos)
372  {
373  afwGeom::Extent2D dSrcA = srcPos - leftSrcPos;
374  afwGeom::Extent2D dSrcB = srcPos - upSrcPos;
375 
376  return std::abs(dSrcA.getX()*dSrcB.getY() - dSrcA.getY()*dSrcB.getX());
377  }
378 
379  template<typename DestImageT, typename SrcImageT>
380  int doWarpImage(
381  DestImageT &destImage,
382  SrcImageT const &srcImage,
383  afwMath::detail::PositionFunctor const &computeSrcPos,
384  afwMath::WarpingControl const &control,
385  typename DestImageT::SinglePixel padValue
386  ) {
387  if (afwMath::details::isSameObject(destImage, srcImage)) {
388  throw LSST_EXCEPT(pexExcept::InvalidParameterError,
389  "destImage is srcImage; cannot warp in place");
390  }
391  if (destImage.getBBox(afwImage::LOCAL).isEmpty()) {
392  return 0;
393  }
394  // if src image is too small then don't try to warp
395  try {
396  PTR(afwMath::SeparableKernel) warpingKernelPtr = control.getWarpingKernel();
397  warpingKernelPtr->shrinkBBox(srcImage.getBBox(afwImage::LOCAL));
398  } catch(...) {
399  for (int y = 0, height = destImage.getHeight(); y < height; ++y) {
400  for (typename DestImageT::x_iterator destPtr = destImage.row_begin(y), end = destImage.row_end(y);
401  destPtr != end; ++destPtr) {
402  *destPtr = padValue;
403  }
404  }
405  return 0;
406  }
407  PTR(afwMath::SeparableKernel) warpingKernelPtr = control.getWarpingKernel();
408  int interpLength = control.getInterpLength();
409  lsst::afw::gpu::DevicePreference devPref = control.getDevicePreference();
410 
411  boost::shared_ptr<afwMath::LanczosWarpingKernel const> const lanczosKernelPtr =
412  boost::dynamic_pointer_cast<afwMath::LanczosWarpingKernel>(warpingKernelPtr);
413 
414  if (lsst::afw::gpu::isGpuEnabled()) {
415  if(!lanczosKernelPtr) {
416  if (devPref == lsst::afw::gpu::USE_GPU) {
417  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "Gpu can process only Lanczos kernels");
418  }
419  } else if (devPref == lsst::afw::gpu::USE_GPU || (lsst::afw::gpu::isGpuBuild() && interpLength > 0) ) {
420  PTR(afwMath::SeparableKernel) maskWarpingKernelPtr = control.getWarpingKernel();
421  if (control.getMaskWarpingKernel() )
422  maskWarpingKernelPtr = control.getMaskWarpingKernel();
423  if (devPref == lsst::afw::gpu::AUTO_WITH_CPU_FALLBACK) {
424  try {
425  std::pair<int, afwMath::detail::WarpImageGpuStatus::ReturnCode> result =
426  afwMath::detail::warpImageGPU(destImage, srcImage,
427  *lanczosKernelPtr, *maskWarpingKernelPtr,
428  computeSrcPos, interpLength, padValue, false);
429  if (result.second == afwMath::detail::WarpImageGpuStatus::OK) return result.first;
430  }
431  catch(lsst::afw::gpu::GpuMemoryError) { }
432  catch(pexExcept::MemoryError) { }
433  catch(lsst::afw::gpu::GpuRuntimeError) { }
434  } else if (devPref != lsst::afw::gpu::USE_CPU) {
435  std::pair<int, afwMath::detail::WarpImageGpuStatus::ReturnCode> result =
436  afwMath::detail::warpImageGPU(destImage, srcImage,
437  *lanczosKernelPtr, *maskWarpingKernelPtr,
438  computeSrcPos, interpLength, padValue,
439  devPref == lsst::afw::gpu::USE_GPU);
440  if (result.second == afwMath::detail::WarpImageGpuStatus::OK) return result.first;
441  if (devPref == lsst::afw::gpu::USE_GPU) {
442  throw LSST_EXCEPT(pexExcept::RuntimeError,
443  "Gpu cannot perform this warp (kernel too big?)");
444  }
445  }
446  }
447  }
448 
449  int numGoodPixels = 0;
450 
451  // Get the source MaskedImage and a pixel accessor to it.
452  int const srcWidth = srcImage.getWidth();
453  int const srcHeight = srcImage.getHeight();
454  pexLog::TTrace<3>("lsst.afw.math.warp", "source image width=%d; height=%d", srcWidth, srcHeight);
455 
456  int const destWidth = destImage.getWidth();
457  int const destHeight = destImage.getHeight();
458 
459  pexLog::TTrace<3>("lsst.afw.math.warp", "remap image width=%d; height=%d", destWidth, destHeight);
460 
461  // Set each pixel of destExposure's MaskedImage
462  pexLog::TTrace<4>("lsst.afw.math.warp", "Remapping masked image");
463 
464  // A cache of pixel positions on the source corresponding to the previous or current row
465  // of the destination image.
466  // The first value is for column -1 because the previous source position is used to compute relative area
467  // To simplify the indexing, use an iterator that starts at begin+1, thus:
468  // srcPosView = _srcPosList.begin() + 1
469  // srcPosView[col-1] and lower indices are for this row
470  // srcPosView[col] and higher indices are for the previous row
471  std::vector<afwGeom::Point2D> _srcPosList(1 + destWidth);
472  std::vector<afwGeom::Point2D>::iterator const srcPosView = _srcPosList.begin() + 1;
473 
474  int const maxCol = destWidth - 1;
475  int const maxRow = destHeight - 1;
476 
477  afwMath::detail::WarpAtOnePoint<DestImageT, SrcImageT> warpAtOnePoint(srcImage, control, padValue);
478 
479  if (interpLength > 0) {
480  // Use interpolation. Note that 1 produces the same result as no interpolation
481  // but uses this code branch, thus providing an easy way to compare the two branches.
482 
483  // Estimate for number of horizontal interpolation band edges, to reserve memory in vectors
484  int const numColEdges = 2 + ((destWidth - 1) / interpLength);
485 
486  // A list of edge column indices for interpolation bands;
487  // starts at -1, increments by interpLen (except the final interval), and ends at destWidth-1
488  std::vector<int> edgeColList;
489  edgeColList.reserve(numColEdges);
490 
491  // A list of 1/column width for horizontal interpolation bands; the first value is garbage.
492  // The inverse is used for speed because the values is always multiplied.
493  std::vector<double> invWidthList;
494  invWidthList.reserve(numColEdges);
495 
496  // Compute edgeColList and invWidthList
497  edgeColList.push_back(-1);
498  invWidthList.push_back(0.0);
499  for (int prevEndCol = -1; prevEndCol < maxCol; prevEndCol += interpLength) {
500  int endCol = prevEndCol + interpLength;
501  if (endCol > maxCol) {
502  endCol = maxCol;
503  }
504  edgeColList.push_back(endCol);
505  assert(endCol - prevEndCol > 0);
506  invWidthList.push_back(1.0 / static_cast<double>(endCol - prevEndCol));
507  }
508  assert(edgeColList.back() == maxCol);
509 
510  // A list of delta source positions along the edge columns of the horizontal interpolation bands
511  std::vector<afwGeom::Extent2D> yDeltaSrcPosList(edgeColList.size());
512 
513  // Initialize _srcPosList for row -1
514  //srcPosView[-1] = computeSrcPos(-1, -1, destXY0, destWcs, srcWcs);
515  srcPosView[-1] = computeSrcPos(-1, -1);
516  for (int colBand = 1, endBand = edgeColList.size(); colBand < endBand; ++colBand) {
517  int const prevEndCol = edgeColList[colBand-1];
518  int const endCol = edgeColList[colBand];
519  afwGeom::Point2D leftSrcPos = srcPosView[prevEndCol];
520  afwGeom::Point2D rightSrcPos = computeSrcPos(endCol, -1);
521  afwGeom::Extent2D xDeltaSrcPos = (rightSrcPos - leftSrcPos) * invWidthList[colBand];
522 
523  for (int col = prevEndCol + 1; col <= endCol; ++col) {
524  srcPosView[col] = srcPosView[col-1] + xDeltaSrcPos;
525  }
526  }
527 
528  int endRow = -1;
529  while (endRow < maxRow) {
530  // Next horizontal interpolation band
531 
532  int prevEndRow = endRow;
533  endRow = prevEndRow + interpLength;
534  if (endRow > maxRow) {
535  endRow = maxRow;
536  }
537  assert(endRow - prevEndRow > 0);
538  double interpInvHeight = 1.0 / static_cast<double>(endRow - prevEndRow);
539 
540  // Set yDeltaSrcPosList for this horizontal interpolation band
541  for (int colBand = 0, endBand = edgeColList.size(); colBand < endBand; ++colBand) {
542  int endCol = edgeColList[colBand];
543  afwGeom::Point2D bottomSrcPos = computeSrcPos(endCol, endRow);
544  yDeltaSrcPosList[colBand] = (bottomSrcPos - srcPosView[endCol]) * interpInvHeight;
545  }
546 
547  for (int row = prevEndRow + 1; row <= endRow; ++row) {
548  typename DestImageT::x_iterator destXIter = destImage.row_begin(row);
549  srcPosView[-1] += yDeltaSrcPosList[0];
550  for (int colBand = 1, endBand = edgeColList.size(); colBand < endBand; ++colBand) {
552 
553  int const prevEndCol = edgeColList[colBand-1];
554  int const endCol = edgeColList[colBand];
555 
556  // Compute xDeltaSrcPos; remember that srcPosView contains
557  // positions for this row in prevEndCol and smaller indices,
558  // and positions for the previous row for larger indices (including endCol)
559  afwGeom::Point2D leftSrcPos = srcPosView[prevEndCol];
560  afwGeom::Point2D rightSrcPos = srcPosView[endCol] + yDeltaSrcPosList[colBand];
561  afwGeom::Extent2D xDeltaSrcPos = (rightSrcPos - leftSrcPos) * invWidthList[colBand];
562 
563  for (int col = prevEndCol + 1; col <= endCol; ++col, ++destXIter) {
564  afwGeom::Point2D leftSrcPos = srcPosView[col-1];
565  afwGeom::Point2D srcPos = leftSrcPos + xDeltaSrcPos;
566  double relativeArea = computeRelativeArea(srcPos, leftSrcPos, srcPosView[col]);
567 
568  srcPosView[col] = srcPos;
569 
570  if (warpAtOnePoint(destXIter, srcPos, relativeArea,
572  ++numGoodPixels;
573  }
574  } // for col
575  } // for col band
576  } // for row
577  } // while next row band
578 
579 
580  } else {
581  // No interpolation
582 
583  // initialize _srcPosList for row -1;
584  // the first value is not needed, but it's safer to compute it
585  std::vector<afwGeom::Point2D>::iterator srcPosView = _srcPosList.begin() + 1;
586  for (int col = -1; col < destWidth; ++col) {
587  srcPosView[col] = computeSrcPos(col, -1);
588  }
589 
590  for (int row = 0; row < destHeight; ++row) {
591  typename DestImageT::x_iterator destXIter = destImage.row_begin(row);
592 
593  srcPosView[-1] = computeSrcPos(-1, row);
594 
595  for (int col = 0; col < destWidth; ++col, ++destXIter) {
596  afwGeom::Point2D srcPos = computeSrcPos(col, row);
597  double relativeArea = computeRelativeArea(srcPos, srcPosView[col-1], srcPosView[col]);
598  srcPosView[col] = srcPos;
599 
600  if (warpAtOnePoint(destXIter, srcPos, relativeArea,
602  ++numGoodPixels;
603  }
604  } // for col
605  } // for row
606  } // if interp
607 
608  return numGoodPixels;
609  }
610 
611 } // namespace
612 
613 template<typename DestImageT, typename SrcImageT>
615  DestImageT &destImage,
616  lsst::afw::image::Wcs const &destWcs,
617  SrcImageT const &srcImage,
618  lsst::afw::image::Wcs const &srcWcs,
619  afwMath::WarpingControl const &control,
620  typename DestImageT::SinglePixel padValue
621 ) {
622  afwGeom::Point2D const destXY0(destImage.getXY0());
623  afwMath::detail::WcsPositionFunctor const computeSrcPos(destXY0, destWcs, srcWcs);
624  return doWarpImage(destImage, srcImage, computeSrcPos, control, padValue);
625 }
626 
627 template<typename DestImageT, typename SrcImageT>
629  DestImageT &destImage,
630  afwImage::Wcs const &destWcs,
631  SrcImageT const &srcImage,
632  afwImage::Wcs const &srcWcs,
633  afwMath::SeparableKernel &warpingKernel,
634  int const interpLength,
635  typename DestImageT::SinglePixel padValue,
637 ) {
638  afwGeom::Point2D const destXY0(destImage.getXY0());
639  afwMath::detail::WcsPositionFunctor const computeSrcPos(destXY0, destWcs, srcWcs);
640  afwMath::WarpingControl control(warpingKernel, interpLength, devPref);
641  return doWarpImage(destImage, srcImage, computeSrcPos, control, padValue);
642 }
643 
644 
645 template<typename DestImageT, typename SrcImageT>
647  DestImageT &destImage,
648  SrcImageT const &srcImage,
649  afwGeom::AffineTransform const &affineTransform,
650  afwMath::WarpingControl const &control,
651  typename DestImageT::SinglePixel padValue
652 ) {
653  afwGeom::Point2D const destXY0(destImage.getXY0());
654  afwMath::detail::AffineTransformPositionFunctor const computeSrcPos(destXY0, affineTransform);
655  return doWarpImage(destImage, srcImage, computeSrcPos, control, padValue);
656 }
657 
658 
659 template<typename DestImageT, typename SrcImageT>
661  DestImageT &destImage,
662  SrcImageT const &srcImage,
663  afwMath::SeparableKernel &warpingKernel,
664  afwGeom::AffineTransform const &affineTransform,
665  int const interpLength,
666  typename DestImageT::SinglePixel padValue,
668  )
669 {
670  afwGeom::Point2D const destXY0(destImage.getXY0());
671  afwMath::detail::AffineTransformPositionFunctor const computeSrcPos(destXY0, affineTransform);
672  afwMath::WarpingControl control(warpingKernel, interpLength, devPref);
673  return doWarpImage(destImage, srcImage, computeSrcPos, control, padValue);
674 }
675 
676 
677 template<typename DestImageT, typename SrcImageT>
679  DestImageT &destImage,
680  SrcImageT const &srcImage,
681  afwGeom::LinearTransform const &linearTransform,
682  afwGeom::Point2D const &centerPosition,
683  afwMath::WarpingControl const &control,
684  typename DestImageT::SinglePixel padValue
685 ) {
686  // force src and dest to be the same size and xy0
687  if (
688  (destImage.getWidth() != srcImage.getWidth()) ||
689  (destImage.getHeight() != srcImage.getHeight()) ||
690  (destImage.getXY0() != srcImage.getXY0())
691  ) {
692  std::ostringstream errStream;
693  errStream << "src and dest images must have same size and xy0.";
694  throw LSST_EXCEPT(pexExcept::InvalidParameterError, errStream.str());
695  }
696 
697  // set the xy0 coords to 0,0 to make life easier
698  SrcImageT srcImageCopy(srcImage, true);
699  srcImageCopy.setXY0(0, 0);
700  destImage.setXY0(0, 0);
701  afwGeom::Extent2D cLocal = afwGeom::Extent2D(centerPosition) - afwGeom::Extent2D(srcImage.getXY0());
702 
703  // for the affine transform, the centerPosition will not only get sheared, but also
704  // moved slightly. So we'll include a translation to move it back by an amount
705  // centerPosition - translatedCenterPosition
706  afwGeom::AffineTransform affTran(linearTransform, cLocal - linearTransform(cLocal));
707 
708  // now warp
709 #if 0
710  static float t = 0.0;
711  float t_before = 1.0*clock()/CLOCKS_PER_SEC;
712  int n = warpImage(destImage, srcImageCopy, affTran, control, padValue);
713  float t_after = 1.0*clock()/CLOCKS_PER_SEC;
714  float dt = t_after - t_before;
715  t += dt;
716  std::cout <<srcImage.getWidth()<<"x"<<srcImage.getHeight()<<": "<< dt <<" "<< t <<std::endl;
717 #else
718  int n = warpImage(destImage, srcImageCopy, affTran, control, padValue);
719 #endif
720 
721  // fix the origin and we're done.
722  destImage.setXY0(srcImage.getXY0());
723 
724  return n;
725 }
726 
727 
728 template<typename DestImageT, typename SrcImageT>
730  DestImageT &destImage,
731  SrcImageT const &srcImage,
732  afwMath::SeparableKernel &warpingKernel,
733  afwGeom::LinearTransform const &linearTransform,
734  afwGeom::Point2D const &centerPosition,
735  int const interpLength,
736  typename DestImageT::SinglePixel padValue,
738 ) {
739  afwMath::WarpingControl control(warpingKernel, interpLength, devPref);
740  return warpCenteredImage(destImage, srcImage, linearTransform, centerPosition, control, padValue);
741 }
742 
743 
744 //
745 // Explicit instantiations
746 //
748 // may need to omit default params for EXPOSURE -- original code did that and it worked
749 #define EXPOSURE(PIXTYPE) afwImage::Exposure<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
750 #define MASKEDIMAGE(PIXTYPE) afwImage::MaskedImage<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
751 #define IMAGE(PIXTYPE) afwImage::Image<PIXTYPE>
752 #define NL /* */
753 
754 #define INSTANTIATE(DESTIMAGEPIXELT, SRCIMAGEPIXELT) \
755  template int afwMath::warpCenteredImage( \
756  IMAGE(DESTIMAGEPIXELT) &destImage, \
757  IMAGE(SRCIMAGEPIXELT) const &srcImage, \
758  afwGeom::LinearTransform const &linearTransform, \
759  afwGeom::Point2D const &centerPosition, \
760  afwMath::WarpingControl const &control, \
761  IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
762  template int afwMath::warpCenteredImage( \
763  MASKEDIMAGE(DESTIMAGEPIXELT) &destImage, \
764  MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
765  afwGeom::LinearTransform const &linearTransform, \
766  afwGeom::Point2D const &centerPosition, \
767  afwMath::WarpingControl const &control, \
768  MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
769  template int afwMath::warpCenteredImage( \
770  IMAGE(DESTIMAGEPIXELT) &destImage, \
771  IMAGE(SRCIMAGEPIXELT) const &srcImage, \
772  afwMath::SeparableKernel &warpingKernel, \
773  afwGeom::LinearTransform const &linearTransform, \
774  afwGeom::Point2D const &centerPosition, \
775  int const interpLength, \
776  IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue, \
777  lsst::afw::gpu::DevicePreference devPref); NL \
778  template int afwMath::warpCenteredImage( \
779  MASKEDIMAGE(DESTIMAGEPIXELT) &destImage, \
780  MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
781  afwMath::SeparableKernel &warpingKernel, \
782  afwGeom::LinearTransform const &linearTransform, \
783  afwGeom::Point2D const &centerPosition, \
784  int const interpLength, \
785  MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue, \
786  lsst::afw::gpu::DevicePreference devPref); NL \
787  template int afwMath::warpImage( \
788  IMAGE(DESTIMAGEPIXELT) &destImage, \
789  IMAGE(SRCIMAGEPIXELT) const &srcImage, \
790  afwGeom::AffineTransform const &affineTransform, \
791  afwMath::WarpingControl const &control, \
792  IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
793  template int afwMath::warpImage( \
794  MASKEDIMAGE(DESTIMAGEPIXELT) &destImage, \
795  MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
796  afwGeom::AffineTransform const &affineTransform, \
797  afwMath::WarpingControl const &control, \
798  MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
799  template int afwMath::warpImage( \
800  IMAGE(DESTIMAGEPIXELT) &destImage, \
801  IMAGE(SRCIMAGEPIXELT) const &srcImage, \
802  afwMath::SeparableKernel &warpingKernel, \
803  afwGeom::AffineTransform const &affineTransform, \
804  int const interpLength, \
805  IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue, \
806  lsst::afw::gpu::DevicePreference devPref); NL \
807  template int afwMath::warpImage( \
808  MASKEDIMAGE(DESTIMAGEPIXELT) &destImage, \
809  MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
810  afwMath::SeparableKernel &warpingKernel, \
811  afwGeom::AffineTransform const &affineTransform, \
812  int const interpLength, \
813  MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue, \
814  lsst::afw::gpu::DevicePreference devPref); NL \
815  template int afwMath::warpImage( \
816  IMAGE(DESTIMAGEPIXELT) &destImage, \
817  afwImage::Wcs const &destWcs, \
818  IMAGE(SRCIMAGEPIXELT) const &srcImage, \
819  afwImage::Wcs const &srcWcs, \
820  afwMath::WarpingControl const &control, \
821  IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
822  template int afwMath::warpImage( \
823  MASKEDIMAGE(DESTIMAGEPIXELT) &destImage, \
824  afwImage::Wcs const &destWcs, \
825  MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
826  afwImage::Wcs const &srcWcs, \
827  afwMath::WarpingControl const &control, \
828  MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue); NL \
829  template int afwMath::warpImage( \
830  IMAGE(DESTIMAGEPIXELT) &destImage, \
831  afwImage::Wcs const &destWcs, \
832  IMAGE(SRCIMAGEPIXELT) const &srcImage, \
833  afwImage::Wcs const &srcWcs, \
834  afwMath::SeparableKernel &warpingKernel, \
835  int const interpLength, \
836  IMAGE(DESTIMAGEPIXELT)::SinglePixel padValue, \
837  lsst::afw::gpu::DevicePreference devPref); NL \
838  template int afwMath::warpImage( \
839  MASKEDIMAGE(DESTIMAGEPIXELT) &destImage, \
840  afwImage::Wcs const &destWcs, \
841  MASKEDIMAGE(SRCIMAGEPIXELT) const &srcImage, \
842  afwImage::Wcs const &srcWcs, \
843  afwMath::SeparableKernel &warpingKernel, \
844  int const interpLength, \
845  MASKEDIMAGE(DESTIMAGEPIXELT)::SinglePixel padValue, \
846  lsst::afw::gpu::DevicePreference devPref); NL \
847  template int afwMath::warpExposure( \
848  EXPOSURE(DESTIMAGEPIXELT) &destExposure, \
849  EXPOSURE(SRCIMAGEPIXELT) const &srcExposure, \
850  afwMath::WarpingControl const &control,\
851  EXPOSURE(DESTIMAGEPIXELT)::MaskedImageT::SinglePixel padValue); NL \
852  template int afwMath::warpExposure( \
853  EXPOSURE(DESTIMAGEPIXELT) &destExposure, \
854  EXPOSURE(SRCIMAGEPIXELT) const &srcExposure, \
855  afwMath::SeparableKernel &warpingKernel, \
856  int const interpLength, \
857  EXPOSURE(DESTIMAGEPIXELT)::MaskedImageT::SinglePixel padValue, \
858  lsst::afw::gpu::DevicePreference devPref);
859 
860 
861 
862 
863 INSTANTIATE(double, double)
864 INSTANTIATE(double, float)
865 INSTANTIATE(double, int)
866 INSTANTIATE(double, boost::uint16_t)
867 INSTANTIATE(float, float)
868 INSTANTIATE(float, int)
869 INSTANTIATE(float, boost::uint16_t)
870 INSTANTIATE(int, int)
871 INSTANTIATE(boost::uint16_t, boost::uint16_t)
int y
bool isGpuEnabled()
returns true if GPU acceleration is enabled
void setWarpingKernel(SeparableKernel const &warpingKernel)
set the warping kernel
GPU accelerared image warping.
An include file to include the header files for lsst::afw::geom.
Declare the Kernel class and subclasses.
int getWidth() const
Return the Kernel&#39;s width.
Definition: Kernel.h:240
#define PTR(...)
Definition: base.h:41
double indexToPosition(double ind)
Convert image index to image position.
Definition: ImageUtils.h:54
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
table::Key< std::string > name
Definition: ApCorrMap.cc:71
additional GPU exceptions
boost::shared_ptr< SeparableKernel > makeWarpingKernel(std::string name)
Return a warping kernel given its name.
Extent< double, 2 > Extent2D
Definition: Extent.h:358
geom::Point2D skyToPixel(geom::Angle sky1, geom::Angle sky2) const
Convert from sky coordinates (e.g. RA/dec) to pixel positions.
Definition: Wcs.cc:782
#define CONST_PTR(...)
Definition: base.h:47
definition of the Trace messaging facilities
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
Definition: Kernel.h:986
Parameters to control convolution.
Definition: warpExposure.h:239
lsst::afw::geom::Point2I getCtr() const
Return index of kernel&#39;s center.
Definition: Kernel.h:254
Implementation of the WCS standard for a any projection.
Definition: Wcs.h:107
int warpCenteredImage(DestImageT &destImage, SrcImageT const &srcImage, lsst::afw::geom::LinearTransform const &linearTransform, lsst::afw::geom::Point2D const &centerPosition, 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. This enables warping an image of e...
boost::shared_ptr< coord::Coord > pixelToSky(double pix1, double pix2) const
Convert from pixel position to sky coordinates (e.g. RA/dec)
Definition: Wcs.cc:858
DevicePreference
A type used to select whether to use CPU or GPU device.
An integer coordinate rectangle.
Definition: Box.h:53
int warpImage(DestImageT &destImage, lsst::afw::image::Wcs const &destWcs, SrcImageT const &srcImage, lsst::afw::image::Wcs 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. See also convenience function warpExposure() to warp an Ex...
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
A 2D linear coordinate transformation.
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
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.
void setMaskWarpingKernelName(std::string const &maskWarpingKernelName)
set or clear the mask warping kernel by name
ImageT::image_category image_category
Definition: Image.h:79
int getOrder() const
get the order of the kernel
An affine coordinate transformation consisting of a linear transformation and an offset.
virtual boost::shared_ptr< Kernel > clone() const
Return a pointer to a deep copy of this kernel.
bool isSameObject(A const &, B const &)
Definition: warpExposure.h:635
void setWarpingKernelName(std::string const &warpingKernelName)
set the warping kernel by name
geom::Extent2I const getDimensions() const
Return the Kernel&#39;s dimensions (width, height)
Definition: Kernel.h:226
bool isGpuBuild()
Inline function which returns true only when GPU_BUILD macro is defined.
Definition: IsGpuBuild.h:45
if(width!=gim.getWidth()||height!=gim.getHeight()||x0!=gim.getX0()||y0!=gim.getY0())
Definition: saturated.cc:47
Interface for CPU/GPU device selection.
bool contains(Point2I const &point) const
Return true if the box contains the point.
std::pair< int, WarpImageGpuStatus::ReturnCode > warpImageGPU(DestImageT &destImage, SrcImageT const &srcImage, lsst::afw::math::LanczosWarpingKernel const &warpingKernel, lsst::afw::math::SeparableKernel const &maskWarpingKernel, PositionFunctor const &computeSrcPos, int const interpLength, typename DestImageT::SinglePixel padValue, const bool forceProcessing=true)
GPU accelerated image warping using Lanczos resampling.
void _testDevicePreference(lsst::afw::gpu::DevicePreference const &devicePreference, boost::shared_ptr< SeparableKernel const > const &warpingKernelPtr) const
test if GPU device preference and main warping kernel are compatible
Bilinear warping: fast; good for undersampled data.
Definition: warpExposure.h:101
int x
int row
Definition: CR.cc:153
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
#define INSTANTIATE(T)
tbl::Key< std::string > warpingKernelName
Definition: CoaddPsf.cc:320
void _testWarpingKernels(SeparableKernel const &warpingKernel, SeparableKernel const &maskWarpingKernel) const
Throw an exception if the two kernels are not compatible in shape.
Support for warping an image to a new WCS.
Nearest neighbor warping: fast; good for undersampled data.
Definition: warpExposure.h:157
Lanczos warping: accurate but slow and can introduce ringing artifacts.
Definition: warpExposure.h:72
GPU accelerared image warping.
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
Kernels are used for convolution with MaskedImages and (eventually) Images.
Definition: Kernel.h:134
int col
Definition: CR.cc:152
Include files required for standard LSST Exception handling.
A function to determine whether compiling for GPU is enabled.
void setMaskWarpingKernel(SeparableKernel const &maskWarpingKernel)
set the mask warping kernel
Functions to handle coordinates.