LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
ConvolveImage.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
34 #include <algorithm>
35 #include <cmath>
36 #include <functional>
37 #include <iostream>
38 #include <sstream>
39 #include <limits>
40 #include <vector>
41 #include <string>
42 
43 #include "boost/cstdint.hpp"
44 
45 #include "lsst/pex/exceptions.h"
46 #include "lsst/pex/logging/Trace.h"
49 #include "lsst/afw/math/Kernel.h"
51 
52 namespace pexExcept = lsst::pex::exceptions;
53 namespace pexLog = lsst::pex::logging;
54 namespace afwGeom = lsst::afw::geom;
55 namespace afwImage = lsst::afw::image;
56 namespace afwMath = lsst::afw::math;
57 namespace mathDetail = lsst::afw::math::detail;
58 
59 namespace {
60 
61  /*
62  * @brief Set the edge pixels of a convolved Image based on size of the convolution kernel used
63  *
64  * Separate specializations for Image and MaskedImage are required to set the EDGE bit of the Mask plane
65  * (if there is one) when doCopyEdge is true.
66  */
67  template <typename OutImageT, typename InImageT>
68  inline void setEdgePixels(
69  OutImageT& outImage,
70  afwMath::Kernel const &kernel,
71  InImageT const &inImage,
73  bool doCopyEdge,
77 
78  {
79  const unsigned int imWidth = outImage.getWidth();
80  const unsigned int imHeight = outImage.getHeight();
81  const unsigned int kWidth = kernel.getWidth();
82  const unsigned int kHeight = kernel.getHeight();
83  const unsigned int kCtrX = kernel.getCtrX();
84  const unsigned int kCtrY = kernel.getCtrY();
85 
86  const typename OutImageT::SinglePixel edgePixel = afwMath::edgePixel<OutImageT>(
88  );
89  std::vector<afwGeom::Box2I> bboxList;
90 
91  // create a list of bounding boxes describing edge regions, in this order:
92  // bottom edge, top edge (both edge to edge),
93  // left edge, right edge (both omitting pixels already in the bottom and top edge regions)
94  int const numHeight = kHeight - (1 + kCtrY);
95  int const numWidth = kWidth - (1 + kCtrX);
96  bboxList.push_back(
97  afwGeom::Box2I(afwGeom::Point2I(0, 0), afwGeom::Extent2I(imWidth, kCtrY))
98  );
99  bboxList.push_back(
100  afwGeom::Box2I(afwGeom::Point2I(0, imHeight - numHeight), afwGeom::Extent2I(imWidth, numHeight))
101  );
102  bboxList.push_back(
103  afwGeom::Box2I(afwGeom::Point2I(0, kCtrY), afwGeom::Extent2I(kCtrX, imHeight + 1 - kHeight))
104  );
105  bboxList.push_back(
106  afwGeom::Box2I(afwGeom::Point2I(imWidth - numWidth, kCtrY), afwGeom::Extent2I(numWidth, imHeight + 1 - kHeight))
107  );
108 
109  for (std::vector<afwGeom::Box2I>::const_iterator bboxIter = bboxList.begin();
110  bboxIter != bboxList.end(); ++bboxIter
111  ) {
112  OutImageT outView(outImage, *bboxIter, afwImage::LOCAL);
113  if (doCopyEdge) {
114  // note: <<= only works with data of the same type
115  // so convert the input image to output format
116  outView <<= OutImageT(InImageT(inImage, *bboxIter, afwImage::LOCAL), true);
117  } else {
118  outView = edgePixel;
119  }
120  }
121  }
122 
123  /*
124  * @brief Set the edge pixels of a convolved MaskedImage based on size of the convolution kernel used
125  *
126  * Separate specializations for Image and MaskedImage are required to set the EDGE bit of the Mask plane
127  * (if there is one) when doCopyEdge is true.
128  */
129  template <typename OutImageT, typename InImageT>
130  inline void setEdgePixels(
131  OutImageT& outImage,
132  afwMath::Kernel const &kernel,
133  InImageT const &inImage,
135  bool doCopyEdge,
139 
140  {
141  const unsigned int imWidth = outImage.getWidth();
142  const unsigned int imHeight = outImage.getHeight();
143  const unsigned int kWidth = kernel.getWidth();
144  const unsigned int kHeight = kernel.getHeight();
145  const unsigned int kCtrX = kernel.getCtrX();
146  const unsigned int kCtrY = kernel.getCtrY();
147 
148  const typename OutImageT::SinglePixel edgePixel = afwMath::edgePixel<OutImageT>(
150  );
151  std::vector<afwGeom::Box2I> bboxList;
152 
153  // create a list of bounding boxes describing edge regions, in this order:
154  // bottom edge, top edge (both edge to edge),
155  // left edge, right edge (both omitting pixels already in the bottom and top edge regions)
156  int const numHeight = kHeight - (1 + kCtrY);
157  int const numWidth = kWidth - (1 + kCtrX);
158  bboxList.push_back(
160  afwGeom::Point2I(0, 0),
161  afwGeom::Extent2I(imWidth, kCtrY)
162  )
163  );
164  bboxList.push_back(
166  afwGeom::Point2I(0, imHeight - numHeight),
167  afwGeom::Extent2I(imWidth, numHeight)
168  )
169  );
170  bboxList.push_back(
172  afwGeom::Point2I(0, kCtrY),
173  afwGeom::Extent2I(kCtrX, imHeight + 1 - kHeight)
174  )
175  );
176  bboxList.push_back(
178  afwGeom::Point2I(imWidth - numWidth, kCtrY),
179  afwGeom::Extent2I(numWidth, imHeight + 1 - kHeight)
180  )
181  );
182 
184  for (std::vector<afwGeom::Box2I>::const_iterator bboxIter = bboxList.begin();
185  bboxIter != bboxList.end(); ++bboxIter) {
186  OutImageT outView(outImage, *bboxIter, afwImage::LOCAL);
187  if (doCopyEdge) {
188  // note: <<= only works with data of the same type
189  // so convert the input image to output format
190  outView <<= OutImageT(InImageT(inImage, *bboxIter, afwImage::LOCAL), true);
191  *(outView.getMask()) |= edgeMask;
192  } else {
193  outView = edgePixel;
194  }
195  }
196  }
197 
198 } // anonymous namespace
199 
216 template <typename OutImageT, typename InImageT>
218  OutImageT &outImage,
219  double c1,
220  InImageT const &inImage1,
221  double c2,
222  InImageT const &inImage2)
223 {
224  if (outImage.getDimensions() != inImage1.getDimensions()) {
225  std::ostringstream os;
226  os << "outImage dimensions = ( " << outImage.getWidth() << ", " << outImage.getHeight()
227  << ") != (" << inImage1.getWidth() << ", " << inImage1.getHeight()
228  << ") = inImage1 dimensions";
229  throw LSST_EXCEPT(pexExcept::InvalidParameterError, os.str());
230  } else if (inImage1.getDimensions() != inImage2.getDimensions()) {
231  std::ostringstream os;
232  os << "inImage1 dimensions = ( " << inImage1.getWidth() << ", " << inImage1.getHeight()
233  << ") != (" << inImage2.getWidth() << ", " << inImage2.getHeight()
234  << ") = inImage2 dimensions";
235  throw LSST_EXCEPT(pexExcept::InvalidParameterError, os.str());
236  }
237 
238  typedef typename InImageT::const_x_iterator InConstXIter;
239  typedef typename OutImageT::x_iterator OutXIter;
240  for (int y = 0; y != inImage1.getHeight(); ++y) {
241  InConstXIter const end1 = inImage1.row_end(y);
242  InConstXIter inIter1 = inImage1.row_begin(y);
243  InConstXIter inIter2 = inImage2.row_begin(y);
244  OutXIter outIter = outImage.row_begin(y);
245  for (; inIter1 != end1; ++inIter1, ++inIter2, ++outIter) {
246  *outIter = (*inIter1 * c1) + (*inIter2 * c2);
247  }
248  }
249 }
250 
327 template <typename OutImageT, typename InImageT, typename KernelT>
329  OutImageT& convolvedImage,
330  InImageT const& inImage,
331  KernelT const& kernel,
332  ConvolutionControl const& convolutionControl)
333 {
334  mathDetail::basicConvolve(convolvedImage, inImage, kernel, convolutionControl);
335  setEdgePixels(convolvedImage, kernel, inImage, convolutionControl.getDoCopyEdge(),
337  );
338  convolvedImage.setXY0(inImage.getXY0());
339 }
340 
346 template <typename OutImageT, typename InImageT, typename KernelT>
348  OutImageT& convolvedImage,
349  InImageT const& inImage,
350  KernelT const& kernel,
351  bool doNormalize,
352  bool doCopyEdge)
353 {
355  ConvolutionControl convolutionControl;
356  convolutionControl.setDoNormalize(doNormalize);
357  convolutionControl.setDoCopyEdge(doCopyEdge);
358  afwMath::convolve(convolvedImage, inImage, kernel, convolutionControl);
359 }
360 
361 
362 
363 
364 /*
365  * Explicit instantiation of all convolve functions.
366  *
367  * This code needs to be compiled with full optimization, and there's no reason why
368  * it should be instantiated in the swig wrappers.
369  */
370 #define IMAGE(PIXTYPE) afwImage::Image<PIXTYPE>
371 #define MASKEDIMAGE(PIXTYPE) afwImage::MaskedImage<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
372 //
373 // Next a macro to generate needed instantiations for IMGMACRO (either IMAGE or MASKEDIMAGE)
374 // and the specified pixel types
375 //
376 /* NL's a newline for debugging -- don't define it and say
377  g++ -C -E -I$(eups list -s -d boost)/include Convolve.cc | perl -pe 's| *NL *|\n|g'
378 */
379 #define NL /* */
380 //
381 // Instantiate one kernel-specific specializations of convolution functions for Image or MaskedImage
382 // IMGMACRO = IMAGE or MASKEDIMAGE
383 // KERNELTYPE = a kernel class
384 //
385 #define INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, KERNELTYPE) \
386  template void afwMath::convolve( \
387  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, KERNELTYPE const&, bool, bool); NL \
388  template void afwMath::convolve( \
389  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, KERNELTYPE const&, ConvolutionControl const&); NL
390 //
391 // Instantiate Image or MaskedImage versions of all functions defined in this file.
392 // Call INSTANTIATE_IM_OR_MI_KERNEL once for each kernel class.
393 // IMGMACRO = IMAGE or MASKEDIMAGE
394 //
395 #define INSTANTIATE_IM_OR_MI(IMGMACRO, OUTPIXTYPE, INPIXTYPE) \
396  template void afwMath::scaledPlus( \
397  IMGMACRO(OUTPIXTYPE)&, double, IMGMACRO(INPIXTYPE) const&, double, IMGMACRO(INPIXTYPE) const&); NL \
398  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::AnalyticKernel) \
399  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::DeltaFunctionKernel) \
400  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::FixedKernel) \
401  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::LinearCombinationKernel) \
402  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::SeparableKernel) \
403  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::Kernel) \
404 //
405 // Instantiate all functions defined in this file for one specific output and input pixel type
406 //
408 #define INSTANTIATE(OUTPIXTYPE, INPIXTYPE) \
409  INSTANTIATE_IM_OR_MI(IMAGE, OUTPIXTYPE, INPIXTYPE) \
410  INSTANTIATE_IM_OR_MI(MASKEDIMAGE, OUTPIXTYPE, INPIXTYPE)
411 //
412 // Instantiate all functions defined in this file
413 //
414 INSTANTIATE(double, double)
415 INSTANTIATE(double, float)
416 INSTANTIATE(double, int)
417 INSTANTIATE(double, boost::uint16_t)
418 INSTANTIATE(float, float)
419 INSTANTIATE(float, int)
420 INSTANTIATE(float, boost::uint16_t)
421 INSTANTIATE(int, int)
422 INSTANTIATE(boost::uint16_t, boost::uint16_t)
int y
Convolution support.
void scaledPlus(OutImageT &outImage, double c1, InImageT const &inImage1, double c2, InImageT const &inImage2)
Declare the Kernel class and subclasses.
Include files required for standard LSST Exception handling.
boost::uint16_t MaskPixel
Parameters to control convolution.
Definition: ConvolveImage.h:58
int getCtrY() const
Return y index of kernel&#39;s center.
Definition: Kernel.h:272
#define INSTANTIATE(MATCH)
definition of the Trace messaging facilities
void setDoCopyEdge(bool doCopyEdge)
Definition: ConvolveImage.h:82
int getCtrX() const
Return x index of kernel&#39;s center.
Definition: Kernel.h:263
void setDoNormalize(bool doNormalize)
Definition: ConvolveImage.h:81
Image utility functions.
An integer coordinate rectangle.
Definition: Box.h:53
int getHeight() const
Return the Kernel&#39;s height.
Definition: Kernel.h:247
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
int getWidth() const
Return the Kernel&#39;s width.
Definition: Kernel.h:240
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 traits class for MaskedImage.
Definition: MaskedImage.h:53
ImageT::SinglePixel edgePixel(lsst::afw::image::detail::Image_tag)
Return an off-the-edge pixel appropriate for a given Image type.
static MaskPixelT getPlaneBitMask(const std::vector< std::string > &names)
Return the bitmask corresponding to a vector of plane names OR&#39;d together.
Definition: Mask.cc:860
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
Convolve an Image or MaskedImage with a Kernel, setting pixels of an existing output image...
ImageT::image_category image_category
Definition: Image.h:79
Implementation of the Class MaskedImage.
Kernels are used for convolution with MaskedImages and (eventually) Images.
Definition: Kernel.h:134