def makeThresholdMask(maskedImage, threshold, growFootprints=1, maskName='SAT'): """Mask pixels based on threshold detection. Parameters ---------- maskedImage : `lsst.afw.image.MaskedImage` Image to process. Only the mask plane is updated. threshold : scalar Detection threshold. growFootprints : scalar, optional Number of pixels to grow footprints of detected regions. maskName : str, optional Mask plane name, or list of names to convert Returns ------- defectList : `lsst.meas.algorithms.Defects` Defect list constructed from pixels above the threshold. """ # find saturated regions thresh = afwDetection.Threshold(threshold) fs = afwDetection.FootprintSet(maskedImage, thresh) if growFootprints > 0: fs = afwDetection.FootprintSet(fs, rGrow=growFootprints, isotropic=False) fpList = fs.getFootprints() # set mask mask = maskedImage.getMask() bitmask = mask.getPlaneBitMask(maskName) afwDetection.setMaskFromFootprintList(mask, fpList, bitmask) return Defects.fromFootprintList(fpList)
def testGrowLRUD2(self): """Grow footprints in various directions using the FootprintSet/FootprintControl constructor Check that overlapping grown Footprints give the expected answers """ ngrow = 3 # How much to grow by for fctrl, xy in [ (afwDetect.FootprintControl(True, True, False, False), [(4, 5), (5, 6), (6, 5)]), (afwDetect.FootprintControl(False, False, True, True), [(5, 4), (6, 5), (5, 6)]), ]: im = afwImage.MaskedImageF(11, 11) for x, y in xy: im[x, y, afwImage.LOCAL] = (10, 0x0, 0.0) fs = afwDetect.FootprintSet(im, afwDetect.Threshold(10)) self.assertEqual(len(fs.getFootprints()), 1) grown = afwDetect.FootprintSet(fs, ngrow, fctrl) im.getMask().set(0) afwDetect.setMaskFromFootprintList(im.getMask(), grown.getFootprints(), 0x10) if display: ds9.mtv(im) self.assertEqual(len(grown.getFootprints()), 1) foot = grown.getFootprints()[0] npix = 1 + 2 * ngrow npix += 3 + 2 * ngrow # 3: distance between pair of set pixels 000X0X000 self.assertEqual(foot.getArea(), npix)
def processSingle(self, sensorRef): """Process a single CCD Besides the regular ISR, also masks cosmic-rays and divides each processed image by the dark time to generate images of the dark rate. The dark time is provided by the 'getDarkTime' method. """ exposure = CalibTask.processSingle(self, sensorRef) if self.config.doRepair: psf = measAlg.DoubleGaussianPsf( self.config.psfSize, self.config.psfSize, self.config.psfFwhm / (2 * math.sqrt(2 * math.log(2)))) exposure.setPsf(psf) self.repair.run(exposure, keepCRs=False) if self.config.crGrow > 0: mask = exposure.getMaskedImage().getMask().clone() mask &= mask.getPlaneBitMask("CR") fpSet = afwDet.FootprintSet(mask, afwDet.Threshold(0.5)) fpSet = afwDet.FootprintSet(fpSet, self.config.crGrow, True) fpSet.setMask(exposure.getMaskedImage().getMask(), "CR") mi = exposure.getMaskedImage() mi /= self.getDarkTime(exposure) return exposure
def makeThresholdMask(maskedImage, threshold, growFootprints=1, maskName='SAT'): """Mask pixels based on threshold detection @param[in,out] maskedImage afw.image.MaskedImage to process; the mask is altered @param[in] threshold detection threshold @param[in] growFootprints amount by which to grow footprints of detected regions @param[in] maskName mask plane name @return a list of defects (meas.algrithms.Defect) of regions set in the mask. """ # find saturated regions thresh = afwDetection.Threshold(threshold) fs = afwDetection.FootprintSet(maskedImage, thresh) if growFootprints > 0: fs = afwDetection.FootprintSet(fs, growFootprints) fpList = fs.getFootprints() # set mask mask = maskedImage.getMask() bitmask = mask.getPlaneBitMask(maskName) afwDetection.setMaskFromFootprintList(mask, fpList, bitmask) return defectListFromFootprintList(fpList, growFootprints=0)
def doTestPeaks(self, dwidth=0, dheight=0, x0=0, y0=0, threshold=10, callback=None, polarity=True, grow=0): """Worker routine for tests polarity: True if should search for +ve pixels""" self.doSetUp(dwidth, dheight, x0, y0) if not polarity: self.im *= -1 if callback: callback() # # Sort self.peaks in decreasing peak height to match Footprint.getPeaks() # for i, peaks in enumerate(self.peaks): self.peaks[i] = sorted([(x, y, self.im.getImage().get(x, y)) for x, y in peaks], lambda x, y: cmpPeaks(self.im, x, y)) threshold = afwDetect.Threshold(threshold, afwDetect.Threshold.VALUE, polarity) fs = afwDetect.FootprintSet(self.im, threshold, "BINNED1") if grow: fs = afwDetect.FootprintSet(fs, grow, True) msk = self.im.getMask() afwDetect.setMaskFromFootprintList(msk, fs.getFootprints(), msk.getPlaneBitMask("DETECTED")) del msk self.fs = fs self.checkPeaks(dwidth, dheight, frame=3)
def detectObjectsInExp(exp, nSigma=10, nPixMin=10, grow=0): """Quick and dirty object detection for an expsure. Return the footPrintSet for the objects in a preferably-postISR exposure. Parameters ---------- exp : `lsst.afw.image.Exposure` The exposure to detect objects in. nSigma : `float` The number of sigma for detection. nPixMin : `int` The minimum number of pixels in an object for detection. grow : `int` The number of pixels to grow the footprint by after detection. Returns ------- footPrintSet : `lsst.afw.detection.FootprintSet` The set of footprints in the image. """ median = np.nanmedian(exp.image.array) exp.image -= median threshold = afwDetect.Threshold(nSigma, afwDetect.Threshold.STDEV) footPrintSet = afwDetect.FootprintSet(exp.getMaskedImage(), threshold, "DETECTED", nPixMin) if grow > 0: isotropic = True footPrintSet = afwDetect.FootprintSet(footPrintSet, grow, isotropic) exp.image += median # add back in to leave background unchanged return footPrintSet
def clean_use_hsc_mask(exposure, ref_plane='THRESH_HIGH', rgrow=None, random_state=None, bright_object_mask=True): # generate array of gaussian noise mi = exposure.getMaskedImage() mask = mi.getMask() noise_array = utils.make_noise_image(mi, random_state) threshold = afwDet.Threshold(mask.getPlaneBitMask(['DETECTED'])) fp_det = afwDet.FootprintSet(mask, threshold, afwDet.Threshold.BITMASK) fp_list = [] for fp in fp_det.getFootprints(): hfp = afwDet.HeavyFootprintF(fp, mi) pix = hfp.getMaskArray() check = (pix & mask.getPlaneBitMask(ref_plane)!=0).sum() if check > 0: fp_list.append(fp) fpset_replace = afwDet.FootprintSet(mi.getBBox()) fpset_replace.setFootprints(fp_list) if rgrow: fpset_replace = afwDet.FootprintSet(fpset_replace, rgrow, True) mask.addMaskPlane('CLEANED') fpset_replace.setMask(mask, 'CLEANED') exp_clean = exposure.clone() mi_clean = exp_clean.getMaskedImage() replace = mask.getArray() & mask.getPlaneBitMask('CLEANED') != 0 if bright_object_mask: replace |= mask.getArray() & mask.getPlaneBitMask('BRIGHT_OBJECT') != 0 mi_clean.getImage().getArray()[replace] = noise_array[replace] return exp_clean
def remove_small_sources_thresholding(exposure, min_radius_arcsec, random_state=None): mi = exposure.getMaskedImage() mask = mi.getMask() noise_array = utils.make_noise_image(mi, random_state) threshold = afwDet.Threshold(mask.getPlaneBitMask(['DETECTED'])) fp_det = afwDet.FootprintSet(mask, threshold, afwDet.Threshold.BITMASK) area_min = np.pi * (min_radius_arcsec / utils.pixscale)**2 fp_list = [] for fp in fp_det.getFootprints(): if fp.getArea() < area_min: fp_list.append(fp) fp_small = afwDet.FootprintSet(mi.getBBox()) fp_small.setFootprints(fp_list) mask.addMaskPlane('SMALL') fp_small.setMask(mask, 'SMALL') exp_clean = exposure.clone() mi_clean = exp_clean.getMaskedImage() replace = mask.getArray() & mask.getPlaneBitMask('SMALL') != 0 mi_clean = exp_clean.getMaskedImage() mi_clean.getImage().getArray()[replace] = noise_array[replace] return exp_clean
def testGrowCircular(self): """Grow footprints in all 4 directions using the FootprintSet/FootprintControl constructor """ im = afwImage.MaskedImageF(11, 11) im[5, 5, afwImage.LOCAL] = (10, 0x0, 0.0) fs = afwDetect.FootprintSet(im, afwDetect.Threshold(10)) self.assertEqual(len(fs.getFootprints()), 1) radius = 3 # How much to grow by for fctrl in ( afwDetect.FootprintControl(), afwDetect.FootprintControl(True), afwDetect.FootprintControl(True, True), ): grown = afwDetect.FootprintSet(fs, radius, fctrl) afwDetect.setMaskFromFootprintList(im.getMask(), grown.getFootprints(), 0x10) if display: ds9.mtv(im) foot = grown.getFootprints()[0] if not fctrl.isCircular()[0]: self.assertEqual(foot.getArea(), 1) elif fctrl.isCircular()[0]: assert radius == 3 if fctrl.isIsotropic()[1]: self.assertEqual(foot.getArea(), 29) else: self.assertEqual(foot.getArea(), 25)
def detectObjectsInExp(exp, nSigma, nPixMin, grow=0): """Run a very basic but fast threshold-based object detection on an exposure Return the footPrintSet for the objects in a postISR exposure. Parameters ---------- exp : `lsst.afw.image.Exposure` Image in which to detect objects. nSigma : `float` nSigma above image's stddev at which to set the detection threshold. nPixMin : `int` Minimum number of pixels for detection. grow : `int` Grow the detected footprint by this many pixels. Returns ------- footPrintSet : `lsst.afw.detection.FootprintSet` FootprintSet containing the detections. """ threshold = afwDetect.Threshold(nSigma, afwDetect.Threshold.STDEV) footPrintSet = afwDetect.FootprintSet(exp.getMaskedImage(), threshold, "DETECTED", nPixMin) if grow > 0: isotropic = True footPrintSet = afwDetect.FootprintSet(footPrintSet, grow, isotropic) return footPrintSet
def Clusterfind_max_timecode_one_file(filename, winow_xmin=0, winow_xmax=999, winow_ymin=0, winow_ymax=999, glitch_threshold=20000, checkerboard_phase=None, npix_min=1): if str(filename).find('.DS') != -1: return import lsst.afw.detection as afwDetect import string, os cluster_sizes = [] timecodes = [] files = [] thresholdValue = 1 npixMin = npix_min grow = 0 isotropic = False image = TimepixToExposure(filename, winow_xmin, winow_xmax, winow_ymin, winow_ymax) threshold = afwDetect.Threshold(thresholdValue) footPrintSet = afwDetect.FootprintSet(image, threshold, npixMin) footPrintSet = afwDetect.FootprintSet(footPrintSet, grow, isotropic) footPrints = footPrintSet.getFootprints() for footprintnum, footprint in enumerate(footPrints): npix = afwDetect.Footprint.getNpix(footprint) cluster_sizes.append(npix) # if npix >= 4: box = footprint.getBBox() bbox_xmin = box.getMinX() bbox_xmax = box.getMaxX() + 1 bbox_ymin = box.getMinY() bbox_ymax = box.getMaxY() + 1 data = image.getArray()[bbox_ymin:bbox_ymax, bbox_xmin:bbox_xmax] # x,y,t,chisq = CentroidTimepixCluster(data, fit_function = 'gaus') # timecodes.append(t) ## centroid_x, centroid_y = footprint.getCentroid() ## x += bbox_xmin ## y += bbox_ymin if checkerboard_phase is not None: print('WARNING - Not yet implemented') exit() if (bbox_xmin + bbox_ymin) % 2 == checkerboard_phase: timecode -= 1 timecodes.append(GetMaxClusterTimecode(data)) return timecodes
def run(frame=6): im = afwImage.MaskedImageF(afwGeom.Extent2I(14, 10)) # # Populate the image with objects that we should detect # objects = [] objects.append([(4, 1, 10), (3, 2, 10), (4, 2, 20), (5, 2, 10), (4, 3, 10),]) objects.append([(9, 7, 30), (10, 7, 29), (12, 7, 28), (10, 8, 27), (11, 8, 26), (10, 4, -5)]) objects.append([(3, 8, 10), (4, 8, 10),]) for obj in objects: for x, y, I in obj: im.getImage().set(x, y, I) im.getVariance().set(1) im.getVariance().set(10, 4, 0.5**2) # # Detect the objects at 10 counts or above # level = 10 fs = afwDetect.FootprintSet(im, afwDetect.Threshold(level), "DETECTED") showPeaks(im, fs, frame=frame) # # Detect the objects at -10 counts or below. N.b. the peak's at -5, so it isn't detected # polarity = False # look for objects below background threshold = afwDetect.Threshold(level, afwDetect.Threshold.VALUE, polarity) fs2 = afwDetect.FootprintSet(im, threshold, "DETECTED_NEGATIVE") print("Detected %d objects below background" % len(fs2.getFootprints())) # # Search in S/N (n.b. the peak's -10sigma) # threshold = afwDetect.Threshold(level, afwDetect.Threshold.PIXEL_STDEV, polarity) fs2 = afwDetect.FootprintSet(im, threshold) # # Here's another way to set a mask plane (we chose not to do so in the FootprintSet call) # msk = im.getMask() afwDetect.setMaskFromFootprintList(msk, fs2.getFootprints(), msk.getPlaneBitMask("DETECTED_NEGATIVE")) if frame is not None: ds9.mtv(msk, isMask=True, frame=frame) # # Merge the positive and negative detections, growing both sets by 1 pixel # fs.merge(fs2, 1, 1) # # Set EDGE so we can see the grown Footprints # afwDetect.setMaskFromFootprintList(msk, fs.getFootprints(), msk.getPlaneBitMask("EDGE")) if frame is not None: ds9.mtv(msk, isMask=True, frame=frame) showPeaks(fs=fs, frame=frame)
def testGrow(self): """Grow footprints using the FootprintSet constructor""" fs = afwDetect.FootprintSet(self.im, afwDetect.Threshold(10)) self.assertEqual(len(fs.getFootprints()), len(self.objects)) for isotropic in (True, False, afwDetect.FootprintControl(True),): grown = afwDetect.FootprintSet(fs, 1, isotropic) self.assertEqual(len(fs.getFootprints()), len(self.objects)) self.assertGreater(len(grown.getFootprints()), 0) self.assertLessEqual(len(grown.getFootprints()), len(fs.getFootprints()))
def testGrowFootprints3(self): """Test that we can grow footprints, correctly merging those that now totally overwritten""" self.im = afwImage.MaskedImageF(14, 11) self.im.getImage().set(0) self.peaks = [] I = 11 for x, y in [(4, 7), (5, 7), (6, 7), (7, 7), (8, 7), (4, 6), (8, 6), (4, 5), (8, 5), (4, 4), (8, 4), (4, 3), (8, 3), ]: self.im.getImage().set(x, y, I) I -= 1e-3 self.im.getImage().set(4, 7, 15) self.peaks.append([(4, 7,),]) self.im.getImage().set(6, 5, 30) self.peaks[0].append((6, 5,)) self.fs = afwDetect.FootprintSet(self.im, afwDetect.Threshold(10), "BINNED1") # # The disappearing Footprint special case only shows up if the outer Footprint is grown # _after_ the inner one. So arrange the order properly feet = self.fs.getFootprints() feet[0], feet[1] = feet[1], feet[0] msk = self.im.getMask() grow = 2 self.fs = afwDetect.FootprintSet(self.fs, grow, False) afwDetect.setMaskFromFootprintList(msk, self.fs.getFootprints(), msk.getPlaneBitMask("DETECTED_NEGATIVE")) if display: frame = 0 ds9.mtv(self.im, frame=frame) with ds9.Buffering(): for i, foot in enumerate(self.fs.getFootprints()): for p in foot.getPeaks(): ds9.dot("+", p.getIx(), p.getIy(), size=0.4, frame=frame) if i < len(self.peaks): for trueX, trueY in self.peaks[i]: ds9.dot("x", trueX, trueY, size=0.4, ctype=ds9.RED, frame=frame) self.assertEqual(len(self.fs.getFootprints()), 1) self.assertEqual(len(self.fs.getFootprints()[0].getPeaks()), len(self.peaks[0]))
def readImage(filename=None): """Read an image and background subtract it""" if not filename: try: afwDataDir = lsst.utils.getPackageDir("afwdata") except Exception: raise RuntimeError( "You must provide a filename or setup afwdata to run these examples" ) filename = os.path.join(afwDataDir, "CFHT", "D4", "cal-53535-i-797722_1.fits") bbox = afwGeom.Box2I(afwGeom.Point2I(270, 2530), afwGeom.Extent2I(512, 512)) else: bbox = None mi = afwImage.MaskedImageF(filename, bbox=bbox, origin=afwImage.LOCAL) mi.setXY0(afwGeom.Point2I(0, 0)) # # Subtract the background. We'd use a canned procedure, but that's in meas/utils/sourceDetection.py. We # can't fix those pesky cosmic rays either, as that's in a dependent product (meas/algorithms) too # bctrl = afwMath.BackgroundControl(afwMath.Interpolate.NATURAL_SPLINE) bctrl.setNxSample(int(mi.getWidth() / 256) + 1) bctrl.setNySample(int(mi.getHeight() / 256) + 1) sctrl = bctrl.getStatisticsControl() sctrl.setNumSigmaClip(3.0) sctrl.setNumIter(2) im = mi.getImage() try: backobj = afwMath.makeBackground(im, bctrl) except Exception as e: print(e, end=' ', file=sys.stderr) bctrl.setInterpStyle(afwMath.Interpolate.CONSTANT) backobj = afwMath.makeBackground(im, bctrl) im -= backobj.getImageF() # # Find sources # threshold = afwDetect.Threshold(5, afwDetect.Threshold.STDEV) npixMin = 5 # we didn't smooth fs = afwDetect.FootprintSet(mi, threshold, "DETECTED", npixMin) grow, isotropic = 1, False fs = afwDetect.FootprintSet(fs, grow, isotropic) fs.setMask(mi.getMask(), "DETECTED") return mi, fs
def setUp(self): """Build up three different sets of objects that are to be merged""" pos1 = [(40, 40), (220, 35), (40, 48), (220, 50), (67, 67), (150, 50), (40, 90), (70, 160), (35, 255), (70, 180), (250, 200), (120, 120), (170, 180), (100, 210), (20, 210), ] pos2 = [(43, 45), (215, 31), (171, 258), (211, 117), (48, 99), (70, 160), (125, 45), (251, 33), (37, 170), (134, 191), (79, 223), (258, 182) ] pos3 = [(70, 170), (219, 41), (253, 173), (253, 192)] box = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Point2I(300, 300)) psfsig = 1. kernelSize = 41 flux = 1000 # Create a different sized psf for each image and insert them at the # desired positions im1 = afwImage.MaskedImageD(box) psf1 = afwDetect.GaussianPsf(kernelSize, kernelSize, psfsig) im2 = afwImage.MaskedImageD(box) psf2 = afwDetect.GaussianPsf(kernelSize, kernelSize, 2*psfsig) im3 = afwImage.MaskedImageD(box) psf3 = afwDetect.GaussianPsf(kernelSize, kernelSize, 1.3*psfsig) insertPsf(pos1, im1, psf1, kernelSize, flux) insertPsf(pos2, im2, psf2, kernelSize, flux) insertPsf(pos3, im3, psf3, kernelSize, flux) schema = afwTable.SourceTable.makeMinimalSchema() self.idFactory = afwTable.IdFactory.makeSimple() self.table = afwTable.SourceTable.make(schema, self.idFactory) # Create SourceCatalogs from these objects fp1 = afwDetect.FootprintSet( im1, afwDetect.Threshold(0.001), "DETECTED") self.catalog1 = afwTable.SourceCatalog(self.table) fp1.makeSources(self.catalog1) fp2 = afwDetect.FootprintSet( im2, afwDetect.Threshold(0.001), "DETECTED") self.catalog2 = afwTable.SourceCatalog(self.table) fp2.makeSources(self.catalog2) fp3 = afwDetect.FootprintSet( im3, afwDetect.Threshold(0.001), "DETECTED") self.catalog3 = afwTable.SourceCatalog(self.table) fp3.makeSources(self.catalog3)
def image_threshold(masked_image, thresh=3.0, thresh_type='stdev', npix=1, rgrow=None, isogrow=False, plane_name='', mask=None, clear_mask=True): """ Image thresholding. A bit mask will be set with name 'plane_name'. Parameters ---------- masked_image : lsst.afw.image.MaskedImageF A masked image object. thresh : float Threshold value. thresh_type : string, optional Threshold type: stdev, pixel_stdev, bitmask, value, or variance. npix : int, optional Minimum number of touching pixels in an object. rgrow : int, optional Number of pixels to grow footprints. isogrow : bool, optional If True, use (expensive) isotropic grow. plane_name : string, optional Name of bit plane. mask : lsst.afw.image.MaskU, optional Mask to set if not same as in masked_imaged clear_mask : bool, optional If True, clear the bit plane before thresholding Returns ------- fpset : lsst.afw.detection.FootprintSet Footprints associated with detected objects. """ mask = masked_image.getMask() if mask is None else mask thresh_type = getattr(afwDet.Threshold, thresh_type.upper()) thresh = afwDet.Threshold(thresh, thresh_type) fpset = afwDet.FootprintSet(masked_image, thresh, plane_name, npix) if rgrow is not None: fpset = afwDet.FootprintSet(fpset, rgrow, isogrow) if plane_name: mask.addMaskPlane(plane_name) if clear_mask: mask.clearMaskPlane(mask.getMaskPlane(plane_name)) fpset.setMask(mask, plane_name) return fpset
def applyThreshold(self, middle, bbox, factor=1.0): """Apply thresholds to the convolved image Identifies ``Footprint``s, both positive and negative. The threshold can be modified by the provided multiplication ``factor``. Parameters ---------- middle : `lsst.afw.image.MaskedImage` Convolved image to threshold. bbox : `lsst.geom.Box2I` Bounding box of unconvolved image. factor : `float` Multiplier for the configured threshold. Return Struct contents ---------------------- positive : `lsst.afw.detection.FootprintSet` or `None` Positive detection footprints, if configured. negative : `lsst.afw.detection.FootprintSet` or `None` Negative detection footprints, if configured. factor : `float` Multiplier for the configured threshold. """ results = pipeBase.Struct(positive=None, negative=None, factor=factor, positiveThreshold=None, negativeThreshold=None) # Detect the Footprints (peaks may be replaced if doTempLocalBackground) if self.config.reEstimateBackground or self.config.thresholdPolarity != "negative": results.positiveThreshold = self.makeThreshold(middle, "positive", factor=factor) results.positive = afwDet.FootprintSet( middle, results.positiveThreshold, "DETECTED", self.config.minPixels ) results.positive.setRegion(bbox) if self.config.reEstimateBackground or self.config.thresholdPolarity != "positive": results.negativeThreshold = self.makeThreshold(middle, "negative", factor=factor) results.negative = afwDet.FootprintSet( middle, results.negativeThreshold, "DETECTED_NEGATIVE", self.config.minPixels ) results.negative.setRegion(bbox) return results
def clipImage(im, minClip, maxClip): """Clip an image to lie between minClip and maxclip (None to ignore)""" if re.search("::MaskedImage<", im.__repr__()): mi = im else: mi = afwImage.makeMaskedImage(im, afwImage.MaskU(im.getDimensions())) if minClip is not None: ds = afwDetect.FootprintSet(mi, afwDetect.Threshold(-minClip, afwDetect.Threshold.VALUE, False)) afwDetect.setImageFromFootprintList(mi.getImage(), ds.getFootprints(), minClip) if maxClip is not None: ds = afwDetect.FootprintSet(mi, afwDetect.Threshold(maxClip)) afwDetect.setImageFromFootprintList(mi.getImage(), ds.getFootprints(), maxClip)
def testFootprintPeaks(self): """Test that we can extract the peaks from a Footprint""" fs = afwDetect.FootprintSet(self.ms, afwDetect.Threshold(10), "OBJECT") foot = fs.getFootprints()[0] self.assertEqual(len(foot.getPeaks()), 5)
def thresholdImage(self, image, thresholdParity, maskName="DETECTED"): """!Threshold the convolved image, returning a FootprintSet. Helper function for detect(). \param image The (optionally convolved) MaskedImage to threshold \param thresholdParity Parity of threshold \param maskName Name of mask to set \return FootprintSet """ parity = False if thresholdParity == "negative" else True threshold = afwDet.createThreshold(self.config.thresholdValue, self.config.thresholdType, parity) threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier) if self.config.thresholdType == 'stdev': bad = image.getMask().getPlaneBitMask([ 'BAD', 'SAT', 'EDGE', 'NO_DATA', ]) sctrl = afwMath.StatisticsControl() sctrl.setAndMask(bad) stats = afwMath.makeStatistics(image, afwMath.STDEVCLIP, sctrl) thres = stats.getValue( afwMath.STDEVCLIP) * self.config.thresholdValue threshold = afwDet.createThreshold(thres, 'value', parity) threshold.setIncludeMultiplier( self.config.includeThresholdMultiplier) fpSet = afwDet.FootprintSet(image, threshold, maskName, self.config.minPixels) return fpSet
def testMakeHeavy(self): """Test that we can make a FootprintSet heavy""" fs = afwDetect.FootprintSet(self.mi, afwDetect.Threshold(1)) ctrl = afwDetect.HeavyFootprintCtrl(afwDetect.HeavyFootprintCtrl.NONE) fs.makeHeavy(self.mi, ctrl) if display: ds9.mtv(self.mi, frame=0, title="input") #ds9.mtv(omi, frame=1, title="output") omi = self.mi.Factory(self.mi.getDimensions()) for foot in fs.getFootprints(): self.assertNotEqual(afwDetect.cast_HeavyFootprint(foot, self.mi), None) afwDetect.cast_HeavyFootprint(foot, self.mi).insert(omi) for foot in fs.getFootprints(): self.assertNotEqual(afwDetect.HeavyFootprintF.cast(foot), None) afwDetect.HeavyFootprintF.cast(foot).insert(omi) self.assertTrue( np.all( np.equal(self.mi.getImage().getArray(), omi.getImage().getArray())))
def gain(self, amp, jmargin=None, max_npix=9, buff=1): if jmargin is None: jmargins = list(range(10)) else: jmargins = (jmargin, ) self._generate_stats(amp) values = [] fp_sets = [] for j in jmargins: margin = self.noise * (j + 3) threshold = afwDetect.Threshold(self.median + margin) fp_set = afwDetect.FootprintSet(self.ccd[amp], threshold) fp_sets.append(fp_set) signals = [ self._footprint_signal(fp, buff) for fp in fp_set.getFootprints() if fp.getNpix() < max_npix ] try: stats = afwMath.makeStatistics(signals, afwMath.MEANCLIP) mean = stats.getValue() values.append(self.fe55_yield / mean) except: pass my_gain = np.median(values) return my_gain
def testMergeFootprints(self): # YYYY """Merge positive and negative Footprints""" x0, y0 = 5, 6 dwidth, dheight = 6, 7 def callback(): x, y, I = x0 + 10, y0 + 4, -20 self.im.getImage().set(x, y, I) peaks2.append((x, y, I)) for grow1, grow2 in [(1, 1), (3, 3), (6, 6), ]: peaks2 = [] self.doTestPeaks(threshold=10, callback=callback, grow=0, x0=x0, y0=y0, dwidth=dwidth, dheight=dheight) threshold = afwDetect.Threshold(10, afwDetect.Threshold.VALUE, False) fs2 = afwDetect.FootprintSet(self.im, threshold) msk = self.im.getMask() afwDetect.setMaskFromFootprintList(msk, fs2.getFootprints(), msk.getPlaneBitMask("DETECTED_NEGATIVE")) self.fs.merge(fs2, grow1, grow2) self.peaks[-2] += peaks2 if grow1 + grow2 > 2: # grow merged all peaks self.peaks[0] = sorted(sum(self.peaks, []), lambda x, y: cmpPeaks(self.im, x, y)) afwDetect.setMaskFromFootprintList(msk, self.fs.getFootprints(), msk.getPlaneBitMask("EDGE")) self.checkPeaks(frame=3)
def detector_crosstalk(ccd, aggressor_amp, dnthresh=None, nsig=5, signal_extractor=extract_mean_signal, min_fp_size=50): """ Compute detector crosstalk from a spot image in the aggressor amplifier. dnthresh is the threshold in DN for detecting the illuminated column in the aggressor amplifier; if set to None, then nsig*clipped_stdev above median is used for the threshold. """ image = ccd.unbiased_and_trimmed_image(aggressor_amp) # # Extract footprint of spot image using nominal detection # threshold. # if dnthresh is None: median, stdev = get_stats(image, ccd.stat_ctrl) # dnthresh = median + nsig*stdev dnthresh = (np.max(image.getImage().getArray()) + median)/2. # print "dnthresh =", dnthresh threshold = afwDetect.Threshold(dnthresh) fp_set = afwDetect.FootprintSet(image, threshold) try: footprint, peak_value = get_footprint(fp_set, min_fp_size, dnthresh) except IndexError: raise RuntimeError('index error in get_footprint') agg_mean = signal_extractor(ccd, aggressor_amp, footprint)[0] ratios = dict([(amp, signal_extractor(ccd, amp, footprint) / agg_mean) for amp in ccd]) # for amp in ratios: # if ratios[amp][0] > 0.1: # ratios[amp] = (0, 0) return ratios
def find_channels_with_saturation(eimage, full_well): """ Find all channels in an eimage that have pixel values above full well. Parameters ---------- eimage: lsst.afw.image.ImageF The "eimage" containing the image data in units of electrons per pixel. This is the image prior to electronic readout (i.e., conversion to ADU, addition of bias, dark current, crosstalk, etc.). For LSST CCDs, the eimages have parallel transfer directions along the x-axis, hence channels correspond to rows in eimages. full_well: int The pixel full well/saturation value in electrons. Returns ------- set of ints: The y-indices of the channels with saturated pixels. """ threshold = afw_detect.Threshold(full_well) fp_set = afw_detect.FootprintSet(eimage, threshold) channels = [] for fp in fp_set.getFootprints(): for span in fp.spans: channels.append(span.getY()) return set(channels)
def setUp(self): config = SingleFrameMeasurementTask.ConfigClass() config.slots.apFlux = 'base_CircularApertureFlux_12_0' self.schema = afwTable.SourceTable.makeMinimalSchema() self.measureSources = SingleFrameMeasurementTask(self.schema, config=config) bbox = afwGeom.BoxI(afwGeom.PointI(0, 0), afwGeom.ExtentI(self.width, self.height)) self.cellSet = afwMath.SpatialCellSet(bbox, 100) self.footprintSet = afwDetection.FootprintSet( self.mi, afwDetection.Threshold(self.detectThresh), "DETECTED") self.catalog = self.measure(self.footprintSet, self.exposure) for source in self.catalog: try: cand = measAlg.makePsfCandidate(source, self.exposure) self.cellSet.insertCandidate(cand) except Exception as e: print(e) continue
def findObjects(self, exp, nSigma=None, grow=0): """Find the objects in a postISR exposure.""" nPixMin = self.config.mainStarNpixMin if not nSigma: nSigma = self.config.mainStarNsigma if not grow: grow = self.config.mainStarGrow isotropic = self.config.mainStarGrowIsotropic threshold = afwDetect.Threshold(nSigma, afwDetect.Threshold.STDEV) footPrintSet = afwDetect.FootprintSet(exp.getMaskedImage(), threshold, "DETECTED", nPixMin) if grow > 0: footPrintSet = afwDetect.FootprintSet(footPrintSet, grow, isotropic) return footPrintSet
def testMergeFootprintsEngulf(self): """Merge two Footprints when growing one Footprint totally replaces the other""" def callback(): self.im.set(0) self.peaks, self.objects = [], [] for x, y, I in [[6, 4, 20], [6, 5, 10]]: self.im.getImage().set(x, y, I) self.peaks.append([[6, 4]]) x, y, I = 8, 4, -20 self.im.getImage().set(x, y, I) peaks2.append((x, y, I)) grow1, grow2 = 0, 3 peaks2 = [] self.doTestPeaks(threshold=10, callback=callback, grow=0) threshold = afwDetect.Threshold(10, afwDetect.Threshold.VALUE, False) fs2 = afwDetect.FootprintSet(self.im, threshold) msk = self.im.getMask() afwDetect.setMaskFromFootprintList( msk, fs2.getFootprints(), msk.getPlaneBitMask("DETECTED_NEGATIVE")) self.fs.merge(fs2, grow1, grow2) self.peaks[0] += peaks2 self.peaks[0] = sorted(sum(self.peaks, []), lambda x, y: cmpPeaks(self.im, x, y)) afwDetect.setMaskFromFootprintList(msk, self.fs.getFootprints(), msk.getPlaneBitMask("EDGE")) self.checkPeaks(frame=3)
def interpolateFromMask(maskedImage, fwhm, growSaturatedFootprints=1, maskNameList=['SAT'], fallbackValue=None): """Interpolate over defects identified by a particular set of mask planes. Parameters ---------- maskedImage : `lsst.afw.image.MaskedImage` Image to process. fwhm : scalar FWHM of double Gaussian smoothing kernel. growSaturatedFootprints : scalar, optional Number of pixels to grow footprints for saturated pixels. maskNameList : `List` of `str`, optional Mask plane name. fallbackValue : scalar, optional Value of last resort for interpolation. """ mask = maskedImage.getMask() if growSaturatedFootprints > 0 and "SAT" in maskNameList: # If we are interpolating over an area larger than the original masked region, we need # to expand the original mask bit to the full area to explain why we interpolated there. growMasks(mask, radius=growSaturatedFootprints, maskNameList=['SAT'], maskValue="SAT") thresh = afwDetection.Threshold(mask.getPlaneBitMask(maskNameList), afwDetection.Threshold.BITMASK) fpSet = afwDetection.FootprintSet(mask, thresh) defectList = Defects.fromFootprintList(fpSet.getFootprints()) interpolateDefectList(maskedImage, defectList, fwhm, fallbackValue=fallbackValue) return maskedImage