LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
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 
325 template <typename OutImageT, typename InImageT, typename KernelT>
327  OutImageT& convolvedImage,
328  InImageT const& inImage,
329  KernelT const& kernel,
330  ConvolutionControl const& convolutionControl)
331 {
332  mathDetail::basicConvolve(convolvedImage, inImage, kernel, convolutionControl);
333  setEdgePixels(convolvedImage, kernel, inImage, convolutionControl.getDoCopyEdge(),
335  );
336  convolvedImage.setXY0(inImage.getXY0());
337 }
338 
344 template <typename OutImageT, typename InImageT, typename KernelT>
346  OutImageT& convolvedImage,
347  InImageT const& inImage,
348  KernelT const& kernel,
349  bool doNormalize,
350  bool doCopyEdge)
351 {
353  ConvolutionControl convolutionControl;
354  convolutionControl.setDoNormalize(doNormalize);
355  convolutionControl.setDoCopyEdge(doCopyEdge);
356  afwMath::convolve(convolvedImage, inImage, kernel, convolutionControl);
357 }
358 
359 
360 
361 
362 /*
363  * Explicit instantiation of all convolve functions.
364  *
365  * This code needs to be compiled with full optimization, and there's no reason why
366  * it should be instantiated in the swig wrappers.
367  */
368 #define IMAGE(PIXTYPE) afwImage::Image<PIXTYPE>
369 #define MASKEDIMAGE(PIXTYPE) afwImage::MaskedImage<PIXTYPE, afwImage::MaskPixel, afwImage::VariancePixel>
370 //
371 // Next a macro to generate needed instantiations for IMGMACRO (either IMAGE or MASKEDIMAGE)
372 // and the specified pixel types
373 //
374 /* NL's a newline for debugging -- don't define it and say
375  g++ -C -E -I$(eups list -s -d boost)/include Convolve.cc | perl -pe 's| *NL *|\n|g'
376 */
377 #define NL /* */
378 //
379 // Instantiate one kernel-specific specializations of convolution functions for Image or MaskedImage
380 // IMGMACRO = IMAGE or MASKEDIMAGE
381 // KERNELTYPE = a kernel class
382 //
383 #define INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, KERNELTYPE) \
384  template void afwMath::convolve( \
385  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, KERNELTYPE const&, bool, bool); NL \
386  template void afwMath::convolve( \
387  IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const&, KERNELTYPE const&, ConvolutionControl const&); NL
388 //
389 // Instantiate Image or MaskedImage versions of all functions defined in this file.
390 // Call INSTANTIATE_IM_OR_MI_KERNEL once for each kernel class.
391 // IMGMACRO = IMAGE or MASKEDIMAGE
392 //
393 #define INSTANTIATE_IM_OR_MI(IMGMACRO, OUTPIXTYPE, INPIXTYPE) \
394  template void afwMath::scaledPlus( \
395  IMGMACRO(OUTPIXTYPE)&, double, IMGMACRO(INPIXTYPE) const&, double, IMGMACRO(INPIXTYPE) const&); NL \
396  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::AnalyticKernel) \
397  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::DeltaFunctionKernel) \
398  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::FixedKernel) \
399  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::LinearCombinationKernel) \
400  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::SeparableKernel) \
401  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, afwMath::Kernel) \
402 //
403 // Instantiate all functions defined in this file for one specific output and input pixel type
404 //
406 #define INSTANTIATE(OUTPIXTYPE, INPIXTYPE) \
407  INSTANTIATE_IM_OR_MI(IMAGE, OUTPIXTYPE, INPIXTYPE) \
408  INSTANTIATE_IM_OR_MI(MASKEDIMAGE, OUTPIXTYPE, INPIXTYPE)
409 //
410 // Instantiate all functions defined in this file
411 //
412 INSTANTIATE(double, double)
413 INSTANTIATE(double, float)
414 INSTANTIATE(double, int)
415 INSTANTIATE(double, std::uint16_t)
416 INSTANTIATE(float, float)
417 INSTANTIATE(float, int)
418 INSTANTIATE(float, std::uint16_t)
419 INSTANTIATE(int, int)
420 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)
Declare the Kernel class and subclasses.
Parameters to control convolution.
Definition: ConvolveImage.h:58
int getCtrY() const
Return y index of kernel&#39;s center.
Definition: Kernel.h:269
void setDoCopyEdge(bool doCopyEdge)
Definition: ConvolveImage.h:82
int getCtrX() const
Return x index of kernel&#39;s center.
Definition: Kernel.h:260
void setDoNormalize(bool doNormalize)
Definition: ConvolveImage.h:81
#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
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,...)
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.
Include files required for standard LSST Exception handling.
Kernels are used for convolution with MaskedImages and (eventually) Images.
Definition: Kernel.h:131