LSSTApplications  11.0-13-gbb96280,12.1+18,12.1+7,12.1-1-g14f38d3+72,12.1-1-g16c0db7+5,12.1-1-g5961e7a+84,12.1-1-ge22e12b+23,12.1-11-g06625e2+4,12.1-11-g0d7f63b+4,12.1-19-gd507bfc,12.1-2-g7dda0ab+38,12.1-2-gc0bc6ab+81,12.1-21-g6ffe579+2,12.1-21-gbdb6c2a+4,12.1-24-g941c398+5,12.1-3-g57f6835+7,12.1-3-gf0736f3,12.1-37-g3ddd237,12.1-4-gf46015e+5,12.1-5-g06c326c+20,12.1-5-g648ee80+3,12.1-5-gc2189d7+4,12.1-6-ga608fc0+1,12.1-7-g3349e2a+5,12.1-7-gfd75620+9,12.1-9-g577b946+5,12.1-9-gc4df26a+10
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 <cstdint>
37 #include <functional>
38 #include <iostream>
39 #include <sstream>
40 #include <limits>
41 #include <vector>
42 #include <string>
43 
44 #include "lsst/pex/exceptions.h"
45 #include "lsst/log/Log.h"
48 #include "lsst/afw/math/Kernel.h"
50 
51 namespace pexExcept = lsst::pex::exceptions;
52 namespace afwGeom = lsst::afw::geom;
53 namespace afwImage = lsst::afw::image;
54 namespace afwMath = lsst::afw::math;
55 namespace mathDetail = lsst::afw::math::detail;
56 
57 namespace {
58 
59  /*
60  * @brief Set the edge pixels of a convolved Image based on size of the convolution kernel used
61  *
62  * Separate specializations for Image and MaskedImage are required to set the EDGE bit of the Mask plane
63  * (if there is one) when doCopyEdge is true.
64  */
65  template <typename OutImageT, typename InImageT>
66  inline void setEdgePixels(
67  OutImageT& outImage,
68  afwMath::Kernel const &kernel,
69  InImageT const &inImage,
71  bool doCopyEdge,
75 
76  {
77  const unsigned int imWidth = outImage.getWidth();
78  const unsigned int imHeight = outImage.getHeight();
79  const unsigned int kWidth = kernel.getWidth();
80  const unsigned int kHeight = kernel.getHeight();
81  const unsigned int kCtrX = kernel.getCtrX();
82  const unsigned int kCtrY = kernel.getCtrY();
83 
84  const typename OutImageT::SinglePixel edgePixel = afwMath::edgePixel<OutImageT>(
86  );
87  std::vector<afwGeom::Box2I> bboxList;
88 
89  // create a list of bounding boxes describing edge regions, in this order:
90  // bottom edge, top edge (both edge to edge),
91  // left edge, right edge (both omitting pixels already in the bottom and top edge regions)
92  int const numHeight = kHeight - (1 + kCtrY);
93  int const numWidth = kWidth - (1 + kCtrX);
94  bboxList.push_back(
95  afwGeom::Box2I(afwGeom::Point2I(0, 0), afwGeom::Extent2I(imWidth, kCtrY))
96  );
97  bboxList.push_back(
98  afwGeom::Box2I(afwGeom::Point2I(0, imHeight - numHeight), afwGeom::Extent2I(imWidth, numHeight))
99  );
100  bboxList.push_back(
101  afwGeom::Box2I(afwGeom::Point2I(0, kCtrY), afwGeom::Extent2I(kCtrX, imHeight + 1 - kHeight))
102  );
103  bboxList.push_back(
104  afwGeom::Box2I(afwGeom::Point2I(imWidth - numWidth, kCtrY), afwGeom::Extent2I(numWidth, imHeight + 1 - kHeight))
105  );
106 
107  for (std::vector<afwGeom::Box2I>::const_iterator bboxIter = bboxList.begin();
108  bboxIter != bboxList.end(); ++bboxIter
109  ) {
110  OutImageT outView(outImage, *bboxIter, afwImage::LOCAL);
111  if (doCopyEdge) {
112  // note: set only works with data of the same type
113  // so convert the input image to output format
114  outView.assign(OutImageT(InImageT(inImage, *bboxIter, afwImage::LOCAL), true));
115  } else {
116  outView = edgePixel;
117  }
118  }
119  }
120 
121  /*
122  * @brief Set the edge pixels of a convolved MaskedImage based on size of the convolution kernel used
123  *
124  * Separate specializations for Image and MaskedImage are required to set the EDGE bit of the Mask plane
125  * (if there is one) when doCopyEdge is true.
126  */
127  template <typename OutImageT, typename InImageT>
128  inline void setEdgePixels(
129  OutImageT& outImage,
130  afwMath::Kernel const &kernel,
131  InImageT const &inImage,
133  bool doCopyEdge,
137 
138  {
139  const unsigned int imWidth = outImage.getWidth();
140  const unsigned int imHeight = outImage.getHeight();
141  const unsigned int kWidth = kernel.getWidth();
142  const unsigned int kHeight = kernel.getHeight();
143  const unsigned int kCtrX = kernel.getCtrX();
144  const unsigned int kCtrY = kernel.getCtrY();
145 
146  const typename OutImageT::SinglePixel edgePixel = afwMath::edgePixel<OutImageT>(
148  );
149  std::vector<afwGeom::Box2I> bboxList;
150 
151  // create a list of bounding boxes describing edge regions, in this order:
152  // bottom edge, top edge (both edge to edge),
153  // left edge, right edge (both omitting pixels already in the bottom and top edge regions)
154  int const numHeight = kHeight - (1 + kCtrY);
155  int const numWidth = kWidth - (1 + kCtrX);
156  bboxList.push_back(
158  afwGeom::Point2I(0, 0),
159  afwGeom::Extent2I(imWidth, kCtrY)
160  )
161  );
162  bboxList.push_back(
164  afwGeom::Point2I(0, imHeight - numHeight),
165  afwGeom::Extent2I(imWidth, numHeight)
166  )
167  );
168  bboxList.push_back(
170  afwGeom::Point2I(0, kCtrY),
171  afwGeom::Extent2I(kCtrX, imHeight + 1 - kHeight)
172  )
173  );
174  bboxList.push_back(
176  afwGeom::Point2I(imWidth - numWidth, kCtrY),
177  afwGeom::Extent2I(numWidth, imHeight + 1 - kHeight)
178  )
179  );
180 
182  for (std::vector<afwGeom::Box2I>::const_iterator bboxIter = bboxList.begin();
183  bboxIter != bboxList.end(); ++bboxIter) {
184  OutImageT outView(outImage, *bboxIter, afwImage::LOCAL);
185  if (doCopyEdge) {
186  // note: set only works with data of the same type
187  // so convert the input image to output format
188  outView.assign(OutImageT(InImageT(inImage, *bboxIter, afwImage::LOCAL), true));
189  *(outView.getMask()) |= edgeMask;
190  } else {
191  outView = edgePixel;
192  }
193  }
194  }
195 
196 } // anonymous namespace
197 
214 template <typename OutImageT, typename InImageT>
216  OutImageT &outImage,
217  double c1,
218  InImageT const &inImage1,
219  double c2,
220  InImageT const &inImage2)
221 {
222  if (outImage.getDimensions() != inImage1.getDimensions()) {
223  std::ostringstream os;
224  os << "outImage dimensions = ( " << outImage.getWidth() << ", " << outImage.getHeight()
225  << ") != (" << inImage1.getWidth() << ", " << inImage1.getHeight()
226  << ") = inImage1 dimensions";
227  throw LSST_EXCEPT(pexExcept::InvalidParameterError, os.str());
228  } else if (inImage1.getDimensions() != inImage2.getDimensions()) {
229  std::ostringstream os;
230  os << "inImage1 dimensions = ( " << inImage1.getWidth() << ", " << inImage1.getHeight()
231  << ") != (" << inImage2.getWidth() << ", " << inImage2.getHeight()
232  << ") = inImage2 dimensions";
233  throw LSST_EXCEPT(pexExcept::InvalidParameterError, os.str());
234  }
235 
236  typedef typename InImageT::const_x_iterator InConstXIter;
237  typedef typename OutImageT::x_iterator OutXIter;
238  for (int y = 0; y != inImage1.getHeight(); ++y) {
239  InConstXIter const end1 = inImage1.row_end(y);
240  InConstXIter inIter1 = inImage1.row_begin(y);
241  InConstXIter inIter2 = inImage2.row_begin(y);
242  OutXIter outIter = outImage.row_begin(y);
243  for (; inIter1 != end1; ++inIter1, ++inIter2, ++outIter) {
244  *outIter = (*inIter1 * c1) + (*inIter2 * c2);
245  }
246  }
247 }
248 
318 template <typename OutImageT, typename InImageT, typename KernelT>
320  OutImageT& convolvedImage,
321  InImageT const& inImage,
322  KernelT const& kernel,
323  ConvolutionControl const& convolutionControl)
324 {
325  mathDetail::basicConvolve(convolvedImage, inImage, kernel, convolutionControl);
326  setEdgePixels(convolvedImage, kernel, inImage, convolutionControl.getDoCopyEdge(),
328  );
329  convolvedImage.setXY0(inImage.getXY0());
330 }
331 
337 template <typename OutImageT, typename InImageT, typename KernelT>
339  OutImageT& convolvedImage,
340  InImageT const& inImage,
341  KernelT const& kernel,
342  bool doNormalize,
343  bool doCopyEdge)
344 {
346  ConvolutionControl convolutionControl;
347  convolutionControl.setDoNormalize(doNormalize);
348  convolutionControl.setDoCopyEdge(doCopyEdge);
349  afwMath::convolve(convolvedImage, inImage, kernel, convolutionControl);
350 }
351 
352 
353 
354 
355 /*
356  * Explicit instantiation of all convolve functions.
357  *
358  * This code needs to be compiled with full optimization, and there's no reason why
359  * it should be instantiated in the swig wrappers.
360  */
361 #define IMAGE(PIXTYPE) afwImage::Image<PIXTYPE>
362 #define MASKEDIMAGE(PIXTYPE) afwImage::MaskedImage<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
363 //
364 // Next a macro to generate needed instantiations for IMGMACRO (either IMAGE or MASKEDIMAGE)
365 // and the specified pixel types
366 //
367 /* NL's a newline for debugging -- don't define it and say
368  g++ -C -E -I$(eups list -s -d boost)/include Convolve.cc | perl -pe 's| *NL *|\n|g'
369 */
370 #define NL /* */
371 //
372 // Instantiate one kernel-specific specializations of convolution functions for Image or MaskedImage
373 // IMGMACRO = IMAGE or MASKEDIMAGE
374 // KERNELTYPE = a kernel class
375 //
376 #define INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, KERNELTYPE) \
377  template void afwMath::convolve( \
378  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, KERNELTYPE const&, bool, bool); NL \
379  template void afwMath::convolve( \
380  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, KERNELTYPE const&, ConvolutionControl const&); NL
381 //
382 // Instantiate Image or MaskedImage versions of all functions defined in this file.
383 // Call INSTANTIATE_IM_OR_MI_KERNEL once for each kernel class.
384 // IMGMACRO = IMAGE or MASKEDIMAGE
385 //
386 #define INSTANTIATE_IM_OR_MI(IMGMACRO, OUTPIXTYPE, INPIXTYPE) \
387  template void afwMath::scaledPlus( \
388  IMGMACRO(OUTPIXTYPE)&, double, IMGMACRO(INPIXTYPE) const&, double, IMGMACRO(INPIXTYPE) const&); NL \
389  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::AnalyticKernel) \
390  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::DeltaFunctionKernel) \
391  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::FixedKernel) \
392  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::LinearCombinationKernel) \
393  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::SeparableKernel) \
394  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::Kernel) \
395 //
396 // Instantiate all functions defined in this file for one specific output and input pixel type
397 //
399 #define INSTANTIATE(OUTPIXTYPE, INPIXTYPE) \
400  INSTANTIATE_IM_OR_MI(IMAGE, OUTPIXTYPE, INPIXTYPE) \
401  INSTANTIATE_IM_OR_MI(MASKEDIMAGE, OUTPIXTYPE, INPIXTYPE)
402 //
403 // Instantiate all functions defined in this file
404 //
405 INSTANTIATE(double, double)
406 INSTANTIATE(double, float)
407 INSTANTIATE(double, int)
408 INSTANTIATE(double, std::uint16_t)
409 INSTANTIATE(float, float)
410 INSTANTIATE(float, int)
411 INSTANTIATE(float, std::uint16_t)
412 INSTANTIATE(int, int)
413 INSTANTIATE(std::uint16_t, std::uint16_t)
int y
std::uint16_t MaskPixel
Convolution support.
void scaledPlus(OutImageT &outImage, double c1, InImageT const &inImage1, double c2, InImageT const &inImage2)
Compute the scaled sum of two images.
Declare the Kernel class and subclasses.
Include files required for standard LSST Exception handling.
Parameters to control convolution.
Definition: ConvolveImage.h:57
int getCtrY() const
Return y index of kernel&#39;s center.
Definition: Kernel.h:269
void setDoCopyEdge(bool doCopyEdge)
Definition: ConvolveImage.h:77
int getCtrX() const
Return x index of kernel&#39;s center.
Definition: Kernel.h:260
void setDoNormalize(bool doNormalize)
Definition: ConvolveImage.h:76
#define INSTANTIATE(T)
Image utility functions.
An integer coordinate rectangle.
Definition: Box.h:53
int getHeight() const
Return the Kernel&#39;s height.
Definition: Kernel.h:244
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
LSST DM logging module built on log4cxx.
int getWidth() const
Return the Kernel&#39;s width.
Definition: Kernel.h:237
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:54
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,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
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:78
Implementation of the Class MaskedImage.
Kernels are used for convolution with MaskedImages and (eventually) Images.
Definition: Kernel.h:131