41 #include "boost/format.hpp"
67 typedef std::shared_ptr<IdSpan>
Ptr;
68 typedef std::shared_ptr<const IdSpan>
ConstPtr;
70 explicit IdSpan(
int id,
int y,
int x0,
int x1) : id(id), y(y), x0(x0), x1(x1) {}
78 struct IdSpanCompar :
public std::binary_function<const IdSpan::ConstPtr, const IdSpan::ConstPtr, bool> {
82 }
else if(a->id > b->id) {
87 }
else if (a->y > b->y) {
90 return (a->x0 < b->x0) ?
true :
false;
102 while (
id != aliases[
id]) {
103 resolved =
id = aliases[
id];
112 namespace algorithms {
114 namespace geom = lsst::afw::geom;
115 namespace math = lsst::afw::math;
117 namespace detection = lsst::afw::detection;
121 template<
typename ImageT,
typename MaskT>
123 double const bkgd, MaskT
const , MaskT
const saturBit, MaskT
const badMask,
124 bool const debias,
bool const grow);
126 template<
typename ImageT>
127 bool condition_3(ImageT *estimate,
double const peak,
128 double const mean_ns,
double const mean_we,
double const mean_swne,
double const mean_nwse,
130 double const dmean_ns,
double const dmean_we,
double const dmean_swne,
double const dmean_nwse,
131 double const thresH,
double const thresV,
double const thresD,
132 double const cond3Fac
138 template<
typename ImageT>
140 typedef typename std::shared_ptr<CRPixel> Ptr;
142 CRPixel(
int _col,
int _row, ImageT _val,
int _id = -1) :
148 bool operator< (
const CRPixel& a)
const {
165 template<
typename ImageT>
166 int CRPixel<ImageT>::i = 0;
168 template<
typename ImageT>
169 struct Sort_CRPixel_by_id {
170 bool operator() (CRPixel<ImageT>
const & a, CRPixel<ImageT>
const &
b)
const {
181 template <
typename MaskedImageT>
182 bool is_cr_pixel(
typename MaskedImageT::Image::Pixel *corr,
183 typename MaskedImageT::xy_locator loc,
184 double const minSigma,
185 double const thresH,
double const thresV,
double const thresD,
187 double const cond3Fac
190 typedef typename MaskedImageT::Image::Pixel ImagePixel;
194 ImagePixel
const v_00 = loc.image(0, 0);
206 ImagePixel
const mean_we = (loc.image(-1, 0) + loc.image( 1, 0))/2;
207 ImagePixel
const mean_ns = (loc.image( 0, 1) + loc.image( 0, -1))/2;
208 ImagePixel
const mean_swne = (loc.image(-1, -1) + loc.image( 1, 1))/2;
209 ImagePixel
const mean_nwse = (loc.image(-1, 1) + loc.image( 1, -1))/2;
212 if (v_00 < -minSigma) {
216 double const thres_sky_sigma = minSigma*sqrt(loc.variance(0, 0));
218 if (v_00 < mean_ns + thres_sky_sigma &&
219 v_00 < mean_we + thres_sky_sigma &&
220 v_00 < mean_swne + thres_sky_sigma &&
221 v_00 < mean_nwse + thres_sky_sigma) {
230 double const dv_00 = sqrt(loc.variance( 0, 0));
232 double const dmean_we = sqrt(loc.variance(-1, 0) + loc.variance( 1, 0))/2;
233 double const dmean_ns = sqrt(loc.variance( 0, 1) + loc.variance( 0, -1))/2;
234 double const dmean_swne = sqrt(loc.variance(-1, -1) + loc.variance( 1, 1))/2;
235 double const dmean_nwse = sqrt(loc.variance(-1, 1) + loc.variance( 1, -1))/2;
237 if (!condition_3(corr,
238 v_00 - bkgd, mean_ns - bkgd, mean_we - bkgd, mean_swne - bkgd, mean_nwse - bkgd,
239 dv_00, dmean_ns, dmean_we, dmean_swne, dmean_nwse,
240 thresH, thresV, thresD, cond3Fac)){
246 *corr +=
static_cast<ImagePixel
>(bkgd);
256 template <
typename MaskedImageT>
258 std::vector<CRPixel<typename MaskedImageT::Image::Pixel> >& crpixels,
261 int const x0,
int const x1,
263 double const minSigma,
264 double const thresH,
double const thresV,
double const thresD,
266 double const cond3Fac,
270 typedef typename MaskedImageT::Image::Pixel MImagePixel;
271 typename MaskedImageT::xy_locator loc = image.xy_at(x0 - 1, y);
273 int const imageX0 = image.getX0();
274 int const imageY0 = image.getY0();
276 for (
int x = x0 - 1;
x <= x1 + 1; ++
x) {
277 MImagePixel corr = 0;
278 if (is_cr_pixel<MaskedImageT>(&corr, loc, minSigma, thresH, thresV, thresD,
281 crpixels.push_back(CRPixel<MImagePixel>(
x + imageX0, y + imageY0, loc.image()));
285 extras->
addSpan(y + imageY0,
x + imageX0,
x + imageX0);
295 template <
typename ImageT>
298 CountsInCR(ImageT
const& mimage,
double const bkgd) :
299 detection::FootprintFunctor<ImageT>(mimage),
304 void operator()(
typename ImageT::xy_locator loc,
311 virtual void reset() {
315 double getCounts()
const {
return _sum; }
325 template <
typename ImageT>
326 static void reinstateCrPixels(
328 std::vector<CRPixel<typename ImageT::Pixel> >
const& crpixels
331 if (crpixels.empty())
return;
333 typedef typename std::vector<CRPixel<typename ImageT::Pixel> >::const_iterator crpixel_iter;
334 for (crpixel_iter crp = crpixels.begin(), end = crpixels.end(); crp < end - 1 ; ++crp) {
335 *image->at(crp->col - image->getX0(), crp->row - image->getY0()) = crp->val;
344 template <
typename MaskedImageT>
345 std::vector<detection::Footprint::Ptr>
352 typedef typename MaskedImageT::Image ImageT;
353 typedef typename ImageT::Pixel ImagePixel;
354 typedef typename MaskedImageT::Mask::Pixel
MaskPixel;
357 double const minSigma = policy.
getDouble(
"minSigma");
358 double const minDn = policy.
getDouble(
"min_DN");
359 double const cond3Fac = policy.
getDouble(
"cond3_fac");
360 double const cond3Fac2 = policy.
getDouble(
"cond3_fac2");
361 int const niteration = policy.
getInt(
"niteration");
363 int const nCrPixelMax = policy.
getInt(
"nCrPixelMax");
371 throw LSST_EXCEPT(pexExcept::NotFoundError,
"Psf is unable to return a kernel");
374 kernel->computeImage(psfImage,
true);
376 int const xc = kernel->getCtrX();
377 int const yc = kernel->getCtrY();
379 double const I0 = psfImage(xc, yc);
380 double const thresH = cond3Fac2*(0.5*(psfImage(xc - 1, yc) + psfImage(xc + 1, yc)))/I0;
381 double const thresV = cond3Fac2*(0.5*(psfImage(xc, yc - 1) + psfImage(xc, yc + 1)))/I0;
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;
387 MaskPixel
const badBit = mimage.getMask()->getPlaneBitMask(
"BAD");
388 MaskPixel
const crBit = mimage.getMask()->getPlaneBitMask(
"CR");
389 MaskPixel
const interpBit = mimage.getMask()->getPlaneBitMask(
"INTRP");
390 MaskPixel
const saturBit = mimage.getMask()->getPlaneBitMask(
"SAT");
391 MaskPixel
const nodataBit = mimage.getMask()->getPlaneBitMask(
"NO_DATA");
393 MaskPixel
const badMask = (badBit | interpBit | saturBit | nodataBit);
397 int const ncol = mimage.getWidth();
398 int const nrow = mimage.getHeight();
400 std::vector<CRPixel<ImagePixel> > crpixels;
401 typedef typename std::vector<CRPixel<ImagePixel> >::iterator crpixel_iter;
402 typedef typename std::vector<CRPixel<ImagePixel> >::reverse_iterator crpixel_riter;
404 for (
int j = 1; j < nrow - 1; ++j) {
405 typename MaskedImageT::xy_locator loc = mimage.xy_at(1, j);
407 for (
int i = 1; i < ncol - 1; ++i, ++loc.x()) {
409 if (!is_cr_pixel<MaskedImageT>(&corr, loc, minSigma,
410 thresH, thresV, thresD, bkgd, cond3Fac)) {
416 if (loc.mask() & badMask) {
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) {
430 crpixels.push_back(CRPixel<ImagePixel>(i + mimage.getX0(), j + mimage.getY0(), loc.image()));
433 if (static_cast<int>(crpixels.size()) > nCrPixelMax) {
434 reinstateCrPixels(mimage.getImage().get(), crpixels);
436 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
437 (
boost::format(
"Too many CR pixels (max %d)") % nCrPixelMax).str());
445 std::vector<int> aliases;
446 aliases.reserve(1 + crpixels.size()/2);
448 std::vector<detection::IdSpan::Ptr> spans;
449 spans.reserve(aliases.capacity());
451 aliases.push_back(0);
459 if (!crpixels.empty()) {
461 int x0 = -1, x1 = -1, y = -1;
464 CRPixel<ImagePixel> dummy(0, -1, 0, -1);
465 crpixels.push_back(dummy);
467 for (crpixel_iter crp = crpixels.begin(); crp < crpixels.end() - 1 ; ++crp) {
472 aliases.push_back(crp->id);
480 if (crp[1].
row == crp[0].
row && crp[1].
col == crp[0].
col + 1) {
485 assert (y >= 0 && x0 >= 0 && x1 >= 0);
494 if (crpixels.size() > 0) {
495 for (crpixel_iter cp = crpixels.begin(); cp != crpixels.end() - 1; cp++) {
497 assert(cp->col >= 0);
498 assert(cp->row >= 0);
501 assert(crpixels[crpixels.size()-1].id == -1);
502 assert(crpixels[crpixels.size()-1].col == 0);
503 assert(crpixels[crpixels.size()-1].row == -1);
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);
522 for (std::vector<detection::IdSpan::Ptr>::iterator sp = spans.begin(), end = spans.end();
524 int const y = (*sp)->y;
525 int const x0 = (*sp)->x0;
526 int const x1 = (*sp)->x1;
529 for (std::vector<detection::IdSpan::Ptr>::iterator sp2 = sp + 1; sp2 != end; ++sp2) {
530 if ((*sp2)->y == y) {
534 }
else if ((*sp2)->y != (y + 1)) {
537 }
else if ((*sp2)->x0 > (x1 + 1)) {
540 }
else if ((*sp2)->x1 >= (x0 - 1)) {
556 for (
unsigned int i = 0; i != spans.size(); ++i) {
563 if (spans.size() > 0) {
570 std::vector<detection::Footprint::Ptr> CRs;
572 if (spans.size() > 0) {
573 int id = spans[0]->id;
575 for (
unsigned int i = i0; i <= spans.size(); ++i) {
576 if (i == spans.size() || spans[i]->id !=
id) {
579 for (; i0 < i; ++i0) {
580 cr->addSpan(spans[i0]->y, spans[i0]->x0, spans[i0]->x1);
585 if (i < spans.size()) {
591 reinstateCrPixels(mimage.getImage().get(), crpixels);
595 CountsInCR<ImageT> CountDN(*mimage.getImage(), bkgd);
596 for (std::vector<detection::Footprint::Ptr>::iterator cr = CRs.begin(), end = CRs.end();
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) {
603 LOGL_DEBUG(
"TRACE5.algorithms.CR",
"Erasing CR");
614 bool const debias_values =
true;
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
620 mimage.getMask()->getPlaneBitMask(
"DETECTED"));
629 bool too_many_crs =
false;
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++) {
641 int const npix = (om) ? om->getNpix() : 0;
643 if (static_cast<std::size_t>(npix) == cr->getNpix()) {
651 for (detection::Footprint::SpanList::const_iterator siter = cr->getSpans().begin();
652 siter != cr->getSpans().end(); siter++) {
653 detection::Span::Ptr
const span = *siter;
661 int const y = span->getY() - mimage.getY0();
662 if (y < 2 || y >= nrow - 2) {
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;
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);
679 if (nextra + static_cast<int>(crpixels.size()) > nCrPixelMax) {
687 for (detection::Footprint::SpanList::const_iterator siter = espans.begin();
688 siter != espans.end(); siter++) {
689 cr->addSpan(**siter);
712 if (keep || too_many_crs) {
713 if (crpixels.size() > 0) {
714 int const imageX0 = mimage.getX0();
715 int const imageY0 = mimage.getY0();
717 std::sort(crpixels.begin(), crpixels.end());
719 crpixel_riter rend = crpixels.rend();
720 for (crpixel_riter crp = crpixels.rbegin(); crp != rend; ++crp) {
724 mimage.at(crp->col - imageX0, crp->row - imageY0).image() = crp->val;
728 if (
true || nextra > 0) {
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);
737 static_cast<MaskPixel
>(crBit | interpBit));
741 throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
742 (
boost::format(
"Too many CR pixels (max %d)") % nCrPixelMax).str());
753 template<
typename ImageT>
754 bool condition_3(ImageT *estimate,
756 double const mean_ns,
757 double const mean_we,
758 double const mean_swne,
759 double const mean_nwse,
761 double const dmean_ns,
762 double const dmean_we,
763 double const dmean_swne,
764 double const dmean_nwse,
768 double const cond3Fac
771 if (thresV*(peak - cond3Fac*dpeak) > mean_ns + cond3Fac*dmean_ns) {
772 *estimate = (ImageT)mean_ns;
776 if (thresH*(peak - cond3Fac*dpeak) > mean_we + cond3Fac*dmean_we) {
781 if (thresD*(peak - cond3Fac*dpeak) > mean_swne + cond3Fac*dmean_swne) {
782 *estimate = mean_swne;
786 if (thresD*(peak - cond3Fac*dpeak) > mean_nwse + cond3Fac*dmean_nwse) {
787 *estimate = mean_nwse;
798 template <
typename MaskedImageT>
801 RemoveCR(MaskedImageT
const& mimage,
803 typename MaskedImageT::Mask::Pixel badMask,
806 ) : detection::FootprintFunctor<MaskedImageT>(mimage),
808 _ncol(mimage.getWidth()),
809 _nrow(mimage.getHeight()),
815 void operator()(
typename MaskedImageT::xy_locator loc,
819 typedef typename MaskedImageT::Image::Pixel MImagePixel;
820 MImagePixel min = std::numeric_limits<MImagePixel>::max();
823 MImagePixel
const minval =
_bkgd - 2*sqrt(loc.variance());
827 if (x - 2 >= 0 && x + 2 <
_ncol) {
832 MImagePixel
const v_m2 = loc.image(-2, 0);
833 MImagePixel
const v_m1 = loc.image(-1, 0);
834 MImagePixel
const v_p1 = loc.image( 1, 0);
835 MImagePixel
const v_p2 = loc.image( 2, 0);
837 MImagePixel
const tmp =
840 if (tmp > minval && tmp < min) {
849 if (y - 2 >= 0 && y + 2 <
_nrow) {
854 MImagePixel
const v_m2 = loc.image(0, -2);
855 MImagePixel
const v_m1 = loc.image(0, -1);
856 MImagePixel
const v_p1 = loc.image(0, 1);
857 MImagePixel
const v_p2 = loc.image(0, 2);
859 MImagePixel
const tmp =
862 if (tmp > minval && tmp < min) {
871 if (x - 2 >= 0 && x + 2 <
_ncol && y - 2 >= 0 && y + 2 <
_nrow) {
876 MImagePixel
const v_m2 = loc.image(-2, -2);
877 MImagePixel
const v_m1 = loc.image(-1, -1);
878 MImagePixel
const v_p1 = loc.image( 1, 1);
879 MImagePixel
const v_p2 = loc.image( 2, 2);
881 MImagePixel
const tmp =
884 if (tmp > minval && tmp < min) {
893 if (x - 2 >= 0 && x + 2 <
_ncol && y - 2 >= 0 && y + 2 <
_nrow) {
898 MImagePixel
const v_m2 = loc.image( 2, -2);
899 MImagePixel
const v_m1 = loc.image( 1, -1);
900 MImagePixel
const v_p1 = loc.image(-1, 1);
901 MImagePixel
const v_p2 = loc.image(-2, 2);
903 MImagePixel
const tmp =
906 if (tmp > minval && tmp < min) {
920 std::pair<bool, MImagePixel const> val_h =
922 std::pair<bool, MImagePixel const> val_v =
927 min =
_bkgd + sqrt(loc.variance())*
_rand.gaussian();
935 min = (val_v.second + val_h.second)/2;
947 LOGL_DEBUG(
"TRACE3.algorithms.CR",
"Adopted min==%g at (%d, %d) (ngood=%d)",
948 static_cast<double>(min), x, y, ngood);
969 template<
typename ImageT,
typename MaskT>
971 std::vector<detection::Footprint::Ptr> & CRs,
974 MaskT
const saturBit,
992 RemoveCR<image::MaskedImage<ImageT, MaskT> > removeCR(mi, bkgd, badMask, debias, rand);
994 for (std::vector<detection::Footprint::Ptr>::reverse_iterator fiter = CRs.rbegin();
995 fiter != CRs.rend(); ++fiter) {
1001 if (grow && cr->getNpix() < 100) {
1003 bool const isotropic =
false;
1007 if (saturPixels->getNpix() > 0) {
1012 }
catch(lsst::pex::exceptions::LengthError &) {
1019 removeCR.apply(*cr);
1028 #define INSTANTIATE(TYPE) \
1030 std::vector<detection::Footprint::Ptr> \
1031 findCosmicRays(lsst::afw::image::MaskedImage<TYPE> &image, \
1032 detection::Psf const &psf, \
1033 double const bkgd, \
1034 lsst::pex::policy::Policy const& policy, \
int getInt(const std::string &name) const
return an integer value associated with the given name.
An include file to include the header files for lsst::afw::geom.
double const min2GaussianBias
Mean value of the minimum of two N(0,1) variates.
Include files required for standard LSST Exception handling.
a container for holding hierarchical configuration data in memory.
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's the intersection of a Footprint with a Mask.
IdSpan(int id, int y, int x0, int x1)
bool operator()(const IdSpan::ConstPtr a, const IdSpan::ConstPtr b)
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
table::Key< table::Array< Kernel::Pixel > > image
LSST DM logging module built on log4cxx.
boost::shared_ptr< Kernel const > ConstPtr
boost::shared_ptr< Footprint > growFootprint(Footprint const &foot, int nGrow, bool isotropic=true)
Grow a Footprint by nGrow pixels, returning a new Footprint.
std::shared_ptr< IdSpan > Ptr
MaskPtr getMask(bool const noThrow=false) const
Return a (Ptr to) the MaskedImage's mask.
A class to manipulate images, masks, and variance as a single object.
comparison functor; sort by ID, then by row (y), then by column range start (x0)
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
double getDouble(const std::string &name) const
return a double value associated with the given name.
std::shared_ptr< const IdSpan > ConstPtr
std::pair< bool, typename MaskedImageT::Image::Pixel > singlePixel(int x, int y, MaskedImageT const &image, bool horizontal, double minval)
Return a boolean status (true: interpolation is OK) and the interpolated value for a pixel...
Random number generator class.
MaskT setMaskFromFootprint(lsst::afw::image::Mask< MaskT > *mask, Footprint const &footprint, MaskT const bitmask)
OR bitmask into all the Mask's pixels that are in the Footprint.
int resolve_alias(const std::vector< int > &aliases, int id)
Follow a chain of aliases, returning the final resolved value.
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.
boost::shared_ptr< math::Kernel const > getLocalKernel(geom::Point2D position=makeNullPoint(), image::Color color=image::Color()) const
Return a FixedKernel corresponding to the Psf image at the given point.
afw::table::Key< double > b
Implementation of the Class MaskedImage.
A polymorphic base class for representing an image's Point Spread Function.
double const lpc_1s2_c1
LPC coefficients for sigma = 1/sqrt(2), S/N = infty.
image::Image< Pixel > Image
Image type returned by computeImage.
double const lpc_1_c1
LPC coefficients for sigma = 1, S/N = infty.
A class that can be used to generate sequences of random numbers according to a number of different a...
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's pixels which are in the set of Footprints.
run-length code for part of object
MaskedImageT::Mask::Pixel _badMask