LSSTApplications  11.0-13-gbb96280,12.1+18,12.1+7,12.1-1-g14f38d3+72,12.1-1-g16c0db7+5,12.1-1-g5961e7a+84,12.1-1-ge22e12b+23,12.1-11-g06625e2+4,12.1-11-g0d7f63b+4,12.1-19-gd507bfc,12.1-2-g7dda0ab+38,12.1-2-gc0bc6ab+81,12.1-21-g6ffe579+2,12.1-21-gbdb6c2a+4,12.1-24-g941c398+5,12.1-3-g57f6835+7,12.1-3-gf0736f3,12.1-37-g3ddd237,12.1-4-gf46015e+5,12.1-5-g06c326c+20,12.1-5-g648ee80+3,12.1-5-gc2189d7+4,12.1-6-ga608fc0+1,12.1-7-g3349e2a+5,12.1-7-gfd75620+9,12.1-9-g577b946+5,12.1-9-gc4df26a+10
LSSTDataManagementBasePackage
BasicConvolve.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
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 
34 #include <algorithm>
35 #include <cmath>
36 #include <cstdint>
37 #include <sstream>
38 #include <vector>
39 
40 #include "lsst/pex/exceptions.h"
41 #include "lsst/log/Log.h"
44 #include "lsst/afw/math/Kernel.h"
45 #include "lsst/afw/geom.h"
47 
48 namespace pexExcept = lsst::pex::exceptions;
49 namespace afwGeom = lsst::afw::geom;
50 namespace afwImage = lsst::afw::image;
51 namespace afwMath = lsst::afw::math;
52 namespace mathDetail = lsst::afw::math::detail;
53 
54 namespace {
55 
56  /*
57  * Assert that the dimensions of convolvedImage, inImage and kernel are compatible with convolution.
58  *
59  * @throw lsst::pex::exceptions::InvalidParameterError if convolvedImage dimensions != inImage dim.
60  * @throw lsst::pex::exceptions::InvalidParameterError if inImage smaller than kernel in width or h.
61  * @throw lsst::pex::exceptions::InvalidParameterError if kernel width or height < 1
62  *
63  */
64  template <typename OutImageT, typename InImageT>
65  void assertDimensionsOK(
66  OutImageT const &convolvedImage,
67  InImageT const &inImage,
68  lsst::afw::math::Kernel const &kernel
69  ) {
70  if (convolvedImage.getDimensions() != inImage.getDimensions()) {
71  std::ostringstream os;
72  os << "convolvedImage dimensions = ( "
73  << convolvedImage.getWidth() << ", " << convolvedImage.getHeight()
74  << ") != (" << inImage.getWidth() << ", " << inImage.getHeight() << ") = inImage dimensions";
75  throw LSST_EXCEPT(pexExcept::InvalidParameterError, os.str());
76  }
77  if (inImage.getWidth() < kernel.getWidth() || inImage.getHeight() < kernel.getHeight()) {
78  std::ostringstream os;
79  os << "inImage dimensions = ( "
80  << inImage.getWidth() << ", " << inImage.getHeight()
81  << ") smaller than (" << kernel.getWidth() << ", " << kernel.getHeight()
82  << ") = kernel dimensions in width and/or height";
83  throw LSST_EXCEPT(pexExcept::InvalidParameterError, os.str());
84  }
85  if ((kernel.getWidth() < 1) || (kernel.getHeight() < 1)) {
86  std::ostringstream os;
87  os << "kernel dimensions = ( "
88  << kernel.getWidth() << ", " << kernel.getHeight()
89  << ") smaller than (1, 1) in width and/or height";
90  throw LSST_EXCEPT(pexExcept::InvalidParameterError, os.str());
91  }
92  }
93  /*
94  * @brief Compute the dot product of a kernel row or column and the overlapping portion of an %image
95  *
96  * @return computed dot product
97  *
98  * The pixel computed belongs at position imageIter + kernel center.
99  *
100  * @todo get rid of KernelPixelT parameter if possible by not computing local variable kVal,
101  * or by using iterator traits:
102  * typedef typename std::iterator_traits<KernelIterT>::value_type KernelPixel;
103  * Unfortunately, in either case compilation fails with this sort of message:
104 \verbatim
105 include/lsst/afw/image/Pixel.h: In instantiation of ‘lsst::afw::image::pixel::exprTraits<boost::gil::pixel<double, boost::gil::layout<boost::mpl::vector1<boost::gil::gray_color_t>, boost::mpl::range_c<int, 0, 1> > > >’:
106 include/lsst/afw/image/Pixel.h:385: instantiated from ‘lsst::afw::image::pixel::BinaryExpr<lsst::afw::image::pixel::Pixel<int, short unsigned int, float>, boost::gil::pixel<double, boost::gil::layout<boost::mpl::vector1<boost::gil::gray_color_t>, boost::mpl::range_c<int, 0, 1> > >, std::multiplies<int>, lsst::afw::image::pixel::bitwise_or<short unsigned int>, lsst::afw::image::pixel::variance_multiplies<float> >’
107 src/math/ConvolveImage.cc:59: instantiated from ‘OutPixelT<unnamed>::kernelDotProduct(ImageIterT, KernelIterT, int) [with OutPixelT = lsst::afw::image::pixel::SinglePixel<int, short unsigned int, float>, ImageIterT = lsst::afw::image::MaskedImage<int, short unsigned int, float>::const_MaskedImageIterator<boost::gil::gray32s_pixel_t*, boost::gil::gray16_pixel_t*, boost::gil::gray32f_noscale_pixel_t*>, KernelIterT = const boost::gil::gray64f_noscalec_pixel_t*]’
108 src/math/ConvolveImage.cc:265: instantiated from ‘void lsst::afw::math::basicConvolve(OutImageT&, const InImageT&, const lsst::afw::math::Kernel&, bool) [with OutImageT = lsst::afw::image::MaskedImage<int, short unsigned int, float>, InImageT = lsst::afw::image::MaskedImage<int, short unsigned int, float>]’
109 src/math/ConvolveImage.cc:451: instantiated from ‘void lsst::afw::math::convolve(OutImageT&, const InImageT&, const KernelT&, bool, int) [with OutImageT = lsst::afw::image::MaskedImage<int, short unsigned int, float>, InImageT = lsst::afw::image::MaskedImage<int, short unsigned int, float>, KernelT = lsst::afw::math::AnalyticKernel]’
110 src/math/ConvolveImage.cc:587: instantiated from here
111 include/lsst/afw/image/Pixel.h:210: error: no type named ‘ImagePixelT’ in ‘struct boost::gil::pixel<double, boost::gil::layout<boost::mpl::vector1<boost::gil::gray_color_t>, boost::mpl::range_c<int, 0, 1> > >’
112 include/lsst/afw/image/Pixel.h:211: error: no type named ‘MaskPixelT’ in ‘struct boost::gil::pixel<double, boost::gil::layout<boost::mpl::vector1<boost::gil::gray_color_t>, boost::mpl::range_c<int, 0, 1> > >’
113 include/lsst/afw/image/Pixel.h:212: error: no type named ‘VariancePixelT’ in ‘struct boost::gil::pixel<double, boost::gil::layout<boost::mpl::vector1<boost::gil::gray_color_t>, boost::mpl::range_c<int, 0, 1> > >’
114 \endverbatim
115  */
116  template <typename OutPixelT, typename ImageIterT, typename KernelIterT, typename KernelPixelT>
117  inline OutPixelT kernelDotProduct(
118  ImageIterT imageIter,
119  KernelIterT kernelIter,
120  int kWidth)
121  {
122  OutPixelT outPixel(0);
123  for (int x = 0; x < kWidth; ++x, ++imageIter, ++kernelIter) {
124  KernelPixelT kVal = *kernelIter;
125  if (kVal != 0) {
126  outPixel += static_cast<OutPixelT>((*imageIter) * kVal);
127  }
128  }
129  return outPixel;
130  }
131 } // anonymous namespace
132 
150 template <typename OutImageT, typename InImageT>
152  OutImageT &convolvedImage,
153  InImageT const& inImage,
154  afwMath::Kernel const& kernel,
155  afwMath::ConvolutionControl const& convolutionControl)
156 {
157  // Because convolve isn't a method of Kernel we can't always use Kernel's vtbl to dynamically
158  // dispatch the correct version of basicConvolve. The case that fails is convolving with a kernel
159  // obtained from a pointer or reference to a Kernel (base class), e.g. as used in LinearCombinationKernel.
161  LOGL_DEBUG("TRACE3.afw.math.convolve.basicConvolve",
162  "generic basicConvolve: dispatch to DeltaFunctionKernel basicConvolve");
163  mathDetail::basicConvolve(convolvedImage, inImage,
164  *dynamic_cast<afwMath::DeltaFunctionKernel const*>(&kernel),
165  convolutionControl);
166  return;
167  } else if (IS_INSTANCE(kernel, afwMath::SeparableKernel)) {
168  LOGL_DEBUG("TRACE3.afw.math.convolve.basicConvolve",
169  "generic basicConvolve: dispatch to SeparableKernel basicConvolve");
170  mathDetail::basicConvolve(convolvedImage, inImage,
171  *dynamic_cast<afwMath::SeparableKernel const*>(&kernel),
172  convolutionControl);
173  return;
174  } else if (IS_INSTANCE(kernel, afwMath::LinearCombinationKernel) && kernel.isSpatiallyVarying()) {
175  LOGL_DEBUG("TRACE3.afw.math.convolve.basicConvolve",
176  "generic basicConvolve: dispatch to spatially varying LinearCombinationKernel basicConvolve");
177  mathDetail::basicConvolve(convolvedImage, inImage,
178  *dynamic_cast<afwMath::LinearCombinationKernel const*>(&kernel),
179  convolutionControl);
180  return;
181  }
182  // OK, use general (and slower) form
183  if (kernel.isSpatiallyVarying() && (convolutionControl.getMaxInterpolationDistance() > 1)) {
184  // use linear interpolation
185  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
186  "generic basicConvolve: using linear interpolation");
187  mathDetail::convolveWithInterpolation(convolvedImage, inImage, kernel, convolutionControl);
188 
189  } else {
190  // use brute force
191  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
192  "generic basicConvolve: using brute force");
193  mathDetail::convolveWithBruteForce(convolvedImage, inImage, kernel,convolutionControl);
194  }
195 }
196 
202 template <typename OutImageT, typename InImageT>
204  OutImageT& convolvedImage,
205  InImageT const& inImage,
206  afwMath::DeltaFunctionKernel const &kernel,
207  afwMath::ConvolutionControl const &convolutionControl)
208 {
209  assert (!kernel.isSpatiallyVarying());
210  assertDimensionsOK(convolvedImage, inImage, kernel);
211 
212  int const mImageWidth = inImage.getWidth(); // size of input region
213  int const mImageHeight = inImage.getHeight();
214  int const cnvWidth = mImageWidth + 1 - kernel.getWidth();
215  int const cnvHeight = mImageHeight + 1 - kernel.getHeight();
216  int const cnvStartX = kernel.getCtrX();
217  int const cnvStartY = kernel.getCtrY();
218  int const inStartX = kernel.getPixel().getX();
219  int const inStartY = kernel.getPixel().getY();
220 
221  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve", "DeltaFunctionKernel basicConvolve");
222 
223  for (int i = 0; i < cnvHeight; ++i) {
224  typename InImageT::x_iterator inPtr = inImage.x_at(inStartX, i + inStartY);
225  for (typename OutImageT::x_iterator cnvPtr = convolvedImage.x_at(cnvStartX, i + cnvStartY),
226  cnvEnd = cnvPtr + cnvWidth; cnvPtr != cnvEnd; ++cnvPtr, ++inPtr){
227  *cnvPtr = *inPtr;
228  }
229  }
230 }
231 
248 template <typename OutImageT, typename InImageT>
250  OutImageT& convolvedImage,
251  InImageT const& inImage,
252  afwMath::LinearCombinationKernel const& kernel,
253  afwMath::ConvolutionControl const & convolutionControl)
254 {
255  if (!kernel.isSpatiallyVarying()) {
256  // use the standard algorithm for the spatially invariant case
257  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
258  "basicConvolve for LinearCombinationKernel: spatially invariant; using brute force");
259  return mathDetail::convolveWithBruteForce(convolvedImage, inImage, kernel,
260  convolutionControl.getDoNormalize());
261  } else {
262  // refactor the kernel if this is reasonable and possible;
263  // then use the standard algorithm for the spatially varying case
264  PTR(afwMath::Kernel) refKernelPtr; // possibly refactored version of kernel
265  if (static_cast<int>(kernel.getNKernelParameters()) > kernel.getNSpatialParameters()) {
266  // refactoring will speed convolution, so try it
267  refKernelPtr = kernel.refactor();
268  if (!refKernelPtr) {
269  refKernelPtr = kernel.clone();
270  }
271  } else {
272  // too few basis kernels for refactoring to be worthwhile
273  refKernelPtr = kernel.clone();
274  }
275  if (convolutionControl.getMaxInterpolationDistance() > 1) {
276  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
277  "basicConvolve for LinearCombinationKernel: using interpolation");
278  return mathDetail::convolveWithInterpolation(convolvedImage, inImage, *refKernelPtr, convolutionControl);
279  } else {
280  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
281  "basicConvolve for LinearCombinationKernel: maxInterpolationError < 0; using brute force");
282  return mathDetail::convolveWithBruteForce(convolvedImage, inImage, *refKernelPtr,
283  convolutionControl.getDoNormalize());
284  }
285  }
286 }
287 
293 template <typename OutImageT, typename InImageT>
295  OutImageT& convolvedImage,
296  InImageT const& inImage,
297  afwMath::SeparableKernel const &kernel,
298  afwMath::ConvolutionControl const & convolutionControl)
299 {
300  typedef typename afwMath::Kernel::Pixel KernelPixel;
301  typedef typename std::vector<KernelPixel> KernelVector;
302  typedef KernelVector::const_iterator KernelIterator;
303  typedef typename InImageT::const_x_iterator InXIterator;
304  typedef typename InImageT::const_xy_locator InXYLocator;
305  typedef typename OutImageT::x_iterator OutXIterator;
306  typedef typename OutImageT::y_iterator OutYIterator;
307  typedef typename OutImageT::SinglePixel OutPixel;
308 
309  assertDimensionsOK(convolvedImage, inImage, kernel);
310 
311  afwGeom::Box2I const fullBBox = inImage.getBBox(image::LOCAL);
312  afwGeom::Box2I const goodBBox = kernel.shrinkBBox(fullBBox);
313 
314  KernelVector kernelXVec(kernel.getWidth());
315  KernelVector kernelYVec(kernel.getHeight());
316 
317  if (kernel.isSpatiallyVarying()) {
318  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
319  "SeparableKernel basicConvolve: kernel is spatially varying");
320 
321  for (int cnvY = goodBBox.getMinY(); cnvY <= goodBBox.getMaxY(); ++cnvY) {
322  double const rowPos = inImage.indexToPosition(cnvY, afwImage::Y);
323 
324  InXYLocator inImLoc = inImage.xy_at(0, cnvY - goodBBox.getMinY());
325  OutXIterator cnvXIter = convolvedImage.row_begin(cnvY) + goodBBox.getMinX();
326  for (int cnvX = goodBBox.getMinX(); cnvX <= goodBBox.getMaxX();
327  ++cnvX, ++inImLoc.x(), ++cnvXIter) {
328  double const colPos = inImage.indexToPosition(cnvX, afwImage::X);
329 
330  KernelPixel kSum = kernel.computeVectors(kernelXVec, kernelYVec,
331  convolutionControl.getDoNormalize(), colPos, rowPos);
332 
333  // why does this trigger warnings? It did not in the past.
334  *cnvXIter = afwMath::convolveAtAPoint<OutImageT, InImageT>(inImLoc, kernelXVec, kernelYVec);
335  if (convolutionControl.getDoNormalize()) {
336  *cnvXIter = *cnvXIter/kSum;
337  }
338  }
339  }
340  } else {
341  // kernel is spatially invariant
342  // The basic sequence:
343  // - For each output row:
344  // - Compute x-convolved data: a kernel height's strip of input image convolved with kernel x vector
345  // - Compute one row of output by dotting each column of x-convolved data with the kernel y vector
346  // The x-convolved data is stored in a kernel-height by good-width buffer.
347  // This is circular buffer along y (to avoid shifting pixels before setting each new row);
348  // so for each new row the kernel y vector is rotated to match the order of the x-convolved data.
349 
350  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
351  "SeparableKernel basicConvolve: kernel is spatially invariant");
352 
353  kernel.computeVectors(kernelXVec, kernelYVec, convolutionControl.getDoNormalize());
354  KernelIterator const kernelXVecBegin = kernelXVec.begin();
355  KernelIterator const kernelYVecBegin = kernelYVec.begin();
356 
357  // buffer for x-convolved data
358  OutImageT buffer(afwGeom::Extent2I(goodBBox.getWidth(), kernel.getHeight()));
359 
360  // pre-fill x-convolved data buffer with all but one row of data
361  int yInd = 0; // during initial fill bufY = inImageY
362  int const yPrefillEnd = buffer.getHeight() - 1;
363  for (; yInd < yPrefillEnd; ++yInd) {
364  OutXIterator bufXIter = buffer.x_at(0, yInd);
365  OutXIterator const bufXEnd = buffer.x_at(goodBBox.getWidth(), yInd);
366  InXIterator inXIter = inImage.x_at(0, yInd);
367  for ( ; bufXIter != bufXEnd; ++bufXIter, ++inXIter) {
368  *bufXIter = kernelDotProduct<OutPixel, InXIterator, KernelIterator, KernelPixel>(
369  inXIter, kernelXVecBegin, kernel.getWidth());
370  }
371  }
372 
373  // compute output pixels using the sequence described above
374  int inY = yPrefillEnd;
375  int bufY = yPrefillEnd;
376  int cnvY = goodBBox.getMinY();
377  while (true) {
378  // fill next buffer row and compute output row
379  InXIterator inXIter = inImage.x_at(0, inY);
380  OutXIterator bufXIter = buffer.x_at(0, bufY);
381  OutXIterator cnvXIter = convolvedImage.x_at(goodBBox.getMinX(), cnvY);
382  for (int bufX = 0; bufX < goodBBox.getWidth(); ++bufX, ++cnvXIter, ++bufXIter, ++inXIter) {
383  // note: bufXIter points to the row of the buffer that is being updated,
384  // whereas bufYIter points to row 0 of the buffer
385  *bufXIter = kernelDotProduct<OutPixel, InXIterator, KernelIterator, KernelPixel>(
386  inXIter, kernelXVecBegin, kernel.getWidth());
387 
388  OutYIterator bufYIter = buffer.y_at(bufX, 0);
389  *cnvXIter = kernelDotProduct<OutPixel, OutYIterator, KernelIterator, KernelPixel>(
390  bufYIter, kernelYVecBegin, kernel.getHeight());
391  }
392 
393  // test for done now, instead of the start of the loop,
394  // to avoid an unnecessary extra rotation of the kernel Y vector
395  if (cnvY >= goodBBox.getMaxY()) break;
396 
397  // update y indices, including bufY, and rotate the kernel y vector to match
398  ++inY;
399  bufY = (bufY + 1) % kernel.getHeight();
400  ++cnvY;
401  std::rotate(kernelYVec.begin(), kernelYVec.end()-1, kernelYVec.end());
402  }
403  }
404 }
405 
426 template <typename OutImageT, typename InImageT>
428  OutImageT &convolvedImage,
429  InImageT const& inImage,
430  afwMath::Kernel const& kernel,
431  afwMath::ConvolutionControl const & convolutionControl)
432 {
433  bool doNormalize=convolutionControl.getDoNormalize();
434 
435  typedef typename afwMath::Kernel::Pixel KernelPixel;
436  typedef afwImage::Image<KernelPixel> KernelImage;
437 
438  typedef typename KernelImage::const_x_iterator KernelXIterator;
439  typedef typename KernelImage::const_xy_locator KernelXYLocator;
440  typedef typename InImageT::const_x_iterator InXIterator;
441  typedef typename InImageT::const_xy_locator InXYLocator;
442  typedef typename OutImageT::x_iterator OutXIterator;
443  typedef typename OutImageT::SinglePixel OutPixel;
444 
445  assertDimensionsOK(convolvedImage, inImage, kernel);
446 
447  int const inImageWidth = inImage.getWidth();
448  int const inImageHeight = inImage.getHeight();
449  int const kWidth = kernel.getWidth();
450  int const kHeight = kernel.getHeight();
451  int const cnvWidth = inImageWidth + 1 - kernel.getWidth();
452  int const cnvHeight = inImageHeight + 1 - kernel.getHeight();
453  int const cnvStartX = kernel.getCtrX();
454  int const cnvStartY = kernel.getCtrY();
455  int const cnvEndX = cnvStartX + cnvWidth; // end index + 1
456  int const cnvEndY = cnvStartY + cnvHeight; // end index + 1
457 
458  KernelImage kernelImage(kernel.getDimensions());
459  KernelXYLocator const kernelLoc = kernelImage.xy_at(0,0);
460 
461  if (kernel.isSpatiallyVarying()) {
462  LOGL_DEBUG("TRACE4.afw.math.convolve.convolveWithBruteForce",
463  "convolveWithBruteForce: kernel is spatially varying");
464 
465  for (int cnvY = cnvStartY; cnvY != cnvEndY; ++cnvY) {
466  double const rowPos = inImage.indexToPosition(cnvY, afwImage::Y);
467 
468  InXYLocator inImLoc = inImage.xy_at(0, cnvY - cnvStartY);
469  OutXIterator cnvXIter = convolvedImage.x_at(cnvStartX, cnvY);
470  for (int cnvX = cnvStartX; cnvX != cnvEndX; ++cnvX, ++inImLoc.x(), ++cnvXIter) {
471  double const colPos = inImage.indexToPosition(cnvX, afwImage::X);
472 
473  KernelPixel kSum = kernel.computeImage(kernelImage, false, colPos, rowPos);
474  *cnvXIter = afwMath::convolveAtAPoint<OutImageT, InImageT>(
475  inImLoc, kernelLoc, kWidth, kHeight);
476  if (doNormalize) {
477  *cnvXIter = *cnvXIter/kSum;
478  }
479  }
480  }
481  } else {
482  LOGL_DEBUG("TRACE4.afw.math.convolve.convolveWithBruteForce",
483  "convolveWithBruteForce: kernel is spatially invariant");
484 
485  (void)kernel.computeImage(kernelImage, doNormalize);
486 
487  for (int inStartY = 0, cnvY = cnvStartY; inStartY < cnvHeight; ++inStartY, ++cnvY) {
488  KernelXIterator kernelXIter = kernelImage.x_at(0, 0);
489  InXIterator inXIter = inImage.x_at(0, inStartY);
490  OutXIterator cnvXIter = convolvedImage.x_at(cnvStartX, cnvY);
491  for (int x = 0; x < cnvWidth; ++x, ++cnvXIter, ++inXIter) {
492  *cnvXIter = kernelDotProduct<OutPixel, InXIterator, KernelXIterator, KernelPixel>(
493  inXIter, kernelXIter, kWidth);
494  }
495  for (int kernelY = 1, inY = inStartY + 1; kernelY < kHeight; ++inY, ++kernelY) {
496  KernelXIterator kernelXIter = kernelImage.x_at(0, kernelY);
497  InXIterator inXIter = inImage.x_at(0, inY);
498  OutXIterator cnvXIter = convolvedImage.x_at(cnvStartX, cnvY);
499  for (int x = 0; x < cnvWidth; ++x, ++cnvXIter, ++inXIter) {
500  *cnvXIter += kernelDotProduct<OutPixel, InXIterator, KernelXIterator, KernelPixel>(
501  inXIter, kernelXIter, kWidth);
502  }
503  }
504  }
505  }
506 }
507 
508 /*
509  * Explicit instantiation
510  */
512 #define IMAGE(PIXTYPE) afwImage::Image<PIXTYPE>
513 #define MASKEDIMAGE(PIXTYPE) afwImage::MaskedImage<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
514 #define NL /* */
515 // Instantiate Image or MaskedImage versions
516 #define INSTANTIATE_IM_OR_MI(IMGMACRO, OUTPIXTYPE, INPIXTYPE) \
517  template void mathDetail::basicConvolve( \
518  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::Kernel const&, \
519  afwMath::ConvolutionControl const&); NL \
520  template void mathDetail::basicConvolve( \
521  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::DeltaFunctionKernel const&, \
522  afwMath::ConvolutionControl const&); NL \
523  template void mathDetail::basicConvolve( \
524  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::LinearCombinationKernel const&, \
525  afwMath::ConvolutionControl const&); NL \
526  template void mathDetail::basicConvolve( \
527  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::SeparableKernel const&, \
528  afwMath::ConvolutionControl const&); NL \
529  template void mathDetail::convolveWithBruteForce( \
530  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::Kernel const&, \
531  afwMath::ConvolutionControl const&);
532 // Instantiate both Image and MaskedImage versions
533 #define INSTANTIATE(OUTPIXTYPE, INPIXTYPE) \
534  INSTANTIATE_IM_OR_MI(IMAGE, OUTPIXTYPE, INPIXTYPE) \
535  INSTANTIATE_IM_OR_MI(MASKEDIMAGE, OUTPIXTYPE, INPIXTYPE)
536 
537 INSTANTIATE(double, double)
538 INSTANTIATE(double, float)
539 INSTANTIATE(double, int)
540 INSTANTIATE(double, std::uint16_t)
541 INSTANTIATE(float, float)
542 INSTANTIATE(float, int)
543 INSTANTIATE(float, std::uint16_t)
544 INSTANTIATE(int, int)
545 INSTANTIATE(std::uint16_t, std::uint16_t)
Convolution support.
An include file to include the header files for lsst::afw::geom.
Declare the Kernel class and subclasses.
geom::Extent2I const getDimensions() const
Return the Kernel&#39;s dimensions (width, height)
Definition: Kernel.h:223
double computeVectors(std::vector< Pixel > &colList, std::vector< Pixel > &rowList, bool doNormalize, double x=0.0, double y=0.0) const
Compute the column and row arrays in place, where kernel(col, row) = colList(col) * rowList(row) ...
boost::shared_ptr< Kernel > refactor() const
Refactor the kernel as a linear combination of N bases where N is the number of parameters for the sp...
int getMinY() const
Definition: Box.h:125
Include files required for standard LSST Exception handling.
Parameters to control convolution.
Definition: ConvolveImage.h:57
int getCtrY() const
Return y index of kernel&#39;s center.
Definition: Kernel.h:269
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
Definition: Kernel.h:983
int getNSpatialParameters() const
Return the number of spatial parameters (0 if not spatially varying)
Definition: Kernel.h:293
void convolveWithBruteForce(OutImageT &convolvedImage, InImageT const &inImage, lsst::afw::math::Kernel const &kernel, lsst::afw::math::ConvolutionControl const &convolutionControl)
Convolve an Image or MaskedImage with a Kernel by computing the kernel image at every point...
int getCtrX() const
Return x index of kernel&#39;s center.
Definition: Kernel.h:260
#define INSTANTIATE(T)
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:513
An integer coordinate rectangle.
Definition: Box.h:53
int getHeight() const
Return the Kernel&#39;s height.
Definition: Kernel.h:244
int getMinX() const
Definition: Box.h:124
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
LSST DM logging module built on log4cxx.
int getWidth() const
Return the Kernel&#39;s width.
Definition: Kernel.h:237
virtual boost::shared_ptr< Kernel > clone() const
Return a pointer to a deep copy of this kernel.
void basicConvolve(OutImageT &convolvedImage, InImageT const &inImage, lsst::afw::math::Kernel const &kernel, lsst::afw::math::ConvolutionControl const &convolutionControl)
Low-level convolution function that does not set edge pixels.
int getMaxX() const
Definition: Box.h:128
int getWidth() const
Definition: Box.h:154
unsigned int getNKernelParameters() const
Return the number of kernel parameters (0 if none)
Definition: Kernel.h:286
double computeImage(lsst::afw::image::Image< Pixel > &image, bool doNormalize, double x=0.0, double y=0.0) const
Compute an image (pixellized representation of the kernel) in place.
Definition: Kernel.cc:94
A kernel that is a linear combination of fixed basis kernels.
Definition: Kernel.h:811
double x
void convolveWithInterpolation(OutImageT &outImage, InImageT const &inImage, lsst::afw::math::Kernel const &kernel, ConvolutionControl const &convolutionControl)
Convolve an Image or MaskedImage with a spatially varying Kernel using linear interpolation.
Convolve and convolveAtAPoint functions for Image and Kernel.
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
lsst::afw::geom::Point2I getPixel() const
Definition: Kernel.h:765
#define PTR(...)
Definition: base.h:41
Implementation of the Class MaskedImage.
int getMaxY() const
Definition: Box.h:129
Kernels are used for convolution with MaskedImages and (eventually) Images.
Definition: Kernel.h:131
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:416
#define IS_INSTANCE(A, B)
Definition: Convolve.h:46
A kernel that has only one non-zero pixel (of value 1)
Definition: Kernel.h:741
lsst::afw::geom::Box2I shrinkBBox(lsst::afw::geom::Box2I const &bbox) const
Given a bounding box for an image one wishes to convolve with this kernel, return the bounding box fo...
Definition: Kernel.cc:207
bool isSpatiallyVarying() const
Return true iff the kernel is spatially varying (has a spatial function)
Definition: Kernel.h:399