LSSTApplications  19.0.0-14-gb0260a2+72efe9b372,20.0.0+7927753e06,20.0.0+8829bf0056,20.0.0+995114c5d2,20.0.0+b6f4b2abd1,20.0.0+bddc4f4cbe,20.0.0-1-g253301a+8829bf0056,20.0.0-1-g2b7511a+0d71a2d77f,20.0.0-1-g5b95a8c+7461dd0434,20.0.0-12-g321c96ea+23efe4bbff,20.0.0-16-gfab17e72e+fdf35455f6,20.0.0-2-g0070d88+ba3ffc8f0b,20.0.0-2-g4dae9ad+ee58a624b3,20.0.0-2-g61b8584+5d3db074ba,20.0.0-2-gb780d76+d529cf1a41,20.0.0-2-ged6426c+226a441f5f,20.0.0-2-gf072044+8829bf0056,20.0.0-2-gf1f7952+ee58a624b3,20.0.0-20-geae50cf+e37fec0aee,20.0.0-25-g3dcad98+544a109665,20.0.0-25-g5eafb0f+ee58a624b3,20.0.0-27-g64178ef+f1f297b00a,20.0.0-3-g4cc78c6+e0676b0dc8,20.0.0-3-g8f21e14+4fd2c12c9a,20.0.0-3-gbd60e8c+187b78b4b8,20.0.0-3-gbecbe05+48431fa087,20.0.0-38-ge4adf513+a12e1f8e37,20.0.0-4-g97dc21a+544a109665,20.0.0-4-gb4befbc+087873070b,20.0.0-4-gf910f65+5d3db074ba,20.0.0-5-gdfe0fee+199202a608,20.0.0-5-gfbfe500+d529cf1a41,20.0.0-6-g64f541c+d529cf1a41,20.0.0-6-g9a5b7a1+a1cd37312e,20.0.0-68-ga3f3dda+5fca18c6a4,20.0.0-9-g4aef684+e18322736b,w.2020.45
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/geom.h"
35 #include "lsst/afw/image/Image.h"
38 
39 namespace lsst {
40 namespace meas {
41 namespace algorithms {
42 
43 /************************************************************************************************************/
44 /*
45  * PsfCandidate's members
46  */
47 template <typename PixelT>
48 int PsfCandidate<PixelT>::_border = 0;
49 template <typename PixelT>
50 int PsfCandidate<PixelT>::_defaultWidth = 21;
51 template <typename PixelT>
52 float PsfCandidate<PixelT>::_pixelThreshold = 0.0;
53 template <typename PixelT>
54 bool PsfCandidate<PixelT>::_doMaskBlends = true;
55 
56 /************************************************************************************************************/
57 namespace {
58 template <typename T> // functor used by makeImageFromMask to return inputMask
59 struct noop : public afw::image::pixelOp1<T> {
60  T operator()(T x) const { return x; }
61 };
62 
63 template <typename T> // functor used by makeImageFromMask to return (inputMask & mask)
64 struct andMask : public afw::image::pixelOp1<T> {
65  andMask(T mask) : _mask(mask) {}
66  T operator()(T x) const { return (x & _mask); }
67 
68 private:
69  T _mask;
70 };
71 
72 template <typename T>
73 andMask<T> makeAndMask(T val) {
74  return andMask<T>(val);
75 }
76 
77 /*
78  * Return an Image initialized from a Mask (possibly modified by func)
79  */
80 template <typename LhsT, typename RhsT>
82  afw::image::Mask<RhsT> const& rhs,
83  afw::image::pixelOp1<RhsT> const& func = noop<RhsT>()
84 ) {
86  std::make_shared<afw::image::Image<LhsT>>(rhs.getDimensions());
87  lhs->setXY0(rhs.getXY0());
88 
89  for (int y = 0; y != lhs->getHeight(); ++y) {
90  typename afw::image::Image<RhsT>::const_x_iterator rhsPtr = rhs.row_begin(y);
91 
92  for (typename afw::image::Image<LhsT>::x_iterator lhsPtr = lhs->row_begin(y),
93  lhsEnd = lhs->row_end(y);
94  lhsPtr != lhsEnd; ++rhsPtr, ++lhsPtr) {
95  *lhsPtr = func(*rhsPtr);
96  }
97  }
98 
99  return lhs;
100 }
101 
103 double distanceSquared(double x, double y, afw::detection::PeakRecord const& peak) {
104  return std::pow(peak.getIx() - x, 2) + std::pow(peak.getIy() - y, 2);
105 }
106 
111 template <typename MaskT>
112 class BlendedFunctor {
113 public:
114  BlendedFunctor(afw::detection::PeakRecord const& central,
115  afw::detection::PeakCatalog const& peaks,
116  afw::image::MaskPixel turnOff,
117  afw::image::MaskPixel turnOn
118  )
119  : _central(central), _peaks(peaks), _turnOff(~turnOff), _turnOn(turnOn) {}
120 
122  void operator()(geom::Point2I const& point, MaskT& val) {
123  int x = point.getX();
124  int y = point.getY();
125  double const central = distanceSquared(x, y, _central);
126  for (afw::detection::PeakCatalog::const_iterator iter = _peaks.begin(), end = _peaks.end();
127  iter != end; ++iter) {
128  double const dist2 = distanceSquared(x, y, *iter);
129  if (dist2 < central) {
130  val &= _turnOff;
131  val |= _turnOn;
132  }
133  }
134  }
135 
136 private:
137  afw::detection::PeakRecord const& _central;
138  afw::detection::PeakCatalog const& _peaks;
139  afw::image::MaskPixel const _turnOff;
140  afw::image::MaskPixel const _turnOn;
141 };
142 
143 } // anonymous namespace
144 
163 template <typename PixelT>
164 PTR(afw::image::MaskedImage<PixelT>)
165 PsfCandidate<PixelT>::extractImage(unsigned int width, // Width of image
166  unsigned int height // Height of image
167  ) const {
168  geom::Point2I const cen(afw::image::positionToIndex(getXCenter()),
169  afw::image::positionToIndex(getYCenter()));
170  geom::Point2I const llc(cen[0] - width / 2 - _parentExposure->getX0(),
171  cen[1] - height / 2 - _parentExposure->getY0());
172 
173  geom::BoxI bbox(llc, geom::ExtentI(width, height));
174 
175  PTR(MaskedImageT) image;
176  try {
177  MaskedImageT mimg = _parentExposure->getMaskedImage();
178  image.reset(new MaskedImageT(mimg, bbox, afw::image::LOCAL, true)); // a deep copy
179  } catch (pex::exceptions::LengthError& e) {
180  LSST_EXCEPT_ADD(e, "Extracting image of PSF candidate");
181  throw e;
182  }
183 
184  //
185  // Set INTRP and unset DETECTED for any pixels we don't want to deal with.
186  //
187  afw::image::MaskPixel const intrp =
188  MaskedImageT::Mask::getPlaneBitMask("INTRP"); // mask bit for bad pixels
189  afw::image::MaskPixel const detected = MaskedImageT::Mask::getPlaneBitMask("DETECTED"); // object pixels
190 
191  // Mask out blended objects
192  if (getMaskBlends()) {
193  CONST_PTR(afw::detection::Footprint) foot = getSource()->getFootprint();
195  PeakCatalog const& peaks = foot->getPeaks();
196  if (peaks.size() > 1) {
197  // Mask all pixels in the footprint except for those closest to the central peak
199  PTR(afw::detection::PeakRecord) central;
200  for (PeakCatalog::const_iterator iter = peaks.begin(), end = peaks.end(); iter != end; ++iter) {
201  double const dist2 = distanceSquared(getXCenter(), getYCenter(), *iter);
202  if (dist2 < best) {
203  best = dist2;
204  central = iter;
205  }
206  }
207  assert(central); // We must have found something
208 
209  PeakCatalog others(peaks.getTable());
210  others.reserve(peaks.size() - 1);
211  for (PeakCatalog::const_iterator iter = peaks.begin(), end = peaks.end(); iter != end; ++iter) {
212  PTR(afw::detection::PeakRecord) ptr(iter);
213  if (central != ptr) {
214  others.push_back(ptr);
215  }
216  }
217 
218  BlendedFunctor<typename MaskedImageT::Mask::Pixel> functor(*central, others, detected, intrp);
219  foot->getSpans()->clippedTo(image->getBBox())->applyFunctor(functor, *image->getMask());
220  }
221  }
222 
223  /*
224  * Mask any DETECTED pixels other than the one in the center of the object;
225  * we grow the Footprint a bit first
226  */
227  typedef afw::detection::FootprintSet::FootprintList FootprintList;
228 
229  PTR(afw::image::Image<int>) mim = makeImageFromMask<int>(*image->getMask(), makeAndMask(detected));
230  PTR(afw::detection::FootprintSet)
231  fs = std::make_shared<afw::detection::FootprintSet>(*mim, afw::detection::Threshold(1));
232  CONST_PTR(FootprintList) feet = fs->getFootprints();
233 
234  if (feet->size() > 1) {
235  int const ngrow = 3; // number of pixels to grow bad Footprints
236  //
237  // Go through Footprints looking for ones that don't contain cen
238  //
239  for (FootprintList::const_iterator fiter = feet->begin(); fiter != feet->end(); ++fiter) {
240  PTR(afw::detection::Footprint) foot = *fiter;
241  if (foot->contains(cen)) {
242  continue;
243  }
244 
245  // Dilate and clip to the image bounding box, incase the span grows outside the image
246  auto bigSpan = foot->getSpans()->dilated(ngrow)->clippedTo(image->getBBox());
247  bigSpan->clearMask(*image->getMask(), detected);
248  bigSpan->setMask(*image->getMask(), intrp);
249  }
250  }
251 
252  // Mask high pixels unconnected to the center
253  if (_pixelThreshold > 0.0) {
254  CONST_PTR(afw::detection::FootprintSet)
255  fpSet = std::make_shared<afw::detection::FootprintSet>(
256  *image, afw::detection::Threshold(_pixelThreshold, afw::detection::Threshold::PIXEL_STDEV));
257  for (FootprintList::const_iterator fpIter = fpSet->getFootprints()->begin();
258  fpIter != fpSet->getFootprints()->end(); ++fpIter) {
259  CONST_PTR(afw::detection::Footprint) fp = *fpIter;
260  if (!fp->contains(cen)) {
261  fp->getSpans()->clearMask(*image->getMask(), detected);
262  fp->getSpans()->setMask(*image->getMask(), intrp);
263  }
264  }
265  }
266 
267  return image;
268 }
269 
275 template <typename PixelT>
276 CONST_PTR(afw::image::MaskedImage<PixelT>)
277 PsfCandidate<PixelT>::getMaskedImage(int width, int height) const {
278  if (!_image || (width != _image->getWidth() || height != _image->getHeight())) {
279  _image = extractImage(width, height);
280  }
281  return _image;
282 }
283 
289 template <typename PixelT>
291 PsfCandidate<PixelT>::getMaskedImage() const {
292  int const width = getWidth() == 0 ? _defaultWidth : getWidth();
293  int const height = getHeight() == 0 ? _defaultWidth : getHeight();
294  return getMaskedImage(width, height);
295 }
296 
297 template <typename PixelT>
299  return _border;
300 }
301 
302 template <typename PixelT>
304  _border = border;
305 }
306 
307 template <typename PixelT>
309  _pixelThreshold = threshold;
310 }
311 
312 template <typename PixelT>
314  return _pixelThreshold;
315 }
316 
317 template <typename PixelT>
318 void PsfCandidate<PixelT>::setMaskBlends(bool doMaskBlends) {
319  _doMaskBlends = doMaskBlends;
320 }
321 
322 template <typename PixelT>
324  return _doMaskBlends;
325 }
326 
332 template <typename PixelT>
334 PsfCandidate<PixelT>::getOffsetImage(std::string const algorithm, // Warping algorithm to use
335  unsigned int buffer // Buffer for warping
336  ) const {
337  unsigned int const width = getWidth() == 0 ? _defaultWidth : getWidth();
338  unsigned int const height = getHeight() == 0 ? _defaultWidth : getHeight();
339  if (_offsetImage && static_cast<unsigned int>(_offsetImage->getWidth()) == width + 2 * buffer &&
340  static_cast<unsigned int>(_offsetImage->getHeight()) == height + 2 * buffer) {
341  return _offsetImage;
342  }
343 
344  PTR(MaskedImageT) image = extractImage(width + 2 * buffer, height + 2 * buffer);
345 
346  double const xcen = getXCenter(), ycen = getYCenter();
347  double const dx = afw::image::positionToIndex(xcen, true).second;
348  double const dy = afw::image::positionToIndex(ycen, true).second;
349 
350  PTR(MaskedImageT) offset = afw::math::offsetImage(*image, -dx, -dy, algorithm);
351  geom::Point2I llc(buffer, buffer);
352  geom::Extent2I dims(width, height);
353  geom::Box2I box(llc, dims);
354  _offsetImage.reset(new MaskedImageT(*offset, box, afw::image::LOCAL, true)); // Deep copy
355 
356  return _offsetImage;
357 }
358 
359 /************************************************************************************************************/
360 //
361 // Explicit instantiations
362 //
364 typedef float Pixel;
365 // template class PsfCandidate<afw::image::MaskedImage<Pixel> >;
366 template class PsfCandidate<Pixel>;
368 
369 } // namespace algorithms
370 } // namespace meas
371 } // namespace lsst
y
int y
Definition: SpanSet.cc:49
lsst::meas::algorithms::PsfCandidate::getMaskBlends
static bool getMaskBlends()
Get whether blends are masked.
Definition: PsfCandidate.cc:323
lsst::afw::table::CatalogT< PeakRecord >::const_iterator
CatalogIterator< typename Internal::const_iterator > const_iterator
Definition: Catalog.h:111
lsst::afw::image
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Definition: imageAlgorithm.dox:1
offsetImage.h
lsst::meas::algorithms::PsfCandidate::setMaskBlends
static void setMaskBlends(bool doMaskBlends)
Set whether blends are masked.
Definition: PsfCandidate.cc:318
lsst::afw::image::LOCAL
@ LOCAL
Definition: ImageBase.h:94
lsst::afw::detection::Threshold::PIXEL_STDEV
@ PIXEL_STDEV
Use number of sigma given per-pixel s.d.
Definition: Threshold.h:51
std::shared_ptr
STL class.
lsst::afw::image::positionToIndex
int positionToIndex(double pos)
Convert image position to nearest integer index.
Definition: ImageUtils.h:69
lsst::meas::modelfit::Pixel
float Pixel
Typedefs to be used for pixel values.
Definition: common.h:37
ImageAlgorithm.h
LSST_EXCEPT_ADD
#define LSST_EXCEPT_ADD(e, m)
Add the current location and a message to an existing exception before rethrowing it.
Definition: Exception.h:54
lsst::ip::diffim::detail::PixelT
float PixelT
Definition: AssessSpatialKernelVisitor.cc:208
lsst::afw::detection::FootprintSet::FootprintList
std::vector< std::shared_ptr< Footprint > > FootprintList
The FootprintSet's set of Footprints.
Definition: FootprintSet.h:56
val
ImageT val
Definition: CR.cc:146
mask
afw::table::Key< afw::table::Array< MaskPixelT > > mask
Definition: HeavyFootprint.cc:217
Image.h
PTR
#define PTR(...)
Definition: base.h:41
end
int end
Definition: BoundedField.cc:105
lsst::afw::image::MaskedImage< PixelT >
image
afw::table::Key< afw::table::Array< ImagePixelT > > image
Definition: HeavyFootprint.cc:216
std::numeric_limits::infinity
T infinity(T... args)
lsst::meas::algorithms::PsfCandidate::getBorderWidth
static int getBorderWidth()
Return the number of pixels being ignored around the candidate image's edge.
Definition: PsfCandidate.cc:298
lsst::meas::algorithms::PsfCandidate::setBorderWidth
static void setBorderWidth(int border)
Set the number of pixels to ignore around the candidate image's edge.
Definition: PsfCandidate.cc:303
x
double x
Definition: ChebyshevBoundedField.cc:277
lsst::afw::table::Footprint
lsst::afw::detection::Footprint Footprint
Definition: Source.h:59
lsst::afw::detection::PeakCatalog
afw::table::CatalogT< PeakRecord > PeakCatalog
Definition: Peak.h:244
Footprint.h
ptr
uint64_t * ptr
Definition: RangeSet.cc:88
PsfCandidate.h
Class used by SpatialCell for spatial PSF fittig.
lsst::afw::image::MaskPixel
std::int32_t MaskPixel
default type for Masks and MaskedImage Masks
Definition: LsstImageTypes.h:34
CONST_PTR
#define CONST_PTR(...)
A shared pointer to a const object.
Definition: base.h:47
lsst.pipe.tasks.mergeDetections.peak
peak
Definition: mergeDetections.py:380
lsst::afw::image::ImageBase::x_iterator
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:133
lsst
A base class for image defects.
Definition: imageAlgorithm.dox:1
lsst::meas::algorithms::PsfCandidate::getPixelThreshold
static float getPixelThreshold()
Get threshold for rejecting pixels unconnected with the central footprint.
Definition: PsfCandidate.cc:313
lsst::meas::algorithms::PsfCandidate
Class stored in SpatialCells for spatial Psf fitting.
Definition: PsfCandidate.h:55
std
STL namespace.
lsst::geom::Point< int, 2 >
lsst::afw::math::offsetImage
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
lsst::geom::Box2I
An integer coordinate rectangle.
Definition: Box.h:55
lsst::afw::image::ImageBase::const_x_iterator
_const_view_t::x_iterator const_x_iterator
A const iterator for traversing the pixels in a row.
Definition: ImageBase.h:141
lsst::meas::algorithms::PsfCandidate::setPixelThreshold
static void setPixelThreshold(float threshold)
Set threshold for rejecting pixels unconnected with the central footprint.
Definition: PsfCandidate.cc:308
lsst::geom::Extent< int, 2 >
astshim.fitsChanContinued.iter
def iter(self)
Definition: fitsChanContinued.py:88
geom.h
bbox
AmpInfoBoxKey bbox
Definition: Amplifier.cc:117
std::pow
T pow(T... args)