lsst.meas.algorithms  14.0-15-gaf93ae82
PsfCandidate.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008-2015 AURA/LSST.
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 
33 #include "lsst/afw/geom/Point.h"
34 #include "lsst/afw/geom/Extent.h"
35 #include "lsst/afw/geom/Box.h"
37 #include "lsst/afw/image/Image.h"
40 
42 namespace afwGeom = lsst::afw::geom;
43 namespace afwImage = lsst::afw::image;
44 namespace afwMath = lsst::afw::math;
46 
47 /************************************************************************************************************/
48 /*
49  * PsfCandidate's members
50  */
51 template <typename PixelT>
53 template <typename PixelT>
55 template <typename PixelT>
57 template <typename PixelT>
59 
60 /************************************************************************************************************/
61 namespace {
62  template<typename T> // functor used by makeImageFromMask to return inputMask
63  struct noop : public afwImage::pixelOp1<T> {
64  T operator()(T x) const { return x; }
65  };
66 
67  template<typename T> // functor used by makeImageFromMask to return (inputMask & mask)
68  struct andMask : public afwImage::pixelOp1<T> {
69  andMask(T mask) : _mask(mask) {}
70  T operator()(T x) const { return (x & _mask); }
71  private:
72  T _mask;
73  };
74 
75  template<typename T>
76  andMask<T> makeAndMask(T val) {
77  return andMask<T>(val);
78  }
79 
80  /*
81  * Return an Image initialized from a Mask (possibly modified by func)
82  */
83  template<typename LhsT, typename RhsT>
85  makeImageFromMask(afwImage::Mask<RhsT> const& rhs,
86  afwImage::pixelOp1<RhsT> const& func=noop<RhsT>()
87  )
88  {
90  std::make_shared<afwImage::Image<LhsT> >(rhs.getDimensions());
91  lhs->setXY0(rhs.getXY0());
92 
93  for (int y = 0; y != lhs->getHeight(); ++y) {
94  typename afwImage::Image<RhsT>::const_x_iterator rhsPtr = rhs.row_begin(y);
95 
96  for (typename afwImage::Image<LhsT>::x_iterator lhsPtr = lhs->row_begin(y),
97  lhsEnd = lhs->row_end(y); lhsPtr != lhsEnd; ++rhsPtr, ++lhsPtr) {
98  *lhsPtr = func(*rhsPtr);
99  }
100  }
101 
102  return lhs;
103  }
104 
106  double distanceSquared(double x, double y, afwDetection::PeakRecord const& peak) {
107  return std::pow(peak.getIx() - x, 2) + std::pow(peak.getIy() - y, 2);
108  }
109 
114  template <typename MaskT>
115  class BlendedFunctor {
116  public:
117  BlendedFunctor(
118  afwDetection::PeakRecord const& central,
119  afwDetection::PeakCatalog const& peaks,
120  afwImage::MaskPixel turnOff,
121  afwImage::MaskPixel turnOn
122  ) :
123  _central(central),
124  _peaks(peaks),
125  _turnOff(~turnOff),
126  _turnOn(turnOn)
127  {}
128 
130  void operator()(afwGeom::Point2I const & point, MaskT & val) {
131  int x = point.getX();
132  int y = point.getY();
133  double const central = distanceSquared(x, y, _central);
134  for (afwDetection::PeakCatalog::const_iterator iter = _peaks.begin(), end = _peaks.end();
135  iter != end; ++iter) {
136  double const dist2 = distanceSquared(x, y, *iter);
137  if (dist2 < central) {
138  val &= _turnOff;
139  val |= _turnOn;
140  }
141  }
142  }
143 
144 
145  private:
146  afwDetection::PeakRecord const& _central;
147  afwDetection::PeakCatalog const& _peaks;
148  afwImage::MaskPixel const _turnOff;
149  afwImage::MaskPixel const _turnOn;
150  };
151 
152 } // anonymous namespace
153 
172 template <typename PixelT>
175  unsigned int width, // Width of image
176  unsigned int height // Height of image
177 ) const {
178  afwGeom::Point2I const cen(afwImage::positionToIndex(getXCenter()),
179  afwImage::positionToIndex(getYCenter()));
180  afwGeom::Point2I const llc(cen[0] - width/2 - _parentExposure->getX0(),
181  cen[1] - height/2 - _parentExposure->getY0());
182 
183  afwGeom::BoxI bbox(llc, afwGeom::ExtentI(width, height));
184 
185  PTR(MaskedImageT) image;
186  try {
187  MaskedImageT mimg = _parentExposure->getMaskedImage();
188  image.reset(new MaskedImageT(mimg, bbox, afwImage::LOCAL, true)); // a deep copy
190  LSST_EXCEPT_ADD(e, "Extracting image of PSF candidate");
191  throw e;
192  }
193 
194  //
195  // Set INTRP and unset DETECTED for any pixels we don't want to deal with.
196  //
197  afwImage::MaskPixel const intrp = MaskedImageT::Mask::getPlaneBitMask("INTRP"); // mask bit for bad pixels
198  afwImage::MaskPixel const detected = MaskedImageT::Mask::getPlaneBitMask("DETECTED"); // object pixels
199 
200  // Mask out blended objects
201  if (getMaskBlends()) {
202  CONST_PTR(afwDetection::Footprint) foot = getSource()->getFootprint();
204  PeakCatalog const& peaks = foot->getPeaks();
205  if (peaks.size() > 1) {
206  // Mask all pixels in the footprint except for those closest to the central peak
208  PTR(afwDetection::PeakRecord) central;
209  for (PeakCatalog::const_iterator iter = peaks.begin(), end = peaks.end(); iter != end; ++iter) {
210  double const dist2 = distanceSquared(getXCenter(), getYCenter(), *iter);
211  if (dist2 < best) {
212  best = dist2;
213  central = iter;
214  }
215  }
216  assert(central); // We must have found something
217 
218  PeakCatalog others(peaks.getTable());
219  others.reserve(peaks.size() - 1);
220  for (PeakCatalog::const_iterator iter = peaks.begin(), end = peaks.end(); iter != end; ++iter) {
221  PTR(afwDetection::PeakRecord) ptr(iter);
222  if (central != ptr) {
223  others.push_back(ptr);
224  }
225  }
226 
227  BlendedFunctor<typename MaskedImageT::Mask::Pixel> functor(*central, others, detected, intrp);
228  foot->getSpans()->clippedTo(image->getBBox())->applyFunctor(functor, *image->getMask());
229  }
230  }
231 
232  /*
233  * Mask any DETECTED pixels other than the one in the center of the object;
234  * we grow the Footprint a bit first
235  */
236  typedef afwDetection::FootprintSet::FootprintList FootprintList;
237 
238  PTR(afwImage::Image<int>) mim = makeImageFromMask<int>(*image->getMask(), makeAndMask(detected));
240  std::make_shared<afwDetection::FootprintSet>(*mim, afwDetection::Threshold(1));
241  CONST_PTR(FootprintList) feet = fs->getFootprints();
242 
243  if (feet->size() > 1) {
244  int const ngrow = 3; // number of pixels to grow bad Footprints
245  //
246  // Go through Footprints looking for ones that don't contain cen
247  //
248  for (FootprintList::const_iterator fiter = feet->begin(); fiter != feet->end(); ++fiter) {
249  PTR(afwDetection::Footprint) foot = *fiter;
250  if (foot->contains(cen)) {
251  continue;
252  }
253 
254  // Dilate and clip to the image bounding box, incase the span grows outside the image
255  auto bigSpan = foot->getSpans()->dilated(ngrow)->clippedTo(image->getBBox());
256  bigSpan->clearMask(*image->getMask(), detected);
257  bigSpan->setMask(*image->getMask(), intrp);
258  }
259  }
260 
261  // Mask high pixels unconnected to the center
262  if (_pixelThreshold > 0.0) {
264  std::make_shared<afwDetection::FootprintSet>(*image,
266  for (FootprintList::const_iterator fpIter = fpSet->getFootprints()->begin();
267  fpIter != fpSet->getFootprints()->end(); ++fpIter) {
268  CONST_PTR(afwDetection::Footprint) fp = *fpIter;
269  if (!fp->contains(cen)) {
270  fp->getSpans()->clearMask(*image->getMask(), detected);
271  fp->getSpans()->setMask(*image->getMask(), intrp);
272  }
273  }
274  }
275 
276  return image;
277 }
278 
279 
285 template <typename PixelT>
287 measAlg::PsfCandidate<PixelT>::getMaskedImage(int width, int height) const {
288  if (!_image || (width != _image->getWidth() || height != _image->getHeight())) {
289  _image = extractImage(width, height);
290  }
291  return _image;
292 }
293 
299 template <typename PixelT>
301  int const width = getWidth() == 0 ? _defaultWidth : getWidth();
302  int const height = getHeight() == 0 ? _defaultWidth : getHeight();
303  return getMaskedImage(width, height);
304 }
305 
306 template <typename PixelT>
308  return _border;
309 }
310 
311 template <typename PixelT>
313  _border = border;
314 }
315 
316 template <typename PixelT>
318  _pixelThreshold = threshold;
319 }
320 
321 template <typename PixelT>
323  return _pixelThreshold;
324 }
325 
326 template <typename PixelT>
328  _doMaskBlends = doMaskBlends;
329 }
330 
331 template <typename PixelT>
333  return _doMaskBlends;
334 }
335 
341 template <typename PixelT>
343 measAlg::PsfCandidate<PixelT>::getOffsetImage(
344  std::string const algorithm, // Warping algorithm to use
345  unsigned int buffer // Buffer for warping
346 ) const {
347  unsigned int const width = getWidth() == 0 ? _defaultWidth : getWidth();
348  unsigned int const height = getHeight() == 0 ? _defaultWidth : getHeight();
349  if (_offsetImage && static_cast<unsigned int>(_offsetImage->getWidth()) == width + 2*buffer &&
350  static_cast<unsigned int>(_offsetImage->getHeight()) == height + 2*buffer) {
351  return _offsetImage;
352  }
353 
354  PTR(MaskedImageT) image = extractImage(width + 2*buffer, height + 2*buffer);
355 
356  double const xcen = getXCenter(), ycen = getYCenter();
357  double const dx = afwImage::positionToIndex(xcen, true).second;
358  double const dy = afwImage::positionToIndex(ycen, true).second;
359 
360  PTR(MaskedImageT) offset = afwMath::offsetImage(*image, -dx, -dy, algorithm);
361  afwGeom::Point2I llc(buffer, buffer);
362  afwGeom::Extent2I dims(width, height);
363  afwGeom::Box2I box(llc, dims);
364  _offsetImage.reset(new MaskedImageT(*offset, box, afwImage::LOCAL, true)); // Deep copy
365 
366  return _offsetImage;
367 }
368 
369 
370 /************************************************************************************************************/
371 //
372 // Explicit instantiations
373 //
375 typedef float Pixel;
376 //template class measAlg::PsfCandidate<afwImage::MaskedImage<Pixel> >;
377 template class measAlg::PsfCandidate<Pixel>;
static void setMaskBlends(bool doMaskBlends)
Set whether blends are masked.
afw::geom::Box2D bbox
std::vector< std::shared_ptr< Footprint > > FootprintList
boost::shared_ptr< afw::image::MaskedImage< PixelT > const > getMaskedImage() const
Return the image at the position of the Source, without any sub-pixel shifts to put the centre of the...
STL namespace.
static float getPixelThreshold()
Get threshold for rejecting pixels unconnected with the central footprint.
#define PTR(...)
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
Definition: mainpage.dox:13
#define CONST_PTR(...)
x_iterator row_begin(int y) const
static void setBorderWidth(int border)
Set the number of pixels to ignore around the candidate image&#39;s edge.
geom::Extent2I getDimensions() const
afw::table::CatalogT< PeakRecord > PeakCatalog
Class used by SpatialCell for spatial PSF fittig.
int end
static void setPixelThreshold(float threshold)
Set threshold for rejecting pixels unconnected with the central footprint.
static int getBorderWidth()
Return the number of pixels being ignored around the candidate image&#39;s edge.
T infinity(T... args)
CatalogIterator< typename Internal::const_iterator > const_iterator
T pow(T... args)
static bool getMaskBlends()
Get whether blends are masked.
#define LSST_EXCEPT_ADD(e, m)
ImageT val
Definition: CR.cc:158
Class stored in SpatialCells for spatial Psf fitting.
Definition: PsfCandidate.h:56
geom::Point2I getXY0() const