54 template <
typename OutImageT,
typename InImageT>
55 void assertDimensionsOK(OutImageT
const& convolvedImage, InImageT
const& inImage,
57 if (convolvedImage.getDimensions() != inImage.getDimensions()) {
59 os <<
"convolvedImage dimensions = ( " << convolvedImage.getWidth() <<
", "
60 << convolvedImage.getHeight() <<
") != (" << inImage.getWidth() <<
", " << inImage.getHeight()
61 <<
") = inImage dimensions";
64 if (inImage.getWidth() < kernel.
getWidth() || inImage.getHeight() < kernel.
getHeight()) {
66 os <<
"inImage dimensions = ( " << inImage.getWidth() <<
", " << inImage.getHeight()
68 <<
") = kernel dimensions in width and/or height";
74 <<
") smaller than (1, 1) in width and/or height";
119 template <
typename OutPixelT,
typename ImageIterT,
typename KernelIterT,
typename KernelPixelT>
120 inline OutPixelT kernelDotProduct(
121 ImageIterT imageIter,
122 KernelIterT kernelIter,
125 OutPixelT outPixel(0);
126 for (
int x = 0;
x < kWidth; ++
x, ++imageIter, ++kernelIter) {
127 KernelPixelT kVal = *kernelIter;
129 outPixel +=
static_cast<OutPixelT
>((*imageIter) * kVal);
141 template <
typename OutImageT,
typename InImageT>
148 LOGL_DEBUG(
"TRACE3.afw.math.convolve.basicConvolve",
149 "generic basicConvolve: dispatch to DeltaFunctionKernel basicConvolve");
154 LOGL_DEBUG(
"TRACE3.afw.math.convolve.basicConvolve",
155 "generic basicConvolve: dispatch to SeparableKernel basicConvolve");
161 "TRACE3.afw.math.convolve.basicConvolve",
162 "generic basicConvolve: dispatch to spatially varying LinearCombinationKernel basicConvolve");
170 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
171 "generic basicConvolve: using linear interpolation");
176 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
"generic basicConvolve: using brute force");
181 template <
typename OutImageT,
typename InImageT>
186 assertDimensionsOK(convolvedImage, inImage, kernel);
188 int const mImageWidth = inImage.getWidth();
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.
getCtr().getX();
193 int const cnvStartY = kernel.
getCtr().getY();
194 int const inStartX = kernel.
getPixel().getX();
195 int const inStartY = kernel.
getPixel().getY();
197 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
"DeltaFunctionKernel basicConvolve");
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) {
209 template <
typename OutImageT,
typename InImageT>
215 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
216 "basicConvolve for LinearCombinationKernel: spatially invariant; using brute force");
226 refKernelPtr = kernel.
clone();
230 refKernelPtr = kernel.
clone();
233 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
234 "basicConvolve for LinearCombinationKernel: using interpolation");
237 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
238 "basicConvolve for LinearCombinationKernel: maxInterpolationError < 0; using brute "
246 template <
typename OutImageT,
typename InImageT>
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;
258 assertDimensionsOK(convolvedImage, inImage, kernel);
263 KernelVector kernelXVec(kernel.
getWidth());
264 KernelVector kernelYVec(kernel.
getHeight());
267 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
268 "SeparableKernel basicConvolve: kernel is spatially varying");
270 for (
int cnvY = goodBBox.
getMinY(); cnvY <= goodBBox.
getMaxY(); ++cnvY) {
271 double const rowPos = inImage.indexToPosition(cnvY,
image::Y);
273 InXYLocator inImLoc = inImage.xy_at(0, cnvY - goodBBox.
getMinY());
274 OutXIterator cnvXIter = convolvedImage.row_begin(cnvY) + goodBBox.
getMinX();
276 ++cnvX, ++inImLoc.x(), ++cnvXIter) {
277 double const colPos = inImage.indexToPosition(cnvX,
image::X);
283 *cnvXIter = math::convolveAtAPoint<OutImageT, InImageT>(inImLoc, kernelXVec, kernelYVec);
285 *cnvXIter = *cnvXIter / kSum;
299 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
300 "SeparableKernel basicConvolve: kernel is spatially invariant");
303 KernelIterator
const kernelXVecBegin = kernelXVec.begin();
304 KernelIterator
const kernelYVecBegin = kernelYVec.begin();
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());
323 int inY = yPrefillEnd;
324 int bufY = yPrefillEnd;
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) {
334 *bufXIter = kernelDotProduct<OutPixel, InXIterator, KernelIterator, KernelPixel>(
335 inXIter, kernelXVecBegin, kernel.
getWidth());
337 OutYIterator bufYIter = buffer.y_at(bufX, 0);
338 *cnvXIter = kernelDotProduct<OutPixel, OutYIterator, KernelIterator, KernelPixel>(
339 bufYIter, kernelYVecBegin, kernel.
getHeight());
344 if (cnvY >= goodBBox.
getMaxY())
break;
350 std::rotate(kernelYVec.begin(), kernelYVec.end() - 1, kernelYVec.end());
355 template <
typename OutImageT,
typename InImageT>
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;
370 assertDimensionsOK(convolvedImage, inImage, kernel);
372 int const inImageWidth = inImage.getWidth();
373 int const inImageHeight = inImage.getHeight();
374 int const kWidth = kernel.
getWidth();
376 int const cnvWidth = inImageWidth + 1 - kernel.
getWidth();
377 int const cnvHeight = inImageHeight + 1 - kernel.
getHeight();
378 int const cnvStartX = kernel.
getCtr().getX();
379 int const cnvStartY = kernel.
getCtr().getY();
380 int const cnvEndX = cnvStartX + cnvWidth;
381 int const cnvEndY = cnvStartY + cnvHeight;
384 KernelXYLocator
const kernelLoc = kernelImage.xy_at(0, 0);
387 LOGL_DEBUG(
"TRACE4.afw.math.convolve.convolveWithBruteForce",
388 "convolveWithBruteForce: kernel is spatially varying");
390 for (
int cnvY = cnvStartY; cnvY != cnvEndY; ++cnvY) {
391 double const rowPos = inImage.indexToPosition(cnvY,
image::Y);
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);
398 KernelPixel kSum = kernel.
computeImage(kernelImage,
false, colPos, rowPos);
399 *cnvXIter = math::convolveAtAPoint<OutImageT, InImageT>(inImLoc, kernelLoc, kWidth, kHeight);
401 *cnvXIter = *cnvXIter / kSum;
406 LOGL_DEBUG(
"TRACE4.afw.math.convolve.convolveWithBruteForce",
407 "convolveWithBruteForce: kernel is spatially invariant");
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);
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);
436 #define IMAGE(PIXTYPE) image::Image<PIXTYPE>
437 #define MASKEDIMAGE(PIXTYPE) image::MaskedImage<PIXTYPE, image::MaskPixel, image::VariancePixel>
440 #define INSTANTIATE_IM_OR_MI(IMGMACRO, OUTPIXTYPE, INPIXTYPE) \
441 template void basicConvolve(IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const &, math::Kernel const&, \
442 math::ConvolutionControl const&); \
443 NL template void basicConvolve(IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const &, \
444 math::DeltaFunctionKernel const&, math::ConvolutionControl const&); \
445 NL template void basicConvolve(IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const &, \
446 math::LinearCombinationKernel const&, math::ConvolutionControl const&); \
447 NL template void basicConvolve(IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const &, \
448 math::SeparableKernel const&, math::ConvolutionControl const&); \
449 NL template void convolveWithBruteForce(IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const &, \
450 math::Kernel const&, math::ConvolutionControl const&);
452 #define INSTANTIATE(OUTPIXTYPE, INPIXTYPE) \
453 INSTANTIATE_IM_OR_MI(IMAGE, OUTPIXTYPE, INPIXTYPE) \
454 INSTANTIATE_IM_OR_MI(MASKEDIMAGE, OUTPIXTYPE, INPIXTYPE)
#define IS_INSTANCE(A, B)
#define INSTANTIATE(FROMSYS, TOSYS)
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
LSST DM logging module built on log4cxx.
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
A class to represent a 2-dimensional array of pixels.
Parameters to control convolution.
int getMaxInterpolationDistance() const
bool getDoNormalize() const
A kernel that has only one non-zero pixel (of value 1)
lsst::geom::Point2I getPixel() const
Kernels are used for convolution with MaskedImages and (eventually) Images.
lsst::geom::Extent2I const getDimensions() const
Return the Kernel's dimensions (width, height)
int getHeight() const
Return the Kernel's height.
lsst::geom::Point2I getCtr() const
Return index of kernel's center.
unsigned int getNKernelParameters() const
Return the number of kernel parameters (0 if none)
int getNSpatialParameters() const
Return the number of spatial parameters (0 if not spatially varying)
lsst::geom::Box2I shrinkBBox(lsst::geom::Box2I const &bbox) const
Given a bounding box for an image one wishes to convolve with this kernel, return the bounding box fo...
int getWidth() const
Return the Kernel's width.
bool isSpatiallyVarying() const
Return true iff the kernel is spatially varying (has a spatial function)
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.
A kernel that is a linear combination of fixed basis kernels.
std::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...
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
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)
An integer coordinate rectangle.
int getMinY() const noexcept
int getMinX() const noexcept
int getWidth() const noexcept
int getMaxX() const noexcept
int getMaxY() const noexcept
Reports invalid arguments.
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.
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.
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.
A base class for image defects.