lsst.meas.algorithms  16.0-19-gb830ed4e+16
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 
41 namespace lsst {
42 namespace meas {
43 namespace algorithms {
44 
45 /************************************************************************************************************/
46 /*
47  * PsfCandidate's members
48  */
49 template <typename PixelT>
50 int PsfCandidate<PixelT>::_border = 0;
51 template <typename PixelT>
52 int PsfCandidate<PixelT>::_defaultWidth = 21;
53 template <typename PixelT>
54 float PsfCandidate<PixelT>::_pixelThreshold = 0.0;
55 template <typename PixelT>
56 bool PsfCandidate<PixelT>::_doMaskBlends = true;
57 
58 /************************************************************************************************************/
59 namespace {
60 template <typename T> // functor used by makeImageFromMask to return inputMask
61 struct noop : public afw::image::pixelOp1<T> {
62  T operator()(T x) const { return x; }
63 };
64 
65 template <typename T> // functor used by makeImageFromMask to return (inputMask & mask)
66 struct andMask : public afw::image::pixelOp1<T> {
67  andMask(T mask) : _mask(mask) {}
68  T operator()(T x) const { return (x & _mask); }
69 
70 private:
71  T _mask;
72 };
73 
74 template <typename T>
75 andMask<T> makeAndMask(T val) {
76  return andMask<T>(val);
77 }
78 
79 /*
80  * Return an Image initialized from a Mask (possibly modified by func)
81  */
82 template <typename LhsT, typename RhsT>
84  afw::image::Mask<RhsT> const& rhs,
85  afw::image::pixelOp1<RhsT> const& func = noop<RhsT>()
86 ) {
88  std::make_shared<afw::image::Image<LhsT>>(rhs.getDimensions());
89  lhs->setXY0(rhs.getXY0());
90 
91  for (int y = 0; y != lhs->getHeight(); ++y) {
92  typename afw::image::Image<RhsT>::const_x_iterator rhsPtr = rhs.row_begin(y);
93 
94  for (typename afw::image::Image<LhsT>::x_iterator lhsPtr = lhs->row_begin(y),
95  lhsEnd = lhs->row_end(y);
96  lhsPtr != lhsEnd; ++rhsPtr, ++lhsPtr) {
97  *lhsPtr = func(*rhsPtr);
98  }
99  }
100 
101  return lhs;
102 }
103 
105 double distanceSquared(double x, double y, afw::detection::PeakRecord const& peak) {
106  return std::pow(peak.getIx() - x, 2) + std::pow(peak.getIy() - y, 2);
107 }
108 
113 template <typename MaskT>
114 class BlendedFunctor {
115 public:
116  BlendedFunctor(afw::detection::PeakRecord const& central,
117  afw::detection::PeakCatalog const& peaks,
118  afw::image::MaskPixel turnOff,
119  afw::image::MaskPixel turnOn
120  )
121  : _central(central), _peaks(peaks), _turnOff(~turnOff), _turnOn(turnOn) {}
122 
124  void operator()(geom::Point2I const& point, MaskT& val) {
125  int x = point.getX();
126  int y = point.getY();
127  double const central = distanceSquared(x, y, _central);
128  for (afw::detection::PeakCatalog::const_iterator iter = _peaks.begin(), end = _peaks.end();
129  iter != end; ++iter) {
130  double const dist2 = distanceSquared(x, y, *iter);
131  if (dist2 < central) {
132  val &= _turnOff;
133  val |= _turnOn;
134  }
135  }
136  }
137 
138 private:
139  afw::detection::PeakRecord const& _central;
140  afw::detection::PeakCatalog const& _peaks;
141  afw::image::MaskPixel const _turnOff;
142  afw::image::MaskPixel const _turnOn;
143 };
144 
145 } // anonymous namespace
146 
165 template <typename PixelT>
166 PTR(afw::image::MaskedImage<PixelT>)
167 PsfCandidate<PixelT>::extractImage(unsigned int width, // Width of image
168  unsigned int height // Height of image
169  ) const {
170  geom::Point2I const cen(afw::image::positionToIndex(getXCenter()),
171  afw::image::positionToIndex(getYCenter()));
172  geom::Point2I const llc(cen[0] - width / 2 - _parentExposure->getX0(),
173  cen[1] - height / 2 - _parentExposure->getY0());
174 
175  geom::BoxI bbox(llc, geom::ExtentI(width, height));
176 
177  PTR(MaskedImageT) image;
178  try {
179  MaskedImageT mimg = _parentExposure->getMaskedImage();
180  image.reset(new MaskedImageT(mimg, bbox, afw::image::LOCAL, true)); // a deep copy
181  } catch (pex::exceptions::LengthError& e) {
182  LSST_EXCEPT_ADD(e, "Extracting image of PSF candidate");
183  throw e;
184  }
185 
186  //
187  // Set INTRP and unset DETECTED for any pixels we don't want to deal with.
188  //
189  afw::image::MaskPixel const intrp =
190  MaskedImageT::Mask::getPlaneBitMask("INTRP"); // mask bit for bad pixels
191  afw::image::MaskPixel const detected = MaskedImageT::Mask::getPlaneBitMask("DETECTED"); // object pixels
192 
193  // Mask out blended objects
194  if (getMaskBlends()) {
195  CONST_PTR(afw::detection::Footprint) foot = getSource()->getFootprint();
197  PeakCatalog const& peaks = foot->getPeaks();
198  if (peaks.size() > 1) {
199  // Mask all pixels in the footprint except for those closest to the central peak
201  PTR(afw::detection::PeakRecord) central;
202  for (PeakCatalog::const_iterator iter = peaks.begin(), end = peaks.end(); iter != end; ++iter) {
203  double const dist2 = distanceSquared(getXCenter(), getYCenter(), *iter);
204  if (dist2 < best) {
205  best = dist2;
206  central = iter;
207  }
208  }
209  assert(central); // We must have found something
210 
211  PeakCatalog others(peaks.getTable());
212  others.reserve(peaks.size() - 1);
213  for (PeakCatalog::const_iterator iter = peaks.begin(), end = peaks.end(); iter != end; ++iter) {
214  PTR(afw::detection::PeakRecord) ptr(iter);
215  if (central != ptr) {
216  others.push_back(ptr);
217  }
218  }
219 
220  BlendedFunctor<typename MaskedImageT::Mask::Pixel> functor(*central, others, detected, intrp);
221  foot->getSpans()->clippedTo(image->getBBox())->applyFunctor(functor, *image->getMask());
222  }
223  }
224 
225  /*
226  * Mask any DETECTED pixels other than the one in the center of the object;
227  * we grow the Footprint a bit first
228  */
229  typedef afw::detection::FootprintSet::FootprintList FootprintList;
230 
231  PTR(afw::image::Image<int>) mim = makeImageFromMask<int>(*image->getMask(), makeAndMask(detected));
232  PTR(afw::detection::FootprintSet)
233  fs = std::make_shared<afw::detection::FootprintSet>(*mim, afw::detection::Threshold(1));
234  CONST_PTR(FootprintList) feet = fs->getFootprints();
235 
236  if (feet->size() > 1) {
237  int const ngrow = 3; // number of pixels to grow bad Footprints
238  //
239  // Go through Footprints looking for ones that don't contain cen
240  //
241  for (FootprintList::const_iterator fiter = feet->begin(); fiter != feet->end(); ++fiter) {
242  PTR(afw::detection::Footprint) foot = *fiter;
243  if (foot->contains(cen)) {
244  continue;
245  }
246 
247  // Dilate and clip to the image bounding box, incase the span grows outside the image
248  auto bigSpan = foot->getSpans()->dilated(ngrow)->clippedTo(image->getBBox());
249  bigSpan->clearMask(*image->getMask(), detected);
250  bigSpan->setMask(*image->getMask(), intrp);
251  }
252  }
253 
254  // Mask high pixels unconnected to the center
255  if (_pixelThreshold > 0.0) {
256  CONST_PTR(afw::detection::FootprintSet)
257  fpSet = std::make_shared<afw::detection::FootprintSet>(
258  *image, afw::detection::Threshold(_pixelThreshold, afw::detection::Threshold::PIXEL_STDEV));
259  for (FootprintList::const_iterator fpIter = fpSet->getFootprints()->begin();
260  fpIter != fpSet->getFootprints()->end(); ++fpIter) {
261  CONST_PTR(afw::detection::Footprint) fp = *fpIter;
262  if (!fp->contains(cen)) {
263  fp->getSpans()->clearMask(*image->getMask(), detected);
264  fp->getSpans()->setMask(*image->getMask(), intrp);
265  }
266  }
267  }
268 
269  return image;
270 }
271 
277 template <typename PixelT>
278 CONST_PTR(afw::image::MaskedImage<PixelT>)
279 PsfCandidate<PixelT>::getMaskedImage(int width, int height) const {
280  if (!_image || (width != _image->getWidth() || height != _image->getHeight())) {
281  _image = extractImage(width, height);
282  }
283  return _image;
284 }
285 
291 template <typename PixelT>
293 PsfCandidate<PixelT>::getMaskedImage() const {
294  int const width = getWidth() == 0 ? _defaultWidth : getWidth();
295  int const height = getHeight() == 0 ? _defaultWidth : getHeight();
296  return getMaskedImage(width, height);
297 }
298 
299 template <typename PixelT>
301  return _border;
302 }
303 
304 template <typename PixelT>
306  _border = border;
307 }
308 
309 template <typename PixelT>
311  _pixelThreshold = threshold;
312 }
313 
314 template <typename PixelT>
316  return _pixelThreshold;
317 }
318 
319 template <typename PixelT>
320 void PsfCandidate<PixelT>::setMaskBlends(bool doMaskBlends) {
321  _doMaskBlends = doMaskBlends;
322 }
323 
324 template <typename PixelT>
326  return _doMaskBlends;
327 }
328 
334 template <typename PixelT>
336 PsfCandidate<PixelT>::getOffsetImage(std::string const algorithm, // Warping algorithm to use
337  unsigned int buffer // Buffer for warping
338  ) const {
339  unsigned int const width = getWidth() == 0 ? _defaultWidth : getWidth();
340  unsigned int const height = getHeight() == 0 ? _defaultWidth : getHeight();
341  if (_offsetImage && static_cast<unsigned int>(_offsetImage->getWidth()) == width + 2 * buffer &&
342  static_cast<unsigned int>(_offsetImage->getHeight()) == height + 2 * buffer) {
343  return _offsetImage;
344  }
345 
346  PTR(MaskedImageT) image = extractImage(width + 2 * buffer, height + 2 * buffer);
347 
348  double const xcen = getXCenter(), ycen = getYCenter();
349  double const dx = afw::image::positionToIndex(xcen, true).second;
350  double const dy = afw::image::positionToIndex(ycen, true).second;
351 
352  PTR(MaskedImageT) offset = afw::math::offsetImage(*image, -dx, -dy, algorithm);
353  geom::Point2I llc(buffer, buffer);
354  geom::Extent2I dims(width, height);
355  geom::Box2I box(llc, dims);
356  _offsetImage.reset(new MaskedImageT(*offset, box, afw::image::LOCAL, true)); // Deep copy
357 
358  return _offsetImage;
359 }
360 
361 /************************************************************************************************************/
362 //
363 // Explicit instantiations
364 //
366 typedef float Pixel;
367 // template class PsfCandidate<afw::image::MaskedImage<Pixel> >;
368 template class PsfCandidate<Pixel>;
370 
371 } // namespace algorithms
372 } // namespace meas
373 } // namespace lsst
afw::table::Key< afw::table::Array< ImagePixelT > > image
static void setMaskBlends(bool doMaskBlends)
Set whether blends are masked.
geom::Box2D bbox
int positionToIndex(double pos)
std::vector< std::shared_ptr< Footprint > > FootprintList
_const_view_t::x_iterator const_x_iterator
_view_t::x_iterator x_iterator
STL namespace.
static float getPixelThreshold()
Get threshold for rejecting pixels unconnected with the central footprint.
#define PTR(...)
#define CONST_PTR(...)
static void setBorderWidth(int border)
Set the number of pixels to ignore around the candidate image&#39;s edge.
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)
std::int32_t MaskPixel
Point< int, 2 > Point2I
CatalogIterator< typename Internal::const_iterator > const_iterator
std::shared_ptr< ImageT > offsetImage(ImageT const &image, float dx, float dy, std::string const &algorithmName="lanczos5", unsigned int buffer=0)
T pow(T... args)
Extent< int, 2 > ExtentI
static bool getMaskBlends()
Get whether blends are masked.
#define LSST_EXCEPT_ADD(e, m)
ImageT val
Definition: CR.cc:146
int y
Class stored in SpatialCells for spatial Psf fitting.
Definition: PsfCandidate.h:57