48 namespace pexExcept = lsst::pex::exceptions;
49 namespace afwGeom = lsst::afw::geom;
51 namespace afwMath = lsst::afw::math;
52 namespace mathDetail = lsst::afw::math::detail;
64 template <
typename OutImageT,
typename InImageT>
65 void assertDimensionsOK(
66 OutImageT
const &convolvedImage,
67 InImageT
const &inImage,
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());
77 if (inImage.getWidth() < kernel.
getWidth() || inImage.getHeight() < kernel.
getHeight()) {
78 std::ostringstream os;
79 os <<
"inImage dimensions = ( "
80 << inImage.getWidth() <<
", " << inImage.getHeight()
82 <<
") = kernel dimensions in width and/or height";
83 throw LSST_EXCEPT(pexExcept::InvalidParameterError, os.str());
86 std::ostringstream os;
87 os <<
"kernel dimensions = ( "
89 <<
") smaller than (1, 1) in width and/or height";
90 throw LSST_EXCEPT(pexExcept::InvalidParameterError, os.str());
116 template <
typename OutPixelT,
typename ImageIterT,
typename KernelIterT,
typename KernelPixelT>
117 inline OutPixelT kernelDotProduct(
118 ImageIterT imageIter,
119 KernelIterT kernelIter,
122 OutPixelT outPixel(0);
123 for (
int x = 0;
x < kWidth; ++
x, ++imageIter, ++kernelIter) {
124 KernelPixelT kVal = *kernelIter;
126 outPixel +=
static_cast<OutPixelT
>((*imageIter) * kVal);
150 template <
typename OutImageT,
typename InImageT>
152 OutImageT &convolvedImage,
153 InImageT
const& inImage,
161 LOGL_DEBUG(
"TRACE3.afw.math.convolve.basicConvolve",
162 "generic basicConvolve: dispatch to DeltaFunctionKernel basicConvolve");
164 *dynamic_cast<afwMath::DeltaFunctionKernel const*>(&kernel),
168 LOGL_DEBUG(
"TRACE3.afw.math.convolve.basicConvolve",
169 "generic basicConvolve: dispatch to SeparableKernel basicConvolve");
171 *dynamic_cast<afwMath::SeparableKernel const*>(&kernel),
175 LOGL_DEBUG(
"TRACE3.afw.math.convolve.basicConvolve",
176 "generic basicConvolve: dispatch to spatially varying LinearCombinationKernel basicConvolve");
178 *dynamic_cast<afwMath::LinearCombinationKernel const*>(&kernel),
185 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
186 "generic basicConvolve: using linear interpolation");
191 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
192 "generic basicConvolve: using brute force");
202 template <
typename OutImageT,
typename InImageT>
204 OutImageT& convolvedImage,
205 InImageT
const& inImage,
210 assertDimensionsOK(convolvedImage, inImage, kernel);
212 int const mImageWidth = inImage.getWidth();
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();
221 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
"DeltaFunctionKernel basicConvolve");
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){
248 template <
typename OutImageT,
typename InImageT>
250 OutImageT& convolvedImage,
251 InImageT
const& inImage,
257 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
258 "basicConvolve for LinearCombinationKernel: spatially invariant; using brute force");
269 refKernelPtr = kernel.
clone();
273 refKernelPtr = kernel.
clone();
276 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
277 "basicConvolve for LinearCombinationKernel: using interpolation");
280 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
281 "basicConvolve for LinearCombinationKernel: maxInterpolationError < 0; using brute force");
293 template <
typename OutImageT,
typename InImageT>
295 OutImageT& convolvedImage,
296 InImageT
const& inImage,
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;
309 assertDimensionsOK(convolvedImage, inImage, kernel);
314 KernelVector kernelXVec(kernel.
getWidth());
315 KernelVector kernelYVec(kernel.
getHeight());
318 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
319 "SeparableKernel basicConvolve: kernel is spatially varying");
321 for (
int cnvY = goodBBox.
getMinY(); cnvY <= goodBBox.
getMaxY(); ++cnvY) {
322 double const rowPos = inImage.indexToPosition(cnvY,
afwImage::Y);
324 InXYLocator inImLoc = inImage.xy_at(0, cnvY - goodBBox.
getMinY());
325 OutXIterator cnvXIter = convolvedImage.row_begin(cnvY) + goodBBox.
getMinX();
327 ++cnvX, ++inImLoc.x(), ++cnvXIter) {
328 double const colPos = inImage.indexToPosition(cnvX,
afwImage::X);
334 *cnvXIter = afwMath::convolveAtAPoint<OutImageT, InImageT>(inImLoc, kernelXVec, kernelYVec);
336 *cnvXIter = *cnvXIter/kSum;
350 LOGL_DEBUG(
"TRACE2.afw.math.convolve.basicConvolve",
351 "SeparableKernel basicConvolve: kernel is spatially invariant");
354 KernelIterator
const kernelXVecBegin = kernelXVec.begin();
355 KernelIterator
const kernelYVecBegin = kernelYVec.begin();
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());
374 int inY = yPrefillEnd;
375 int bufY = yPrefillEnd;
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) {
385 *bufXIter = kernelDotProduct<OutPixel, InXIterator, KernelIterator, KernelPixel>(
386 inXIter, kernelXVecBegin, kernel.
getWidth());
388 OutYIterator bufYIter = buffer.y_at(bufX, 0);
389 *cnvXIter = kernelDotProduct<OutPixel, OutYIterator, KernelIterator, KernelPixel>(
390 bufYIter, kernelYVecBegin, kernel.
getHeight());
395 if (cnvY >= goodBBox.
getMaxY())
break;
401 std::rotate(kernelYVec.begin(), kernelYVec.end()-1, kernelYVec.end());
426 template <
typename OutImageT,
typename InImageT>
428 OutImageT &convolvedImage,
429 InImageT
const& inImage,
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;
445 assertDimensionsOK(convolvedImage, inImage, kernel);
447 int const inImageWidth = inImage.getWidth();
448 int const inImageHeight = inImage.getHeight();
449 int const kWidth = kernel.
getWidth();
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;
456 int const cnvEndY = cnvStartY + cnvHeight;
459 KernelXYLocator
const kernelLoc = kernelImage.xy_at(0,0);
462 LOGL_DEBUG(
"TRACE4.afw.math.convolve.convolveWithBruteForce",
463 "convolveWithBruteForce: kernel is spatially varying");
465 for (
int cnvY = cnvStartY; cnvY != cnvEndY; ++cnvY) {
466 double const rowPos = inImage.indexToPosition(cnvY,
afwImage::Y);
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);
473 KernelPixel kSum = kernel.
computeImage(kernelImage,
false, colPos, rowPos);
474 *cnvXIter = afwMath::convolveAtAPoint<OutImageT, InImageT>(
475 inImLoc, kernelLoc, kWidth, kHeight);
477 *cnvXIter = *cnvXIter/kSum;
482 LOGL_DEBUG(
"TRACE4.afw.math.convolve.convolveWithBruteForce",
483 "convolveWithBruteForce: kernel is spatially invariant");
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);
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);
512 #define IMAGE(PIXTYPE) afwImage::Image<PIXTYPE>
513 #define MASKEDIMAGE(PIXTYPE) afwImage::MaskedImage<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
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&);
533 #define INSTANTIATE(OUTPIXTYPE, INPIXTYPE) \
534 INSTANTIATE_IM_OR_MI(IMAGE, OUTPIXTYPE, INPIXTYPE) \
535 INSTANTIATE_IM_OR_MI(MASKEDIMAGE, OUTPIXTYPE, INPIXTYPE)
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's dimensions (width, height)
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...
Include files required for standard LSST Exception handling.
Parameters to control convolution.
int getCtrY() const
Return y index of kernel's center.
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
int getNSpatialParameters() const
Return the number of spatial parameters (0 if not spatially varying)
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's center.
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
An integer coordinate rectangle.
int getHeight() const
Return the Kernel's height.
table::Key< table::Array< Kernel::Pixel > > image
LSST DM logging module built on log4cxx.
int getWidth() const
Return the Kernel's width.
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.
unsigned int getNKernelParameters() const
Return the number of kernel parameters (0 if none)
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.
bool getDoNormalize() const
A kernel that is a linear combination of fixed basis kernels.
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...
lsst::afw::geom::Point2I getPixel() const
Implementation of the Class MaskedImage.
Kernels are used for convolution with MaskedImages and (eventually) Images.
A class to represent a 2-dimensional array of pixels.
#define IS_INSTANCE(A, B)
A kernel that has only one non-zero pixel (of value 1)
int getMaxInterpolationDistance() const
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...
bool isSpatiallyVarying() const
Return true iff the kernel is spatially varying (has a spatial function)