def displayCutouts(source, exposure, posImage=None, negImage=None, asHeavyFootprint=False, title='', figsize=(8, 2.5)): """Use matplotlib.pyplot.imshow() to display cutouts within up to three afw.image.Exposure's, given by an input SourceRecord. @param source afw.table.SourceRecord defining the footprint to extract and display @param exposure afw.image.Exposure from which to extract the cutout to display @param posImage Second exposure from which to extract the cutout to display @param negImage Third exposure from which to extract the cutout to display @param asHeavyFootprint Display the cutouts as afw.detection.HeavyFootprint, with regions outside the footprint removed @return matplotlib.pyplot.figure dispaying the image """ plt = importMatplotlib() if not plt: return fp = source.getFootprint() bbox = fp.getBBox() extent = (bbox.getBeginX(), bbox.getEndX(), bbox.getBeginY(), bbox.getEndY()) fig = plt.figure(figsize=figsize) if not asHeavyFootprint: subexp = afwImage.ImageF(exposure.getMaskedImage().getImage(), bbox, afwImage.PARENT) else: hfp = afwDet.HeavyFootprintF(fp, exposure.getMaskedImage()) subexp = getHeavyFootprintSubimage(hfp) plt.subplot(1, 3, 1) display2dArray(subexp.getArray(), title=title + ' Diffim', extent=extent) if posImage is not None: if not asHeavyFootprint: subexp = afwImage.ImageF(posImage.getMaskedImage().getImage(), bbox, afwImage.PARENT) else: hfp = afwDet.HeavyFootprintF(fp, posImage.getMaskedImage()) subexp = getHeavyFootprintSubimage(hfp) plt.subplot(1, 3, 2) display2dArray(subexp.getArray(), title=title + ' Pos', extent=extent) if negImage is not None: if not asHeavyFootprint: subexp = afwImage.ImageF(negImage.getMaskedImage().getImage(), bbox, afwImage.PARENT) else: hfp = afwDet.HeavyFootprintF(fp, negImage.getMaskedImage()) subexp = getHeavyFootprintSubimage(hfp) plt.subplot(1, 3, 3) display2dArray(subexp.getArray(), title=title + ' Neg', extent=extent) return fig
def testFitsPersistence(self): heavy1 = afwDetect.HeavyFootprintF(self.foot) heavy1.getImageArray()[:] = np.random.randn( self.foot.getArea()).astype(np.float32) heavy1.getMaskArray()[:] = np.random.randint( low=0, high=2, size=self.foot.getArea()).astype(np.uint16) heavy1.getVarianceArray()[:] = np.random.randn( self.foot.getArea()).astype(np.float32) filename = "heavyFootprint-testFitsPersistence.fits" heavy1.writeFits(filename) heavy2 = afwDetect.HeavyFootprintF.readFits(filename) self.assertEqual(heavy1.getArea(), heavy2.getArea()) self.assertEqual(list(heavy1.getSpans()), list(heavy2.getSpans())) self.assertEqual(list(heavy1.getPeaks()), list(heavy2.getPeaks())) self.assertClose(heavy1.getImageArray(), heavy2.getImageArray(), rtol=0.0, atol=0.0) self.assertClose(heavy1.getMaskArray(), heavy2.getMaskArray(), rtol=0.0, atol=0.0) self.assertClose(heavy1.getVarianceArray(), heavy2.getVarianceArray(), rtol=0.0, atol=0.0) os.remove(filename)
def testFitsPersistence(self): heavy1 = afwDetect.HeavyFootprintF(self.foot) heavy1.getImageArray()[:] = \ np.random.randn(self.foot.getArea()).astype(np.float32) heavy1.getMaskArray()[:] = \ np.random.randint(low=0, high=2, size=self.foot.getArea()).astype(np.uint16) heavy1.getVarianceArray()[:] = \ np.random.randn(self.foot.getArea()).astype(np.float32) with lsst.utils.tests.getTempFilePath(".fits") as filename: heavy1.writeFits(filename) heavy2 = afwDetect.HeavyFootprintF.readFits(filename) self.assertEqual(heavy1.getArea(), heavy2.getArea()) self.assertEqual(list(heavy1.getSpans()), list(heavy2.getSpans())) self.assertEqual(list(heavy1.getPeaks()), list(heavy2.getPeaks())) self.assertFloatsAlmostEqual(heavy1.getImageArray(), heavy2.getImageArray(), rtol=0.0, atol=0.0) self.assertFloatsAlmostEqual(heavy1.getMaskArray(), heavy2.getMaskArray(), rtol=0.0, atol=0.0) self.assertFloatsAlmostEqual(heavy1.getVarianceArray(), heavy2.getVarianceArray(), rtol=0.0, atol=0.0)
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 makeHeavyCatalog(catalog, exposure, verbose=False): """Turn all footprints in a catalog into heavy footprints.""" for i, source in enumerate(catalog): fp = source.getFootprint() if not fp.isHeavy(): if verbose: print(i, 'not heavy => heavy') hfp = afwDet.HeavyFootprintF(fp, exposure.getMaskedImage()) source.setFootprint(hfp) return catalog
def clean(exposure, fpset_low, min_pix_low_thresh=100, name_high='THRESH_HIGH', max_frac_high_thresh=0.3, rgrow=None, random_state=None): """ Clean image of bright sources and associated diffuse regions by replacing them with sky noise. Also, remove low-threshold regions that are smaller than min_pix_low_thresh. Parameters ---------- exposure : lsst.afw.image.ExposureF Exposure object with masks from hugsPipe.run. fpset_low : lsst.afw.detection.FootprintSet Low threshold footprints. min_pix_low_thresh : int, optional Minimum number of pixels for a low-thresh footprint. name_high : string, optional The name of the high-threshold bit plane. max_frac_high_thresh : float, optional Maximum fraction of high-thresh pixels to keep footprint. rgrow : int, optional Number of pixels to grow footprints. random_state : int, list of ints, RandomState instance, or None, optional If int or list of ints, random_state is the rng seed. If RandomState instance, random_state is the rng. If None, the rng is the RandomState instance used by np.random. Returns ------- exp_clean : lsst.afw.ExposureF The cleaned exposure object. """ # generate array of gaussian noise mi = exposure.getMaskedImage() mask = mi.getMask() noise_array = utils.make_noise_image(mi, random_state) # associate high thresh with low thresh and find small fps fpset_replace = afwDet.FootprintSet(mi.getBBox()) fp_list = [] for fp in fpset_low.getFootprints(): hfp = afwDet.HeavyFootprintF(fp, mi) pix = hfp.getMaskArray() bits_hi = (pix & mask.getPlaneBitMask(name_high) != 0).sum() if bits_hi > 0: ratio = bits_hi / float(fp.getArea()) if ratio > max_frac_high_thresh: fp_list.append(fp) else: if fp.getArea() < min_pix_low_thresh: fp_list.append(fp) fpset_replace.setFootprints(fp_list) if rgrow: fpset_replace = afwDet.FootprintSet(fpset_replace, rgrow, True) mask.addMaskPlane('CLEANED') fpset_replace.setMask(mask, 'CLEANED') # create new exposure and replace footprints with noise exp_clean = exposure.clone() mi_clean = exp_clean.getMaskedImage() replace = mask.getArray() & mask.getPlaneBitMask('BRIGHT_OBJECT') != 0 replace |= mask.getArray() & mask.getPlaneBitMask('CLEANED') != 0 mi_clean.getImage().getArray()[replace] = noise_array[replace] return exp_clean
def testUndeblendedMeasurement(self): """Check undeblended measurement and aperture correction""" width, height = 100, 100 # Dimensions of image x0, y0 = 1234, 5678 # Offset of image radius = 3.0 # Aperture radius xCenter, yCenter = width//2, height//2 # Position of first source; integer values, for convenience xOffset, yOffset = 1, 1 # Offset from first source to second source flux1, flux2 = 1000, 1 # Flux of sources apCorrValue = 3.21 # Aperture correction value to apply image = afwImage.MaskedImageF(afwGeom.ExtentI(width, height)) image.setXY0(x0, y0) image.getVariance().set(1.0) schema = afwTable.SourceTable.makeMinimalSchema() schema.addField("centroid_x", type=np.float64) schema.addField("centroid_y", type=np.float64) schema.addField("centroid_flag", type='Flag') schema.getAliasMap().set("slot_Centroid", "centroid") sfmConfig = measBase.SingleFrameMeasurementConfig() algName = "base_CircularApertureFlux" for subConfig in (sfmConfig.plugins, sfmConfig.undeblended): subConfig.names = [algName] subConfig[algName].radii = [radius] subConfig[algName].maxSincRadius = 0 # Disable sinc photometry because we're undersampled slots = sfmConfig.slots slots.centroid = "centroid" slots.shape = None slots.psfShape = None slots.apFlux = None slots.modelFlux = None slots.psfFlux = None slots.instFlux = None slots.calibFlux = None fieldName = lsst.meas.base.CircularApertureFluxAlgorithm.makeFieldPrefix(algName, radius) measBase.addApCorrName(fieldName) apCorrConfig = measBase.ApplyApCorrConfig() apCorrConfig.proxies = {"undeblended_" + fieldName: fieldName} sfm = measBase.SingleFrameMeasurementTask(config=sfmConfig, schema=schema) apCorr = measBase.ApplyApCorrTask(config=apCorrConfig, schema=schema) cat = afwTable.SourceCatalog(schema) parent = cat.addNew() parent.set("centroid_x", x0 + xCenter) parent.set("centroid_y", y0 + yCenter) spanSetParent = afwGeom.SpanSet.fromShape(int(radius)) spanSetParent = spanSetParent.shiftedBy(x0 + xCenter, y0 + yCenter) parent.setFootprint(afwDetection.Footprint(spanSetParent)) # First child is bright, dominating the blend child1 = cat.addNew() child1.set("centroid_x", parent.get("centroid_x")) child1.set("centroid_y", parent.get("centroid_y")) child1.setParent(parent.getId()) image.set(xCenter, yCenter, (flux1, 0, 0)) spanSetChild1 = afwGeom.SpanSet.fromShape(1) spanSetChild1 = spanSetChild1.shiftedBy(x0 + xCenter, y0 + yCenter) foot1 = afwDetection.Footprint(spanSetChild1) child1.setFootprint(afwDetection.HeavyFootprintF(foot1, image)) # Second child is fainter, but we want to be able to measure it! child2 = cat.addNew() child2.set("centroid_x", parent.get("centroid_x") + xOffset) child2.set("centroid_y", parent.get("centroid_y") + yOffset) child2.setParent(parent.getId()) image.set(xCenter + xOffset, yCenter + yOffset, (flux2, 0, 0)) spanSetChild2 = afwGeom.SpanSet.fromShape(1) tmpPoint = (x0 + xCenter + xOffset, y0 + yCenter + yOffset) spanSetChild2 = spanSetChild2.shiftedBy(*tmpPoint) foot2 = afwDetection.Footprint(spanSetChild2) child2.setFootprint(afwDetection.HeavyFootprintF(foot2, image)) spans = foot1.spans.union(foot2.spans) bbox = afwGeom.Box2I() bbox.include(foot1.getBBox()) bbox.include(foot2.getBBox()) parent.setFootprint(afwDetection.Footprint(spans, bbox)) exposure = afwImage.makeExposure(image) sfm.run(cat, exposure) def checkSource(source, baseName, expectedFlux): """Check that we get the expected results""" self.assertEqual(source.get(baseName + "_flux"), expectedFlux) self.assertGreater(source.get(baseName + "_fluxSigma"), 0) self.assertFalse(source.get(baseName + "_flag")) # Deblended checkSource(child1, fieldName, flux1) checkSource(child2, fieldName, flux2) # Undeblended checkSource(child1, "undeblended_" + fieldName, flux1 + flux2) checkSource(child2, "undeblended_" + fieldName, flux1 + flux2) # Apply aperture correction apCorrMap = afwImage.ApCorrMap() apCorrMap[fieldName + "_flux"] = afwMath.ChebyshevBoundedField( image.getBBox(), apCorrValue*np.ones((1, 1), dtype=np.float64) ) apCorrMap[fieldName + "_fluxSigma"] = afwMath.ChebyshevBoundedField( image.getBBox(), apCorrValue*np.zeros((1, 1), dtype=np.float64) ) apCorr.run(cat, apCorrMap) # Deblended checkSource(child1, fieldName, flux1*apCorrValue) checkSource(child2, fieldName, flux2*apCorrValue) # Undeblended checkSource(child1, "undeblended_" + fieldName, (flux1 + flux2)*apCorrValue) checkSource(child2, "undeblended_" + fieldName, (flux1 + flux2)*apCorrValue) self.assertIn(fieldName + "_apCorr", schema) self.assertIn(fieldName + "_apCorrSigma", schema) self.assertIn("undeblended_" + fieldName + "_apCorr", schema) self.assertIn("undeblended_" + fieldName + "_apCorrSigma", schema)