39 #include "boost/cstdint.hpp"
52 namespace pexExcept = lsst::pex::exceptions;
53 namespace pexLog = lsst::pex::logging;
54 namespace afwGeom = lsst::afw::geom;
56 namespace afwMath = lsst::afw::math;
57 namespace mathDetail = lsst::afw::math::detail;
84 template <
typename OutPixelT,
typename ImageIterT,
typename KernelIterT,
typename KernelPixelT>
85 inline OutPixelT kernelDotProduct(
87 KernelIterT kernelIter,
90 OutPixelT outPixel(0);
91 for (
int x = 0;
x < kWidth; ++
x, ++imageIter, ++kernelIter) {
92 KernelPixelT kVal = *kernelIter;
94 outPixel +=
static_cast<OutPixelT
>((*imageIter) * kVal);
116 "Gpu acceleration must be enabled at compiling for lsst::afw::gpu::USE_GPU");
133 throw LSST_EXCEPT(pexExcept::InvalidParameterError,
"Gpu can not process this type of kernel");
158 template <
typename OutImageT,
typename InImageT>
160 OutImageT &convolvedImage,
161 InImageT
const& inImage,
169 pexLog::TTrace<4>(
"lsst.afw.math.convolve",
170 "generic basicConvolve: dispatch to DeltaFunctionKernel basicConvolve");
172 *dynamic_cast<afwMath::DeltaFunctionKernel const*>(&kernel),
176 pexLog::TTrace<4>(
"lsst.afw.math.convolve",
177 "generic basicConvolve: dispatch to SeparableKernel basicConvolve");
179 *dynamic_cast<afwMath::SeparableKernel const*>(&kernel),
183 pexLog::TTrace<4>(
"lsst.afw.math.convolve",
184 "generic basicConvolve: dispatch to spatially varying LinearCombinationKernel basicConvolve");
186 *dynamic_cast<afwMath::LinearCombinationKernel const*>(&kernel),
193 pexLog::TTrace<3>(
"lsst.afw.math.convolve",
"generic basicConvolve: using linear interpolation");
198 pexLog::TTrace<3>(
"lsst.afw.math.convolve",
"generic basicConvolve: using brute force");
210 template <
typename OutImageT,
typename InImageT>
212 OutImageT& convolvedImage,
213 InImageT
const& inImage,
220 CheckForceGpuOnUnsupportedKernel(convolutionControl);
222 int const mImageWidth = inImage.getWidth();
223 int const mImageHeight = inImage.getHeight();
224 int const cnvWidth = mImageWidth + 1 - kernel.
getWidth();
225 int const cnvHeight = mImageHeight + 1 - kernel.
getHeight();
226 int const cnvStartX = kernel.
getCtrX();
227 int const cnvStartY = kernel.
getCtrY();
228 int const inStartX = kernel.
getPixel().getX();
229 int const inStartY = kernel.
getPixel().getY();
231 pexLog::TTrace<3>(
"lsst.afw.math.convolve",
"DeltaFunctionKernel basicConvolve");
233 for (
int i = 0; i < cnvHeight; ++i) {
234 typename InImageT::x_iterator inPtr = inImage.x_at(inStartX, i + inStartY);
235 for (
typename OutImageT::x_iterator cnvPtr = convolvedImage.x_at(cnvStartX, i + cnvStartY),
236 cnvEnd = cnvPtr + cnvWidth; cnvPtr != cnvEnd; ++cnvPtr, ++inPtr){
260 template <
typename OutImageT,
typename InImageT>
262 OutImageT& convolvedImage,
263 InImageT
const& inImage,
269 pexLog::TTrace<3>(
"lsst.afw.math.convolve",
270 "basicConvolve for LinearCombinationKernel: spatially invariant; using brute force");
274 CheckForceGpuOnNoGpu(convolutionControl);
282 }
catch(lsst::afw::gpu::GpuMemoryError) { }
283 catch(pexExcept::MemoryError) { }
284 catch(lsst::afw::gpu::GpuRuntimeError) { }
291 throw LSST_EXCEPT(pexExcept::RuntimeError,
"Gpu will not process this kernel");
303 refKernelPtr = kernel.
clone();
307 refKernelPtr = kernel.
clone();
310 pexLog::TTrace<3>(
"lsst.afw.math.convolve",
311 "basicConvolve for LinearCombinationKernel: using interpolation");
314 pexLog::TTrace<3>(
"lsst.afw.math.convolve",
315 "basicConvolve for LinearCombinationKernel: maxInterpolationError < 0; using brute force");
329 template <
typename OutImageT,
typename InImageT>
331 OutImageT& convolvedImage,
332 InImageT
const& inImage,
337 typedef typename std::vector<KernelPixel> KernelVector;
338 typedef KernelVector::const_iterator KernelIterator;
339 typedef typename InImageT::const_x_iterator InXIterator;
340 typedef typename InImageT::const_xy_locator InXYLocator;
341 typedef typename OutImageT::x_iterator OutXIterator;
342 typedef typename OutImageT::y_iterator OutYIterator;
343 typedef typename OutImageT::SinglePixel OutPixel;
347 CheckForceGpuOnUnsupportedKernel(convolutionControl);
352 KernelVector kernelXVec(kernel.
getWidth());
353 KernelVector kernelYVec(kernel.
getHeight());
356 pexLog::TTrace<3>(
"lsst.afw.math.convolve",
357 "SeparableKernel basicConvolve: kernel is spatially varying");
359 for (
int cnvY = goodBBox.
getMinY(); cnvY <= goodBBox.
getMaxY(); ++cnvY) {
360 double const rowPos = inImage.indexToPosition(cnvY,
afwImage::Y);
362 InXYLocator inImLoc = inImage.xy_at(0, cnvY - goodBBox.
getMinY());
363 OutXIterator cnvXIter = convolvedImage.row_begin(cnvY) + goodBBox.
getMinX();
365 ++cnvX, ++inImLoc.x(), ++cnvXIter) {
366 double const colPos = inImage.indexToPosition(cnvX,
afwImage::X);
372 *cnvXIter = afwMath::convolveAtAPoint<OutImageT, InImageT>(inImLoc, kernelXVec, kernelYVec);
374 *cnvXIter = *cnvXIter/kSum;
388 pexLog::TTrace<3>(
"lsst.afw.math.convolve",
389 "SeparableKernel basicConvolve: kernel is spatially invariant");
392 KernelIterator
const kernelXVecBegin = kernelXVec.begin();
393 KernelIterator
const kernelYVecBegin = kernelYVec.begin();
400 int const yPrefillEnd = buffer.getHeight() - 1;
401 for (; yInd < yPrefillEnd; ++yInd) {
402 OutXIterator bufXIter = buffer.x_at(0, yInd);
403 OutXIterator
const bufXEnd = buffer.x_at(goodBBox.
getWidth(), yInd);
404 InXIterator inXIter = inImage.x_at(0, yInd);
405 for ( ; bufXIter != bufXEnd; ++bufXIter, ++inXIter) {
406 *bufXIter = kernelDotProduct<OutPixel, InXIterator, KernelIterator, KernelPixel>(
407 inXIter, kernelXVecBegin, kernel.
getWidth());
412 int inY = yPrefillEnd;
413 int bufY = yPrefillEnd;
417 InXIterator inXIter = inImage.x_at(0, inY);
418 OutXIterator bufXIter = buffer.x_at(0, bufY);
419 OutXIterator cnvXIter = convolvedImage.x_at(goodBBox.
getMinX(), cnvY);
420 for (
int bufX = 0; bufX < goodBBox.
getWidth(); ++bufX, ++cnvXIter, ++bufXIter, ++inXIter) {
423 *bufXIter = kernelDotProduct<OutPixel, InXIterator, KernelIterator, KernelPixel>(
424 inXIter, kernelXVecBegin, kernel.
getWidth());
426 OutYIterator bufYIter = buffer.y_at(bufX, 0);
427 *cnvXIter = kernelDotProduct<OutPixel, OutYIterator, KernelIterator, KernelPixel>(
428 bufYIter, kernelYVecBegin, kernel.
getHeight());
433 if (cnvY >= goodBBox.
getMaxY())
break;
439 std::rotate(kernelYVec.begin(), kernelYVec.end()-1, kernelYVec.end());
467 template <
typename OutImageT,
typename InImageT>
469 OutImageT &convolvedImage,
470 InImageT
const& inImage,
479 typedef typename KernelImage::const_x_iterator KernelXIterator;
480 typedef typename KernelImage::const_xy_locator KernelXYLocator;
481 typedef typename InImageT::const_x_iterator InXIterator;
482 typedef typename InImageT::const_xy_locator InXYLocator;
483 typedef typename OutImageT::x_iterator OutXIterator;
484 typedef typename OutImageT::SinglePixel OutPixel;
488 int const inImageWidth = inImage.getWidth();
489 int const inImageHeight = inImage.getHeight();
490 int const kWidth = kernel.
getWidth();
492 int const cnvWidth = inImageWidth + 1 - kernel.
getWidth();
493 int const cnvHeight = inImageHeight + 1 - kernel.
getHeight();
494 int const cnvStartX = kernel.
getCtrX();
495 int const cnvStartY = kernel.
getCtrY();
496 int const cnvEndX = cnvStartX + cnvWidth;
497 int const cnvEndY = cnvStartY + cnvHeight;
500 KernelXYLocator
const kernelLoc = kernelImage.xy_at(0,0);
503 pexLog::TTrace<5>(
"lsst.afw.math.convolve",
504 "convolveWithBruteForce: kernel is spatially varying");
506 CheckForceGpuOnUnsupportedKernel(convolutionControl);
508 for (
int cnvY = cnvStartY; cnvY != cnvEndY; ++cnvY) {
509 double const rowPos = inImage.indexToPosition(cnvY,
afwImage::Y);
511 InXYLocator inImLoc = inImage.xy_at(0, cnvY - cnvStartY);
512 OutXIterator cnvXIter = convolvedImage.x_at(cnvStartX, cnvY);
513 for (
int cnvX = cnvStartX; cnvX != cnvEndX; ++cnvX, ++inImLoc.x(), ++cnvXIter) {
514 double const colPos = inImage.indexToPosition(cnvX,
afwImage::X);
516 KernelPixel kSum = kernel.
computeImage(kernelImage,
false, colPos, rowPos);
517 *cnvXIter = afwMath::convolveAtAPoint<OutImageT, InImageT>(
518 inImLoc, kernelLoc, kWidth, kHeight);
520 *cnvXIter = *cnvXIter/kSum;
525 pexLog::TTrace<5>(
"lsst.afw.math.convolve",
526 "convolveWithBruteForce: kernel is spatially invariant");
528 CheckForceGpuOnNoGpu(convolutionControl);
536 }
catch(lsst::afw::gpu::GpuMemoryError) { }
537 catch(pexExcept::MemoryError) { }
538 catch(lsst::afw::gpu::GpuRuntimeError) { }
545 throw LSST_EXCEPT(pexExcept::RuntimeError,
"Gpu will not process this kernel");
552 for (
int inStartY = 0, cnvY = cnvStartY; inStartY < cnvHeight; ++inStartY, ++cnvY) {
553 KernelXIterator kernelXIter = kernelImage.x_at(0, 0);
554 InXIterator inXIter = inImage.x_at(0, inStartY);
555 OutXIterator cnvXIter = convolvedImage.x_at(cnvStartX, cnvY);
556 for (
int x = 0;
x < cnvWidth; ++
x, ++cnvXIter, ++inXIter) {
557 *cnvXIter = kernelDotProduct<OutPixel, InXIterator, KernelXIterator, KernelPixel>(
558 inXIter, kernelXIter, kWidth);
560 for (
int kernelY = 1, inY = inStartY + 1; kernelY < kHeight; ++inY, ++kernelY) {
561 KernelXIterator kernelXIter = kernelImage.x_at(0, kernelY);
562 InXIterator inXIter = inImage.x_at(0, inY);
563 OutXIterator cnvXIter = convolvedImage.x_at(cnvStartX, cnvY);
564 for (
int x = 0;
x < cnvWidth; ++
x, ++cnvXIter, ++inXIter) {
565 *cnvXIter += kernelDotProduct<OutPixel, InXIterator, KernelXIterator, KernelPixel>(
566 inXIter, kernelXIter, kWidth);
577 #define IMAGE(PIXTYPE) afwImage::Image<PIXTYPE>
578 #define MASKEDIMAGE(PIXTYPE) afwImage::MaskedImage<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
581 #define INSTANTIATE_IM_OR_MI(IMGMACRO, OUTPIXTYPE, INPIXTYPE) \
582 template void mathDetail::basicConvolve( \
583 IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::Kernel const&, \
584 afwMath::ConvolutionControl const&); NL \
585 template void mathDetail::basicConvolve( \
586 IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::DeltaFunctionKernel const&, \
587 afwMath::ConvolutionControl const&); NL \
588 template void mathDetail::basicConvolve( \
589 IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::LinearCombinationKernel const&, \
590 afwMath::ConvolutionControl const&); NL \
591 template void mathDetail::basicConvolve( \
592 IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::SeparableKernel const&, \
593 afwMath::ConvolutionControl const&); NL \
594 template void mathDetail::convolveWithBruteForce( \
595 IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, afwMath::Kernel const&, \
596 afwMath::ConvolutionControl const&);
598 #define INSTANTIATE(OUTPIXTYPE, INPIXTYPE) \
599 INSTANTIATE_IM_OR_MI(IMAGE, OUTPIXTYPE, INPIXTYPE) \
600 INSTANTIATE_IM_OR_MI(MASKEDIMAGE, OUTPIXTYPE, INPIXTYPE)
bool isGpuEnabled()
returns true if GPU acceleration is enabled
An include file to include the header files for lsst::afw::geom.
Declare the Kernel class and subclasses.
ConvolveGpuStatus::ReturnCode convolveLinearCombinationGPU(lsst::afw::image::MaskedImage< OutPixelT, lsst::afw::image::MaskPixel, lsst::afw::image::VariancePixel > &convolvedImage, lsst::afw::image::MaskedImage< InPixelT, lsst::afw::image::MaskPixel, lsst::afw::image::VariancePixel > const &inImage, lsst::afw::math::LinearCombinationKernel const &kernel, lsst::afw::math::ConvolutionControl const &convolutionControl)
int getWidth() const
Return the Kernel's width.
int getHeight() const
Return the Kernel's height.
virtual boost::shared_ptr< Kernel > clone() const
Return a pointer to a deep copy of this kernel.
Parameters to control convolution.
definition of the Trace messaging facilities
bool getDoNormalize() const
A kernel described by a pair of functions: func(x, y) = colFunc(x) * rowFunc(y)
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)
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...
CPU and GPU convolution shared code.
ConvolveGpuStatus::ReturnCode convolveSpatiallyInvariantGPU(lsst::afw::image::MaskedImage< OutPixelT, lsst::afw::image::MaskPixel, lsst::afw::image::VariancePixel > &convolvedImage, lsst::afw::image::MaskedImage< InPixelT, lsst::afw::image::MaskPixel, lsst::afw::image::VariancePixel > const &inImage, lsst::afw::math::Kernel const &kernel, lsst::afw::math::ConvolutionControl const &convolutionControl)
bool isSpatiallyVarying() const
Return true iff the kernel is spatially varying (has a spatial function)
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.
table::Key< table::Array< Kernel::Pixel > > image
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.
A kernel that is a linear combination of fixed basis kernels.
geom::Extent2I const getDimensions() const
Return the Kernel's dimensions (width, height)
bool isGpuBuild()
Inline function which returns true only when GPU_BUILD macro is defined.
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.
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...
Convolve and convolveAtAPoint functions for Image and Kernel.
#define LSST_EXCEPT(type,...)
int getMaxInterpolationDistance() const
void assertDimensionsOK(OutImageT const &convolvedImage, InImageT const &inImage, lsst::afw::math::Kernel const &kernel)
lsst::afw::geom::Point2I getPixel() const
Implementation of the Class MaskedImage.
int getCtrY() const
Return y index of kernel's center.
lsst::afw::geom::Box2I shrinkBBox(lsst::afw::geom::Box2I const &bbox) const
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)
lsst::afw::gpu::DevicePreference getDevicePreference() const
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.
Include files required for standard LSST Exception handling.
A function to determine whether compiling for GPU is enabled.
int getCtrX() const
Return x index of kernel's center.