LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
LSSTDataManagementBasePackage
Classes | Functions
lsst::afw::math::detail Namespace Reference

Classes

struct  ConvolveWithInterpolationWorkingImages
 kernel images used by convolveRegionWithInterpolation More...
 
class  KernelImagesForRegion
 A collection of Kernel images for special locations on a rectangular region of an image. More...
 
class  RowOfKernelImagesForRegion
 A row of KernelImagesForRegion. More...
 
class  SmoothedSpline
 
class  Spline
 
class  TautSpline
 
struct  TrapezoidalPacker
 A helper class ChebyshevBoundedField, for mapping trapezoidal matrices to 1-d arrays. More...
 
class  WarpAtOnePoint
 A functor that computes one warped pixel. More...
 

Functions

template<typename OutImageT , typename InImageT >
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. More...
 
template<typename OutImageT , typename InImageT >
void basicConvolve (OutImageT &convolvedImage, InImageT const &inImage, lsst::afw::math::DeltaFunctionKernel const &kernel, lsst::afw::math::ConvolutionControl const &convolutionControl)
 A version of basicConvolve that should be used when convolving delta function kernels. More...
 
template<typename OutImageT , typename InImageT >
void basicConvolve (OutImageT &convolvedImage, InImageT const &inImage, lsst::afw::math::LinearCombinationKernel const &kernel, lsst::afw::math::ConvolutionControl const &convolutionControl)
 A version of basicConvolve that should be used when convolving a LinearCombinationKernel. More...
 
template<typename OutImageT , typename InImageT >
void basicConvolve (OutImageT &convolvedImage, InImageT const &inImage, lsst::afw::math::SeparableKernel const &kernel, lsst::afw::math::ConvolutionControl const &convolutionControl)
 A version of basicConvolve that should be used when convolving separable kernels. More...
 
template<typename OutImageT , typename InImageT >
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. More...
 
template<typename OutImageT , typename InImageT >
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. More...
 
template<typename OutImageT , typename InImageT >
void convolveRegionWithInterpolation (OutImageT &outImage, InImageT const &inImage, KernelImagesForRegion const &region, ConvolveWithInterpolationWorkingImages &workingImages)
 Convolve a region of an Image or MaskedImage with a spatially varying Kernel using interpolation. More...
 
 PYBIND11_MODULE (convolve, mod)
 

Function Documentation

◆ basicConvolve() [1/4]

template<typename OutImageT , typename InImageT >
void lsst::afw::math::detail::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.

convolvedImage must be the same size as inImage. convolvedImage has a border in which the output pixels are not set. This border has size:

Parameters
[out]convolvedImageconvolved image
[in]inImageimage to convolve
[in]kernelconvolution kernel
[in]convolutionControlconvolution control parameters
Exceptions
lsst::pex::exceptions::InvalidParameterErrorif convolvedImage dimensions != inImage dimensions
lsst::pex::exceptions::InvalidParameterErrorif inImage smaller than kernel in width or height
lsst::pex::exceptions::InvalidParameterErrorif kernel width or height < 1
std::bad_allocwhen allocation of CPU memory fails

Definition at line 142 of file BasicConvolve.cc.

143  {
144  // Because convolve isn't a method of Kernel we can't always use Kernel's vtbl to dynamically
145  // dispatch the correct version of basicConvolve. The case that fails is convolving with a kernel
146  // obtained from a pointer or reference to a Kernel (base class), e.g. as used in LinearCombinationKernel.
147  if (IS_INSTANCE(kernel, math::DeltaFunctionKernel)) {
148  LOGL_DEBUG("TRACE3.afw.math.convolve.basicConvolve",
149  "generic basicConvolve: dispatch to DeltaFunctionKernel basicConvolve");
150  basicConvolve(convolvedImage, inImage, *dynamic_cast<math::DeltaFunctionKernel const*>(&kernel),
151  convolutionControl);
152  return;
153  } else if (IS_INSTANCE(kernel, math::SeparableKernel)) {
154  LOGL_DEBUG("TRACE3.afw.math.convolve.basicConvolve",
155  "generic basicConvolve: dispatch to SeparableKernel basicConvolve");
156  basicConvolve(convolvedImage, inImage, *dynamic_cast<math::SeparableKernel const*>(&kernel),
157  convolutionControl);
158  return;
159  } else if (IS_INSTANCE(kernel, math::LinearCombinationKernel) && kernel.isSpatiallyVarying()) {
160  LOGL_DEBUG(
161  "TRACE3.afw.math.convolve.basicConvolve",
162  "generic basicConvolve: dispatch to spatially varying LinearCombinationKernel basicConvolve");
163  basicConvolve(convolvedImage, inImage, *dynamic_cast<math::LinearCombinationKernel const*>(&kernel),
164  convolutionControl);
165  return;
166  }
167  // OK, use general (and slower) form
168  if (kernel.isSpatiallyVarying() && (convolutionControl.getMaxInterpolationDistance() > 1)) {
169  // use linear interpolation
170  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
171  "generic basicConvolve: using linear interpolation");
172  convolveWithInterpolation(convolvedImage, inImage, kernel, convolutionControl);
173 
174  } else {
175  // use brute force
176  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve", "generic basicConvolve: using brute force");
177  convolveWithBruteForce(convolvedImage, inImage, kernel, convolutionControl);
178  }
179 }
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...
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:504
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.
#define IS_INSTANCE(A, B)
Definition: Convolve.h:40
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.

◆ basicConvolve() [2/4]

template<typename OutImageT , typename InImageT >
void lsst::afw::math::detail::basicConvolve ( OutImageT &  convolvedImage,
InImageT const &  inImage,
lsst::afw::math::DeltaFunctionKernel const &  kernel,
lsst::afw::math::ConvolutionControl const &  convolutionControl 
)

A version of basicConvolve that should be used when convolving delta function kernels.

Parameters
[out]convolvedImageconvolved image
[in]inImageimage to convolve
[in]kernelconvolution kernel
[in]convolutionControlconvolution control parameters

Definition at line 182 of file BasicConvolve.cc.

184  {
185  assert(!kernel.isSpatiallyVarying());
186  assertDimensionsOK(convolvedImage, inImage, kernel);
187 
188  int const mImageWidth = inImage.getWidth(); // size of input region
189  int const mImageHeight = inImage.getHeight();
190  int const cnvWidth = mImageWidth + 1 - kernel.getWidth();
191  int const cnvHeight = mImageHeight + 1 - kernel.getHeight();
192  int const cnvStartX = kernel.getCtrX();
193  int const cnvStartY = kernel.getCtrY();
194  int const inStartX = kernel.getPixel().getX();
195  int const inStartY = kernel.getPixel().getY();
196 
197  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve", "DeltaFunctionKernel basicConvolve");
198 
199  for (int i = 0; i < cnvHeight; ++i) {
200  typename InImageT::x_iterator inPtr = inImage.x_at(inStartX, i + inStartY);
201  for (typename OutImageT::x_iterator cnvPtr = convolvedImage.x_at(cnvStartX, i + cnvStartY),
202  cnvEnd = cnvPtr + cnvWidth;
203  cnvPtr != cnvEnd; ++cnvPtr, ++inPtr) {
204  *cnvPtr = *inPtr;
205  }
206  }
207 }
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:504

◆ basicConvolve() [3/4]

template<typename OutImageT , typename InImageT >
void lsst::afw::math::detail::basicConvolve ( OutImageT &  convolvedImage,
InImageT const &  inImage,
lsst::afw::math::LinearCombinationKernel const &  kernel,
lsst::afw::math::ConvolutionControl const &  convolutionControl 
)

A version of basicConvolve that should be used when convolving a LinearCombinationKernel.

The Algorithm:

  • If the kernel is spatially varying and contains only DeltaFunctionKernels then convolves the input Image by each basis kernel in turn, solves the spatial model for that component and adds in the appropriate amount of the convolved image.
  • In all other cases uses normal convolution
Parameters
[out]convolvedImageconvolved image
[in]inImageimage to convolve
[in]kernelconvolution kernel
[in]convolutionControlconvolution control parameters
Exceptions
lsst::pex::exceptions::InvalidParameterErrorif convolvedImage dimensions != inImage dimensions
lsst::pex::exceptions::InvalidParameterErrorif inImage smaller than kernel in width or height
lsst::pex::exceptions::InvalidParameterErrorif kernel width or height < 1
std::bad_allocwhen allocation of CPU memory fails

Definition at line 210 of file BasicConvolve.cc.

212  {
213  if (!kernel.isSpatiallyVarying()) {
214  // use the standard algorithm for the spatially invariant case
215  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
216  "basicConvolve for LinearCombinationKernel: spatially invariant; using brute force");
217  return convolveWithBruteForce(convolvedImage, inImage, kernel, convolutionControl.getDoNormalize());
218  } else {
219  // refactor the kernel if this is reasonable and possible;
220  // then use the standard algorithm for the spatially varying case
221  std::shared_ptr<Kernel> refKernelPtr; // possibly refactored version of kernel
222  if (static_cast<int>(kernel.getNKernelParameters()) > kernel.getNSpatialParameters()) {
223  // refactoring will speed convolution, so try it
224  refKernelPtr = kernel.refactor();
225  if (!refKernelPtr) {
226  refKernelPtr = kernel.clone();
227  }
228  } else {
229  // too few basis kernels for refactoring to be worthwhile
230  refKernelPtr = kernel.clone();
231  }
232  if (convolutionControl.getMaxInterpolationDistance() > 1) {
233  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
234  "basicConvolve for LinearCombinationKernel: using interpolation");
235  return convolveWithInterpolation(convolvedImage, inImage, *refKernelPtr, convolutionControl);
236  } else {
237  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
238  "basicConvolve for LinearCombinationKernel: maxInterpolationError < 0; using brute "
239  "force");
240  return convolveWithBruteForce(convolvedImage, inImage, *refKernelPtr,
241  convolutionControl.getDoNormalize());
242  }
243  }
244 }
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...
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:504
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.

◆ basicConvolve() [4/4]

template<typename OutImageT , typename InImageT >
void lsst::afw::math::detail::basicConvolve ( OutImageT &  convolvedImage,
InImageT const &  inImage,
lsst::afw::math::SeparableKernel const &  kernel,
lsst::afw::math::ConvolutionControl const &  convolutionControl 
)

A version of basicConvolve that should be used when convolving separable kernels.

Parameters
[out]convolvedImageconvolved image
[in]inImageimage to convolve
[in]kernelconvolution kernel
[in]convolutionControlconvolution control parameters

Definition at line 247 of file BasicConvolve.cc.

248  {
249  typedef typename math::Kernel::Pixel KernelPixel;
250  typedef typename std::vector<KernelPixel> KernelVector;
251  typedef KernelVector::const_iterator KernelIterator;
252  typedef typename InImageT::const_x_iterator InXIterator;
253  typedef typename InImageT::const_xy_locator InXYLocator;
254  typedef typename OutImageT::x_iterator OutXIterator;
255  typedef typename OutImageT::y_iterator OutYIterator;
256  typedef typename OutImageT::SinglePixel OutPixel;
257 
258  assertDimensionsOK(convolvedImage, inImage, kernel);
259 
260  lsst::geom::Box2I const fullBBox = inImage.getBBox(image::LOCAL);
261  lsst::geom::Box2I const goodBBox = kernel.shrinkBBox(fullBBox);
262 
263  KernelVector kernelXVec(kernel.getWidth());
264  KernelVector kernelYVec(kernel.getHeight());
265 
266  if (kernel.isSpatiallyVarying()) {
267  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
268  "SeparableKernel basicConvolve: kernel is spatially varying");
269 
270  for (int cnvY = goodBBox.getMinY(); cnvY <= goodBBox.getMaxY(); ++cnvY) {
271  double const rowPos = inImage.indexToPosition(cnvY, image::Y);
272 
273  InXYLocator inImLoc = inImage.xy_at(0, cnvY - goodBBox.getMinY());
274  OutXIterator cnvXIter = convolvedImage.row_begin(cnvY) + goodBBox.getMinX();
275  for (int cnvX = goodBBox.getMinX(); cnvX <= goodBBox.getMaxX();
276  ++cnvX, ++inImLoc.x(), ++cnvXIter) {
277  double const colPos = inImage.indexToPosition(cnvX, image::X);
278 
279  KernelPixel kSum = kernel.computeVectors(kernelXVec, kernelYVec,
280  convolutionControl.getDoNormalize(), colPos, rowPos);
281 
282  // why does this trigger warnings? It did not in the past.
283  *cnvXIter = math::convolveAtAPoint<OutImageT, InImageT>(inImLoc, kernelXVec, kernelYVec);
284  if (convolutionControl.getDoNormalize()) {
285  *cnvXIter = *cnvXIter / kSum;
286  }
287  }
288  }
289  } else {
290  // kernel is spatially invariant
291  // The basic sequence:
292  // - For each output row:
293  // - Compute x-convolved data: a kernel height's strip of input image convolved with kernel x vector
294  // - Compute one row of output by dotting each column of x-convolved data with the kernel y vector
295  // The x-convolved data is stored in a kernel-height by good-width buffer.
296  // This is circular buffer along y (to avoid shifting pixels before setting each new row);
297  // so for each new row the kernel y vector is rotated to match the order of the x-convolved data.
298 
299  LOGL_DEBUG("TRACE2.afw.math.convolve.basicConvolve",
300  "SeparableKernel basicConvolve: kernel is spatially invariant");
301 
302  kernel.computeVectors(kernelXVec, kernelYVec, convolutionControl.getDoNormalize());
303  KernelIterator const kernelXVecBegin = kernelXVec.begin();
304  KernelIterator const kernelYVecBegin = kernelYVec.begin();
305 
306  // buffer for x-convolved data
307  OutImageT buffer(lsst::geom::Extent2I(goodBBox.getWidth(), kernel.getHeight()));
308 
309  // pre-fill x-convolved data buffer with all but one row of data
310  int yInd = 0; // during initial fill bufY = inImageY
311  int const yPrefillEnd = buffer.getHeight() - 1;
312  for (; yInd < yPrefillEnd; ++yInd) {
313  OutXIterator bufXIter = buffer.x_at(0, yInd);
314  OutXIterator const bufXEnd = buffer.x_at(goodBBox.getWidth(), yInd);
315  InXIterator inXIter = inImage.x_at(0, yInd);
316  for (; bufXIter != bufXEnd; ++bufXIter, ++inXIter) {
317  *bufXIter = kernelDotProduct<OutPixel, InXIterator, KernelIterator, KernelPixel>(
318  inXIter, kernelXVecBegin, kernel.getWidth());
319  }
320  }
321 
322  // compute output pixels using the sequence described above
323  int inY = yPrefillEnd;
324  int bufY = yPrefillEnd;
325  int cnvY = goodBBox.getMinY();
326  while (true) {
327  // fill next buffer row and compute output row
328  InXIterator inXIter = inImage.x_at(0, inY);
329  OutXIterator bufXIter = buffer.x_at(0, bufY);
330  OutXIterator cnvXIter = convolvedImage.x_at(goodBBox.getMinX(), cnvY);
331  for (int bufX = 0; bufX < goodBBox.getWidth(); ++bufX, ++cnvXIter, ++bufXIter, ++inXIter) {
332  // note: bufXIter points to the row of the buffer that is being updated,
333  // whereas bufYIter points to row 0 of the buffer
334  *bufXIter = kernelDotProduct<OutPixel, InXIterator, KernelIterator, KernelPixel>(
335  inXIter, kernelXVecBegin, kernel.getWidth());
336 
337  OutYIterator bufYIter = buffer.y_at(bufX, 0);
338  *cnvXIter = kernelDotProduct<OutPixel, OutYIterator, KernelIterator, KernelPixel>(
339  bufYIter, kernelYVecBegin, kernel.getHeight());
340  }
341 
342  // test for done now, instead of the start of the loop,
343  // to avoid an unnecessary extra rotation of the kernel Y vector
344  if (cnvY >= goodBBox.getMaxY()) break;
345 
346  // update y indices, including bufY, and rotate the kernel y vector to match
347  ++inY;
348  bufY = (bufY + 1) % kernel.getHeight();
349  ++cnvY;
350  std::rotate(kernelYVec.begin(), kernelYVec.end() - 1, kernelYVec.end());
351  }
352  }
353 }
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:504
int getMaxY() const noexcept
Definition: Box.h:162
int getWidth() const noexcept
Definition: Box.h:187
int getMaxX() const noexcept
Definition: Box.h:161
int getMinX() const noexcept
Definition: Box.h:157
STL class.
T rotate(T... args)
An integer coordinate rectangle.
Definition: Box.h:55
int getMinY() const noexcept
Definition: Box.h:158

◆ convolveRegionWithInterpolation()

template<typename OutImageT , typename InImageT >
void lsst::afw::math::detail::convolveRegionWithInterpolation ( OutImageT &  outImage,
InImageT const &  inImage,
KernelImagesForRegion const &  region,
ConvolveWithInterpolationWorkingImages workingImages 
)

Convolve a region of an Image or MaskedImage with a spatially varying Kernel using interpolation.

This is a low-level convolution function that does not set edge pixels.

Parameters
[out]outImageconvolved image = inImage convolved with kernel
[in]inImageinput image
[in]regionkernel image region over which to convolve
[in]workingImagesworking kernel images
Warning
: this is a low-level routine that performs no bounds checking.

Definition at line 94 of file ConvolveWithInterpolation.cc.

96  {
97  typedef typename OutImageT::xy_locator OutLocator;
98  typedef typename InImageT::const_xy_locator InConstLocator;
99  typedef KernelImagesForRegion::Image KernelImage;
100  typedef KernelImage::const_xy_locator KernelConstLocator;
101 
102  std::shared_ptr<Kernel const> kernelPtr = region.getKernel();
103  lsst::geom::Extent2I const kernelDimensions(kernelPtr->getDimensions());
104  workingImages.leftImage.assign(*region.getImage(KernelImagesForRegion::BOTTOM_LEFT));
105  workingImages.rightImage.assign(*region.getImage(KernelImagesForRegion::BOTTOM_RIGHT));
106  workingImages.kernelImage.assign(workingImages.leftImage);
107 
108  lsst::geom::Box2I const goodBBox = region.getBBox();
109  lsst::geom::Box2I const fullBBox = kernelPtr->growBBox(goodBBox);
110 
111  // top and right images are computed one beyond bbox boundary,
112  // so the distance between edge images is bbox width/height pixels
113  double xfrac = 1.0 / static_cast<double>(goodBBox.getWidth());
114  double yfrac = 1.0 / static_cast<double>(goodBBox.getHeight());
115  math::scaledPlus(workingImages.leftDeltaImage, yfrac, *region.getImage(KernelImagesForRegion::TOP_LEFT),
116  -yfrac, workingImages.leftImage);
117  math::scaledPlus(workingImages.rightDeltaImage, yfrac, *region.getImage(KernelImagesForRegion::TOP_RIGHT),
118  -yfrac, workingImages.rightImage);
119 
120  KernelConstLocator const kernelLocator = workingImages.kernelImage.xy_at(0, 0);
121 
122  // The loop is a bit odd for efficiency: the initial value of workingImages.kernelImage
123  // and related kernel images are set when they are allocated,
124  // so they are not computed in the loop until after the convolution; to save cpu cycles
125  // they are not computed at all for the last iteration.
126  InConstLocator inLocator = inImage.xy_at(fullBBox.getMinX(), fullBBox.getMinY());
127  OutLocator outLocator = outImage.xy_at(goodBBox.getMinX(), goodBBox.getMinY());
128  for (int j = 0;;) {
129  auto inLocatorInitialPosition = inLocator;
130  auto outLocatorInitialPosition = outLocator;
131  math::scaledPlus(workingImages.deltaImage, xfrac, workingImages.rightImage, -xfrac,
132  workingImages.leftImage);
133  for (int i = 0;;) {
134  *outLocator = math::convolveAtAPoint<OutImageT, InImageT>(
135  inLocator, kernelLocator, kernelDimensions.getX(), kernelDimensions.getY());
136  ++outLocator.x();
137  ++inLocator.x();
138  ++i;
139  if (i >= goodBBox.getWidth()) {
140  break;
141  }
142  workingImages.kernelImage += workingImages.deltaImage;
143  }
144 
145  ++j;
146  if (j >= goodBBox.getHeight()) {
147  break;
148  }
149  workingImages.leftImage += workingImages.leftDeltaImage;
150  workingImages.rightImage += workingImages.rightDeltaImage;
151  workingImages.kernelImage.assign(workingImages.leftImage);
152 
153  // Workaround for DM-5822
154  // Boost GIL locator won't decrement in x-dimension for some strange and still
155  // not understood reason. So instead store position at start of previous row,
156  // reset and move down.
157  inLocator = inLocatorInitialPosition;
158  outLocator = outLocatorInitialPosition;
159  ++inLocator.y();
160  ++outLocator.y();
161  }
162 }
void scaledPlus(OutImageT &outImage, double c1, InImageT const &inImage1, double c2, InImageT const &inImage2)
Compute the scaled sum of two images.
int getHeight() const noexcept
Definition: Box.h:188
int getWidth() const noexcept
Definition: Box.h:187
int getMinX() const noexcept
Definition: Box.h:157
An integer coordinate rectangle.
Definition: Box.h:55
int getMinY() const noexcept
Definition: Box.h:158

◆ convolveWithBruteForce()

template<typename OutImageT , typename InImageT >
void lsst::afw::math::detail::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.

(If the kernel is not spatially varying then only compute it once).

convolvedImage must be the same size as inImage. convolvedImage has a border in which the output pixels are not set. This border has size:

Parameters
[out]convolvedImageconvolved image
[in]inImageimage to convolve
[in]kernelconvolution kernel
[in]convolutionControlconvolution control parameters
Exceptions
lsst::pex::exceptions::InvalidParameterErrorif convolvedImage dimensions != inImage dimensions
lsst::pex::exceptions::InvalidParameterErrorif inImage smaller than kernel in width or height
lsst::pex::exceptions::InvalidParameterErrorif kernel width or height < 1
std::bad_allocwhen allocation of CPU memory fails
Warning
Low-level convolution function that does not set edge pixels.

Definition at line 356 of file BasicConvolve.cc.

357  {
358  bool doNormalize = convolutionControl.getDoNormalize();
359 
360  typedef typename math::Kernel::Pixel KernelPixel;
361  typedef image::Image<KernelPixel> KernelImage;
362 
363  typedef typename KernelImage::const_x_iterator KernelXIterator;
364  typedef typename KernelImage::const_xy_locator KernelXYLocator;
365  typedef typename InImageT::const_x_iterator InXIterator;
366  typedef typename InImageT::const_xy_locator InXYLocator;
367  typedef typename OutImageT::x_iterator OutXIterator;
368  typedef typename OutImageT::SinglePixel OutPixel;
369 
370  assertDimensionsOK(convolvedImage, inImage, kernel);
371 
372  int const inImageWidth = inImage.getWidth();
373  int const inImageHeight = inImage.getHeight();
374  int const kWidth = kernel.getWidth();
375  int const kHeight = kernel.getHeight();
376  int const cnvWidth = inImageWidth + 1 - kernel.getWidth();
377  int const cnvHeight = inImageHeight + 1 - kernel.getHeight();
378  int const cnvStartX = kernel.getCtrX();
379  int const cnvStartY = kernel.getCtrY();
380  int const cnvEndX = cnvStartX + cnvWidth; // end index + 1
381  int const cnvEndY = cnvStartY + cnvHeight; // end index + 1
382 
383  KernelImage kernelImage(kernel.getDimensions());
384  KernelXYLocator const kernelLoc = kernelImage.xy_at(0, 0);
385 
386  if (kernel.isSpatiallyVarying()) {
387  LOGL_DEBUG("TRACE4.afw.math.convolve.convolveWithBruteForce",
388  "convolveWithBruteForce: kernel is spatially varying");
389 
390  for (int cnvY = cnvStartY; cnvY != cnvEndY; ++cnvY) {
391  double const rowPos = inImage.indexToPosition(cnvY, image::Y);
392 
393  InXYLocator inImLoc = inImage.xy_at(0, cnvY - cnvStartY);
394  OutXIterator cnvXIter = convolvedImage.x_at(cnvStartX, cnvY);
395  for (int cnvX = cnvStartX; cnvX != cnvEndX; ++cnvX, ++inImLoc.x(), ++cnvXIter) {
396  double const colPos = inImage.indexToPosition(cnvX, image::X);
397 
398  KernelPixel kSum = kernel.computeImage(kernelImage, false, colPos, rowPos);
399  *cnvXIter = math::convolveAtAPoint<OutImageT, InImageT>(inImLoc, kernelLoc, kWidth, kHeight);
400  if (doNormalize) {
401  *cnvXIter = *cnvXIter / kSum;
402  }
403  }
404  }
405  } else {
406  LOGL_DEBUG("TRACE4.afw.math.convolve.convolveWithBruteForce",
407  "convolveWithBruteForce: kernel is spatially invariant");
408 
409  (void)kernel.computeImage(kernelImage, doNormalize);
410 
411  for (int inStartY = 0, cnvY = cnvStartY; inStartY < cnvHeight; ++inStartY, ++cnvY) {
412  KernelXIterator kernelXIter = kernelImage.x_at(0, 0);
413  InXIterator inXIter = inImage.x_at(0, inStartY);
414  OutXIterator cnvXIter = convolvedImage.x_at(cnvStartX, cnvY);
415  for (int x = 0; x < cnvWidth; ++x, ++cnvXIter, ++inXIter) {
416  *cnvXIter = kernelDotProduct<OutPixel, InXIterator, KernelXIterator, KernelPixel>(
417  inXIter, kernelXIter, kWidth);
418  }
419  for (int kernelY = 1, inY = inStartY + 1; kernelY < kHeight; ++inY, ++kernelY) {
420  KernelXIterator kernelXIter = kernelImage.x_at(0, kernelY);
421  InXIterator inXIter = inImage.x_at(0, inY);
422  OutXIterator cnvXIter = convolvedImage.x_at(cnvStartX, cnvY);
423  for (int x = 0; x < cnvWidth; ++x, ++cnvXIter, ++inXIter) {
424  *cnvXIter += kernelDotProduct<OutPixel, InXIterator, KernelXIterator, KernelPixel>(
425  inXIter, kernelXIter, kWidth);
426  }
427  }
428  }
429  }
430 }
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:504
double x
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:58

◆ convolveWithInterpolation()

template<typename OutImageT , typename InImageT >
void lsst::afw::math::detail::convolveWithInterpolation ( OutImageT &  outImage,
InImageT const &  inImage,
lsst::afw::math::Kernel const &  kernel,
math::ConvolutionControl const &  convolutionControl 
)

Convolve an Image or MaskedImage with a spatially varying Kernel using linear interpolation.

This is a low-level convolution function that does not set edge pixels.

The algorithm is as follows:

  • divide the image into regions whose size is no larger than maxInterpolationDistance
  • for each region:
    • convolve it using convolveRegionWithInterpolation (which see)

Note that this routine will also work with spatially invariant kernels, but not efficiently.

Parameters
[out]outImageconvolved image = inImage convolved with kernel
[in]inImageinput image
[in]kernelconvolution kernel
[in]convolutionControlconvolution control parameters
Exceptions
lsst::pex::exceptions::InvalidParameterErrorif outImage is not the same size as inImage

Definition at line 50 of file ConvolveWithInterpolation.cc.

51  {
52  if (outImage.getDimensions() != inImage.getDimensions()) {
54  os << "outImage dimensions = ( " << outImage.getWidth() << ", " << outImage.getHeight() << ") != ("
55  << inImage.getWidth() << ", " << inImage.getHeight() << ") = inImage dimensions";
57  }
58 
59  // compute region covering good area of output image
61  lsst::geom::Point2I(0, 0), lsst::geom::Extent2I(outImage.getWidth(), outImage.getHeight()));
62  lsst::geom::Box2I goodBBox = kernel.shrinkBBox(fullBBox);
63  KernelImagesForRegion goodRegion(KernelImagesForRegion(kernel.clone(), goodBBox, inImage.getXY0(),
64  convolutionControl.getDoNormalize()));
65  LOGL_DEBUG("TRACE5.afw.math.convolve.convolveWithInterpolation",
66  "convolveWithInterpolation: full bbox minimum=(%d, %d), extent=(%d, %d)", fullBBox.getMinX(),
67  fullBBox.getMinY(), fullBBox.getWidth(), fullBBox.getHeight());
68  LOGL_DEBUG("TRACE5.afw.math.convolve.convolveWithInterpolation",
69  "convolveWithInterpolation: goodRegion bbox minimum=(%d, %d), extent=(%d, %d)",
70  goodRegion.getBBox().getMinX(), goodRegion.getBBox().getMinY(),
71  goodRegion.getBBox().getWidth(), goodRegion.getBBox().getHeight());
72 
73  // divide good region into subregions small enough to interpolate over
74  int nx = 1 + (goodBBox.getWidth() / convolutionControl.getMaxInterpolationDistance());
75  int ny = 1 + (goodBBox.getHeight() / convolutionControl.getMaxInterpolationDistance());
76  LOGL_DEBUG("TRACE3.afw.math.convolve.convolveWithInterpolation",
77  "convolveWithInterpolation: divide into %d x %d subregions", nx, ny);
78 
79  ConvolveWithInterpolationWorkingImages workingImages(kernel.getDimensions());
80  RowOfKernelImagesForRegion regionRow(nx, ny);
81  while (goodRegion.computeNextRow(regionRow)) {
82  for (RowOfKernelImagesForRegion::ConstIterator rgnIter = regionRow.begin(), rgnEnd = regionRow.end();
83  rgnIter != rgnEnd; ++rgnIter) {
84  LOGL_DEBUG("TRACE5.afw.math.convolve.convolveWithInterpolation",
85  "convolveWithInterpolation: bbox minimum=(%d, %d), extent=(%d, %d)",
86  (*rgnIter)->getBBox().getMinX(), (*rgnIter)->getBBox().getMinY(),
87  (*rgnIter)->getBBox().getWidth(), (*rgnIter)->getBBox().getHeight());
88  convolveRegionWithInterpolation(outImage, inImage, **rgnIter, workingImages);
89  }
90  }
91 }
int getHeight() const noexcept
Definition: Box.h:188
void convolveRegionWithInterpolation(OutImageT &outImage, InImageT const &inImage, KernelImagesForRegion const &region, ConvolveWithInterpolationWorkingImages &workingImages)
Convolve a region of an Image or MaskedImage with a spatially varying Kernel using interpolation...
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:504
T str(T... args)
int getWidth() const noexcept
Definition: Box.h:187
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
Reports invalid arguments.
Definition: Runtime.h:66
std::ostream * os
Definition: Schema.cc:746
An integer coordinate rectangle.
Definition: Box.h:55

◆ PYBIND11_MODULE()

lsst::afw::math::detail::PYBIND11_MODULE ( convolve  ,
mod   
)

Definition at line 68 of file convolve.cc.

68  {
69  declareAll<double, double>(mod);
70  declareAll<double, float>(mod);
71  declareAll<double, int>(mod);
72  declareAll<double, std::uint16_t>(mod);
73  declareAll<float, float>(mod);
74  declareAll<float, int>(mod);
75  declareAll<float, std::uint16_t>(mod);
76  declareAll<int, int>(mod);
77  declareAll<std::uint16_t, std::uint16_t>(mod);
78 
79  py::class_<KernelImagesForRegion, std::shared_ptr<KernelImagesForRegion>> clsKernelImagesForRegion(
80  mod, "KernelImagesForRegion");
81 
82  py::enum_<KernelImagesForRegion::Location>(clsKernelImagesForRegion, "Location")
83  .value("BOTTOM_LEFT", KernelImagesForRegion::Location::BOTTOM_LEFT)
84  .value("BOTTOM_RIGHT", KernelImagesForRegion::Location::BOTTOM_RIGHT)
85  .value("TOP_LEFT", KernelImagesForRegion::Location::TOP_LEFT)
86  .value("TOP_RIGHT", KernelImagesForRegion::Location::TOP_RIGHT)
87  .export_values();
88 
89  clsKernelImagesForRegion.def(
90  py::init<KernelImagesForRegion::KernelConstPtr, lsst::geom::Box2I const &,
91  lsst::geom::Point2I const &, bool>(),
92  "kernelPtr"_a, "bbox"_a, "xy0"_a, "doNormalize"_a);
93  clsKernelImagesForRegion.def(
94  py::init<KernelImagesForRegion::KernelConstPtr, lsst::geom::Box2I const &,
95  lsst::geom::Point2I const &, bool, KernelImagesForRegion::ImagePtr,
96  KernelImagesForRegion::ImagePtr, KernelImagesForRegion::ImagePtr,
97  KernelImagesForRegion::ImagePtr>(),
98  "kernelPtr"_a, "bbox"_a, "xy0"_a, "doNormalize"_a, "bottomLeftImagePtr"_a,
99  "bottomRightImagePtr"_a, "topLeftImagePtr"_a, "topRightImagePtr"_a);
100 
101  clsKernelImagesForRegion.def("getBBox", &KernelImagesForRegion::getBBox);
102  clsKernelImagesForRegion.def("getXY0", &KernelImagesForRegion::getXY0);
103  clsKernelImagesForRegion.def("getDoNormalize", &KernelImagesForRegion::getDoNormalize);
104  clsKernelImagesForRegion.def("getImage", &KernelImagesForRegion::getImage);
105  clsKernelImagesForRegion.def("getKernel", &KernelImagesForRegion::getKernel);
106  clsKernelImagesForRegion.def("getPixelIndex", &KernelImagesForRegion::getPixelIndex);
107  clsKernelImagesForRegion.def("computeNextRow", &KernelImagesForRegion::computeNextRow);
108  clsKernelImagesForRegion.def_static("getMinInterpolationSize",
109  KernelImagesForRegion::getMinInterpolationSize);
110 
111  py::class_<RowOfKernelImagesForRegion, std::shared_ptr<RowOfKernelImagesForRegion>>
112  clsRowOfKernelImagesForRegion(mod, "RowOfKernelImagesForRegion");
113 
114  clsRowOfKernelImagesForRegion.def(py::init<int, int>(), "nx"_a, "ny"_a);
115 
116  clsRowOfKernelImagesForRegion.def("front", &RowOfKernelImagesForRegion::front);
117  clsRowOfKernelImagesForRegion.def("back", &RowOfKernelImagesForRegion::back);
118  clsRowOfKernelImagesForRegion.def("getNX", &RowOfKernelImagesForRegion::getNX);
119  clsRowOfKernelImagesForRegion.def("getNY", &RowOfKernelImagesForRegion::getNY);
120  clsRowOfKernelImagesForRegion.def("getYInd", &RowOfKernelImagesForRegion::getYInd);
121  clsRowOfKernelImagesForRegion.def("getRegion", &RowOfKernelImagesForRegion::getRegion);
122  clsRowOfKernelImagesForRegion.def("hasData", &RowOfKernelImagesForRegion::hasData);
123  clsRowOfKernelImagesForRegion.def("isLastRow", &RowOfKernelImagesForRegion::isLastRow);
124  clsRowOfKernelImagesForRegion.def("incrYInd", &RowOfKernelImagesForRegion::incrYInd);
125 
126  /* Module level */
127 
128  /* Member types and enums */
129 
130  /* Constructors */
131 
132  /* Operators */
133 
134  /* Members */
135 }
def init()
Definition: tests.py:65
An integer coordinate rectangle.
Definition: Box.h:55