lsst.afw  22.0.1-31-gd62ef0f05+23bd69c089
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 
25 /*
26  * Definition of functions declared in ConvolveImage.h
27  */
28 #include <algorithm>
29 #include <cmath>
30 #include <cstdint>
31 #include <functional>
32 #include <iostream>
33 #include <sstream>
34 #include <limits>
35 #include <vector>
36 #include <string>
37 
38 #include "lsst/pex/exceptions.h"
39 #include "lsst/log/Log.h"
42 #include "lsst/afw/math/Kernel.h"
44 
46 
47 namespace lsst {
48 namespace afw {
49 namespace math {
50 
51 namespace {
52 
65 template <typename OutImageT, typename InImageT>
66 inline void setEdgePixels(OutImageT& outImage, Kernel const& kernel, InImageT const& inImage, bool doCopyEdge,
67  image::detail::Image_tag) {
68  const unsigned int imWidth = outImage.getWidth();
69  const unsigned int imHeight = outImage.getHeight();
70  const unsigned int kWidth = kernel.getWidth();
71  const unsigned int kHeight = kernel.getHeight();
72  const unsigned int kCtrX = kernel.getCtr().getX();
73  const unsigned int kCtrY = kernel.getCtr().getY();
74 
75  const typename OutImageT::SinglePixel edgePixel =
76  math::edgePixel<OutImageT>(typename image::detail::image_traits<OutImageT>::image_category());
78 
79  // create a list of bounding boxes describing edge regions, in this order:
80  // bottom edge, top edge (both edge to edge),
81  // left edge, right edge (both omitting pixels already in the bottom and top edge regions)
82  int const numHeight = kHeight - (1 + kCtrY);
83  int const numWidth = kWidth - (1 + kCtrX);
84  bboxList.emplace_back(lsst::geom::Point2I(0, 0), lsst::geom::Extent2I(imWidth, kCtrY));
85  bboxList.emplace_back(lsst::geom::Point2I(0, imHeight - numHeight),
86  lsst::geom::Extent2I(imWidth, numHeight));
87  bboxList.emplace_back(lsst::geom::Point2I(0, kCtrY),
88  lsst::geom::Extent2I(kCtrX, imHeight + 1 - kHeight));
89  bboxList.emplace_back(lsst::geom::Point2I(imWidth - numWidth, kCtrY),
90  lsst::geom::Extent2I(numWidth, imHeight + 1 - kHeight));
91 
92  for (auto const &bboxIter : bboxList) {
93  OutImageT outView(outImage, bboxIter, image::LOCAL);
94  if (doCopyEdge) {
95  // note: set only works with data of the same type
96  // so convert the input image to output format
97  outView.assign(OutImageT(InImageT(inImage, bboxIter, image::LOCAL), true));
98  } else {
99  outView = edgePixel;
100  }
101  }
102 }
103 
116 template <typename OutImageT, typename InImageT>
117 inline void setEdgePixels(OutImageT& outImage, Kernel const& kernel, InImageT const& inImage, bool doCopyEdge,
118  image::detail::MaskedImage_tag) {
119  const unsigned int imWidth = outImage.getWidth();
120  const unsigned int imHeight = outImage.getHeight();
121  const unsigned int kWidth = kernel.getWidth();
122  const unsigned int kHeight = kernel.getHeight();
123  const unsigned int kCtrX = kernel.getCtr().getX();
124  const unsigned int kCtrY = kernel.getCtr().getY();
125 
126  const typename OutImageT::SinglePixel edgePixel =
127  math::edgePixel<OutImageT>(typename image::detail::image_traits<OutImageT>::image_category());
129 
130  // create a list of bounding boxes describing edge regions, in this order:
131  // bottom edge, top edge (both edge to edge),
132  // left edge, right edge (both omitting pixels already in the bottom and top edge regions)
133  int const numHeight = kHeight - (1 + kCtrY);
134  int const numWidth = kWidth - (1 + kCtrX);
135  bboxList.emplace_back(lsst::geom::Point2I(0, 0), lsst::geom::Extent2I(imWidth, kCtrY));
136  bboxList.emplace_back(lsst::geom::Point2I(0, imHeight - numHeight),
137  lsst::geom::Extent2I(imWidth, numHeight));
138  bboxList.emplace_back(lsst::geom::Point2I(0, kCtrY),
139  lsst::geom::Extent2I(kCtrX, imHeight + 1 - kHeight));
140  bboxList.emplace_back(lsst::geom::Point2I(imWidth - numWidth, kCtrY),
141  lsst::geom::Extent2I(numWidth, imHeight + 1 - kHeight));
142 
144  for (auto const &bboxIter : bboxList) {
145  OutImageT outView(outImage, bboxIter, image::LOCAL);
146  if (doCopyEdge) {
147  // note: set only works with data of the same type
148  // so convert the input image to output format
149  outView.assign(OutImageT(InImageT(inImage, bboxIter, image::LOCAL), true));
150  *(outView.getMask()) |= edgeMask;
151  } else {
152  outView = edgePixel;
153  }
154  }
155 }
156 
157 } // anonymous namespace
158 
159 template <typename OutImageT, typename InImageT>
160 void scaledPlus(OutImageT& outImage, double c1, InImageT const& inImage1, double c2,
161  InImageT const& inImage2) {
162  if (outImage.getDimensions() != inImage1.getDimensions()) {
164  os << "outImage dimensions = ( " << outImage.getWidth() << ", " << outImage.getHeight() << ") != ("
165  << inImage1.getWidth() << ", " << inImage1.getHeight() << ") = inImage1 dimensions";
167  } else if (inImage1.getDimensions() != inImage2.getDimensions()) {
169  os << "inImage1 dimensions = ( " << inImage1.getWidth() << ", " << inImage1.getHeight() << ") != ("
170  << inImage2.getWidth() << ", " << inImage2.getHeight() << ") = inImage2 dimensions";
172  }
173 
174  using InConstXIter = typename InImageT::const_x_iterator;
175  using OutXIter = typename OutImageT::x_iterator;
176  for (int y = 0; y != inImage1.getHeight(); ++y) {
177  InConstXIter const end1 = inImage1.row_end(y);
178  InConstXIter inIter1 = inImage1.row_begin(y);
179  InConstXIter inIter2 = inImage2.row_begin(y);
180  OutXIter outIter = outImage.row_begin(y);
181  for (; inIter1 != end1; ++inIter1, ++inIter2, ++outIter) {
182  *outIter = (*inIter1 * c1) + (*inIter2 * c2);
183  }
184  }
185 }
186 
187 template <typename OutImageT, typename InImageT, typename KernelT>
188 void convolve(OutImageT& convolvedImage, InImageT const& inImage, KernelT const& kernel,
189  ConvolutionControl const& convolutionControl) {
190  detail::basicConvolve(convolvedImage, inImage, kernel, convolutionControl);
191  setEdgePixels(convolvedImage, kernel, inImage, convolutionControl.getDoCopyEdge(),
193  convolvedImage.setXY0(inImage.getXY0());
194 }
195 
196 template <typename OutImageT, typename InImageT, typename KernelT>
197 void convolve(OutImageT& convolvedImage, InImageT const& inImage, KernelT const& kernel, bool doNormalize,
198  bool doCopyEdge) {
199  ConvolutionControl convolutionControl;
200  convolutionControl.setDoNormalize(doNormalize);
201  convolutionControl.setDoCopyEdge(doCopyEdge);
202  convolve(convolvedImage, inImage, kernel, convolutionControl);
203 }
204 
206 /*
207  * Explicit instantiation of all convolve functions.
208  *
209  * This code needs to be compiled with full optimization, and there's no reason why
210  * it should be instantiated in the swig wrappers.
211  */
212 #define IMAGE(PIXTYPE) image::Image<PIXTYPE>
213 #define MASKEDIMAGE(PIXTYPE) image::MaskedImage<PIXTYPE, image::MaskPixel, image::VariancePixel>
214 //
215 // Next a macro to generate needed instantiations for IMGMACRO (either IMAGE or MASKEDIMAGE)
216 // and the specified pixel types
217 //
218 /* NL's a newline for debugging -- don't define it and say
219  g++ -C -E -I$(eups list -s -d boost)/include Convolve.cc | perl -pe 's| *NL *|\n|g'
220 */
221 #define NL /* */
222 //
223 // Instantiate one kernel-specific specializations of convolution functions for Image or MaskedImage
224 // IMGMACRO = IMAGE or MASKEDIMAGE
225 // KERNELTYPE = a kernel class
226 //
227 #define INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, KERNELTYPE) \
228  template void convolve(IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const &, KERNELTYPE const&, bool, \
229  bool); \
230  NL template void convolve(IMGMACRO(OUTPIXTYPE)&, IMGMACRO(INPIXTYPE) const &, KERNELTYPE const&, \
231  ConvolutionControl const&); \
232  NL
233 //
234 // Instantiate Image or MaskedImage versions of all functions defined in this file.
235 // Call INSTANTIATE_IM_OR_MI_KERNEL once for each kernel class.
236 // IMGMACRO = IMAGE or MASKEDIMAGE
237 //
238 #define INSTANTIATE_IM_OR_MI(IMGMACRO, OUTPIXTYPE, INPIXTYPE) \
239  template void scaledPlus(IMGMACRO(OUTPIXTYPE)&, double, IMGMACRO(INPIXTYPE) const &, double, \
240  IMGMACRO(INPIXTYPE) const &); \
241  NL INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, \
242  AnalyticKernel) INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, \
243  INPIXTYPE, \
244  DeltaFunctionKernel) \
245  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, FixedKernel) \
246  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, LinearCombinationKernel) \
247  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, SeparableKernel) \
248  INSTANTIATE_IM_OR_MI_KERNEL(IMGMACRO, OUTPIXTYPE, INPIXTYPE, Kernel) //
249 // Instantiate all functions defined in this file for one specific output and input pixel type
250 //
251 #define INSTANTIATE(OUTPIXTYPE, INPIXTYPE) \
252  INSTANTIATE_IM_OR_MI(IMAGE, OUTPIXTYPE, INPIXTYPE) \
253  INSTANTIATE_IM_OR_MI(MASKEDIMAGE, OUTPIXTYPE, INPIXTYPE)
254 //
255 // Instantiate all functions defined in this file
256 //
257 INSTANTIATE(double, double)
258 INSTANTIATE(double, float)
259 INSTANTIATE(double, int)
260 INSTANTIATE(double, std::uint16_t)
261 INSTANTIATE(float, float)
262 INSTANTIATE(float, int)
264 INSTANTIATE(int, int)
267 } // namespace math
268 } // namespace afw
269 } // namespace lsst
#define INSTANTIATE(FROMSYS, TOSYS)
Definition: Detector.cc:484
#define LSST_EXCEPT(type,...)
std::ostream * os
Definition: Schema.cc:558
int y
Definition: SpanSet.cc:49
static MaskPixelT getPlaneBitMask(const std::vector< std::string > &names)
Return the bitmask corresponding to a vector of plane names OR'd together.
Definition: Mask.cc:378
Parameters to control convolution.
Definition: ConvolveImage.h:50
void setDoCopyEdge(bool doCopyEdge)
Definition: ConvolveImage.h:67
void setDoNormalize(bool doNormalize)
Definition: ConvolveImage.h:66
T emplace_back(T... args)
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.
void scaledPlus(OutImageT &outImage, double c1, InImageT const &inImage1, double c2, InImageT const &inImage2)
Compute the scaled sum of two images.
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::SinglePixel edgePixel(lsst::afw::image::detail::Image_tag)
Return an off-the-edge pixel appropriate for a given Image type.
Extent< int, 2 > Extent2I
A base class for image defects.
typename ImageT::image_category image_category
Definition: ImageBase.h:67