LSSTApplications  16.0-10-g0ee56ad+5,16.0-11-ga33d1f2+5,16.0-12-g3ef5c14+3,16.0-12-g71e5ef5+18,16.0-12-gbdf3636+3,16.0-13-g118c103+3,16.0-13-g8f68b0a+3,16.0-15-gbf5c1cb+4,16.0-16-gfd17674+3,16.0-17-g7c01f5c+3,16.0-18-g0a50484+1,16.0-20-ga20f992+8,16.0-21-g0e05fd4+6,16.0-21-g15e2d33+4,16.0-22-g62d8060+4,16.0-22-g847a80f+4,16.0-25-gf00d9b8+1,16.0-28-g3990c221+4,16.0-3-gf928089+3,16.0-32-g88a4f23+5,16.0-34-gd7987ad+3,16.0-37-gc7333cb+2,16.0-4-g10fc685+2,16.0-4-g18f3627+26,16.0-4-g5f3a788+26,16.0-5-gaf5c3d7+4,16.0-5-gcc1f4bb+1,16.0-6-g3b92700+4,16.0-6-g4412fcd+3,16.0-6-g7235603+4,16.0-69-g2562ce1b+2,16.0-8-g14ebd58+4,16.0-8-g2df868b+1,16.0-8-g4cec79c+6,16.0-8-gadf6c7a+1,16.0-8-gfc7ad86,16.0-82-g59ec2a54a+1,16.0-9-g5400cdc+2,16.0-9-ge6233d7+5,master-g2880f2d8cf+3,v17.0.rc1
LSSTDataManagementBasePackage
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
uint64_t * ptr
Definition: RangeSet.cc:88
static void setMaskBlends(bool doMaskBlends)
Set whether blends are masked.
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
int positionToIndex(double pos)
Convert image position to nearest integer index.
Definition: ImageUtils.h:69
std::vector< std::shared_ptr< Footprint > > FootprintList
The FootprintSet&#39;s set of Footprints.
Definition: FootprintSet.h:56
_const_view_t::x_iterator const_x_iterator
A const iterator for traversing the pixels in a row.
Definition: ImageBase.h:142
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:134
int y
Definition: SpanSet.cc:49
STL namespace.
static float getPixelThreshold()
Get threshold for rejecting pixels unconnected with the central footprint.
ImageT val
Definition: CR.cc:146
static void setBorderWidth(int border)
Set the number of pixels to ignore around the candidate image&#39;s edge.
A base class for image defects.
afw::table::CatalogT< PeakRecord > PeakCatalog
Definition: Peak.h:234
Class used by SpatialCell for spatial PSF fittig.
static void setPixelThreshold(float threshold)
Set threshold for rejecting pixels unconnected with the central footprint.
#define PTR(...)
Definition: base.h:41
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:74
static int getBorderWidth()
Return the number of pixels being ignored around the candidate image&#39;s edge.
#define CONST_PTR(...)
A shared pointer to a const object.
Definition: base.h:47
T infinity(T... args)
table::Box2IKey bbox
Definition: Detector.cc:166
std::int32_t MaskPixel
default type for Masks and MaskedImage Masks
Point< int, 2 > Point2I
Definition: Point.h:321
CatalogIterator< typename Internal::const_iterator > const_iterator
Definition: Catalog.h:111
double x
afw::table::Key< afw::table::Array< MaskPixelT > > mask
std::shared_ptr< ImageT > offsetImage(ImageT const &image, float dx, float dy, std::string const &algorithmName="lanczos5", unsigned int buffer=0)
Return an image offset by (dx, dy) using the specified algorithm.
Definition: offsetImage.cc:41
T pow(T... args)
Extent< int, 2 > ExtentI
Definition: Extent.h:396
lsst::afw::detection::Footprint Footprint
Definition: Source.h:61
afw::table::Key< afw::table::Array< ImagePixelT > > image
Use number of sigma given per-pixel s.d.
Definition: Threshold.h:51
static bool getMaskBlends()
Get whether blends are masked.
#define LSST_EXCEPT_ADD(e, m)
Add the current location and a message to an existing exception before rethrowing it...
Definition: Exception.h:54
An integer coordinate rectangle.
Definition: Box.h:54
int end
Class stored in SpatialCells for spatial Psf fitting.
Definition: PsfCandidate.h:57
Box2I BoxI
Definition: Box.h:528