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)