LSSTApplications  11.0-13-gbb96280,12.1+18,12.1+7,12.1-1-g14f38d3+72,12.1-1-g16c0db7+5,12.1-1-g5961e7a+84,12.1-1-ge22e12b+23,12.1-11-g06625e2+4,12.1-11-g0d7f63b+4,12.1-19-gd507bfc,12.1-2-g7dda0ab+38,12.1-2-gc0bc6ab+81,12.1-21-g6ffe579+2,12.1-21-gbdb6c2a+4,12.1-24-g941c398+5,12.1-3-g57f6835+7,12.1-3-gf0736f3,12.1-37-g3ddd237,12.1-4-gf46015e+5,12.1-5-g06c326c+20,12.1-5-g648ee80+3,12.1-5-gc2189d7+4,12.1-6-ga608fc0+1,12.1-7-g3349e2a+5,12.1-7-gfd75620+9,12.1-9-g577b946+5,12.1-9-gc4df26a+10
LSSTDataManagementBasePackage
Namespaces | Classes | Typedefs | Functions
lsst::meas::algorithms Namespace Reference

Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations. More...

Namespaces

 astrometrySourceSelector
 
 debugger
 
 defects
 
 detection
 
 findCosmicRaysConfig
 
 flaggedStarSelector
 
 gaussianPsfFactory
 
 htmIndexer
 
 indexerRegistry
 
 ingestIndexReferenceTask
 
 installGaussianPsf
 
 interp
 
 loadIndexedReferenceObjects
 
 loadReferenceObjects
 
 makeCoaddApCorrMap
 
 matcherSourceSelector
 
 measureApCorr
 
 measureSourceUtils
 
 objectSizeStarSelector
 
 pcaPsfDeterminer
 
 psfDeterminer
 
 psfSelectionFromMatchList
 
 readFitsCatalogTask
 
 readTextCatalogTask
 
 secondMomentStarSelector
 
 sourceSelector
 
 starSelector
 
 subtractBackground
 
 testUtils
 
 utils
 
 version
 

Classes

class  CoaddPsf
 CoaddPsf is the Psf derived to be used for non-PSF-matched Coadd images. More...
 
class  evalChi2Visitor
 A class to pass around to all our PsfCandidates to evaluate the PSF fit's X^2. More...
 
class  MinimizeChi2
 
class  BinnedWcs
 
struct  CoaddBoundedFieldElement
 Struct used to hold one Exposure's data in a CoaddBoundedField. More...
 
class  CoaddBoundedField
 
class  DoubleGaussianPsf
 Represent a Psf as a circularly symmetrical double Gaussian. More...
 
class  ExposurePatch
 A convenience container for the exposure, peak and footprint that will be measured. More...
 
class  PsfImagePca
 
class  ImagePsf
 An intermediate base class for Psfs that use an image representation. More...
 
class  Defect
 Encapsulate information about a bad portion of a detector. More...
 
class  KernelPsf
 A Psf defined by a Kernel. More...
 
struct  KernelPsfPersistenceHelper
 A read-only singleton struct containing the schema and key used in persistence for KernelPsf. More...
 
class  KernelPsfFactory
 A PersistableFactory for KernelPsf and its subclasses. More...
 
class  PcaPsf
 Represent a PSF as a linear combination of PCA (== Karhunen-Loeve) basis functions. More...
 
class  PsfAttributes
 A class to contain various attributes of the Psf. More...
 
class  PsfCandidate
 Class stored in SpatialCells for spatial Psf fitting. More...
 
class  SingleGaussianPsf
 Represent a PSF as a circularly symmetrical Gaussian. More...
 
class  WarpedPsf
 A Psf class that maps an arbitrary Psf through a coordinate transformation. More...
 

Typedefs

typedef std::vector
< Defect::Ptr >
::const_iterator 
DefectCIter
 

Functions

afw::geom::Box2I getOverallBBox (std::vector< boost::shared_ptr< afw::image::Image< double > >> const &imgVector)
 
void addToImage (boost::shared_ptr< afw::image::Image< double > > image, std::vector< boost::shared_ptr< afw::image::Image< double > >> const &imgVector, std::vector< double > const &weightVector)
 
template<typename MaskedImageT >
std::vector
< detection::Footprint::Ptr
findCosmicRays (MaskedImageT &mimage, detection::Psf const &psf, double const bkgd, lsst::pex::policy::Policy const &policy, bool const keep)
 Find cosmic rays in an Image, and mask and remove them. More...
 
template<typename MaskedImageT >
void interpolateOverDefects (MaskedImageT &mimage, lsst::afw::detection::Psf const &, std::vector< Defect::Ptr > &_badList, double fallbackValue, bool useFallbackValueAtEdge)
 Process a set of known bad pixels in an image. More...
 
template<typename PixelT >
std::pair
< afwMath::LinearCombinationKernel::Ptr,
std::vector< double > > 
createKernelFromPsfCandidates (afwMath::SpatialCellSet const &psfCells, lsst::afw::geom::Extent2I const &dims, lsst::afw::geom::Point2I const &xy0, int const nEigenComponents, int const spatialOrder, int const ksize, int const nStarPerCell, bool const constantWeight, int const border)
 Return a Kernel::Ptr and a list of eigenvalues resulting from analysing the provided SpatialCellSet. More...
 
template<typename PixelT >
int countPsfCandidates (afwMath::SpatialCellSet const &psfCells, int const nStarPerCell)
 Count the number of candidates in use. More...
 
void setSpatialParameters (afwMath::Kernel *kernel, std::vector< double > const &coeffs)
 Fit a Kernel's spatial variability from a set of stars. More...
 
void setSpatialParameters (afwMath::Kernel *kernel, Eigen::VectorXd const &vec)
 Fit a Kernel's spatial variability from a set of stars. More...
 
template<typename PixelT >
std::pair< bool, double > fitSpatialKernelFromPsfCandidates (afwMath::Kernel *kernel, afwMath::SpatialCellSet const &psfCells, int const nStarPerCell, double const tolerance, double const lambda)
 Fit spatial kernel using full-nonlinear optimization to estimate candidate amplitudes. More...
 
template<typename PixelT >
std::pair< bool, double > fitSpatialKernelFromPsfCandidates (afwMath::Kernel *kernel, afwMath::SpatialCellSet const &psfCells, bool const doNonLinearFit, int const nStarPerCell, double const tolerance, double const lambda)
 
template<typename MaskedImageT >
double subtractPsf (afwDetection::Psf const &psf, MaskedImageT *data, double x, double y, double psfFlux)
 Subtract a PSF from an image at a given position. More...
 
template<typename Image >
std::pair< std::vector< double >
, afwMath::KernelList
fitKernelParamsToImage (afwMath::LinearCombinationKernel const &kernel, Image const &image, afwGeom::Point2D const &pos)
 Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary. More...
 
template<typename Image >
std::pair
< afwMath::Kernel::Ptr,
std::pair< double, double > > 
fitKernelToImage (afwMath::LinearCombinationKernel const &kernel, Image const &image, afwGeom::Point2D const &pos)
 Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary. More...
 
 LSST_EXCEPTION_TYPE (NotImplementedException, lsst::pex::exceptions::RuntimeError, lsst::meas::algorithms::NotImplementedException)
 An exception that indicates the feature has not been implemented. More...
 
template<typename MaskedImageT >
std::vector< std::shared_ptr
< lsst::afw::detection::Footprint > > 
findCosmicRays (MaskedImageT &image, lsst::afw::detection::Psf const &psf, double const bkgd, lsst::pex::policy::Policy const &policy, bool const keep=false)
 Find cosmic rays in an Image, and mask and remove them. More...
 
template<typename ExposureT >
boost::shared_ptr
< ExposurePatch< ExposureT > > 
makeExposurePatch (boost::shared_ptr< ExposureT const > exp, boost::shared_ptr< afw::detection::Footprint const > foot, afw::geom::Point2D const &center)
 Factory function for ExposurePatch. More...
 
template<typename ExposureT >
boost::shared_ptr
< ExposurePatch< ExposureT > > 
makeExposurePatch (boost::shared_ptr< ExposureT const > exp, afw::detection::Footprint const &standardFoot, afw::geom::Point2D const &standardCenter, afw::image::Wcs const &standardWcs)
 
template<typename PixelT >
std::shared_ptr< PsfCandidate
< PixelT > > 
makePsfCandidate (boost::shared_ptr< afw::table::SourceRecord > const &source, boost::shared_ptr< afw::image::Exposure< PixelT > > image)
 Return a PsfCandidate of the right sort. More...
 
template<typename PixelT >
std::pair
< lsst::afw::math::LinearCombinationKernel::Ptr,
std::vector< double > > 
createKernelFromPsfCandidates (lsst::afw::math::SpatialCellSet const &psfCells, lsst::afw::geom::Extent2I const &dims, lsst::afw::geom::Point2I const &xy0, int const nEigenComponents, int const spatialOrder, int const ksize, int const nStarPerCell=-1, bool const constantWeight=true, int const border=3)
 Return a Kernel::Ptr and a list of eigenvalues resulting from analysing the provided SpatialCellSet. More...
 
template<typename ImageT >
double subtractPsf (lsst::afw::detection::Psf const &psf, ImageT *data, double x, double y, double psfFlux=std::numeric_limits< double >::quiet_NaN())
 
template<typename Image >
std::pair< std::vector< double >
, lsst::afw::math::KernelList
fitKernelParamsToImage (lsst::afw::math::LinearCombinationKernel const &kernel, Image const &image, lsst::afw::geom::Point2D const &pos)
 Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary. More...
 
template<typename Image >
std::pair
< lsst::afw::math::Kernel::Ptr,
std::pair< double, double > > 
fitKernelToImage (lsst::afw::math::LinearCombinationKernel const &kernel, Image const &image, lsst::afw::geom::Point2D const &pos)
 Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary. More...
 

Detailed Description

Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.

Typedef Documentation

typedef std::vector<Defect::Ptr>::const_iterator lsst::meas::algorithms::DefectCIter

Definition at line 52 of file Interp.cc.

Function Documentation

void lsst::meas::algorithms::addToImage ( boost::shared_ptr< afw::image::Image< double > >  image,
std::vector< boost::shared_ptr< afw::image::Image< double > >> const &  imgVector,
std::vector< double > const &  weightVector 
)

Definition at line 198 of file CoaddPsf.cc.

202  {
203  assert(imgVector.size() == weightVector.size());
204  for (unsigned int i = 0; i < imgVector.size(); i ++) {
205  PTR(afw::image::Image<double>) componentImg = imgVector[i];
206  double weight = weightVector[i];
207  double sum = componentImg->getArray().asEigen().sum();
208 
209  // Now get the portion of the component image which is appropriate to add
210  // If the default image size is used, the component is guaranteed to fit,
211  // but not if a size has been specified.
212  afw::geom::Box2I cBBox = componentImg->getBBox();
213  afw::geom::Box2I overlap(cBBox);
214  overlap.clip(image->getBBox());
215  // JFB: A subimage view of the image we want to add to, containing only the overlap region.
216  afw::image::Image<double> targetSubImage(*image, overlap);
217  // JFB: A subimage view of the image we want to add from, containing only the overlap region.
218  afw::image::Image<double> cSubImage(*componentImg, overlap);
219  targetSubImage.scaledPlus(weight/sum, cSubImage);
220  }
221 }
void scaledPlus(OutImageT &outImage, double c1, InImageT const &inImage1, double c2, InImageT const &inImage2)
Compute the scaled sum of two images.
tbl::Key< double > weight
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
#define PTR(...)
Definition: base.h:41
template<typename PixelT >
int lsst::meas::algorithms::countPsfCandidates ( afwMath::SpatialCellSet const &  psfCells,
int const  nStarPerCell 
)

Count the number of candidates in use.

Definition at line 352 of file SpatialModelPsf.cc.

354 {
355  countVisitor<PixelT> counter;
356  psfCells.visitCandidates(&counter, nStarPerCell);
357 
358  return counter.getN();
359 }
template<typename PixelT >
std::pair<lsst::afw::math::LinearCombinationKernel::Ptr, std::vector<double> > lsst::meas::algorithms::createKernelFromPsfCandidates ( afwMath::SpatialCellSet const &  psfCells,
lsst::afw::geom::Extent2I const &  dims,
lsst::afw::geom::Point2I const &  xy0,
int const  nEigenComponents,
int const  spatialOrder,
int const  ksize,
int const  nStarPerCell,
bool const  constantWeight,
int const  border 
)

Return a Kernel::Ptr and a list of eigenvalues resulting from analysing the provided SpatialCellSet.

The Kernel is a LinearCombinationKernel of the first nEigenComponents eigenImages

N.b. This is templated over the Pixel type of the science image

Parameters
psfCellsA SpatialCellSet containing PsfCandidates
dimsDimensions of image
xy0Origin of image
nEigenComponentsnumber of eigen components to keep; <= 0 => infty
spatialOrderOrder of spatial variation (cf. afw::math::PolynomialFunction2)
ksizeSize of generated Kernel images
nStarPerCellmax no. of stars per cell; <= 0 => infty
constantWeightshould each star have equal weight in the fit?
borderBorder size for background subtraction

Definition at line 206 of file SpatialModelPsf.cc.

217 {
218  typedef typename afwImage::Image<PixelT> ImageT;
219  typedef typename afwImage::MaskedImage<PixelT> MaskedImageT;
220  typedef typename afwImage::Exposure<PixelT> ExposureT;
221 
222  //
223  // Set the sizes for PsfCandidates made from either Images or MaskedImages
224  //
225  //lsst::meas::algorithms::PsfCandidate<ImageT>::setWidth(ksize);
226  //lsst::meas::algorithms::PsfCandidate<ImageT>::setHeight(ksize);
227  //lsst::meas::algorithms::PsfCandidate<MaskedImageT>::setWidth(ksize);
228  //lsst::meas::algorithms::PsfCandidate<MaskedImageT>::setHeight(ksize);
231 
232 
233  PsfImagePca<MaskedImageT> imagePca(constantWeight, border); // Here's the set of images we'll analyze
234 
235  {
236  SetPcaImageVisitor<PixelT> importStarVisitor(&imagePca);
237  bool const ignoreExceptions = true;
238  psfCells.visitCandidates(&importStarVisitor, nStarPerCell, ignoreExceptions);
239  }
240 
241  //
242  // Do a PCA decomposition of those PSF candidates.
243  //
244  // We have "gappy" data; in other words we don't want to include any pixels with INTRP set
245  //
246  int niter = 10; // number of iterations of updateBadPixels
247  double deltaLim = 10.0; // acceptable value of delta, the max change due to updateBadPixels
251 
252  for (int i = 0; i != niter; ++i) {
253  int const ncomp = (i == 0) ? 0 :
254  ((nEigenComponents == 0) ? imagePca.getEigenImages().size() : nEigenComponents);
255  double delta = imagePca.updateBadPixels(BAD | CR | INTRP, ncomp);
256  if (i > 0 && delta < deltaLim) {
257  break;
258  }
259 
260  imagePca.analyze();
261  }
262 
263  std::vector<typename MaskedImageT::Ptr> eigenImages = imagePca.getEigenImages();
264  std::vector<double> eigenValues = imagePca.getEigenValues();
265  int const nEigen = static_cast<int>(eigenValues.size());
266 
267  int const ncomp = (nEigenComponents <= 0 || nEigen < nEigenComponents) ? nEigen : nEigenComponents;
268  //
269  // Set the background level of the components to 0.0 to avoid coupling variable background
270  // levels to the form of the Psf. More precisely, we calculate the mean of an outer "annulus"
271  // of width bkg_border
272  //
273  for (int k = 0; k != ncomp; ++k) {
274  ImageT const& im = *eigenImages[k]->getImage();
275 
276  int bkg_border = 2;
277  if (bkg_border > im.getWidth()) {
278  bkg_border = im.getWidth() / 2;
279  }
280  if (bkg_border > im.getHeight()) {
281  bkg_border = im.getHeight() / 2;
282  }
283 
284  double sum = 0;
285  // Bottom and Top borders
286  for (int i = 0; i != bkg_border; ++i) {
287  typename ImageT::const_x_iterator
288  ptrB = im.row_begin(i), ptrT = im.row_begin(im.getHeight() - i - 1);
289  for (int j = 0; j != im.getWidth(); ++j, ++ptrB, ++ptrT) {
290  sum += *ptrB + *ptrT;
291  }
292  }
293  for (int i = bkg_border; i < im.getHeight() - bkg_border; ++i) {
294  // Left and Right borders
295  typename ImageT::const_x_iterator
296  ptrL = im.row_begin(i), ptrR = im.row_begin(i) + im.getWidth() - bkg_border;
297  for (int j = 0; j != bkg_border; ++j, ++ptrL, ++ptrR) {
298  sum += *ptrL + *ptrR;
299  }
300  }
301  sum /= 2*(bkg_border*im.getWidth() + bkg_border*(im.getHeight() - 2*bkg_border));
302 
303  *eigenImages[k] -= sum;
304  }
305  //
306  // Now build our LinearCombinationKernel; build the lists of basis functions
307  // and spatial variation, then assemble the Kernel
308  //
309  afwMath::KernelList kernelList;
310  std::vector<afwMath::Kernel::SpatialFunctionPtr> spatialFunctionList;
312 
313  for (int i = 0; i != ncomp; ++i) {
314  {
315  // Enforce unit sum for kernel by construction
316  // Zeroth component has unit sum
317  // Other components have zero sum by normalising and then subtracting the zeroth component
318  ImageT& image = *eigenImages[i]->getImage();
319  double sum = std::accumulate(image.begin(true), image.end(true), 0.0);
320  if (i == 0) {
321  image /= sum;
322  } else {
323  for (typename ImageT::fast_iterator ptr0 = eigenImages[0]->getImage()->begin(true),
324  ptr1 = image.begin(true), end = image.end(true); ptr1 != end; ++ptr0, ++ptr1) {
325  *ptr1 = *ptr1 / sum - *ptr0;
326  }
327  }
328  }
329 
330  kernelList.push_back(afwMath::Kernel::Ptr(new afwMath::FixedKernel(
331  afwImage::Image<afwMath::Kernel::Pixel>(*eigenImages[i]->getImage(),true)
332  )));
333 
335 // spatialFunction(new afwMath::PolynomialFunction2<double>(spatialOrder));
336  spatialFunction(new afwMath::Chebyshev1Function2<double>(spatialOrder, range));
337  spatialFunction->setParameter(0, 1.0); // the constant term; all others are 0
338  spatialFunctionList.push_back(spatialFunction);
339  }
340 
342  psf(new afwMath::LinearCombinationKernel(kernelList, spatialFunctionList));
343 
344  return std::make_pair(psf, eigenValues);
345 }
2-dimensional weighted sum of Chebyshev polynomials of the first kind.
std::uint16_t MaskPixel
boost::shared_ptr< lsst::afw::math::Function2< double > > SpatialFunctionPtr
Definition: Kernel.h:140
static void setHeight(int height)
Set the height of the image that getImage should return.
Definition: SpatialCell.h:153
A class to contain the data, WCS, and other information needed to describe an image of the sky...
Definition: Exposure.h:46
boost::shared_ptr< LinearCombinationKernel > Ptr
Definition: Kernel.h:815
A coordinate class intended to represent absolute positions.
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
boost::shared_ptr< Kernel > Ptr
Definition: Kernel.h:138
A kernel that is a linear combination of fixed basis kernels.
Definition: Kernel.h:811
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:78
static MaskPixelT getPlaneBitMask(const std::vector< std::string > &names)
Return the bitmask corresponding to a vector of plane names OR&#39;d together.
Definition: Mask.cc:860
static void setWidth(int width)
Set the width of the image that getImage should return.
Definition: SpatialCell.h:146
A floating-point coordinate rectangle geometry.
Definition: Box.h:271
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:416
A kernel created from an Image.
Definition: Kernel.h:548
std::vector< boost::shared_ptr< Kernel > > KernelList
Definition: Kernel.h:539
template<typename PixelT >
std::pair<afwMath::LinearCombinationKernel::Ptr, std::vector<double> > lsst::meas::algorithms::createKernelFromPsfCandidates ( afwMath::SpatialCellSet const &  psfCells,
lsst::afw::geom::Extent2I const &  dims,
lsst::afw::geom::Point2I const &  xy0,
int const  nEigenComponents,
int const  spatialOrder,
int const  ksize,
int const  nStarPerCell,
bool const  constantWeight,
int const  border 
)

Return a Kernel::Ptr and a list of eigenvalues resulting from analysing the provided SpatialCellSet.

The Kernel is a LinearCombinationKernel of the first nEigenComponents eigenImages

N.b. This is templated over the Pixel type of the science image

Parameters
psfCellsA SpatialCellSet containing PsfCandidates
dimsDimensions of image
xy0Origin of image
nEigenComponentsnumber of eigen components to keep; <= 0 => infty
spatialOrderOrder of spatial variation (cf. afw::math::PolynomialFunction2)
ksizeSize of generated Kernel images
nStarPerCellmax no. of stars per cell; <= 0 => infty
constantWeightshould each star have equal weight in the fit?
borderBorder size for background subtraction

Definition at line 206 of file SpatialModelPsf.cc.

217 {
218  typedef typename afwImage::Image<PixelT> ImageT;
219  typedef typename afwImage::MaskedImage<PixelT> MaskedImageT;
220  typedef typename afwImage::Exposure<PixelT> ExposureT;
221 
222  //
223  // Set the sizes for PsfCandidates made from either Images or MaskedImages
224  //
225  //lsst::meas::algorithms::PsfCandidate<ImageT>::setWidth(ksize);
226  //lsst::meas::algorithms::PsfCandidate<ImageT>::setHeight(ksize);
227  //lsst::meas::algorithms::PsfCandidate<MaskedImageT>::setWidth(ksize);
228  //lsst::meas::algorithms::PsfCandidate<MaskedImageT>::setHeight(ksize);
231 
232 
233  PsfImagePca<MaskedImageT> imagePca(constantWeight, border); // Here's the set of images we'll analyze
234 
235  {
236  SetPcaImageVisitor<PixelT> importStarVisitor(&imagePca);
237  bool const ignoreExceptions = true;
238  psfCells.visitCandidates(&importStarVisitor, nStarPerCell, ignoreExceptions);
239  }
240 
241  //
242  // Do a PCA decomposition of those PSF candidates.
243  //
244  // We have "gappy" data; in other words we don't want to include any pixels with INTRP set
245  //
246  int niter = 10; // number of iterations of updateBadPixels
247  double deltaLim = 10.0; // acceptable value of delta, the max change due to updateBadPixels
251 
252  for (int i = 0; i != niter; ++i) {
253  int const ncomp = (i == 0) ? 0 :
254  ((nEigenComponents == 0) ? imagePca.getEigenImages().size() : nEigenComponents);
255  double delta = imagePca.updateBadPixels(BAD | CR | INTRP, ncomp);
256  if (i > 0 && delta < deltaLim) {
257  break;
258  }
259 
260  imagePca.analyze();
261  }
262 
263  std::vector<typename MaskedImageT::Ptr> eigenImages = imagePca.getEigenImages();
264  std::vector<double> eigenValues = imagePca.getEigenValues();
265  int const nEigen = static_cast<int>(eigenValues.size());
266 
267  int const ncomp = (nEigenComponents <= 0 || nEigen < nEigenComponents) ? nEigen : nEigenComponents;
268  //
269  // Set the background level of the components to 0.0 to avoid coupling variable background
270  // levels to the form of the Psf. More precisely, we calculate the mean of an outer "annulus"
271  // of width bkg_border
272  //
273  for (int k = 0; k != ncomp; ++k) {
274  ImageT const& im = *eigenImages[k]->getImage();
275 
276  int bkg_border = 2;
277  if (bkg_border > im.getWidth()) {
278  bkg_border = im.getWidth() / 2;
279  }
280  if (bkg_border > im.getHeight()) {
281  bkg_border = im.getHeight() / 2;
282  }
283 
284  double sum = 0;
285  // Bottom and Top borders
286  for (int i = 0; i != bkg_border; ++i) {
287  typename ImageT::const_x_iterator
288  ptrB = im.row_begin(i), ptrT = im.row_begin(im.getHeight() - i - 1);
289  for (int j = 0; j != im.getWidth(); ++j, ++ptrB, ++ptrT) {
290  sum += *ptrB + *ptrT;
291  }
292  }
293  for (int i = bkg_border; i < im.getHeight() - bkg_border; ++i) {
294  // Left and Right borders
295  typename ImageT::const_x_iterator
296  ptrL = im.row_begin(i), ptrR = im.row_begin(i) + im.getWidth() - bkg_border;
297  for (int j = 0; j != bkg_border; ++j, ++ptrL, ++ptrR) {
298  sum += *ptrL + *ptrR;
299  }
300  }
301  sum /= 2*(bkg_border*im.getWidth() + bkg_border*(im.getHeight() - 2*bkg_border));
302 
303  *eigenImages[k] -= sum;
304  }
305  //
306  // Now build our LinearCombinationKernel; build the lists of basis functions
307  // and spatial variation, then assemble the Kernel
308  //
309  afwMath::KernelList kernelList;
310  std::vector<afwMath::Kernel::SpatialFunctionPtr> spatialFunctionList;
312 
313  for (int i = 0; i != ncomp; ++i) {
314  {
315  // Enforce unit sum for kernel by construction
316  // Zeroth component has unit sum
317  // Other components have zero sum by normalising and then subtracting the zeroth component
318  ImageT& image = *eigenImages[i]->getImage();
319  double sum = std::accumulate(image.begin(true), image.end(true), 0.0);
320  if (i == 0) {
321  image /= sum;
322  } else {
323  for (typename ImageT::fast_iterator ptr0 = eigenImages[0]->getImage()->begin(true),
324  ptr1 = image.begin(true), end = image.end(true); ptr1 != end; ++ptr0, ++ptr1) {
325  *ptr1 = *ptr1 / sum - *ptr0;
326  }
327  }
328  }
329 
330  kernelList.push_back(afwMath::Kernel::Ptr(new afwMath::FixedKernel(
331  afwImage::Image<afwMath::Kernel::Pixel>(*eigenImages[i]->getImage(),true)
332  )));
333 
335 // spatialFunction(new afwMath::PolynomialFunction2<double>(spatialOrder));
336  spatialFunction(new afwMath::Chebyshev1Function2<double>(spatialOrder, range));
337  spatialFunction->setParameter(0, 1.0); // the constant term; all others are 0
338  spatialFunctionList.push_back(spatialFunction);
339  }
340 
342  psf(new afwMath::LinearCombinationKernel(kernelList, spatialFunctionList));
343 
344  return std::make_pair(psf, eigenValues);
345 }
2-dimensional weighted sum of Chebyshev polynomials of the first kind.
std::uint16_t MaskPixel
boost::shared_ptr< lsst::afw::math::Function2< double > > SpatialFunctionPtr
Definition: Kernel.h:140
static void setHeight(int height)
Set the height of the image that getImage should return.
Definition: SpatialCell.h:153
A class to contain the data, WCS, and other information needed to describe an image of the sky...
Definition: Exposure.h:46
boost::shared_ptr< LinearCombinationKernel > Ptr
Definition: Kernel.h:815
A coordinate class intended to represent absolute positions.
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
boost::shared_ptr< Kernel > Ptr
Definition: Kernel.h:138
A kernel that is a linear combination of fixed basis kernels.
Definition: Kernel.h:811
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:78
static MaskPixelT getPlaneBitMask(const std::vector< std::string > &names)
Return the bitmask corresponding to a vector of plane names OR&#39;d together.
Definition: Mask.cc:860
static void setWidth(int width)
Set the width of the image that getImage should return.
Definition: SpatialCell.h:146
A floating-point coordinate rectangle geometry.
Definition: Box.h:271
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:416
A kernel created from an Image.
Definition: Kernel.h:548
std::vector< boost::shared_ptr< Kernel > > KernelList
Definition: Kernel.h:539
template<typename MaskedImageT >
std::vector<std::shared_ptr<lsst::afw::detection::Footprint> > lsst::meas::algorithms::findCosmicRays ( MaskedImageT &  mimage,
detection::Psf const &  psf,
double const  bkgd,
lsst::pex::policy::Policy const &  policy,
bool const  keep 
)

Find cosmic rays in an Image, and mask and remove them.

Returns
vector of CR's Footprints

In this loop, we look for strings of CRpixels on the same row and adjoining columns; each of these becomes a Span with a unique ID.

Parameters
mimageImage to search
psfthe Image's PSF
bkgdunsubtracted background of frame, DN
policyPolicy directing the behavior
keepif true, don't remove the CRs

Definition at line 346 of file CR.cc.

351  {
352  typedef typename MaskedImageT::Image ImageT;
353  typedef typename ImageT::Pixel ImagePixel;
354  typedef typename MaskedImageT::Mask::Pixel MaskPixel;
355 
356  // Parse the Policy
357  double const minSigma = policy.getDouble("minSigma"); // min sigma over sky in pixel for CR candidate
358  double const minDn = policy.getDouble("min_DN"); // min number of DN in an CRs
359  double const cond3Fac = policy.getDouble("cond3_fac"); // fiddle factor for condition #3
360  double const cond3Fac2 = policy.getDouble("cond3_fac2"); // 2nd fiddle factor for condition #3
361  int const niteration = policy.getInt("niteration"); // Number of times to look for contaminated
362  // pixels near CRs
363  int const nCrPixelMax = policy.getInt("nCrPixelMax"); // maximum number of contaminated pixels
364 /*
365  * thresholds for 3rd condition
366  *
367  * Realise PSF at center of image
368  */
369  lsst::afw::math::Kernel::ConstPtr kernel = psf.getLocalKernel();
370  if (!kernel) {
371  throw LSST_EXCEPT(pexExcept::NotFoundError, "Psf is unable to return a kernel");
372  }
373  detection::Psf::Image psfImage = detection::Psf::Image(geom::ExtentI(kernel->getWidth(), kernel->getHeight()));
374  kernel->computeImage(psfImage, true);
375 
376  int const xc = kernel->getCtrX(); // center of PSF
377  int const yc = kernel->getCtrY();
378 
379  double const I0 = psfImage(xc, yc);
380  double const thresH = cond3Fac2*(0.5*(psfImage(xc - 1, yc) + psfImage(xc + 1, yc)))/I0; // horizontal
381  double const thresV = cond3Fac2*(0.5*(psfImage(xc, yc - 1) + psfImage(xc, yc + 1)))/I0; // vertical
382  double const thresD = cond3Fac2*(0.25*(psfImage(xc - 1, yc - 1) + psfImage(xc + 1, yc + 1) +
383  psfImage(xc - 1, yc + 1) + psfImage(xc + 1, yc - 1)))/I0; // diag
384 /*
385  * Setup desired mask planes
386  */
387  MaskPixel const badBit = mimage.getMask()->getPlaneBitMask("BAD"); // Generic bad pixels
388  MaskPixel const crBit = mimage.getMask()->getPlaneBitMask("CR"); // CR-contaminated pixels
389  MaskPixel const interpBit = mimage.getMask()->getPlaneBitMask("INTRP"); // Interpolated pixels
390  MaskPixel const saturBit = mimage.getMask()->getPlaneBitMask("SAT"); // Saturated pixels
391  MaskPixel const nodataBit = mimage.getMask()->getPlaneBitMask("NO_DATA"); // Non data pixels
392 
393  MaskPixel const badMask = (badBit | interpBit | saturBit | nodataBit); // naughty pixels
394 /*
395  * Go through the frame looking at each pixel (except the edge ones which we ignore)
396  */
397  int const ncol = mimage.getWidth();
398  int const nrow = mimage.getHeight();
399 
400  std::vector<CRPixel<ImagePixel> > crpixels; // storage for detected CR-contaminated pixels
401  typedef typename std::vector<CRPixel<ImagePixel> >::iterator crpixel_iter;
402  typedef typename std::vector<CRPixel<ImagePixel> >::reverse_iterator crpixel_riter;
403 
404  for (int j = 1; j < nrow - 1; ++j) {
405  typename MaskedImageT::xy_locator loc = mimage.xy_at(1, j); // locator for data
406 
407  for (int i = 1; i < ncol - 1; ++i, ++loc.x()) {
408  ImagePixel corr = 0;
409  if (!is_cr_pixel<MaskedImageT>(&corr, loc, minSigma,
410  thresH, thresV, thresD, bkgd, cond3Fac)) {
411  continue;
412  }
413 /*
414  * condition #4
415  */
416  if (loc.mask() & badMask) {
417  continue;
418  }
419  if ((loc.mask(-1, 1) | loc.mask(0, 1) | loc.mask(1, 1) |
420  loc.mask(-1, 0) | loc.mask(1, 0) |
421  loc.mask(-1, -1) | loc.mask(0, -1) | loc.mask(1, -1)) & interpBit) {
422  continue;
423  }
424 /*
425  * OK, it's a CR
426  *
427  * replace CR-contaminated pixels with reasonable values as we go through
428  * image, which increases the detection rate
429  */
430  crpixels.push_back(CRPixel<ImagePixel>(i + mimage.getX0(), j + mimage.getY0(), loc.image()));
431  loc.image() = corr; /* just a preliminary estimate */
432 
433  if (static_cast<int>(crpixels.size()) > nCrPixelMax) {
434  reinstateCrPixels(mimage.getImage().get(), crpixels);
435 
436  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
437  (boost::format("Too many CR pixels (max %d)") % nCrPixelMax).str());
438  }
439  }
440  }
441 /*
442  * We've found them on a pixel-by-pixel basis, now merge those pixels
443  * into cosmic rays
444  */
445  std::vector<int> aliases; // aliases for initially disjoint parts of CRs
446  aliases.reserve(1 + crpixels.size()/2); // initial size of aliases
447 
448  std::vector<detection::IdSpan::Ptr> spans; // y:x0,x1 for objects
449  spans.reserve(aliases.capacity()); // initial size of spans
450 
451  aliases.push_back(0); // 0 --> 0
452 
458  int ncr = 0; // number of detected cosmic rays
459  if (!crpixels.empty()) {
460  int id; // id number for a CR
461  int x0 = -1, x1 = -1, y = -1; // the beginning and end column, and row of this span in a CR
462 
463  // I am dummy
464  CRPixel<ImagePixel> dummy(0, -1, 0, -1);
465  crpixels.push_back(dummy);
466  //printf("Created dummy CR: i %i, id %i, col %i, row %i, val %g\n", dummy.get_i(), dummy.id, dummy.col, dummy.row, (double)dummy.val);
467  for (crpixel_iter crp = crpixels.begin(); crp < crpixels.end() - 1 ; ++crp) {
468  //printf("Looking at CR: i %i, id %i, col %i, row %i, val %g\n", crp->get_i(), crp->id, crp->col, crp->row, (double)crp->val);
469 
470  if (crp->id < 0) { // not already assigned
471  crp->id = ++ncr; // a new CR
472  aliases.push_back(crp->id);
473  y = crp->row;
474  x0 = x1 = crp->col;
475  //printf(" Assigned ID %i; looking at row %i, start col %i\n", crp->id, crp->row, crp->col);
476  }
477  id = crp->id;
478  //printf(" Next CRpix has i=%i, id=%i, row %i, col %i\n", crp[1].get_i(), crp[1].id, crp[1].row, crp[1].col);
479 
480  if (crp[1].row == crp[0].row && crp[1].col == crp[0].col + 1) {
481  //printf(" Adjoining! Set next CRpix id = %i; x1=%i\n", crp[1].id, x1);
482  crp[1].id = id;
483  ++x1;
484  } else {
485  assert (y >= 0 && x0 >= 0 && x1 >= 0);
486  spans.push_back(detection::IdSpan::Ptr(new detection::IdSpan(id, y, x0, x1)));
487  //printf(" Not adjoining; adding span id=%i, y=%i, x = [%i, %i]\n", id, y, x0, x1);
488  }
489  }
490  }
491 
492  // At the end of this loop, all crpixel entries have been assigned an ID,
493  // except for the "dummy" entry at the end of the array.
494  if (crpixels.size() > 0) {
495  for (crpixel_iter cp = crpixels.begin(); cp != crpixels.end() - 1; cp++) {
496  assert(cp->id >= 0);
497  assert(cp->col >= 0);
498  assert(cp->row >= 0);
499  }
500  // dummy:
501  assert(crpixels[crpixels.size()-1].id == -1);
502  assert(crpixels[crpixels.size()-1].col == 0);
503  assert(crpixels[crpixels.size()-1].row == -1);
504  }
505 
506  for (std::vector<detection::IdSpan::Ptr>::iterator sp = spans.begin(), end = spans.end(); sp != end; sp++) {
507  assert((*sp)->id >= 0);
508  assert((*sp)->y >= 0);
509  assert((*sp)->x0 >= 0);
510  assert((*sp)->x1 >= (*sp)->x0);
511  for (std::vector<detection::IdSpan::Ptr>::iterator sp2 = sp + 1; sp2 != end; sp2++) {
512  assert((*sp2)->y >= (*sp)->y);
513  if ((*sp2)->y == (*sp)->y) {
514  assert((*sp2)->x0 > (*sp)->x1);
515  }
516  }
517  }
518 
519 /*
520  * See if spans touch each other
521  */
522  for (std::vector<detection::IdSpan::Ptr>::iterator sp = spans.begin(), end = spans.end();
523  sp != end; ++sp) {
524  int const y = (*sp)->y;
525  int const x0 = (*sp)->x0;
526  int const x1 = (*sp)->x1;
527 
528  // this loop will probably run for only a few steps
529  for (std::vector<detection::IdSpan::Ptr>::iterator sp2 = sp + 1; sp2 != end; ++sp2) {
530  if ((*sp2)->y == y) {
531  // on this row (but not adjoining columns, since it would have been merged into this span);
532  // keep looking.
533  continue;
534  } else if ((*sp2)->y != (y + 1)) {
535  // sp2 is more than one row below; can't be connected.
536  break;
537  } else if ((*sp2)->x0 > (x1 + 1)) {
538  // sp2 is more than one column away to the right; can't be connected
539  break;
540  } else if ((*sp2)->x1 >= (x0 - 1)) {
541  // touches
542  int r1 = detection::resolve_alias(aliases, (*sp)->id);
543  int r2 = detection::resolve_alias(aliases, (*sp2)->id);
544  aliases[r1] = r2;
545  }
546  }
547  }
548 
549 
550 
551 
552 
553 /*
554  * Resolve aliases; first alias chains, then the IDs in the spans
555  */
556  for (unsigned int i = 0; i != spans.size(); ++i) {
557  spans[i]->id = detection::resolve_alias(aliases, spans[i]->id);
558  }
559 
560 /*
561  * Sort spans by ID, so we can sweep through them once
562  */
563  if (spans.size() > 0) {
564  std::sort(spans.begin(), spans.end(), detection::IdSpanCompar());
565  }
566 
567 /*
568  * Build Footprints from spans
569  */
570  std::vector<detection::Footprint::Ptr> CRs; // our cosmic rays
571 
572  if (spans.size() > 0) {
573  int id = spans[0]->id;
574  unsigned int i0 = 0; // initial value of i
575  for (unsigned int i = i0; i <= spans.size(); ++i) { // <= size to catch the last object
576  if (i == spans.size() || spans[i]->id != id) {
578 
579  for (; i0 < i; ++i0) {
580  cr->addSpan(spans[i0]->y, spans[i0]->x0, spans[i0]->x1);
581  }
582  CRs.push_back(cr);
583  }
584 
585  if (i < spans.size()) {
586  id = spans[i]->id;
587  }
588  }
589  }
590 
591  reinstateCrPixels(mimage.getImage().get(), crpixels);
592 /*
593  * apply condition #1
594  */
595  CountsInCR<ImageT> CountDN(*mimage.getImage(), bkgd);
596  for (std::vector<detection::Footprint::Ptr>::iterator cr = CRs.begin(), end = CRs.end();
597  cr != end; ++cr) {
598  CountDN.apply(**cr); // find the sum of pixel values within the CR
599 
600  LOGL_DEBUG("TRACE4.algorithms.CR", "CR at (%d, %d) has %g DN",
601  (*cr)->getBBox().getMinX(), (*cr)->getBBox().getMinY(), CountDN.getCounts());
602  if (CountDN.getCounts() < minDn) { /* not bright enough */
603  LOGL_DEBUG("TRACE5.algorithms.CR", "Erasing CR");
604 
605  cr = CRs.erase(cr);
606  --cr; // back up to previous CR (we're going to increment it)
607  --end;
608  }
609  }
610  ncr = CRs.size(); /* some may have been too faint */
611 /*
612  * We've found them all, time to kill them all
613  */
614  bool const debias_values = true;
615  bool grow = false;
616  LOGL_DEBUG("TRACE2.algorithms.CR", "Removing initial list of CRs");
617  removeCR(mimage, CRs, bkgd, crBit, saturBit, badMask, debias_values, grow);
618 #if 0 // Useful to see phase 2 in ds9; debugging only
619  (void)setMaskFromFootprintList(mimage.getMask().get(), CRs,
620  mimage.getMask()->getPlaneBitMask("DETECTED"));
621 #endif
622 /*
623  * Now that we've removed them, go through image again, examining area around
624  * each CR for extra bad pixels. Note that we set cond3Fac = 0 for this pass
625  *
626  * We iterate niteration times; niter==1 was sufficient for SDSS data, but megacam
627  * CCDs are different -- who knows for other devices?
628  */
629  bool too_many_crs = false; // we've seen too many CR pixels
630  int nextra = 0; // number of pixels added to list of CRs
631  for (int i = 0; i != niteration && !too_many_crs; ++i) {
632  LOGL_DEBUG("TRACE1.algorithms.CR", "Starting iteration %d", i);
633  for (std::vector<detection::Footprint::Ptr>::iterator fiter = CRs.begin();
634  fiter != CRs.end(); fiter++) {
635  detection::Footprint::Ptr cr = *fiter;
636 /*
637  * Are all those `CR' pixels interpolated? If so, don't grow it
638  */
639  {
640  detection::Footprint::Ptr om = footprintAndMask(cr, mimage.getMask(), interpBit);
641  int const npix = (om) ? om->getNpix() : 0;
642 
643  if (static_cast<std::size_t>(npix) == cr->getNpix()) {
644  continue;
645  }
646  }
647 /*
648  * No; some of the suspect pixels aren't interpolated
649  */
650  detection::Footprint extra; // extra pixels added to cr
651  for (detection::Footprint::SpanList::const_iterator siter = cr->getSpans().begin();
652  siter != cr->getSpans().end(); siter++) {
653  detection::Span::Ptr const span = *siter;
654 
655  /*
656  * Check the lines above and below the span. We're going to check a 3x3 region around
657  * the pixels, so we need a buffer around the edge. We check the pixels just to the
658  * left/right of the span, so the buffer needs to be 2 pixels (not just 1) in the
659  * column direction, but only 1 in the row direction.
660  */
661  int const y = span->getY() - mimage.getY0();
662  if (y < 2 || y >= nrow - 2) {
663  continue;
664  }
665  int x0 = span->getX0() - mimage.getX0();
666  int x1 = span->getX1() - mimage.getX0();
667  x0 = (x0 < 2) ? 2 : (x0 > ncol - 3) ? ncol - 3 : x0;
668  x1 = (x1 < 2) ? 2 : (x1 > ncol - 3) ? ncol - 3 : x1;
669 
670  checkSpanForCRs(&extra, crpixels, y - 1, x0, x1, mimage,
671  minSigma/2, thresH, thresV, thresD, bkgd, 0, keep);
672  checkSpanForCRs(&extra, crpixels, y, x0, x1, mimage,
673  minSigma/2, thresH, thresV, thresD, bkgd, 0, keep);
674  checkSpanForCRs(&extra, crpixels, y + 1, x0, x1, mimage,
675  minSigma/2, thresH, thresV, thresD, bkgd, 0, keep);
676  }
677 
678  if (extra.getSpans().size() > 0) { // we added some pixels
679  if (nextra + static_cast<int>(crpixels.size()) > nCrPixelMax) {
680  too_many_crs = true;
681  break;
682  }
683 
684  nextra += extra.getNpix();
685 
686  detection::Footprint::SpanList &espans = extra.getSpans();
687  for (detection::Footprint::SpanList::const_iterator siter = espans.begin();
688  siter != espans.end(); siter++) {
689  cr->addSpan(**siter);
690  }
691  cr->normalize();
692  }
693  }
694 
695  if (nextra == 0) {
696  break;
697  }
698  }
699 /*
700  * mark those pixels as CRs
701  */
702  if (!too_many_crs) {
703  (void)setMaskFromFootprintList(mimage.getMask().get(), CRs, crBit);
704  }
705 /*
706  * Maybe reinstate initial values; n.b. the same pixel may appear twice, so we want the
707  * first value stored (hence the uses of rbegin/rend)
708  *
709  * We have to do this if we decide _not_ to remove certain CRs,
710  * for example those which lie next to saturated pixels
711  */
712  if (keep || too_many_crs) {
713  if (crpixels.size() > 0) {
714  int const imageX0 = mimage.getX0();
715  int const imageY0 = mimage.getY0();
716 
717  std::sort(crpixels.begin(), crpixels.end()); // sort into birth order
718 
719  crpixel_riter rend = crpixels.rend();
720  for (crpixel_riter crp = crpixels.rbegin(); crp != rend; ++crp) {
721  if (crp->row == -1)
722  // dummy; skip it.
723  continue;
724  mimage.at(crp->col - imageX0, crp->row - imageY0).image() = crp->val;
725  }
726  }
727  } else {
728  if (true || nextra > 0) {
729  grow = true;
730  LOGL_DEBUG("TRACE2.algorithms.CR", "Removing final list of CRs, grow = %d", grow);
731  removeCR(mimage, CRs, bkgd, crBit, saturBit, badMask, debias_values, grow);
732  }
733 /*
734  * we interpolated over all CR pixels, so set the interp bits too
735  */
736  (void)setMaskFromFootprintList(mimage.getMask().get(), CRs,
737  static_cast<MaskPixel>(crBit | interpBit));
738  }
739 
740  if (too_many_crs) { // we've cleaned up, so we can throw the exception
741  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
742  (boost::format("Too many CR pixels (max %d)") % nCrPixelMax).str());
743  }
744 
745  return CRs;
746 }
std::vector< Span::Ptr > SpanList
The Footprint&#39;s Span list.
Definition: Footprint.h:71
int y
std::uint16_t MaskPixel
boost::shared_ptr< Footprint > footprintAndMask(boost::shared_ptr< Footprint > const &foot, typename image::Mask< MaskT >::Ptr const &mask, MaskT const bitmask)
Return a Footprint that&#39;s the intersection of a Footprint with a Mask.
std::shared_ptr< Footprint > Ptr
Definition: Footprint.h:67
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:513
int const x0
Definition: saturated.cc:45
boost::shared_ptr< Kernel const > ConstPtr
Definition: Kernel.h:139
std::shared_ptr< IdSpan > Ptr
Definition: CR.cc:67
comparison functor; sort by ID, then by row (y), then by column range start (x0)
Definition: CR.cc:78
A set of pixels in an Image.
Definition: Footprint.h:62
int row
Definition: CR.cc:158
size_t getNpix() const
Return the number of pixels in this Footprint (the real number of pixels, not the area of the bbox)...
Definition: Footprint.h:152
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
SpanList & getSpans()
Return the Spans contained in this Footprint.
Definition: Footprint.h:112
int id
Definition: CR.cc:156
int resolve_alias(const std::vector< int > &aliases, int id)
Follow a chain of aliases, returning the final resolved value.
Definition: CR.cc:98
int col
Definition: CR.cc:157
image::Image< Pixel > Image
Image type returned by computeImage.
Definition: Psf.h:79
MaskT setMaskFromFootprintList(lsst::afw::image::Mask< MaskT > *mask, std::vector< boost::shared_ptr< Footprint >> const &footprints, MaskT const bitmask)
OR bitmask into all the Mask&#39;s pixels which are in the set of Footprints.
run-length code for part of object
Definition: CR.cc:65
template<typename MaskedImageT >
std::vector<detection::Footprint::Ptr> lsst::meas::algorithms::findCosmicRays ( MaskedImageT &  mimage,
detection::Psf const &  psf,
double const  bkgd,
lsst::pex::policy::Policy const &  policy,
bool const  keep 
)

Find cosmic rays in an Image, and mask and remove them.

Returns
vector of CR's Footprints

In this loop, we look for strings of CRpixels on the same row and adjoining columns; each of these becomes a Span with a unique ID.

Parameters
mimageImage to search
psfthe Image's PSF
bkgdunsubtracted background of frame, DN
policyPolicy directing the behavior
keepif true, don't remove the CRs

Definition at line 346 of file CR.cc.

351  {
352  typedef typename MaskedImageT::Image ImageT;
353  typedef typename ImageT::Pixel ImagePixel;
354  typedef typename MaskedImageT::Mask::Pixel MaskPixel;
355 
356  // Parse the Policy
357  double const minSigma = policy.getDouble("minSigma"); // min sigma over sky in pixel for CR candidate
358  double const minDn = policy.getDouble("min_DN"); // min number of DN in an CRs
359  double const cond3Fac = policy.getDouble("cond3_fac"); // fiddle factor for condition #3
360  double const cond3Fac2 = policy.getDouble("cond3_fac2"); // 2nd fiddle factor for condition #3
361  int const niteration = policy.getInt("niteration"); // Number of times to look for contaminated
362  // pixels near CRs
363  int const nCrPixelMax = policy.getInt("nCrPixelMax"); // maximum number of contaminated pixels
364 /*
365  * thresholds for 3rd condition
366  *
367  * Realise PSF at center of image
368  */
369  lsst::afw::math::Kernel::ConstPtr kernel = psf.getLocalKernel();
370  if (!kernel) {
371  throw LSST_EXCEPT(pexExcept::NotFoundError, "Psf is unable to return a kernel");
372  }
373  detection::Psf::Image psfImage = detection::Psf::Image(geom::ExtentI(kernel->getWidth(), kernel->getHeight()));
374  kernel->computeImage(psfImage, true);
375 
376  int const xc = kernel->getCtrX(); // center of PSF
377  int const yc = kernel->getCtrY();
378 
379  double const I0 = psfImage(xc, yc);
380  double const thresH = cond3Fac2*(0.5*(psfImage(xc - 1, yc) + psfImage(xc + 1, yc)))/I0; // horizontal
381  double const thresV = cond3Fac2*(0.5*(psfImage(xc, yc - 1) + psfImage(xc, yc + 1)))/I0; // vertical
382  double const thresD = cond3Fac2*(0.25*(psfImage(xc - 1, yc - 1) + psfImage(xc + 1, yc + 1) +
383  psfImage(xc - 1, yc + 1) + psfImage(xc + 1, yc - 1)))/I0; // diag
384 /*
385  * Setup desired mask planes
386  */
387  MaskPixel const badBit = mimage.getMask()->getPlaneBitMask("BAD"); // Generic bad pixels
388  MaskPixel const crBit = mimage.getMask()->getPlaneBitMask("CR"); // CR-contaminated pixels
389  MaskPixel const interpBit = mimage.getMask()->getPlaneBitMask("INTRP"); // Interpolated pixels
390  MaskPixel const saturBit = mimage.getMask()->getPlaneBitMask("SAT"); // Saturated pixels
391  MaskPixel const nodataBit = mimage.getMask()->getPlaneBitMask("NO_DATA"); // Non data pixels
392 
393  MaskPixel const badMask = (badBit | interpBit | saturBit | nodataBit); // naughty pixels
394 /*
395  * Go through the frame looking at each pixel (except the edge ones which we ignore)
396  */
397  int const ncol = mimage.getWidth();
398  int const nrow = mimage.getHeight();
399 
400  std::vector<CRPixel<ImagePixel> > crpixels; // storage for detected CR-contaminated pixels
401  typedef typename std::vector<CRPixel<ImagePixel> >::iterator crpixel_iter;
402  typedef typename std::vector<CRPixel<ImagePixel> >::reverse_iterator crpixel_riter;
403 
404  for (int j = 1; j < nrow - 1; ++j) {
405  typename MaskedImageT::xy_locator loc = mimage.xy_at(1, j); // locator for data
406 
407  for (int i = 1; i < ncol - 1; ++i, ++loc.x()) {
408  ImagePixel corr = 0;
409  if (!is_cr_pixel<MaskedImageT>(&corr, loc, minSigma,
410  thresH, thresV, thresD, bkgd, cond3Fac)) {
411  continue;
412  }
413 /*
414  * condition #4
415  */
416  if (loc.mask() & badMask) {
417  continue;
418  }
419  if ((loc.mask(-1, 1) | loc.mask(0, 1) | loc.mask(1, 1) |
420  loc.mask(-1, 0) | loc.mask(1, 0) |
421  loc.mask(-1, -1) | loc.mask(0, -1) | loc.mask(1, -1)) & interpBit) {
422  continue;
423  }
424 /*
425  * OK, it's a CR
426  *
427  * replace CR-contaminated pixels with reasonable values as we go through
428  * image, which increases the detection rate
429  */
430  crpixels.push_back(CRPixel<ImagePixel>(i + mimage.getX0(), j + mimage.getY0(), loc.image()));
431  loc.image() = corr; /* just a preliminary estimate */
432 
433  if (static_cast<int>(crpixels.size()) > nCrPixelMax) {
434  reinstateCrPixels(mimage.getImage().get(), crpixels);
435 
436  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
437  (boost::format("Too many CR pixels (max %d)") % nCrPixelMax).str());
438  }
439  }
440  }
441 /*
442  * We've found them on a pixel-by-pixel basis, now merge those pixels
443  * into cosmic rays
444  */
445  std::vector<int> aliases; // aliases for initially disjoint parts of CRs
446  aliases.reserve(1 + crpixels.size()/2); // initial size of aliases
447 
448  std::vector<detection::IdSpan::Ptr> spans; // y:x0,x1 for objects
449  spans.reserve(aliases.capacity()); // initial size of spans
450 
451  aliases.push_back(0); // 0 --> 0
452 
458  int ncr = 0; // number of detected cosmic rays
459  if (!crpixels.empty()) {
460  int id; // id number for a CR
461  int x0 = -1, x1 = -1, y = -1; // the beginning and end column, and row of this span in a CR
462 
463  // I am dummy
464  CRPixel<ImagePixel> dummy(0, -1, 0, -1);
465  crpixels.push_back(dummy);
466  //printf("Created dummy CR: i %i, id %i, col %i, row %i, val %g\n", dummy.get_i(), dummy.id, dummy.col, dummy.row, (double)dummy.val);
467  for (crpixel_iter crp = crpixels.begin(); crp < crpixels.end() - 1 ; ++crp) {
468  //printf("Looking at CR: i %i, id %i, col %i, row %i, val %g\n", crp->get_i(), crp->id, crp->col, crp->row, (double)crp->val);
469 
470  if (crp->id < 0) { // not already assigned
471  crp->id = ++ncr; // a new CR
472  aliases.push_back(crp->id);
473  y = crp->row;
474  x0 = x1 = crp->col;
475  //printf(" Assigned ID %i; looking at row %i, start col %i\n", crp->id, crp->row, crp->col);
476  }
477  id = crp->id;
478  //printf(" Next CRpix has i=%i, id=%i, row %i, col %i\n", crp[1].get_i(), crp[1].id, crp[1].row, crp[1].col);
479 
480  if (crp[1].row == crp[0].row && crp[1].col == crp[0].col + 1) {
481  //printf(" Adjoining! Set next CRpix id = %i; x1=%i\n", crp[1].id, x1);
482  crp[1].id = id;
483  ++x1;
484  } else {
485  assert (y >= 0 && x0 >= 0 && x1 >= 0);
486  spans.push_back(detection::IdSpan::Ptr(new detection::IdSpan(id, y, x0, x1)));
487  //printf(" Not adjoining; adding span id=%i, y=%i, x = [%i, %i]\n", id, y, x0, x1);
488  }
489  }
490  }
491 
492  // At the end of this loop, all crpixel entries have been assigned an ID,
493  // except for the "dummy" entry at the end of the array.
494  if (crpixels.size() > 0) {
495  for (crpixel_iter cp = crpixels.begin(); cp != crpixels.end() - 1; cp++) {
496  assert(cp->id >= 0);
497  assert(cp->col >= 0);
498  assert(cp->row >= 0);
499  }
500  // dummy:
501  assert(crpixels[crpixels.size()-1].id == -1);
502  assert(crpixels[crpixels.size()-1].col == 0);
503  assert(crpixels[crpixels.size()-1].row == -1);
504  }
505 
506  for (std::vector<detection::IdSpan::Ptr>::iterator sp = spans.begin(), end = spans.end(); sp != end; sp++) {
507  assert((*sp)->id >= 0);
508  assert((*sp)->y >= 0);
509  assert((*sp)->x0 >= 0);
510  assert((*sp)->x1 >= (*sp)->x0);
511  for (std::vector<detection::IdSpan::Ptr>::iterator sp2 = sp + 1; sp2 != end; sp2++) {
512  assert((*sp2)->y >= (*sp)->y);
513  if ((*sp2)->y == (*sp)->y) {
514  assert((*sp2)->x0 > (*sp)->x1);
515  }
516  }
517  }
518 
519 /*
520  * See if spans touch each other
521  */
522  for (std::vector<detection::IdSpan::Ptr>::iterator sp = spans.begin(), end = spans.end();
523  sp != end; ++sp) {
524  int const y = (*sp)->y;
525  int const x0 = (*sp)->x0;
526  int const x1 = (*sp)->x1;
527 
528  // this loop will probably run for only a few steps
529  for (std::vector<detection::IdSpan::Ptr>::iterator sp2 = sp + 1; sp2 != end; ++sp2) {
530  if ((*sp2)->y == y) {
531  // on this row (but not adjoining columns, since it would have been merged into this span);
532  // keep looking.
533  continue;
534  } else if ((*sp2)->y != (y + 1)) {
535  // sp2 is more than one row below; can't be connected.
536  break;
537  } else if ((*sp2)->x0 > (x1 + 1)) {
538  // sp2 is more than one column away to the right; can't be connected
539  break;
540  } else if ((*sp2)->x1 >= (x0 - 1)) {
541  // touches
542  int r1 = detection::resolve_alias(aliases, (*sp)->id);
543  int r2 = detection::resolve_alias(aliases, (*sp2)->id);
544  aliases[r1] = r2;
545  }
546  }
547  }
548 
549 
550 
551 
552 
553 /*
554  * Resolve aliases; first alias chains, then the IDs in the spans
555  */
556  for (unsigned int i = 0; i != spans.size(); ++i) {
557  spans[i]->id = detection::resolve_alias(aliases, spans[i]->id);
558  }
559 
560 /*
561  * Sort spans by ID, so we can sweep through them once
562  */
563  if (spans.size() > 0) {
564  std::sort(spans.begin(), spans.end(), detection::IdSpanCompar());
565  }
566 
567 /*
568  * Build Footprints from spans
569  */
570  std::vector<detection::Footprint::Ptr> CRs; // our cosmic rays
571 
572  if (spans.size() > 0) {
573  int id = spans[0]->id;
574  unsigned int i0 = 0; // initial value of i
575  for (unsigned int i = i0; i <= spans.size(); ++i) { // <= size to catch the last object
576  if (i == spans.size() || spans[i]->id != id) {
578 
579  for (; i0 < i; ++i0) {
580  cr->addSpan(spans[i0]->y, spans[i0]->x0, spans[i0]->x1);
581  }
582  CRs.push_back(cr);
583  }
584 
585  if (i < spans.size()) {
586  id = spans[i]->id;
587  }
588  }
589  }
590 
591  reinstateCrPixels(mimage.getImage().get(), crpixels);
592 /*
593  * apply condition #1
594  */
595  CountsInCR<ImageT> CountDN(*mimage.getImage(), bkgd);
596  for (std::vector<detection::Footprint::Ptr>::iterator cr = CRs.begin(), end = CRs.end();
597  cr != end; ++cr) {
598  CountDN.apply(**cr); // find the sum of pixel values within the CR
599 
600  LOGL_DEBUG("TRACE4.algorithms.CR", "CR at (%d, %d) has %g DN",
601  (*cr)->getBBox().getMinX(), (*cr)->getBBox().getMinY(), CountDN.getCounts());
602  if (CountDN.getCounts() < minDn) { /* not bright enough */
603  LOGL_DEBUG("TRACE5.algorithms.CR", "Erasing CR");
604 
605  cr = CRs.erase(cr);
606  --cr; // back up to previous CR (we're going to increment it)
607  --end;
608  }
609  }
610  ncr = CRs.size(); /* some may have been too faint */
611 /*
612  * We've found them all, time to kill them all
613  */
614  bool const debias_values = true;
615  bool grow = false;
616  LOGL_DEBUG("TRACE2.algorithms.CR", "Removing initial list of CRs");
617  removeCR(mimage, CRs, bkgd, crBit, saturBit, badMask, debias_values, grow);
618 #if 0 // Useful to see phase 2 in ds9; debugging only
619  (void)setMaskFromFootprintList(mimage.getMask().get(), CRs,
620  mimage.getMask()->getPlaneBitMask("DETECTED"));
621 #endif
622 /*
623  * Now that we've removed them, go through image again, examining area around
624  * each CR for extra bad pixels. Note that we set cond3Fac = 0 for this pass
625  *
626  * We iterate niteration times; niter==1 was sufficient for SDSS data, but megacam
627  * CCDs are different -- who knows for other devices?
628  */
629  bool too_many_crs = false; // we've seen too many CR pixels
630  int nextra = 0; // number of pixels added to list of CRs
631  for (int i = 0; i != niteration && !too_many_crs; ++i) {
632  LOGL_DEBUG("TRACE1.algorithms.CR", "Starting iteration %d", i);
633  for (std::vector<detection::Footprint::Ptr>::iterator fiter = CRs.begin();
634  fiter != CRs.end(); fiter++) {
635  detection::Footprint::Ptr cr = *fiter;
636 /*
637  * Are all those `CR' pixels interpolated? If so, don't grow it
638  */
639  {
640  detection::Footprint::Ptr om = footprintAndMask(cr, mimage.getMask(), interpBit);
641  int const npix = (om) ? om->getNpix() : 0;
642 
643  if (static_cast<std::size_t>(npix) == cr->getNpix()) {
644  continue;
645  }
646  }
647 /*
648  * No; some of the suspect pixels aren't interpolated
649  */
650  detection::Footprint extra; // extra pixels added to cr
651  for (detection::Footprint::SpanList::const_iterator siter = cr->getSpans().begin();
652  siter != cr->getSpans().end(); siter++) {
653  detection::Span::Ptr const span = *siter;
654 
655  /*
656  * Check the lines above and below the span. We're going to check a 3x3 region around
657  * the pixels, so we need a buffer around the edge. We check the pixels just to the
658  * left/right of the span, so the buffer needs to be 2 pixels (not just 1) in the
659  * column direction, but only 1 in the row direction.
660  */
661  int const y = span->getY() - mimage.getY0();
662  if (y < 2 || y >= nrow - 2) {
663  continue;
664  }
665  int x0 = span->getX0() - mimage.getX0();
666  int x1 = span->getX1() - mimage.getX0();
667  x0 = (x0 < 2) ? 2 : (x0 > ncol - 3) ? ncol - 3 : x0;
668  x1 = (x1 < 2) ? 2 : (x1 > ncol - 3) ? ncol - 3 : x1;
669 
670  checkSpanForCRs(&extra, crpixels, y - 1, x0, x1, mimage,
671  minSigma/2, thresH, thresV, thresD, bkgd, 0, keep);
672  checkSpanForCRs(&extra, crpixels, y, x0, x1, mimage,
673  minSigma/2, thresH, thresV, thresD, bkgd, 0, keep);
674  checkSpanForCRs(&extra, crpixels, y + 1, x0, x1, mimage,
675  minSigma/2, thresH, thresV, thresD, bkgd, 0, keep);
676  }
677 
678  if (extra.getSpans().size() > 0) { // we added some pixels
679  if (nextra + static_cast<int>(crpixels.size()) > nCrPixelMax) {
680  too_many_crs = true;
681  break;
682  }
683 
684  nextra += extra.getNpix();
685 
686  detection::Footprint::SpanList &espans = extra.getSpans();
687  for (detection::Footprint::SpanList::const_iterator siter = espans.begin();
688  siter != espans.end(); siter++) {
689  cr->addSpan(**siter);
690  }
691  cr->normalize();
692  }
693  }
694 
695  if (nextra == 0) {
696  break;
697  }
698  }
699 /*
700  * mark those pixels as CRs
701  */
702  if (!too_many_crs) {
703  (void)setMaskFromFootprintList(mimage.getMask().get(), CRs, crBit);
704  }
705 /*
706  * Maybe reinstate initial values; n.b. the same pixel may appear twice, so we want the
707  * first value stored (hence the uses of rbegin/rend)
708  *
709  * We have to do this if we decide _not_ to remove certain CRs,
710  * for example those which lie next to saturated pixels
711  */
712  if (keep || too_many_crs) {
713  if (crpixels.size() > 0) {
714  int const imageX0 = mimage.getX0();
715  int const imageY0 = mimage.getY0();
716 
717  std::sort(crpixels.begin(), crpixels.end()); // sort into birth order
718 
719  crpixel_riter rend = crpixels.rend();
720  for (crpixel_riter crp = crpixels.rbegin(); crp != rend; ++crp) {
721  if (crp->row == -1)
722  // dummy; skip it.
723  continue;
724  mimage.at(crp->col - imageX0, crp->row - imageY0).image() = crp->val;
725  }
726  }
727  } else {
728  if (true || nextra > 0) {
729  grow = true;
730  LOGL_DEBUG("TRACE2.algorithms.CR", "Removing final list of CRs, grow = %d", grow);
731  removeCR(mimage, CRs, bkgd, crBit, saturBit, badMask, debias_values, grow);
732  }
733 /*
734  * we interpolated over all CR pixels, so set the interp bits too
735  */
736  (void)setMaskFromFootprintList(mimage.getMask().get(), CRs,
737  static_cast<MaskPixel>(crBit | interpBit));
738  }
739 
740  if (too_many_crs) { // we've cleaned up, so we can throw the exception
741  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
742  (boost::format("Too many CR pixels (max %d)") % nCrPixelMax).str());
743  }
744 
745  return CRs;
746 }
std::vector< Span::Ptr > SpanList
The Footprint&#39;s Span list.
Definition: Footprint.h:71
int y
std::uint16_t MaskPixel
boost::shared_ptr< Footprint > footprintAndMask(boost::shared_ptr< Footprint > const &foot, typename image::Mask< MaskT >::Ptr const &mask, MaskT const bitmask)
Return a Footprint that&#39;s the intersection of a Footprint with a Mask.
std::shared_ptr< Footprint > Ptr
Definition: Footprint.h:67
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:513
int const x0
Definition: saturated.cc:45
boost::shared_ptr< Kernel const > ConstPtr
Definition: Kernel.h:139
std::shared_ptr< IdSpan > Ptr
Definition: CR.cc:67
comparison functor; sort by ID, then by row (y), then by column range start (x0)
Definition: CR.cc:78
A set of pixels in an Image.
Definition: Footprint.h:62
int row
Definition: CR.cc:158
size_t getNpix() const
Return the number of pixels in this Footprint (the real number of pixels, not the area of the bbox)...
Definition: Footprint.h:152
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
SpanList & getSpans()
Return the Spans contained in this Footprint.
Definition: Footprint.h:112
int id
Definition: CR.cc:156
int resolve_alias(const std::vector< int > &aliases, int id)
Follow a chain of aliases, returning the final resolved value.
Definition: CR.cc:98
int col
Definition: CR.cc:157
image::Image< Pixel > Image
Image type returned by computeImage.
Definition: Psf.h:79
MaskT setMaskFromFootprintList(lsst::afw::image::Mask< MaskT > *mask, std::vector< boost::shared_ptr< Footprint >> const &footprints, MaskT const bitmask)
OR bitmask into all the Mask&#39;s pixels which are in the set of Footprints.
run-length code for part of object
Definition: CR.cc:65
template<typename Image >
std::pair<std::vector<double>, lsst::afw::math::KernelList> lsst::meas::algorithms::fitKernelParamsToImage ( afwMath::LinearCombinationKernel const &  kernel,
Image const &  image,
afwGeom::Point2D const &  pos 
)

Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary.

Returns
std::pair(coefficients, std::pair(kernels, center amplitude))
Parameters
kernelthe Kernel to fit
imagethe image to be fit
posthe position of the object

Definition at line 1071 of file SpatialModelPsf.cc.

1076 {
1078 
1079  afwMath::KernelList kernels = kernel.getKernelList(); // the Kernels that kernel adds together
1080  int const nKernel = kernels.size();
1081 
1082  if (nKernel == 0) {
1083  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
1084  "Your kernel must have at least one component");
1085  }
1086 
1087  /*
1088  * Go through all the kernels, get a copy centered at the desired sub-pixel position, and then
1089  * extract a subImage from the parent image at the same place
1090  */
1091  std::vector<KernelT::Ptr> kernelImages = offsetKernel<KernelT>(kernel, pos[0], pos[1]);
1092  afwGeom::BoxI bbox(kernelImages[0]->getBBox());
1093  Image const& subImage(Image(image, bbox, afwImage::PARENT, false)); // shallow copy
1094 
1095  /*
1096  * Solve the linear problem subImage = sum x_i K_i + epsilon; we solve this for x_i by constructing the
1097  * normal equations, A x = b
1098  */
1099  Eigen::MatrixXd A(nKernel, nKernel);
1100  Eigen::VectorXd b(nKernel);
1101 
1102  for (int i = 0; i != nKernel; ++i) {
1103  b(i) = afwImage::innerProduct(*kernelImages[i], *subImage.getImage());
1104 
1105  for (int j = i; j != nKernel; ++j) {
1106  A(i, j) = A(j, i) = afwImage::innerProduct(*kernelImages[i], *kernelImages[j]);
1107  }
1108  }
1109  Eigen::VectorXd x(nKernel);
1110 
1111  if (nKernel == 1) {
1112  x(0) = b(0)/A(0, 0);
1113  } else {
1114  x = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
1115  }
1116 
1117  // the XY0() point of the shifted Kernel basis functions
1118  int const x0 = kernelImages[0]->getX0(), y0 = kernelImages[0]->getY0();
1119 
1120  afwMath::KernelList newKernels(nKernel);
1121  std::vector<double> params(nKernel);
1122  for (int i = 0; i != nKernel; ++i) {
1123  afwMath::Kernel::Ptr newKernel(new afwMath::FixedKernel(*kernelImages[i]));
1124  newKernel->setCtrX(x0 + static_cast<int>(newKernel->getWidth()/2));
1125  newKernel->setCtrY(y0 + static_cast<int>(newKernel->getHeight()/2));
1126 
1127  params[i] = x[i];
1128  newKernels[i] = newKernel;
1129  }
1130 
1131  return std::make_pair(params, newKernels);
1132 }
int const x0
Definition: saturated.cc:45
An integer coordinate rectangle.
Definition: Box.h:53
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
double innerProduct(Image1T const &lhs, Image2T const &rhs, int border)
Calculate the inner product of two images.
Definition: ImagePca.cc:455
boost::shared_ptr< Kernel > Ptr
Definition: Kernel.h:138
double x
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
afw::table::Key< double > b
int const y0
Definition: saturated.cc:45
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:416
A kernel created from an Image.
Definition: Kernel.h:548
std::vector< boost::shared_ptr< Kernel > > KernelList
Definition: Kernel.h:539
template<typename Image >
std::pair<std::vector<double>, afwMath::KernelList> lsst::meas::algorithms::fitKernelParamsToImage ( afwMath::LinearCombinationKernel const &  kernel,
Image const &  image,
afwGeom::Point2D const &  pos 
)

Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary.

Returns
std::pair(coefficients, std::pair(kernels, center amplitude))
Parameters
kernelthe Kernel to fit
imagethe image to be fit
posthe position of the object

Definition at line 1071 of file SpatialModelPsf.cc.

1076 {
1078 
1079  afwMath::KernelList kernels = kernel.getKernelList(); // the Kernels that kernel adds together
1080  int const nKernel = kernels.size();
1081 
1082  if (nKernel == 0) {
1083  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
1084  "Your kernel must have at least one component");
1085  }
1086 
1087  /*
1088  * Go through all the kernels, get a copy centered at the desired sub-pixel position, and then
1089  * extract a subImage from the parent image at the same place
1090  */
1091  std::vector<KernelT::Ptr> kernelImages = offsetKernel<KernelT>(kernel, pos[0], pos[1]);
1092  afwGeom::BoxI bbox(kernelImages[0]->getBBox());
1093  Image const& subImage(Image(image, bbox, afwImage::PARENT, false)); // shallow copy
1094 
1095  /*
1096  * Solve the linear problem subImage = sum x_i K_i + epsilon; we solve this for x_i by constructing the
1097  * normal equations, A x = b
1098  */
1099  Eigen::MatrixXd A(nKernel, nKernel);
1100  Eigen::VectorXd b(nKernel);
1101 
1102  for (int i = 0; i != nKernel; ++i) {
1103  b(i) = afwImage::innerProduct(*kernelImages[i], *subImage.getImage());
1104 
1105  for (int j = i; j != nKernel; ++j) {
1106  A(i, j) = A(j, i) = afwImage::innerProduct(*kernelImages[i], *kernelImages[j]);
1107  }
1108  }
1109  Eigen::VectorXd x(nKernel);
1110 
1111  if (nKernel == 1) {
1112  x(0) = b(0)/A(0, 0);
1113  } else {
1114  x = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
1115  }
1116 
1117  // the XY0() point of the shifted Kernel basis functions
1118  int const x0 = kernelImages[0]->getX0(), y0 = kernelImages[0]->getY0();
1119 
1120  afwMath::KernelList newKernels(nKernel);
1121  std::vector<double> params(nKernel);
1122  for (int i = 0; i != nKernel; ++i) {
1123  afwMath::Kernel::Ptr newKernel(new afwMath::FixedKernel(*kernelImages[i]));
1124  newKernel->setCtrX(x0 + static_cast<int>(newKernel->getWidth()/2));
1125  newKernel->setCtrY(y0 + static_cast<int>(newKernel->getHeight()/2));
1126 
1127  params[i] = x[i];
1128  newKernels[i] = newKernel;
1129  }
1130 
1131  return std::make_pair(params, newKernels);
1132 }
int const x0
Definition: saturated.cc:45
An integer coordinate rectangle.
Definition: Box.h:53
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
double innerProduct(Image1T const &lhs, Image2T const &rhs, int border)
Calculate the inner product of two images.
Definition: ImagePca.cc:455
boost::shared_ptr< Kernel > Ptr
Definition: Kernel.h:138
double x
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
afw::table::Key< double > b
int const y0
Definition: saturated.cc:45
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:416
A kernel created from an Image.
Definition: Kernel.h:548
std::vector< boost::shared_ptr< Kernel > > KernelList
Definition: Kernel.h:539
template<typename Image >
std::pair<lsst::afw::math::Kernel::Ptr, std::pair<double, double> > lsst::meas::algorithms::fitKernelToImage ( afwMath::LinearCombinationKernel const &  kernel,
Image const &  image,
afwGeom::Point2D const &  pos 
)

Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary.

Returns
std::pair(best-fit kernel, std::pair(amp, chi^2))
Parameters
kernelthe Kernel to fit
imagethe image to be fit
posthe position of the object

Definition at line 1143 of file SpatialModelPsf.cc.

1148 {
1149  std::pair<std::vector<double>, afwMath::KernelList> const fit =
1150  fitKernelParamsToImage(kernel, image, pos);
1151  std::vector<double> params = fit.first;
1152  afwMath::KernelList kernels = fit.second;
1153  int const nKernel = params.size();
1154  assert(kernels.size() == static_cast<unsigned int>(nKernel));
1155 
1156  double amp = 0.0;
1157  for (int i = 0; i != nKernel; ++i) {
1158  afwMath::Kernel::Ptr base = kernels[i];
1159  afwMath::FixedKernel::Ptr k = std::static_pointer_cast<afwMath::FixedKernel>(base);
1160  amp += params[i] * k->getSum();
1161  }
1162 
1163  afwMath::Kernel::Ptr outputKernel(new afwMath::LinearCombinationKernel(kernels, params));
1164  double chisq = 0.0;
1165  outputKernel->setCtrX(kernels[0]->getCtrX());
1166  outputKernel->setCtrY(kernels[0]->getCtrY());
1167 
1168  return std::make_pair(outputKernel, std::make_pair(amp, chisq));
1169 }
std::pair< std::vector< double >, afwMath::KernelList > fitKernelParamsToImage(afwMath::LinearCombinationKernel const &kernel, Image const &image, afwGeom::Point2D const &pos)
Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary...
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
boost::shared_ptr< Kernel > Ptr
Definition: Kernel.h:138
A kernel that is a linear combination of fixed basis kernels.
Definition: Kernel.h:811
double chisq
boost::shared_ptr< FixedKernel > Ptr
Definition: Kernel.h:550
A kernel created from an Image.
Definition: Kernel.h:548
std::vector< boost::shared_ptr< Kernel > > KernelList
Definition: Kernel.h:539
template<typename Image >
std::pair<afwMath::Kernel::Ptr, std::pair<double, double> > lsst::meas::algorithms::fitKernelToImage ( afwMath::LinearCombinationKernel const &  kernel,
Image const &  image,
afwGeom::Point2D const &  pos 
)

Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary.

Returns
std::pair(best-fit kernel, std::pair(amp, chi^2))
Parameters
kernelthe Kernel to fit
imagethe image to be fit
posthe position of the object

Definition at line 1143 of file SpatialModelPsf.cc.

1148 {
1149  std::pair<std::vector<double>, afwMath::KernelList> const fit =
1150  fitKernelParamsToImage(kernel, image, pos);
1151  std::vector<double> params = fit.first;
1152  afwMath::KernelList kernels = fit.second;
1153  int const nKernel = params.size();
1154  assert(kernels.size() == static_cast<unsigned int>(nKernel));
1155 
1156  double amp = 0.0;
1157  for (int i = 0; i != nKernel; ++i) {
1158  afwMath::Kernel::Ptr base = kernels[i];
1159  afwMath::FixedKernel::Ptr k = std::static_pointer_cast<afwMath::FixedKernel>(base);
1160  amp += params[i] * k->getSum();
1161  }
1162 
1163  afwMath::Kernel::Ptr outputKernel(new afwMath::LinearCombinationKernel(kernels, params));
1164  double chisq = 0.0;
1165  outputKernel->setCtrX(kernels[0]->getCtrX());
1166  outputKernel->setCtrY(kernels[0]->getCtrY());
1167 
1168  return std::make_pair(outputKernel, std::make_pair(amp, chisq));
1169 }
std::pair< std::vector< double >, afwMath::KernelList > fitKernelParamsToImage(afwMath::LinearCombinationKernel const &kernel, Image const &image, afwGeom::Point2D const &pos)
Fit a LinearCombinationKernel to an Image, allowing the coefficients of the components to vary...
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
boost::shared_ptr< Kernel > Ptr
Definition: Kernel.h:138
A kernel that is a linear combination of fixed basis kernels.
Definition: Kernel.h:811
double chisq
boost::shared_ptr< FixedKernel > Ptr
Definition: Kernel.h:550
A kernel created from an Image.
Definition: Kernel.h:548
std::vector< boost::shared_ptr< Kernel > > KernelList
Definition: Kernel.h:539
template<typename PixelT >
std::pair< bool, double > lsst::meas::algorithms::fitSpatialKernelFromPsfCandidates ( afwMath::Kernel kernel,
afwMath::SpatialCellSet const &  psfCells,
int const  nStarPerCell,
double const  tolerance,
double const  lambda 
)

Fit spatial kernel using full-nonlinear optimization to estimate candidate amplitudes.

Parameters
kernelthe Kernel to fit
psfCellsA SpatialCellSet containing PsfCandidates
nStarPerCellmax no. of stars per cell; <= 0 => infty
toleranceTolerance; how close chi^2 should be to true minimum
lambdafloor for variance is lambda*data

Definition at line 621 of file SpatialModelPsf.cc.

627  {
628  typedef typename afwImage::Image<PixelT> Image;
629 
630  int const nComponents = kernel->getNKernelParameters();
631  int const nSpatialParams = kernel->getNSpatialParameters();
632  //
633  // visitor that evaluates the chi^2 of the current fit
634  //
635  evalChi2Visitor<PixelT> getChi2(*kernel, lambda);
636  //
637  // We have to unpack the Kernel coefficients into a linear array, coeffs
638  //
639  std::vector<double> coeffs; // The coefficients we want to fit
640  coeffs.assign(nComponents*nSpatialParams, 0.0);
641 
642  std::vector<double> stepSize; // step sizes
643  stepSize.assign(nComponents*nSpatialParams, 100);
644  //
645  // Translate that into minuit's language
646  //
647  ROOT::Minuit2::MnUserParameters fitPar;
648  std::vector<std::string> paramNames;
649  paramNames.reserve(nComponents*nSpatialParams);
650 
651  for (int i = 0, c = 0; c != nComponents; ++c) {
652  coeffs[i] = 1; // the constant part of each spatial order
653  for (int s = 0; s != nSpatialParams; ++s, ++i) {
654  paramNames.push_back((boost::format("C%d:%d") % c % s).str());
655  fitPar.Add(paramNames[i].c_str(), coeffs[i], stepSize[i]);
656  }
657  }
658  fitPar.Fix("C0:0");
659  //
660  // Create the minuit object that knows how to minimise our functor
661  //
662  MinimizeChi2<PixelT> minimizerFunc(getChi2, kernel, psfCells, nStarPerCell, nComponents, nSpatialParams);
663 
664  double const errorDef = 1.0; // use +- 1sigma errors
665  minimizerFunc.setErrorDef(errorDef);
666  //
667  // tell minuit about it
668  //
669  ROOT::Minuit2::MnMigrad migrad(minimizerFunc, fitPar);
670  //
671  // And let it loose
672  //
673  int maxFnCalls = 0; // i.e. unlimited
674  ROOT::Minuit2::FunctionMinimum min =
675  migrad(maxFnCalls, tolerance/(1e-4*errorDef)); // minuit uses 0.1*1e-3*tolerance*errorDef
676 
677  float minChi2 = min.Fval();
678  bool const isValid = min.IsValid() && std::isfinite(minChi2);
679 
680  if (true || isValid) { // calculate coeffs even in minuit is unhappy
681  for (int i = 0; i != nComponents*nSpatialParams; ++i) {
682  coeffs[i] = min.UserState().Value(i);
683  }
684 
685  setSpatialParameters(kernel, coeffs);
686  }
687 
688 #if 0 // Estimate errors; we don't really need this
689  ROOT::Minuit2::MnMinos minos(minimizerFunc, min);
690  for (int i = 0, c = 0; c != nComponents; ++c) {
691  for (int s = 0; s != nSpatialParams; ++s, ++i) {
692  char const *name = paramNames[i].c_str();
693  printf("%s %g", name, min.UserState().Value(name));
694  if (isValid && !fitPar.Parameter(fitPar.Index(name)).IsFixed()) {
695  printf(" (%g+%g)\n", minos(i).first, minos(i).second);
696  }
697  printf("\n");
698  }
699  }
700 #endif
701  //
702  // One time more through the Candidates setting their chi^2 values. We'll
703  // do all the candidates this time, not just the first nStarPerCell
704  //
705  psfCells.visitAllCandidates(&getChi2, true);
706 
707  return std::make_pair(isValid, minChi2);
708 }
table::Key< std::string > name
Definition: ApCorrMap.cc:71
int getNSpatialParameters() const
Return the number of spatial parameters (0 if not spatially varying)
Definition: Kernel.h:293
unsigned int getNKernelParameters() const
Return the number of kernel parameters (0 if none)
Definition: Kernel.h:286
void setSpatialParameters(afwMath::Kernel *kernel, std::vector< double > const &coeffs)
Fit a Kernel&#39;s spatial variability from a set of stars.
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:416
template<typename PixelT >
std::pair< bool, double > lsst::meas::algorithms::fitSpatialKernelFromPsfCandidates ( afwMath::Kernel kernel,
afwMath::SpatialCellSet const &  psfCells,
bool const  doNonLinearFit,
int const  nStarPerCell,
double const  tolerance,
double const  lambda 
)
Parameters
kernelthe Kernel to fit
psfCellsA SpatialCellSet containing PsfCandidates
doNonLinearFitUse the full-up nonlinear fitter
nStarPerCellmax no. of stars per cell; <= 0 => infty
toleranceTolerance; how close chi^2 should be to true minimum
lambdafloor for variance is lambda*data

Definition at line 909 of file SpatialModelPsf.cc.

917 {
918  if (doNonLinearFit) {
919  return fitSpatialKernelFromPsfCandidates<PixelT>(kernel, psfCells, nStarPerCell, tolerance);
920  }
921 
922  double const tau = 0; // softening for errors
923 
924  afwMath::LinearCombinationKernel const* lcKernel =
925  dynamic_cast<afwMath::LinearCombinationKernel const*>(kernel);
926  if (!lcKernel) {
927  throw LSST_EXCEPT(lsst::pex::exceptions::LogicError,
928  "Failed to cast Kernel to LinearCombinationKernel while building spatial PSF model");
929  }
930 #if 1
931  //
932  // Set the initial amplitudes of all our candidates
933  //
934  setAmplitudeVisitor<PixelT> setAmplitude;
935  psfCells.visitAllCandidates(&setAmplitude, true);
936 #endif
937  //
938  // visitor that fills out the A and b matrices (we'll solve A x = b for the coeffs, x)
939  //
940  FillABVisitor<PixelT> getAB(*lcKernel, tau);
941  //
942  // Actually visit all our candidates
943  //
944  psfCells.visitCandidates(&getAB, nStarPerCell, true);
945  //
946  // Extract A and b, and solve Ax = b
947  //
948  Eigen::MatrixXd const& A = getAB.getA();
949  Eigen::VectorXd const& b = getAB.getB();
950  Eigen::VectorXd x0(b.size()); // Solution to matrix problem
951 
952  switch (b.size()) {
953  case 0: // One candidate, no spatial variability
954  break;
955  case 1: // eigen can't/won't handle 1x1 matrices
956  x0(0) = b(0)/A(0, 0);
957  break;
958  default:
959  x0 = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
960  break;
961  }
962 #if 0
963  std::cout << "A " << A << std::endl;
964  std::cout << "b " << b.transpose() << std::endl;
965  std::cout << "x " << x.transpose() << std::endl;
966 
967  afwImage::Image<double> img(b.size(), b.size());
968  for (int j = 0; j < b.size(); ++j) {
969  for (int i = 0; i < b.size(); ++i) {
970  img(i, j) = A(i, j);
971  }
972  }
973  img.writeFits("a.fits");
974 
975  if (x.cols() >= 6) {
976  for (int i = 0; i != 6; ++i) {
977  double xcen = 25; double ycen = 35 + 35*i;
978  std::cout << "x, y " << xcen << " , " << ycen << " b "
979  << (x[3] + xcen*x[4] + ycen*x[5])/(x[0] + xcen*x[1] + ycen*x[2]) << std::endl;
980  }
981  }
982 #endif
983 
984  // Generate kernel parameters (including 0th component) from matrix solution
985  Eigen::VectorXd x(kernel->getNKernelParameters() * kernel->getNSpatialParameters()); // Kernel parameters
986  x(0) = 1.0;
987  std::fill(x.data() + 1, x.data() + kernel->getNSpatialParameters(), 0.0);
988  std::copy(x0.data(), x0.data() + x0.size(), x.data() + kernel->getNSpatialParameters());
989 
990  setSpatialParameters(kernel, x);
991  //
992  // One time more through the Candidates setting their chi^2 values. We'll
993  // do all the candidates this time, not just the first nStarPerCell
994  //
995  // visitor that evaluates the chi^2 of the current fit
996  //
997  evalChi2Visitor<PixelT> getChi2(*kernel, lambda);
998 
999  psfCells.visitAllCandidates(&getChi2, true);
1000 
1001  return std::make_pair(true, getChi2.getValue());
1002 }
int getNSpatialParameters() const
Return the number of spatial parameters (0 if not spatially varying)
Definition: Kernel.h:293
int const x0
Definition: saturated.cc:45
unsigned int getNKernelParameters() const
Return the number of kernel parameters (0 if none)
Definition: Kernel.h:286
A kernel that is a linear combination of fixed basis kernels.
Definition: Kernel.h:811
double x
void setSpatialParameters(afwMath::Kernel *kernel, std::vector< double > const &coeffs)
Fit a Kernel&#39;s spatial variability from a set of stars.
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
afw::table::Key< double > b
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:416
afw::geom::Box2I lsst::meas::algorithms::getOverallBBox ( std::vector< boost::shared_ptr< afw::image::Image< double > >> const &  imgVector)

Definition at line 183 of file CoaddPsf.cc.

183  {
184 
185  afw::geom::Box2I bbox;
186  // Calculate the box which will contain them all
187  for (unsigned int i = 0; i < imgVector.size(); i ++) {
188  PTR(afw::image::Image<double>) componentImg = imgVector[i];
189  afw::geom::Box2I cBBox = componentImg->getBBox();
190  bbox.include(cBBox); // JFB: this works even on empty bboxes
191  }
192  return bbox;
193 }
#define PTR(...)
Definition: base.h:41
template<typename MaskedImageT >
void lsst::meas::algorithms::interpolateOverDefects ( MaskedImageT &  mimage,
lsst::afw::detection::Psf const &  ,
std::vector< Defect::Ptr > &  _badList,
double  fallbackValue,
bool  useFallbackValueAtEdge 
)

Process a set of known bad pixels in an image.

Parameters
mimageImage to patch
psfthe Image's PSF
_badListList of Defects to patch
fallbackValueValue to fallback to if all else fails
useFallbackValueAtEdgeUse the fallback value at the image's edge?

Definition at line 2057 of file Interp.cc.

2062  {
2063 /*
2064  * Allow for image's origin
2065  */
2066  int const width = mimage.getWidth();
2067  int const height = mimage.getHeight();
2068 
2069  std::vector<Defect::Ptr> badList;
2070  badList.reserve(_badList.size());
2071  for (std::vector<Defect::Ptr>::iterator ptr = _badList.begin(), end = _badList.end(); ptr != end; ++ptr) {
2072  geom::BoxI bbox = (*ptr)->getBBox();
2073  bbox.shift(geom::ExtentI(-mimage.getX0(), -mimage.getY0())); //allow for image's origin
2074  geom::PointI min = bbox.getMin(), max = bbox.getMax();
2075  if(min.getX() >= width){
2076  continue;
2077  } else if (min.getX() < 0) {
2078  if (max.getX() < 0) {
2079  continue;
2080  } else {
2081  min.setX(0);
2082  }
2083  }
2084 
2085  if (max.getX() < 0) {
2086  continue;
2087  } else if (max.getX() >= width) {
2088  max.setX(width - 1);
2089  }
2090 
2091  bbox = geom::BoxI(min, max);
2092  Defect::Ptr ndefect(new Defect(bbox));
2093  ndefect->classify((*ptr)->getPos(), (*ptr)->getType());
2094  badList.push_back(ndefect);
2095  }
2096 
2097  sort(badList.begin(), badList.end(), Sort_ByX0<Defect>());
2098 /*
2099  * Go through the frame looking at each pixel (except the edge ones which we ignore)
2100  */
2101  typename MaskedImageT::Mask::Pixel const interpBit =
2102  mimage.getMask()->getPlaneBitMask("INTRP"); // interp'd pixels
2103 
2104  constexpr int nUseInterp = 6; // no. of pixels to interpolate towards edge
2105  static_assert(nUseInterp < Defect::WIDE_DEFECT, "make sure that we can handle these defects using"
2106  "the full interpolation not edge code");
2107 
2108  for (int y = 0; y != height; y++) {
2109  std::vector<Defect::Ptr> badList1D = classify_defects(badList, y, width);
2110 
2111  do_defects(badList1D, y, *mimage.getImage(),
2112  -std::numeric_limits<typename MaskedImageT::Image::Pixel>::max(),
2113  fallbackValue, useFallbackValueAtEdge, nUseInterp);
2114 
2115  do_defects(badList1D, y, *mimage.getMask(), interpBit, useFallbackValueAtEdge, nUseInterp);
2116 
2117  do_defects(badList1D, y, *mimage.getVariance(),
2118  -std::numeric_limits<typename MaskedImageT::Image::Pixel>::max(),
2119  fallbackValue, useFallbackValueAtEdge, nUseInterp);
2120  }
2121 }
int y
Point2I const getMin() const
Definition: Box.h:123
Box2I BoxI
Definition: Box.h:479
An integer coordinate rectangle.
Definition: Box.h:53
void ImageT ImageT int float saturatedPixelValue int const width
Definition: saturated.cc:44
void shift(Extent2I const &offset)
Shift the position of the box by the given offset.
Point2I const getMax() const
Definition: Box.h:127
void ImageT ImageT int float saturatedPixelValue int const height
Definition: saturated.cc:44
lsst::meas::algorithms::LSST_EXCEPTION_TYPE ( NotImplementedException  ,
lsst::pex::exceptions::RuntimeError  ,
lsst::meas::algorithms::NotImplementedException   
)

An exception that indicates the feature has not been implemented.

template<typename ExposureT >
boost::shared_ptr< ExposurePatch<ExposureT> > lsst::meas::algorithms::makeExposurePatch ( boost::shared_ptr< ExposureT const >  exp,
boost::shared_ptr< afw::detection::Footprint const >  foot,
afw::geom::Point2D const &  center 
)

Factory function for ExposurePatch.

Definition at line 86 of file ExposurePatch.h.

90  {
91  return std::make_shared<ExposurePatch<ExposureT> >(exp, foot, center);
92 }
template<typename ExposureT >
boost::shared_ptr< ExposurePatch<ExposureT> > lsst::meas::algorithms::makeExposurePatch ( boost::shared_ptr< ExposureT const >  exp,
afw::detection::Footprint const &  standardFoot,
afw::geom::Point2D const &  standardCenter,
afw::image::Wcs const &  standardWcs 
)

Definition at line 94 of file ExposurePatch.h.

99  {
100  return std::make_shared<ExposurePatch<ExposureT> >(exp, standardFoot, standardCenter, standardWcs);
101 }
template<typename PixelT >
std::shared_ptr<PsfCandidate<PixelT> > lsst::meas::algorithms::makePsfCandidate ( boost::shared_ptr< afw::table::SourceRecord > const &  source,
boost::shared_ptr< afw::image::Exposure< PixelT > >  image 
)

Return a PsfCandidate of the right sort.

Cf. std::make_pair

Parameters
sourceThe detected Source
imageThe image wherein lies the object

Definition at line 182 of file PsfCandidate.h.

185  {
186  return std::make_shared< PsfCandidate<PixelT> >(source, image);
187  }
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
void lsst::meas::algorithms::setSpatialParameters ( afwMath::Kernel kernel,
std::vector< double > const &  coeffs 
)

Fit a Kernel's spatial variability from a set of stars.

Definition at line 520 of file SpatialModelPsf.cc.

523 {
524  int const nComponents = kernel->getNKernelParameters();
525  int const nSpatialParams = kernel->getNSpatialParameters();
526 
527  assert (nComponents*nSpatialParams == static_cast<long>(coeffs.size()));
528 
529  std::vector<std::vector<double> > kCoeffs; // coefficients rearranged for Kernel
530  kCoeffs.reserve(nComponents);
531  for (int i = 0; i != nComponents; ++i) {
532  kCoeffs.push_back(std::vector<double>(nSpatialParams));
533  std::copy(coeffs.begin() + i*nSpatialParams,
534  coeffs.begin() + (i + 1)*nSpatialParams, kCoeffs[i].begin());
535  }
536 
537  kernel->setSpatialParameters(kCoeffs);
538 }
int getNSpatialParameters() const
Return the number of spatial parameters (0 if not spatially varying)
Definition: Kernel.h:293
unsigned int getNKernelParameters() const
Return the number of kernel parameters (0 if none)
Definition: Kernel.h:286
void setSpatialParameters(const std::vector< std::vector< double > > params)
Set the parameters of all spatial functions.
Definition: Kernel.cc:139
void lsst::meas::algorithms::setSpatialParameters ( afwMath::Kernel kernel,
Eigen::VectorXd const &  vec 
)

Fit a Kernel's spatial variability from a set of stars.

Definition at line 544 of file SpatialModelPsf.cc.

547 {
548  int const nComponents = kernel->getNKernelParameters();
549  int const nSpatialParams = kernel->getNSpatialParameters();
550 
551  assert (nComponents*nSpatialParams == vec.size());
552 
553  std::vector<std::vector<double> > kCoeffs; // coefficients rearranged for Kernel
554  kCoeffs.reserve(nComponents);
555  for (int i = 0; i != nComponents; ++i) {
556  std::vector<double> spatialCoeffs(nSpatialParams);
557  for (int j = 0; j != nSpatialParams; ++j) {
558  spatialCoeffs[j] = vec[i*nSpatialParams + j];
559  }
560  kCoeffs.push_back(spatialCoeffs);
561  }
562 
563  kernel->setSpatialParameters(kCoeffs);
564 }
int getNSpatialParameters() const
Return the number of spatial parameters (0 if not spatially varying)
Definition: Kernel.h:293
unsigned int getNKernelParameters() const
Return the number of kernel parameters (0 if none)
Definition: Kernel.h:286
void setSpatialParameters(const std::vector< std::vector< double > > params)
Set the parameters of all spatial functions.
Definition: Kernel.cc:139
template<typename ImageT >
double lsst::meas::algorithms::subtractPsf ( lsst::afw::detection::Psf const &  psf,
ImageT *  data,
double  x,
double  y,
double  psfFlux = std::numeric_limits< double >::quiet_NaN() 
)
template<typename MaskedImageT >
double lsst::meas::algorithms::subtractPsf ( afwDetection::Psf const &  psf,
MaskedImageT *  data,
double  x,
double  y,
double  psfFlux 
)

Subtract a PSF from an image at a given position.

Parameters
psfthe PSF to subtract
dataImage to subtract PSF from
xcolumn position
yrow position
psfFluxobject's PSF flux (if not NaN)

Definition at line 1009 of file SpatialModelPsf.cc.

1015 {
1016  if (std::isnan(x + y)) {
1017  return std::numeric_limits<double>::quiet_NaN();
1018  }
1019 
1020  //
1021  // Get Psf candidate
1022  //
1023  afwDetection::Psf::Image::Ptr kImage = psf.computeImage(afwGeom::PointD(x, y));
1024 
1025  //
1026  // Now find the proper sub-Image
1027  //
1028  afwGeom::BoxI bbox = kImage->getBBox();
1029 
1030  typename MaskedImageT::Ptr subData(new MaskedImageT(*data, bbox, afwImage::PARENT, false)); // shallow copy
1031  //
1032  // Now we've got both; find the PSF's amplitude
1033  //
1034  double lambda = 0.0; // floor for variance is lambda*data
1035  try {
1036  double chi2; // chi^2 for fit
1037  double amp; // estimate of amplitude of model at this point
1038 
1039  if (std::isnan(psfFlux)) {
1040  std::pair<double, double> result = fitKernel(*kImage, *subData, lambda, true);
1041  chi2 = result.first; // chi^2 for fit
1042  amp = result.second; // estimate of amplitude of model at this point
1043  } else {
1044  chi2 = std::numeric_limits<double>::quiet_NaN();
1045  amp = psfFlux/afwMath::makeStatistics(*kImage, afwMath::SUM).getValue();
1046  }
1047  //
1048  // Convert kImage to the proper type so that I can subtract it.
1049  //
1050  typename MaskedImageT::Image::Ptr
1051  kImageF(new typename MaskedImageT::Image(*kImage, true)); // of data's type
1052 
1053  *kImageF *= amp;
1054  *subData->getImage() -= *kImageF;
1055 
1056  return chi2;
1057  } catch(lsst::pex::exceptions::RangeError &e) {
1058  LSST_EXCEPT_ADD(e, (boost::format("Object at (%.2f, %.2f)") % x % y).str());
1059  throw e;
1060  }
1061 }
int y
An integer coordinate rectangle.
Definition: Box.h:53
double getValue(Property const prop=NOTHING) const
Return the value of the desired property (if specified in the constructor)
Definition: Statistics.cc:1034
double x
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
Definition: Statistics.cc:1107
find sum of pixels in the image
Definition: Statistics.h:78
#define LSST_EXCEPT_ADD(e, m)
Add the current location and a message to an existing exception before rethrowing it...
Definition: Exception.h:51