LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
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
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
GPU accelerared image warping.
An include file to include the header files for lsst::afw::geom.
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
Declare the Kernel class and subclasses.
geom::Extent2I const getDimensions() const
Return the Kernel&#39;s dimensions (width, height)
Definition: Kernel.h:226
double indexToPosition(double ind)
Convert image index to image position.
Definition: ImageUtils.h:54
table::Key< std::string > name
Definition: ApCorrMap.cc:71
bool contains(Point2I const &point) const
Return true if the box contains the point.
Include files required for standard LSST Exception handling.
additional GPU exceptions
boost::shared_ptr< SeparableKernel > makeWarpingKernel(std::string name)
Return a warping kernel given its name.
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 INSTANTIATE(MATCH)
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
void setWarpingKernelName(std::string const &warpingKernelName)
set the warping kernel by name
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
#define PTR(...)
Definition: base.h:41
Parameters to control convolution.
Definition: warpExposure.h:239
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.
void setMaskWarpingKernel(SeparableKernel const &maskWarpingKernel)
set the mask warping kernel
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
int getOrder() const
get the order of the kernel
int getWidth() const
Return the Kernel&#39;s width.
Definition: Kernel.h:240
A 2D linear coordinate transformation.
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.
An affine coordinate transformation consisting of a linear transformation and an offset.
void setMaskWarpingKernelName(std::string const &maskWarpingKernelName)
set or clear the mask warping kernel by name
bool isSameObject(A const &, B const &)
Definition: warpExposure.h:635
bool isGpuBuild()
Inline function which returns true only when GPU_BUILD macro is defined.
Definition: IsGpuBuild.h:45
void setWarpingKernel(SeparableKernel const &warpingKernel)
set the warping kernel
if(width!=gim.getWidth()||height!=gim.getHeight()||x0!=gim.getX0()||y0!=gim.getY0())
Definition: saturated.cc:47
Interface for CPU/GPU device selection.
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.
double x
lsst::afw::geom::Point2I getCtr() const
Return index of kernel&#39;s center.
Definition: Kernel.h:254
Bilinear warping: fast; good for undersampled data.
Definition: warpExposure.h:101
void ImageT ImageT int float saturatedPixelValue int const height
Definition: saturated.cc:44
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
int row
Definition: CR.cc:153
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
tbl::Key< std::string > warpingKernelName
Definition: CoaddPsf.cc:329
Support for warping an image to a new WCS.
virtual void setKernelParameter(unsigned int ind, double value) const
Set one kernel parameter.
Nearest neighbor warping: fast; good for undersampled data.
Definition: warpExposure.h:157
void _testWarpingKernels(SeparableKernel const &warpingKernel, SeparableKernel const &maskWarpingKernel) const
Throw an exception if the two kernels are not compatible in shape.
#define CONST_PTR(...)
Definition: base.h:47
Lanczos warping: accurate but slow and can introduce ringing artifacts.
Definition: warpExposure.h:72
ImageT::image_category image_category
Definition: Image.h:79
Extent< double, 2 > Extent2D
Definition: Extent.h:358
GPU accelerared image warping.
virtual boost::shared_ptr< Kernel > clone() const
Return a pointer to a deep copy of this kernel.
Kernels are used for convolution with MaskedImages and (eventually) Images.
Definition: Kernel.h:134
int col
Definition: CR.cc:152
A function to determine whether compiling for GPU is enabled.
Functions to handle coordinates.