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)
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...
Parameters to control convolution.
int getCtrY() const
Return y index of kernel's center.
definition of the Trace messaging facilities
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...
CPU and GPU convolution shared code.
int getCtrX() const
Return x index of kernel's center.
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)
An integer coordinate rectangle.
int getHeight() const
Return the Kernel's height.
table::Key< table::Array< Kernel::Pixel > > image
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.
Include files required for standard LSST Exception handling.
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.
bool isGpuBuild()
Inline function which returns true only when GPU_BUILD macro is defined.
std::pair< double, double > rotate(double x, double y, double angle)
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.
lsst::afw::gpu::DevicePreference getDevicePreference() const
Convolve and convolveAtAPoint functions for Image and Kernel.
#define LSST_EXCEPT(type,...)
lsst::afw::geom::Point2I getPixel() const
void assertDimensionsOK(OutImageT const &convolvedImage, InImageT const &inImage, lsst::afw::math::Kernel const &kernel)
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
A function to determine whether compiling for GPU is enabled.
bool isSpatiallyVarying() const
Return true iff the kernel is spatially varying (has a spatial function)