lsst.afw  21.0.0-13-g512c41855+47cba9fc36
SeparableKernel.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 #include <algorithm>
25 #include <iterator>
26 #include <sstream>
27 
28 #include "lsst/pex/exceptions.h"
29 #include "lsst/afw/math/Kernel.h"
32 
34 
35 namespace lsst {
36 namespace afw {
37 
38 template std::shared_ptr<math::SeparableKernel> table::io::PersistableFacade<
39  math::SeparableKernel>::dynamicCast(std::shared_ptr<table::io::Persistable> const&);
40 
41 namespace math {
42 
44  : Kernel(),
45  _kernelColFunctionPtr(),
46  _kernelRowFunctionPtr(),
47  _localColList(0),
48  _localRowList(0),
49  _kernelX(0),
50  _kernelY(0),
51  _kernelRowCache(0),
52  _kernelColCache(0) {
53  _setKernelXY();
54 }
55 
56 SeparableKernel::SeparableKernel(int width, int height, KernelFunction const& kernelColFunction,
57  KernelFunction const& kernelRowFunction,
58  Kernel::SpatialFunction const& spatialFunction)
59  : Kernel(width, height, kernelColFunction.getNParameters() + kernelRowFunction.getNParameters(),
60  spatialFunction),
61  _kernelColFunctionPtr(kernelColFunction.clone()),
62  _kernelRowFunctionPtr(kernelRowFunction.clone()),
63  _localColList(width),
64  _localRowList(height),
65  _kernelX(width),
66  _kernelY(height),
67  _kernelRowCache(0),
68  _kernelColCache(0) {
69  _setKernelXY();
70 }
71 
72 SeparableKernel::SeparableKernel(int width, int height, KernelFunction const& kernelColFunction,
73  KernelFunction const& kernelRowFunction,
74  std::vector<Kernel::SpatialFunctionPtr> const& spatialFunctionList)
75  : Kernel(width, height, spatialFunctionList),
76  _kernelColFunctionPtr(kernelColFunction.clone()),
77  _kernelRowFunctionPtr(kernelRowFunction.clone()),
78  _localColList(width),
79  _localRowList(height),
80  _kernelX(width),
81  _kernelY(height),
82  _kernelRowCache(0),
83  _kernelColCache(0) {
84  if (kernelColFunction.getNParameters() + kernelRowFunction.getNParameters() !=
85  spatialFunctionList.size()) {
87  os << "kernelColFunction.getNParameters() + kernelRowFunction.getNParameters() = "
88  << kernelColFunction.getNParameters() << " + " << kernelRowFunction.getNParameters()
89  << " != " << spatialFunctionList.size() << " = "
90  << "spatialFunctionList.size()";
92  }
93 
94  _setKernelXY();
95 }
96 
99  if (this->isSpatiallyVarying()) {
100  retPtr.reset(new SeparableKernel(this->getWidth(), this->getHeight(), *(this->_kernelColFunctionPtr),
101  *(this->_kernelRowFunctionPtr), this->_spatialFunctionList));
102  } else {
103  retPtr.reset(new SeparableKernel(this->getWidth(), this->getHeight(), *(this->_kernelColFunctionPtr),
104  *(this->_kernelRowFunctionPtr)));
105  }
106  retPtr->setCtr(this->getCtr());
107  retPtr->computeCache(this->getCacheSize());
108  return retPtr;
109 }
110 
111 std::shared_ptr<Kernel> SeparableKernel::resized(int width, int height) const {
113  if (isSpatiallyVarying()) {
114  retPtr = std::make_shared<SeparableKernel>(width, height, *_kernelColFunctionPtr,
115  *_kernelRowFunctionPtr, _spatialFunctionList);
116  } else {
117  retPtr = std::make_shared<SeparableKernel>(width, height, *_kernelColFunctionPtr,
118  *_kernelRowFunctionPtr);
119  }
120  return retPtr;
121 }
122 
124  bool doNormalize, double x, double y) const {
125  if (static_cast<int>(colList.size()) != this->getWidth() ||
126  static_cast<int>(rowList.size()) != this->getHeight()) {
128  os << "colList.size(), rowList.size() = (" << colList.size() << ", " << rowList.size() << ") != ("
129  << this->getWidth() << ", " << this->getHeight() << ") = "
130  << "kernel dimensions";
132  }
133  if (this->isSpatiallyVarying()) {
135  }
136 
137  return basicComputeVectors(colList, rowList, doNormalize);
138 }
139 
141  return _kernelColFunctionPtr->clone();
142 }
143 
145  return _kernelRowFunctionPtr->clone();
146 }
147 
150  os << prefix << "SeparableKernel:" << std::endl;
151  os << prefix
152  << "..x (width) function: " << (_kernelColFunctionPtr ? _kernelColFunctionPtr->toString() : "None")
153  << std::endl;
154  os << prefix
155  << "..y (rows) function: " << (_kernelRowFunctionPtr ? _kernelRowFunctionPtr->toString() : "None")
156  << std::endl;
157  os << Kernel::toString(prefix + "\t");
158  return os.str();
159 }
160 
162  std::vector<double> allParams = _kernelColFunctionPtr->getParameters();
163  std::vector<double> yParams = _kernelRowFunctionPtr->getParameters();
164  std::copy(yParams.begin(), yParams.end(), std::back_inserter(allParams));
165  return allParams;
166 }
167 
168 //
169 // Protected Member Functions
170 //
171 
173  double imSum = basicComputeVectors(_localColList, _localRowList, doNormalize);
174 
175  for (int y = 0; y != image.getHeight(); ++y) {
176  image::Image<Pixel>::x_iterator imPtr = image.row_begin(y);
177  for (std::vector<Pixel>::iterator colIter = _localColList.begin(); colIter != _localColList.end();
178  ++colIter, ++imPtr) {
179  *imPtr = (*colIter) * _localRowList[y];
180  }
181  }
182 
183  return imSum;
184 }
185 
186 void SeparableKernel::setKernelParameter(unsigned int ind, double value) const {
187  unsigned int const nColParams = _kernelColFunctionPtr->getNParameters();
188  if (ind < nColParams) {
189  _kernelColFunctionPtr->setParameter(ind, value);
190  } else {
191  _kernelRowFunctionPtr->setParameter(ind - nColParams, value);
192  }
193 }
194 
195 //
196 // Private Member Functions
197 //
198 
199 double SeparableKernel::basicComputeVectors(std::vector<Pixel>& colList, std::vector<Pixel>& rowList,
200  bool doNormalize) const {
201  double colSum = 0.0;
202  if (_kernelColCache.empty()) {
203  for (unsigned int i = 0; i != colList.size(); ++i) {
204  double colFuncValue = (*_kernelColFunctionPtr)(_kernelX[i]);
205  colList[i] = colFuncValue;
206  colSum += colFuncValue;
207  }
208  } else {
209  int const cacheSize = _kernelColCache.size();
210 
211  int const indx = this->getKernelParameter(0) * cacheSize;
212 
213  std::vector<double>& cachedValues = _kernelColCache.at(indx);
214  for (unsigned int i = 0; i != colList.size(); ++i) {
215  double colFuncValue = cachedValues[i];
216  colList[i] = colFuncValue;
217  colSum += colFuncValue;
218  }
219  }
220 
221  double rowSum = 0.0;
222  if (_kernelRowCache.empty()) {
223  for (unsigned int i = 0; i != rowList.size(); ++i) {
224  double rowFuncValue = (*_kernelRowFunctionPtr)(_kernelY[i]);
225  rowList[i] = rowFuncValue;
226  rowSum += rowFuncValue;
227  }
228  } else {
229  int const cacheSize = _kernelRowCache.size();
230 
231  int const indx = this->getKernelParameter(1) * cacheSize;
232 
233  std::vector<double>& cachedValues = _kernelRowCache.at(indx);
234  for (unsigned int i = 0; i != rowList.size(); ++i) {
235  double rowFuncValue = cachedValues[i];
236  rowList[i] = rowFuncValue;
237  rowSum += rowFuncValue;
238 
239 #if 0
240  if (indx == cacheSize/2) {
241  if (::fabs(rowFuncValue - (*_kernelRowFunctionPtr)(_kernelX[i])) > 1e-2) {
242  std::cout << indx << " " << i << " "
243  << rowFuncValue << " "
244  << (*_kernelRowFunctionPtr)(_kernelX[i])
245  << std::endl;
246  }
247  }
248 #endif
249  }
250  }
251 
252  double imSum = colSum * rowSum;
253  if (doNormalize) {
254  if ((colSum == 0) || (rowSum == 0)) {
255  throw LSST_EXCEPT(pexExcept::OverflowError, "Cannot normalize; kernel sum is 0");
256  }
257  for (std::vector<Pixel>::iterator colIter = colList.begin(); colIter != colList.end(); ++colIter) {
258  *colIter /= colSum;
259  }
260 
261  for (std::vector<Pixel>::iterator rowIter = rowList.begin(); rowIter != rowList.end(); ++rowIter) {
262  *rowIter /= rowSum;
263  }
264  imSum = 1.0;
265  }
266  return imSum;
267 }
268 
269 namespace {
273 void _computeCache(int const cacheSize, std::vector<double> const& x,
275  if (cacheSize <= 0) {
276  kernelCache->erase(kernelCache->begin(), kernelCache->end());
277  return;
278  }
279 
280  if (kernelCache[0].size() != x.size()) { // invalid
281  kernelCache->erase(kernelCache->begin(), kernelCache->end());
282  }
283 
284  int const old_cacheSize = kernelCache->size();
285 
286  if (cacheSize == old_cacheSize) {
287  return; // nothing to do
288  }
289 
290  if (cacheSize < old_cacheSize) {
291  kernelCache->erase(kernelCache->begin() + cacheSize, kernelCache->end());
292  } else {
293  kernelCache->resize(cacheSize);
294  for (int i = old_cacheSize; i != cacheSize; ++i) {
295  (*kernelCache)[i].resize(x.size());
296  }
297  }
298  //
299  // Actually fill the cache
300  //
301  for (int i = 0; i != cacheSize; ++i) {
302  func->setParameter(0, (i + 0.5) / static_cast<double>(cacheSize));
303  for (unsigned int j = 0; j != x.size(); ++j) {
304  (*kernelCache)[i][j] = (*func)(x[j]);
305  }
306  }
307 }
308 } // namespace
309 
310 void SeparableKernel::computeCache(int const cacheSize) {
312 
313  func = getKernelColFunction();
314  _computeCache(cacheSize, _kernelY, func, &_kernelColCache);
315 
316  func = getKernelRowFunction();
317  _computeCache(cacheSize, _kernelX, func, &_kernelRowCache);
318 }
319 
320 int SeparableKernel::getCacheSize() const { return _kernelColCache.size(); };
321 } // namespace math
322 } // namespace afw
323 } // namespace lsst
double x
#define LSST_EXCEPT(type,...)
std::ostream * os
Definition: Schema.cc:746
std::string prefix
Definition: SchemaMapper.cc:79
int y
Definition: SpanSet.cc:49
T at(T... args)
T back_inserter(T... args)
T begin(T... args)
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:133
A Function taking one argument.
Definition: Function.h:202
std::string toString(std::string const &prefix="") const override
Return a string representation of the function.
Definition: Function.h:240
virtual std::shared_ptr< Function1< ReturnT > > clone() const =0
Return a pointer to a deep copy of this function.
A Function taking two arguments.
Definition: Function.h:259
std::vector< double > const & getParameters() const noexcept
Return all function parameters.
Definition: Function.h:129
void setParameter(unsigned int ind, double newValue)
Set one function parameter without range checking.
Definition: Function.h:143
unsigned int getNParameters() const noexcept
Return the number of function parameters.
Definition: Function.h:112
Kernels are used for convolution with MaskedImages and (eventually) Images.
Definition: Kernel.h:111
std::vector< SpatialFunctionPtr > _spatialFunctionList
Definition: Kernel.h:450
int getHeight() const
Return the Kernel's height.
Definition: Kernel.h:230
lsst::geom::Point2I getCtr() const
Return index of kernel's center.
Definition: Kernel.h:235
virtual std::string toString(std::string const &prefix="") const
Return a string representation of the kernel.
Definition: Kernel.cc:195
int getWidth() const
Return the Kernel's width.
Definition: Kernel.h:225
bool isSpatiallyVarying() const
Return true iff the kernel is spatially varying (has a spatial function)
Definition: Kernel.h:334
void setKernelParametersFromSpatialModel(double x, double y) const
Set the kernel parameters from the spatial model (if any).
Definition: Kernel.cc:228
KernelFunctionPtr getKernelRowFunction() const
Get a deep copy of the row kernel function.
std::string toString(std::string const &prefix="") const override
Return a string representation of the kernel.
std::shared_ptr< Kernel > clone() const override
Return a pointer to a deep copy of this kernel.
std::vector< double > getKernelParameters() const override
Return the current kernel parameters.
double getKernelParameter(unsigned int i) const override
Return a particular Kernel Parameter (no bounds checking).
Definition: Kernel.h:934
int getCacheSize() const override
Get the current cache size (0 if none)
double doComputeImage(lsst::afw::image::Image< Pixel > &image, bool doNormalize) const override
Low-level version of computeImage.
KernelFunctionPtr getKernelColFunction() const
Get a deep copy of the col kernel function.
double computeVectors(std::vector< Pixel > &colList, std::vector< Pixel > &rowList, bool doNormalize, double x=0.0, double y=0.0) const
Compute the column and row arrays in place, where kernel(col, row) = colList(col) * rowList(row)
std::shared_ptr< KernelFunction > KernelFunctionPtr
Definition: Kernel.h:864
std::shared_ptr< Kernel > resized(int width, int height) const override
Return a pointer to a clone with specified kernel dimensions.
void setKernelParameter(unsigned int ind, double value) const override
Set one kernel parameter.
SeparableKernel()
Construct an empty spatially invariant SeparableKernel of size 0x0.
void computeCache(int const cacheSize) override
Compute a cache of Kernel values, if desired.
T copy(T... args)
T empty(T... args)
T end(T... args)
T endl(T... args)
T fabs(T... args)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
A base class for image defects.
T reset(T... args)
T size(T... args)