def testReadFitsConform(self): if not self.maskFile: print >> sys.stderr, "Warning: afwdata is not set up; not running the FITS I/O tests" return hdu = 3 mask = afwImage.MaskU(self.maskFile, hdu, None, afwGeom.Box2I(), afwImage.LOCAL, True) if False: import lsst.afw.display.ds9 as ds9 ds9.mtv(mask) self.assertEqual(mask.get(32, 1), 0) self.assertEqual(mask.get(50, 50), 0) self.assertEqual(mask.get(0, 0), 1)
def testImageTypes(self): """Check that we can display a range of types of image""" with afwDisplay.getDisplay("dummy", "virtualDevice") as dummy: for imageType in [ afwImage.DecoratedImageF, afwImage.ExposureF, afwImage.ImageU, afwImage.ImageI, afwImage.ImageF, afwImage.MaskedImageF, ]: im = imageType(self.fileName) dummy.mtv(im) im = afwImage.MaskU(self.fileName, 3) dummy.mtv(im)
def testMask(self): mask = afwImage.MaskU(afwGeom.Extent2I(10, 10)) mask.set(0x0) mask.set(1, 1, 0x10) mask.set(3, 1, 0x08) mask.set(5, 4, 0x08) mask.set(4, 5, 0x02) stats = afwMath.makeStatistics(mask, afwMath.SUM | afwMath.NPOINT) self.assertEqual(mask.getWidth()*mask.getHeight(), stats.getValue(afwMath.NPOINT)) self.assertEqual(0x1a, stats.getValue(afwMath.SUM)) def tst(): stats = afwMath.makeStatistics(mask, afwMath.MEAN) self.assertRaises(lsst.pex.exceptions.InvalidParameterError, tst)
def setUp(self): # Set a (non-standard) initial Mask plane definition # # Ideally we'd use the standard dictionary and a non-standard file, but # a standard file's what we have # mask = afwImage.MaskU() mask.clearMaskPlaneDict() for p in ("ZERO", "BAD", "SAT", "INTRP", "CR", "EDGE"): mask.addMaskPlane(p) if False: self.fileName = os.path.join(dataDir, "Small_MI.fits") else: self.fileName = os.path.join(dataDir, "CFHT", "D4", "cal-53535-i-797722_1.fits") self.mi = afwImage.MaskedImageF(self.fileName)
class ProcessFileConfig(pexConfig.Config): """A container for the Configs that ProcessFile needs Using such a container allows us to use the standard -c/-C/--show config options that pipe_base provides """ variance = pexConfig.Field( dtype=float, default=np.nan, doc="Initial per-pixel variance (if <= 0, estimate from inputs)") badPixelValue = pexConfig.Field(dtype=float, default=np.nan, doc="Value indicating a bad pixel") interpPlanes = pexConfig.ListField( dtype=str, default=[ "BAD", ], doc="Names of mask planes to interpolate over (e.g. ['BAD', 'SAT'])", itemCheck=lambda x: x in afwImage.MaskU().getMaskPlaneDict().keys()) isr = MyIsrConfig() doCalibrate = pexConfig.Field(dtype=bool, default=True, doc="Calibrate input data?") charImage = pexConfig.ConfigField( dtype=CharacterizeImageTask.ConfigClass, doc=CharacterizeImageTask.ConfigClass.__doc__) detection = pexConfig.ConfigField( dtype=SourceDetectionTask.ConfigClass, doc=SourceDetectionTask.ConfigClass.__doc__) detection.returnOriginalFootprints = False measurement = pexConfig.ConfigField( dtype=SingleFrameMeasurementTask.ConfigClass, doc=SingleFrameMeasurementTask.ConfigClass.__doc__) doDeblend = pexConfig.Field(dtype=bool, default=True, doc="Deblend sources?") if SourceDeblendTask: deblend = pexConfig.ConfigField( dtype=SourceDeblendTask.ConfigClass, doc=SourceDeblendTask.ConfigClass.__doc__)
def testIntersectMask(self): bbox = afwGeom.BoxI(afwGeom.PointI(0,0), afwGeom.ExtentI(10)) fp = afwDetect.Footprint(bbox) maskBBox = afwGeom.BoxI(bbox) maskBBox.grow(-2) mask = afwImage.MaskU(maskBBox) innerBBox = afwGeom.BoxI(maskBBox) innerBBox.grow(-2) subMask = mask.Factory(mask, innerBBox) subMask.set(1) fp.intersectMask(mask) fpBBox = fp.getBBox() self.assertEqual(fpBBox.getMinX(), maskBBox.getMinX()) self.assertEqual(fpBBox.getMinY(), maskBBox.getMinY()) self.assertEqual(fpBBox.getMaxX(), maskBBox.getMaxX()) self.assertEqual(fpBBox.getMaxY(), maskBBox.getMaxY()) self.assertEqual(fp.getArea(), maskBBox.getArea() - innerBBox.getArea())
def translate_dqmask(self, dqmask): # TODO: make a class member variable that knows the mappings # below instead of hard-coding them dqmArr = dqmask.getArray() mask = afwImage.MaskU(dqmask.getDimensions()) mArr = mask.getArray() idxBad = np.where(dqmArr & 1) idxSat = np.where(dqmArr & 2) idxIntrp = np.where(dqmArr & 4) idxCr = np.where(dqmArr & 16) idxBleed = np.where(dqmArr & 64) idxEdge = np.where(dqmArr & 512) mArr[idxBad] |= mask.getPlaneBitMask("BAD") mArr[idxSat] |= mask.getPlaneBitMask("SAT") mArr[idxIntrp] |= mask.getPlaneBitMask("INTRP") mArr[idxCr] |= mask.getPlaneBitMask("CR") mArr[idxBleed] |= mask.getPlaneBitMask("SAT") mArr[idxEdge] |= mask.getPlaneBitMask("EDGE") return mask
def readFits(fileName, hdu=0, flags=0): """Read a our list of Backgrounds from a file @param fileName FITS file to read @param hdu First Header/Data Unit to attempt to read from @param flags Flags to control details of reading; currently unused, but present for consistency with afw.table.BaseCatalog.readFits. See also getImage() """ if not isinstance(fileName, MemFileManager) and not os.path.exists(fileName): raise RuntimeError("File not found: %s" % fileName) self = BackgroundList() while True: hdu += 1 md = dafBase.PropertyList() try: img = afwImage.ImageF(fileName, hdu, md); hdu += 1 except FitsError as e: break msk = afwImage.MaskU( fileName, hdu); hdu += 1 var = afwImage.ImageF(fileName, hdu) statsImage = afwImage.makeMaskedImage(img, msk, var) x0 = md.get("BKGD_X0") y0 = md.get("BKGD_Y0") width = md.get("BKGD_WIDTH") height = md.get("BKGD_HEIGHT") imageBBox = afwGeom.BoxI(afwGeom.PointI(x0, y0), afwGeom.ExtentI(width, height)) interpStyle = md.get("INTERPSTYLE") undersampleStyle = md.get("UNDERSAMPLESTYLE") bkgd = afwMath.BackgroundMI(imageBBox, statsImage) self.append((bkgd, interpStyle, undersampleStyle,)) return self
def testMaskedImageFromImage(self): w, h = 10, 20 dims = afwGeom.Extent2I(w, h) im, mask, var = afwImage.ImageF(dims), afwImage.MaskU( dims), afwImage.ImageF(dims) im.set(666) maskedImage = afwImage.MaskedImageF(im, mask, var) maskedImage = afwImage.makeMaskedImage(im, mask, var) maskedImage = afwImage.MaskedImageF(im) self.assertEqual(im.getDimensions(), maskedImage.getImage().getDimensions()) self.assertEqual(im.getDimensions(), maskedImage.getMask().getDimensions()) self.assertEqual(im.getDimensions(), maskedImage.getVariance().getDimensions()) self.assertEqual(maskedImage.get(0, 0), (im.get(0, 0), 0x0, 0.0))
def makeExposure(self, im, mask=None, variance=None): """Method for constructing an exposure object from an image and the information contained in this class to construct the Detector and Calib objects. @param[in] im Image used to construct the exposure @param[in] mask Optional mask plane as a <askU @param[in] variance Optional variance plance as an image of the same type as im @param[out] Exposure object """ if mask is None: mask = afwImage.MaskU(im.getDimensions()) if variance is None: variance = im mi = afwImage.makeMaskedImage(im, mask, variance) detector = self.buildDetector() wcs = afwImage.makeWcs(self.detectorMetadata) calib = self.makeCalib() exp = afwImage.makeExposure(mi, wcs) exp.setCalib(calib) exp.setDetector(detector) return exp
def testImageSlices(self): """Test image slicing, which generate sub-images using Box2I under the covers""" im = afwImage.MaskU(10, 20) im[-3:, -2:] = 0x4 im[4, 10] = 0x2 sim = im[1:4, 6:10] sim[:] = 0x8 im[0:4, 0:4] = im[2:6, 8:12] if display: ds9.mtv(im) self.assertEqual(im.get(0, 6), 0) self.assertEqual(im.get(6, 17), 0) self.assertEqual(im.get(7, 18), 0x4) self.assertEqual(im.get(9, 19), 0x4) self.assertEqual(im.get(1, 6), 0x8) self.assertEqual(im.get(3, 9), 0x8) self.assertEqual(im.get(4, 10), 0x2) self.assertEqual(im.get(4, 9), 0) self.assertEqual(im.get(2, 2), 0x2) self.assertEqual(im.get(0, 0), 0x8)
def setUp(self): im = afwImage.ImageF(self.monetFile("small.fits")) self.mi = afwImage.MaskedImageF(im, afwImage.MaskU(im.getDimensions()), afwImage.ImageF(im.getDimensions())) self.ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(100)) if display: ds9.mtv(self.mi.getImage()) ds9.erase() for foot in self.ds.getFootprints(): bbox = foot.getBBox() x0, y0 = bbox.getMinX(), bbox.getMinY() x1, y1 = bbox.getMaxX(), bbox.getMaxY() xc = (x0 + x1) / 2.0 yc = (y0 + y1) / 2.0 if display: ds9.dot("+", xc, yc, ctype=ds9.BLUE) if False: x0 -= 0.5 y0 -= 0.5 x1 += 0.5 y1 += 0.5 ds9.line([(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)], ctype=ds9.RED) self.control = algorithms.GaussianCentroidControl() schema = afwTable.SourceTable.makeMinimalSchema() self.centroider = algorithms.MeasureSourcesBuilder().addAlgorithm( self.control).build(schema) self.ssMeasured = afwTable.SourceCatalog(schema) self.ssMeasured.table.defineCentroid(self.control.name) self.ssTruth = afwTable.SourceCatalog(schema) self.readTruth(self.monetFile("positions.dat-original"))
basedir = os.path.join(rootdir, basename) if not os.path.isdir(basedir): os.mkdir(basedir) maskFormat = re.compile('^\[(\d+):(\d+),(\d+):(\d+)\]$') ptr = pyfits.open(infile) for i in range(1, 37): #raftdir = os.path.join(basedir, str(i)) #if not os.path.isdir(raftdir): # os.mkdir(raftdir) ccdHeader = ptr[i].header nColMask = ccdHeader['NAXIS1'] nRowMask = ccdHeader['NAXIS2'] mask = afwImage.MaskU(nColMask, nRowMask) mask.set(0) bitmask = mask.getPlaneBitMask('BAD') for card in ccdHeader.ascardlist().keys(): if card.startswith('MASK_'): datasec = ccdHeader[card] # Unfortunately, the format of the masks is wrong. Its # x0,y0 x1,y1 # e.g. # MASK_000= '[1:1,2112:1]' / Bad pixels area definition # # Datasecs normally have # x0,x1 y0,y1 # e.g.
def getClumps(self, sigma=1.0, display=False): if self._num <= 0: raise RuntimeError("No candidate PSF sources") psfImage = self.getImage() # # Embed psfImage into a larger image so we can smooth when measuring it # width, height = psfImage.getWidth(), psfImage.getHeight() largeImg = psfImage.Factory(afwGeom.ExtentI(2 * width, 2 * height)) largeImg.set(0) bbox = afwGeom.BoxI(afwGeom.PointI(width, height), afwGeom.ExtentI(width, height)) largeImg.assign(psfImage, bbox, afwImage.LOCAL) # # Now measure that image, looking for the highest peak. Start by building an Exposure # msk = afwImage.MaskU(largeImg.getDimensions()) msk.set(0) var = afwImage.ImageF(largeImg.getDimensions()) var.set(1) mpsfImage = afwImage.MaskedImageF(largeImg, msk, var) mpsfImage.setXY0(afwGeom.PointI(-width, -height)) del msk del var exposure = afwImage.makeExposure(mpsfImage) # # Next run an object detector # maxVal = afwMath.makeStatistics(psfImage, afwMath.MAX).getValue() threshold = maxVal - sigma * math.sqrt(maxVal) if threshold <= 0.0: threshold = maxVal threshold = afwDetection.Threshold(threshold) ds = afwDetection.FootprintSet(mpsfImage, threshold, "DETECTED") # # And measure it. This policy isn't the one we use to measure # Sources, it's only used to characterize this PSF histogram # schema = SourceTable.makeMinimalSchema() psfImageConfig = SingleFrameMeasurementConfig() psfImageConfig.slots.centroid = "base_SdssCentroid" psfImageConfig.plugins["base_SdssCentroid"].doFootprintCheck = False psfImageConfig.slots.psfFlux = None # "base_PsfFlux" psfImageConfig.slots.apFlux = "base_CircularApertureFlux_3_0" psfImageConfig.slots.modelFlux = None psfImageConfig.slots.instFlux = None psfImageConfig.slots.calibFlux = None psfImageConfig.slots.shape = "base_SdssShape" # Formerly, this code had centroid.sdss, flux.psf, flux.naive, # flags.pixel, and shape.sdss psfImageConfig.algorithms.names = [ "base_SdssCentroid", "base_CircularApertureFlux", "base_SdssShape" ] psfImageConfig.algorithms["base_CircularApertureFlux"].radii = [3.0] psfImageConfig.validate() task = SingleFrameMeasurementTask(schema, config=psfImageConfig) sourceCat = SourceCatalog(schema) gaussianWidth = 1.5 # Gaussian sigma for detection convolution exposure.setPsf(algorithmsLib.DoubleGaussianPsf(11, 11, gaussianWidth)) ds.makeSources(sourceCat) # # Show us the Histogram # if display: frame = 1 dispImage = mpsfImage.Factory( mpsfImage, afwGeom.BoxI(afwGeom.PointI(width, height), afwGeom.ExtentI(width, height)), afwImage.LOCAL) ds9.mtv(dispImage, title="PSF Selection Image", frame=frame) clumps = list() # List of clumps, to return e = None # thrown exception IzzMin = 1.0 # Minimum value for second moments IzzMax = ( self._xSize / 8.0)**2 # Max value ... clump radius should be < clumpImgSize/8 apFluxes = [] task.run( sourceCat, exposure) # notes that this is backwards for the new framework for i, source in enumerate(sourceCat): if source.getCentroidFlag(): continue x, y = source.getX(), source.getY() apFluxes.append(source.getApFlux()) val = mpsfImage.getImage().get(int(x) + width, int(y) + height) psfClumpIxx = source.getIxx() psfClumpIxy = source.getIxy() psfClumpIyy = source.getIyy() if display: if i == 0: ds9.pan(x, y, frame=frame) ds9.dot("+", x, y, ctype=ds9.YELLOW, frame=frame) ds9.dot("@:%g,%g,%g" % (psfClumpIxx, psfClumpIxy, psfClumpIyy), x, y, ctype=ds9.YELLOW, frame=frame) if psfClumpIxx < IzzMin or psfClumpIyy < IzzMin: psfClumpIxx = max(psfClumpIxx, IzzMin) psfClumpIyy = max(psfClumpIyy, IzzMin) if display: ds9.dot("@:%g,%g,%g" % (psfClumpIxx, psfClumpIxy, psfClumpIyy), x, y, ctype=ds9.RED, frame=frame) det = psfClumpIxx * psfClumpIyy - psfClumpIxy * psfClumpIxy try: a, b, c = psfClumpIyy / det, -psfClumpIxy / det, psfClumpIxx / det except ZeroDivisionError: a, b, c = 1e4, 0, 1e4 clumps.append( Clump(peak=val, x=x, y=y, a=a, b=b, c=c, ixx=psfClumpIxx, ixy=psfClumpIxy, iyy=psfClumpIyy)) if len(clumps) == 0: msg = "Failed to determine center of PSF clump" if e: msg += ": %s" % e raise RuntimeError(msg) # if it's all we got return it if len(clumps) == 1: return clumps # which clump is the best? # if we've undistorted the moments, stars should only have 1 clump # use the apFlux from the clump measurement, and take the highest # ... this clump has more psf star candidate neighbours than the others. # get rid of any that are huge, and thus poorly defined goodClumps = [] for clump in clumps: if clump.ixx < IzzMax and clump.iyy < IzzMax: goodClumps.append(clump) # if culling > IzzMax cost us all clumps, we'll have to take what we have if len(goodClumps) == 0: goodClumps = clumps # use the 'brightest' clump iBestClump = numpy.argsort(apFluxes)[0] clumps = [clumps[iBestClump]] return clumps
def testMask(self): """Test that we can flip a Mask""" mask = afwImage.MaskU(10, 20) afwMath.flipImage( mask, True, False) # for a while, swig couldn't handle the resulting Mask::Ptr
class MaskedCCDTestCase(unittest.TestCase): gain = 1 exptime = 1 signal = 1 xmin, xmax = 200, 250 ymin, ymax = 1000, 1050 mask_image = 'mask_image.fits' mpd = dict(afwImage.MaskU().getMaskPlaneDict().items()) @classmethod def setUpClass(cls): ccd = sim_tools.CCD(exptime=cls.exptime, gain=cls.gain) for amp in ccd.segments: imarr = ccd.segments[amp].image.getArray() imarr[cls.ymin:cls.ymax, cls.xmin:cls.xmax] += cls.signal ccd.writeto(cls.mask_image) cls.mask_files = [] for mask_plane, bit in cls.mpd.items(): mask_file = 'mask_file_%s.fits' % mask_plane cls.mask_files.append(mask_file) masked_ccd = MaskedCCD(cls.mask_image) pixels, columns = {}, {} for amp in masked_ccd: bp = BrightPixels(masked_ccd, amp, cls.exptime, cls.gain, mask_plane=mask_plane, ethresh=cls.signal / 2.) pixels[amp], columns[amp] = bp.find() generate_mask(cls.mask_image, mask_file, mask_plane, pixels=pixels, columns=columns) cls.summed_mask_file = 'summed_mask_file.fits' add_mask_files(cls.mask_files, cls.summed_mask_file) @classmethod def tearDownClass(cls): os.remove(cls.mask_image) for mask_file in cls.mask_files: os.remove(mask_file) os.remove(cls.summed_mask_file) # @unittest.skip('skip test_add_masks') def test_add_masks(self): ccd = MaskedCCD(self.mask_image) ccd.add_masks(self.summed_mask_file) total_signal = (self.signal * (self.ymax - self.ymin) * (self.xmax - self.xmin)) ny, nx = ccd[ccd.keys()[0]].getImage().getArray().shape for amp in ccd: self.assertEqual(sum(ccd[amp].getImage().getArray().flat), total_signal) stat_ctrl = ccd.setMask('BAD') for amp in ccd: stats = afwMath.makeStatistics(ccd[amp], afwMath.MEAN, stat_ctrl) self.assertEqual(0, stats.getValue(afwMath.MEAN)) stat_ctrl = ccd.setMask(clear=True) for amp in ccd: stats = afwMath.makeStatistics(ccd[amp], afwMath.MEAN, stat_ctrl) self.assertAlmostEqual(float(total_signal) / (nx * ny), stats.getValue(afwMath.MEAN), places=10) # @unittest.skip('skip test_setMask') def test_setMask(self): ccd = MaskedCCD(self.mask_image) for mp, bit in self.mpd.items(): sctrl = ccd.setMask(mask_name=mp, clear=True) self.assertEqual(sctrl.getAndMask(), 2**bit)
subim = afwImage.ImageF(im, box, afwImage.LOCAL) try: subim += psf_im except NotImplementedError: psf_im = psf_im.convertF() subim += psf_im print(" subim = ", subim) back_im = afwImage.ImageF(im.getBBox()) afwMath.randomPoissonImage(back_im, rand, 100) im += back_im display.mtv(im) display.incrDefaultFrame() mask = afwImage.MaskU(im.getBBox()) masked_im = afwImage.MaskedImageF(im, mask, im) sys.exit() threshold = afwDetect.createThreshold(5., 'stdev') fs = afwDetect.FootprintSet(masked_im, threshold, 'DETECTED') #display.mtv(masked_im) #display.incrDefaultFrame() bctrl = afwMath.BackgroundControl(11, 11) bkgd = afwMath.makeBackground(masked_im, bctrl) masked_im -= bkgd.getImageF() masked_im.getMask().set(0) # reset mask fs = afwDetect.FootprintSet(masked_im, threshold, 'DETECTED') #display.mtv(masked_im)
class BackgroundConfig(pexConfig.Config): statisticsProperty = pexConfig.ChoiceField( doc="type of statistic to use for grid points", dtype=str, default="MEANCLIP", allowed={ "MEANCLIP": "clipped mean", "MEAN": "unclipped mean", "MEDIAN": "median", }) undersampleStyle = pexConfig.ChoiceField( doc= "behaviour if there are too few points in grid for requested interpolation style", dtype=str, default="REDUCE_INTERP_ORDER", allowed={ "THROW_EXCEPTION": "throw an exception if there are too few points", "REDUCE_INTERP_ORDER": "use an interpolation style with a lower order.", "INCREASE_NXNYSAMPLE": "Increase the number of samples used to make the interpolation grid.", }) binSize = pexConfig.RangeField( doc= "how large a region of the sky should be used for each background point", dtype=int, default=256, min=10) algorithm = pexConfig.ChoiceField( doc= "how to interpolate the background values. This maps to an enum; see afw::math::Background", dtype=str, default="NATURAL_SPLINE", optional=True, allowed={ "CONSTANT": "Use a single constant value", "LINEAR": "Use linear interpolation", "NATURAL_SPLINE": "cubic spline with zero second derivative at endpoints", "AKIMA_SPLINE": "higher-level nonlinear spline that is more robust to outliers", "NONE": "No background estimation is to be attempted", }) ignoredPixelMask = pexConfig.ListField( doc="Names of mask planes to ignore while estimating the background", dtype=str, default=["EDGE", "DETECTED", "DETECTED_NEGATIVE"], itemCheck=lambda x: x in afwImage.MaskU().getMaskPlaneDict().keys(), ) isNanSafe = pexConfig.Field( doc="Ignore NaNs when estimating the background", dtype=bool, default=False, ) def validate(self): pexConfig.Config.validate(self) # Allow None to be used as an equivalent for "NONE", even though C++ expects the latter. if self.algorithm is None: self.algorithm = "NONE"
def testInitializeMasks(self): val = 0x1234 msk = afwImage.MaskU(afwGeom.ExtentI(10, 10), val) self.assertEqual(msk.get(0, 0), val)
def readFits(fileName, hdu=0, flags=0): """Read a our list of Backgrounds from a file @param fileName FITS file to read @param hdu First Header/Data Unit to attempt to read from @param flags Flags to control details of reading; currently unused, but present for consistency with afw.table.BaseCatalog.readFits. See also getImage() """ if not isinstance(fileName, MemFileManager) and not os.path.exists(fileName): raise RuntimeError("File not found: %s" % fileName) self = BackgroundList() while True: hdu += 1 md = dafBase.PropertyList() try: img = afwImage.ImageF(fileName, hdu, md) hdu += 1 except FitsError: break msk = afwImage.MaskU(fileName, hdu) hdu += 1 var = afwImage.ImageF(fileName, hdu) statsImage = afwImage.makeMaskedImage(img, msk, var) x0 = md.get("BKGD_X0") y0 = md.get("BKGD_Y0") width = md.get("BKGD_WIDTH") height = md.get("BKGD_HEIGHT") imageBBox = afwGeom.BoxI(afwGeom.PointI(x0, y0), afwGeom.ExtentI(width, height)) interpStyle = md.get("INTERPSTYLE") undersampleStyle = md.get("UNDERSAMPLESTYLE") # Older outputs won't have APPROX* settings. Provide alternative defaults. # Note: Currently X- and Y-orders must be equal due to a limitation in # math::Chebyshev1Function2. Setting approxOrderY = -1 is equivalent # to saying approxOrderY = approxOrderX. approxStyle = md.get("APPROXSTYLE") if "APPROXSTYLE" in md.names() \ else afwMath.ApproximateControl.UNKNOWN approxOrderX = md.get( "APPROXORDERX") if "APPROXORDERX" in md.names() else 1 approxOrderY = md.get( "APPROXORDERY") if "APPROXORDERY" in md.names() else -1 approxWeighting = md.get( "APPROXWEIGHTING") if "APPROXWEIGHTING" in md.names() else True bkgd = afwMath.BackgroundMI(imageBBox, statsImage) bctrl = bkgd.getBackgroundControl() bctrl.setInterpStyle(interpStyle) bctrl.setUndersampleStyle(undersampleStyle) actrl = afwMath.ApproximateControl(approxStyle, approxOrderX, approxOrderY, approxWeighting) bctrl.setApproximateControl(actrl) bgInfo = (bkgd, interpStyle, undersampleStyle, approxStyle, approxOrderX, approxOrderY, approxWeighting) self.append(bgInfo) return self
def rolloff_mask(infile, outfile, mask_plane='ROLLOFF_DEFECTS', tmp_mask_image=None, outer_edge_width=10, bloom_stop_width=5, signal=10, cleanup=True): """ This function creates a file containing masks for each segment to mask pixels affected the edge roll-off and midline blooming stop distortions. infile: Input file to mask. outfile: The name of the file to contain the masks. outer_edge_width: This is the width in pixels of the masked region along the sides closest to the sensor edges of the imaging region of each segment. bloom_stop_width: The width in pixels of the masked region of the imaging region of each segment, on either side of the central blooming stop implant. signal: This is the artificial signal written to the mask image so that the afwDetect code can generate the footprints used define the masks. It basically just needs to be some positive (non-zero) number. """ # # Create an empty set of frames to fill with an image of the mask # from which we will generate the masks. The exposure time and # system gain need to be set to unity so that the BrightPixels.py # code can interpret DN directly as e- per second. # amp_geom = makeAmplifierGeometry(infile) gain = 1 exptime = 1 all_amps = imutils.allAmps(infile) ccd = CCD(exptime=exptime, gain=gain, geometry=amp_geom, amps=all_amps) # # Write the output file with a primary HDU so that the DMstack code # can append only image extensions (and not write to the PHDU). # warnings.filterwarnings('ignore', category=fits.verify.VerifyWarning, append=True) hdulist = fits.HDUList() hdulist.append(fits.PrimaryHDU()) with fits.open(infile) as fd: hdulist[0].header.update(fd[0].header) # Use the mask_plane value ('ROLLOFF_DEFECTS') to distinguish # this file from other mask files. hdulist[0].header['MASKTYPE'] = mask_plane fitsWriteto(hdulist, outfile, overwrite=True) # # Amplifiers 1 (AMP10), 8 (AMP17), 9 (AMP07) and 16 (AMP00) are # along the perimeter, but have different edge rolloff pixels # depending on the vendor. # # These amps have edge roll-off adjacent to the prescan. amps = (8, 16) if amp_geom.vendor == 'E2V' else (8, 9) xmin = amp_geom.imaging.getMinX() xmax = xmin + outer_edge_width for amp in amps: if amp not in all_amps: continue imarr = ccd.segments[amp].image.getArray() imarr[:, xmin:xmax] += signal # # These amps have edge roll-off adjacent to the serial overscan: # amps = (1, 9) if amp_geom.vendor == 'E2V' else (1, 16) xmax = amp_geom.imaging.getMaxX() + 1 xmin = xmax - outer_edge_width for amp in amps: if amp not in all_amps: continue imarr = ccd.segments[amp].image.getArray() imarr[:, xmin:xmax] += signal # # Loop over all amps, set signal in perimeter and around blooming # stop. # ymax = amp_geom.imaging.getMaxY() + 1 ymin = ymax - bloom_stop_width for i, amp in enumerate(ccd.segments): image = ccd.segments[amp].image imarr = image.getArray() # # Set signal in row direction along perimeter. # xmin = amp_geom.imaging.getMinX() xmax = amp_geom.imaging.getMaxX() imarr[0:outer_edge_width, xmin:xmax] += signal if amp_geom.amp_loc == amp_loc['E2V']: #if True: # # Set signal around blooming stop # imarr[ymin:ymax, :] += signal # # Write the images of the mask regions to the FITS file. # if tmp_mask_image is None: tmp_mask_image = tempfile.mkstemp(suffix='.fits', dir='.')[-1] fitsWriteto(ccd, tmp_mask_image) # # Use BrightPixels code to detect the mask regions and write the mask file. # try: mask = afwImage.Mask(image.getDimensions()) except AttributeError: mask = afwImage.MaskU(image.getDimensions()) mask.addMaskPlane(mask_plane) maskedCCD = MaskedCCD(tmp_mask_image) pixels, columns = {}, {} for amp in maskedCCD: bright_pixels = BrightPixels(maskedCCD, amp, exptime, gain, ethresh=signal/2., mask_plane=mask_plane) pixels[amp], columns[amp] = bright_pixels.find() generate_mask(infile, outfile, mask_plane, pixels=pixels, columns=columns) if cleanup: os.remove(tmp_mask_image)
class SubtractBackgroundConfig(pexConfig.Config): """!Config for SubtractBackgroundTask @note Many of these fields match fields in lsst.afw.math.BackgroundControl, the control class for lsst.afw.math.makeBackground """ statisticsProperty = pexConfig.ChoiceField( doc="type of statistic to use for grid points", dtype=str, default="MEANCLIP", allowed={ "MEANCLIP": "clipped mean", "MEAN": "unclipped mean", "MEDIAN": "median", }) undersampleStyle = pexConfig.ChoiceField( doc= "behaviour if there are too few points in grid for requested interpolation style", dtype=str, default="REDUCE_INTERP_ORDER", allowed={ "THROW_EXCEPTION": "throw an exception if there are too few points", "REDUCE_INTERP_ORDER": "use an interpolation style with a lower order.", "INCREASE_NXNYSAMPLE": "Increase the number of samples used to make the interpolation grid.", }, ) binSize = pexConfig.RangeField( doc= "how large a region of the sky should be used for each background point", dtype=int, default=256, min=1, ) algorithm = pexConfig.ChoiceField( doc= "how to interpolate the background values. This maps to an enum; see afw::math::Background", dtype=str, default="NATURAL_SPLINE", optional=True, allowed={ "CONSTANT": "Use a single constant value", "LINEAR": "Use linear interpolation", "NATURAL_SPLINE": "cubic spline with zero second derivative at endpoints", "AKIMA_SPLINE": "higher-level nonlinear spline that is more robust to outliers", "NONE": "No background estimation is to be attempted", }, ) ignoredPixelMask = pexConfig.ListField( doc="Names of mask planes to ignore while estimating the background", dtype=str, default=[ "BAD", "EDGE", "DETECTED", "DETECTED_NEGATIVE", "NO_DATA", ], itemCheck=lambda x: x in afwImage.MaskU().getMaskPlaneDict().keys(), ) isNanSafe = pexConfig.Field( doc="Ignore NaNs when estimating the background", dtype=bool, default=False, ) useApprox = pexConfig.Field( doc="Use Approximate (Chebyshev) to model background.", dtype=bool, default=False, ) approxOrderX = pexConfig.Field( doc= "Approximation order in X for background Chebyshev (valid only with useApprox=True)", dtype=int, default=6, ) # Note: Currently X- and Y-orders must be equal due to a limitation in math::Chebyshev1Function2 # The following is being added so that the weighting attribute can also be configurable for the # call to afwMath.ApproximateControl approxOrderY = pexConfig.Field( doc= "Approximation order in Y for background Chebyshev (valid only with useApprox=True)", dtype=int, default=-1, ) weighting = pexConfig.Field( doc= "Use inverse variance weighting in calculation (valid only with useApprox=True)", dtype=bool, default=True, )
class MatchBackgroundsConfig(pexConfig.Config): usePolynomial = pexConfig.Field( dtype = bool, doc = "Fit background difference with Chebychev polynomial interpolation " \ "(using afw.math.Approximate)? If False, fit with spline interpolation using afw.math.Background", default = False ) order = pexConfig.Field( dtype=int, doc= "Order of Chebyshev polynomial background model. Ignored if usePolynomial False", default=8) badMaskPlanes = pexConfig.ListField( doc="Names of mask planes to ignore while estimating the background", dtype=str, default=[ "NO_DATA", "DETECTED", "DETECTED_NEGATIVE", "SAT", "BAD", "INTRP", "CR" ], itemCheck=lambda x: x in afwImage.MaskU().getMaskPlaneDict().keys(), ) gridStatistic = pexConfig.ChoiceField( dtype=str, doc="Type of statistic to estimate pixel value for the grid points", default="MEAN", allowed={ "MEAN": "mean", "MEDIAN": "median", "MEANCLIP": "clipped mean" }) undersampleStyle = pexConfig.ChoiceField( doc = "Behaviour if there are too few points in grid for requested interpolation style. " \ "Note: INCREASE_NXNYSAMPLE only allowed for usePolynomial=True.", dtype = str, default = "REDUCE_INTERP_ORDER", allowed = { "THROW_EXCEPTION": "throw an exception if there are too few points", "REDUCE_INTERP_ORDER": "use an interpolation style with a lower order.", "INCREASE_NXNYSAMPLE": "Increase the number of samples used to make the interpolation grid.", } ) binSize = pexConfig.Field( doc= "Bin size for gridding the difference image and fitting a spatial model", dtype=int, default=256) interpStyle = pexConfig.ChoiceField( dtype = str, doc = "Algorithm to interpolate the background values; ignored if usePolynomial is True" \ "Maps to an enum; see afw.math.Background", default = "AKIMA_SPLINE", allowed={ "CONSTANT" : "Use a single constant value", "LINEAR" : "Use linear interpolation", "NATURAL_SPLINE" : "cubic spline with zero second derivative at endpoints", "AKIMA_SPLINE": "higher-level nonlinear spline that is more robust to outliers", "NONE": "No background estimation is to be attempted", } ) numSigmaClip = pexConfig.Field( dtype=int, doc= "Sigma for outlier rejection; ignored if gridStatistic != 'MEANCLIP'.", default=3) numIter = pexConfig.Field( dtype=int, doc= "Number of iterations of outlier rejection; ignored if gridStatistic != 'MEANCLIP'.", default=2) bestRefWeightCoverage = pexConfig.RangeField( dtype = float, doc = "Weight given to coverage (number of pixels that overlap with patch), " \ "when calculating best reference exposure. Higher weight prefers exposures with high coverage." \ "Ignored when reference visit is supplied", default = 0.4, min = 0., max = 1. ) bestRefWeightVariance = pexConfig.RangeField( dtype = float, doc = "Weight given to image variance when calculating best reference exposure. " \ "Higher weight prefers exposures with low image variance. Ignored when reference visit is supplied", default = 0.4, min = 0., max = 1. ) bestRefWeightLevel = pexConfig.RangeField( dtype = float, doc = "Weight given to mean background level when calculating best reference exposure. " \ "Higher weight prefers exposures with low mean background level. " \ "Ignored when reference visit is supplied.", default = 0.2, min = 0., max = 1. ) approxWeighting = pexConfig.Field( dtype=bool, doc= ("Use inverse-variance weighting when approximating background offset model? " + "This will fail when the background offset is constant " + "(this is usually only the case in testing with artificial images)." + "(usePolynomial=True)"), default=True, ) gridStdevEpsilon = pexConfig.RangeField( dtype = float, doc = "Tolerance on almost zero standard deviation in a background-offset grid bin. " \ "If all bins have a standard deviation below this value, the background offset model " \ "is approximated without inverse-variance weighting. (usePolynomial=True)", default = 1e-8, min = 0. )
def main(): date = datetime.datetime.now().strftime("%a %Y-%m-%d %H:%M:%S") ######################################################################## # command line arguments and options ######################################################################## parser = optparse.OptionParser(usage = __doc__) #parser.add_option("-a", "--aa", dest="aa", type=float, # default=1.0, help="default=%default") opts, args = parser.parse_args() if len(args) == 0: r1, r2, dr = 3.0, 3.0, 0.5 elif len(args) == 3: r1, r2, dr = map(float, args) else: parser.print_help() sys.exit(1) # make a list of radii to compute the growthcurve points radius = [] nR = int( (r2 - r1)/dr + 1 ) for iR in range(nR): radius.append(r1 + iR*dr) # make an image big enough to hold the largest requested aperture xwidth = 2*(0 + 128) ywidth = xwidth # initializations sigmas = [1.5, 2.5] # the Gaussian widths of the psfs we'll use nS = len(sigmas) a = 100.0 aptaper = 2.0 xcen = xwidth/2 ycen = ywidth/2 alg = measBase.PsfFluxAlgorithm schema = afwTable.SourceTable.makeMinimalSchema() schema.addField("centroid_x", type=float) schema.addField("centroid_y", type=float) plugin = alg(measBase.PsfFluxControl(), "test", schema) cat = afwTable.SourceCatalog(schema) cat.defineCentroid("centroid") print "# sig rad Naive Sinc Psf" for iS in range(nS): sigma = sigmas[iS]; # make a Gaussian star to measure gauss = afwMath.GaussianFunction2D(sigma, sigma) kernel = afwMath.AnalyticKernel(xwidth, ywidth, gauss) kimg = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(kimg, False) kimg *= 100.0 mimg = afwImage.MaskedImageF(kimg.convertFloat(), afwImage.MaskU(kimg.getDimensions(), 0x0), afwImage.ImageF(kimg.getDimensions(), 0.0)) exposure = afwImage.ExposureF(mimg) # loop over all the radii in the growthcurve for iR in range(nR): psfH = int(2.0*(r2 + 2.0)) + 1 psfW = int(2.0*(r2 + 2.0)) + 1 # this test uses a single Gaussian instead of the original double gaussian psf = afwDet.GaussianPsf(psfW, psfH, sigma) # get the aperture fluxes for Naive and Sinc methods axes = afwGeom.ellipses.Axes(radius[iR], radius[iR], math.radians(0)); center = afwGeom.Point2D(0,0) ellipse = afwGeom.ellipses.Ellipse(axes, center) resultSinc = measBase.ApertureFluxAlgorithm.computeSincFlux(mimg.getImage(), ellipse) resultNaive = measBase.ApertureFluxAlgorithm.computeNaiveFlux(mimg.getImage(), ellipse) source = cat.addNew() source["centroid_x"] = 0 source["centroid_y"] = 0 exposure.setPsf(psf) plugin.measure(source, exposure) fluxNaive = resultNaive.flux fluxSinc = resultSinc.flux fluxPsf = source["test_flux"] # get the exact flux for the theoretical smooth PSF # rpsf = RGaussian(sigma, a, radius[iR], aptaper) # *** not sure how to integrate a python functor *** print "%.2f %.2f %.3f %.3f %.3f" % (sigma, radius[iR], fluxNaive, fluxSinc, fluxPsf)
def testReadFitsConform(self): hdu = 3 mask = afwImage.MaskU(self.maskFile, hdu, None, afwGeom.Box2I(), afwImage.LOCAL, True) self.assertMasksEqual(mask, self.expect)
def main(rerun, dataIds, fakes, root='/lustre/Subaru/SSP', rad=10): doCoadd = 'tract' in dataIds[0].keys() butler = dafPer.Butler(os.path.join(root, "rerun", rerun)) #read in fits file, replace with txt file or anything else fits = pyfits.open(fakes) data = fits[1].data radecCat = loadRaDec(data) ndata = len(data) datamask = np.ones(ndata, dtype=bool) ids = data["ID"] if "ID" in data.names else range(len(data)) idDict = dict(zip(ids, xrange(ndata))) for dataId in dataIds: print dataId try: sources = butler.get('deepCoadd_src' if doCoadd else 'src', dataId, immediate=True, flags=afwTable.SOURCE_IO_NO_FOOTPRINTS) cal_md = butler.get('deepCoadd_md' if doCoadd else 'calexp_md', dataId, immediate=True) calexp = butler.get('deepCoadd' if doCoadd else 'calexp', dataId, immediate=True) except: print "skipping", dataId continue if False: matches = afwTable.matchRaDec(sources, radecCat, 3.3 * afwGeom.arcseconds) for (src, fake, d) in matches: datamask[idDict[fake.getId()]] = False msk = calexp.getMaskedImage().getMask() detected = msk.clone() detected &= msk.getPlaneBitMask("DETECTED") wcs = calexp.getWcs() count, good_count = 0, 0 for i_d, datum in enumerate(radecCat): pixCoord = afwGeom.Point2I(wcs.skyToPixel(datum.getCoord())) pixBox = afwGeom.BoxI(pixCoord, afwGeom.Extent2I(1, 1)) pixBox.grow(rad) pixBox.clip(calexp.getBBox(afwImage.PARENT)) if pixBox.isEmpty(): continue else: count += 1 subMask = afwImage.MaskU(detected, pixBox, afwImage.PARENT) if sum(subMask.getArray().ravel()) != 0: datamask[i_d] = False else: good_count += 1 print count, good_count newdata = data[datamask] print ndata, len(newdata) hdu = pyfits.BinTableHDU(newdata) hdu.writeto('blank_sources.fits', clobber=True)
def plantSources(x0, y0, nx, ny, sky, nObj, wid, detector, useRandom=False): tanSys = detector.makeCameraSys(cameraGeom.TAN_PIXELS) pixToTanXYTransform = detector.getTransformMap()[tanSys] img0 = afwImage.ImageF(afwGeom.ExtentI(nx, ny)) img = afwImage.ImageF(afwGeom.ExtentI(nx, ny)) ixx0, iyy0, ixy0 = wid*wid, wid*wid, 0.0 edgeBuffer = 40.0*wid flux = 1.0e4 nkx, nky = int(10*wid) + 1, int(10*wid) + 1 xhwid,yhwid = nkx/2, nky/2 nRow = int(math.sqrt(nObj)) xstep = (nx - 1 - 0.0*edgeBuffer)/(nRow+1) ystep = (ny - 1 - 0.0*edgeBuffer)/(nRow+1) if useRandom: nObj = nRow*nRow goodAdded0 = [] goodAdded = [] for i in range(nObj): # get our position if useRandom: xcen0, ycen0 = numpy.random.uniform(nx), numpy.random.uniform(ny) else: xcen0, ycen0 = xstep*((i%nRow) + 1), ystep*(int(i/nRow) + 1) ixcen0, iycen0 = int(xcen0), int(ycen0) # distort position and shape pTan = afwGeom.Point2D(xcen0, ycen0) linTransform = pixToTanXYTransform.linearizeReverseTransform(pTan).getLinear() m = geomEllip.Quadrupole(ixx0, iyy0, ixy0) m.transform(linTransform) p = pixToTanXYTransform.reverseTransform(pTan) xcen, ycen = xcen0, ycen0 #p.getX(), p.getY() if (xcen < 1.0*edgeBuffer or (nx - xcen) < 1.0*edgeBuffer or ycen < 1.0*edgeBuffer or (ny - ycen) < 1.0*edgeBuffer): continue ixcen, iycen = int(xcen), int(ycen) ixx, iyy, ixy = m.getIxx(), m.getIyy(), m.getIxy() # plant the object tmp = 0.25*(ixx-iyy)**2 + ixy**2 a2 = 0.5*(ixx+iyy) + numpy.sqrt(tmp) b2 = 0.5*(ixx+iyy) - numpy.sqrt(tmp) #ellip = 1.0 - numpy.sqrt(b2/a2) theta = 0.5*numpy.arctan2(2.0*ixy, ixx-iyy) a = numpy.sqrt(a2) b = numpy.sqrt(b2) c, s = math.cos(theta), math.sin(theta) good0, good = True, True for y in range(nky): iy = iycen + y - yhwid iy0 = iycen0 + y - yhwid for x in range(nkx): ix = ixcen + x - xhwid ix0 = ixcen0 + x - xhwid if ix >= 0 and ix < nx and iy >= 0 and iy < ny: dx, dy = ix - xcen, iy - ycen u = c*dx + s*dy v = -s*dx + c*dy I0 = flux/(2*math.pi*a*b) val = I0*math.exp(-0.5*((u/a)**2 + (v/b)**2)) if val < 0: val = 0 prevVal = img.get(ix, iy) img.set(ix, iy, val+prevVal) else: good = False if ix0 >=0 and ix0 < nx and iy0 >= 0 and iy0 < ny: dx, dy = ix - xcen, iy - ycen I0 = flux/(2*math.pi*wid*wid) val = I0*math.exp(-0.5*((dx/wid)**2 + (dy/wid)**2)) if val < 0: val = 0 prevVal = img0.get(ix0, iy0) img0.set(ix0, iy0, val+prevVal) else: good0 = False if good0: goodAdded0.append([xcen,ycen]) if good: goodAdded.append([xcen,ycen]) # add sky and noise img += sky img0 += sky noise = afwImage.ImageF(afwGeom.ExtentI(nx, ny)) noise0 = afwImage.ImageF(afwGeom.ExtentI(nx, ny)) for i in range(nx): for j in range(ny): noise.set(i, j, numpy.random.poisson(img.get(i,j) )) noise0.set(i, j, numpy.random.poisson(img0.get(i,j) )) edgeWidth = int(0.5*edgeBuffer) mask = afwImage.MaskU(afwGeom.ExtentI(nx, ny)) left = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.ExtentI(edgeWidth, ny)) right = afwGeom.Box2I(afwGeom.Point2I(nx - edgeWidth,0), afwGeom.ExtentI(edgeWidth, ny)) top = afwGeom.Box2I(afwGeom.Point2I(0,ny - edgeWidth), afwGeom.ExtentI(nx, edgeWidth)) bottom = afwGeom.Box2I(afwGeom.Point2I(0,0), afwGeom.ExtentI(nx, edgeWidth)) for pos in [left, right, top, bottom]: msk = afwImage.MaskU(mask, pos, False) msk.set(msk.getPlaneBitMask('EDGE')) expos = afwImage.makeExposure(afwImage.makeMaskedImage(noise, mask, afwImage.ImageF(noise, True))) expos0 = afwImage.makeExposure(afwImage.makeMaskedImage(noise0, mask, afwImage.ImageF(noise0, True))) im = expos.getMaskedImage().getImage() im0 = expos0.getMaskedImage().getImage() im -= sky im0 -= sky return expos, goodAdded, expos0, goodAdded0
def do_testmeasureShape(self): """Test that we can instantiate and play with a measureShape""" im = afwImage.ImageF(afwGeom.ExtentI(100)) msk = afwImage.MaskU(im.getDimensions()) msk.set(0) var = afwImage.ImageF(im.getDimensions()) var.set(10) mi = afwImage.MaskedImageF(im, msk, var) del im del msk del var exp = afwImage.makeExposure(mi) bkgd = 100.0 control = measBase.SdssShapeControl() control.background = bkgd control.maxShift = 2 plugin, cat = makePluginAndCat(measBase.SdssShapeAlgorithm, "test", control, centroid="centroid") #cat.defineCentroid("test") cat.defineShape("test") #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # # Add a Gaussian to the image # for a, b, phi, tol in [ # n.b. phi in degrees (2.5, 1.5, 90.0, 1e-3), (1.5, 2.5, 0.0, 1e-3), (1.5, 2.5, 45.0, 1e-3), (1.5, 2.5, 90.0, 1e-3), (3.0, 2.5, 0.0, 1e-3), (3.0, 12.5, 0.0, 1e-3), (3.0, 12.5, 0.0, 2e-4), (1.0, 1.0, 0.0, 4e-3), (1.0, 0.75, 0.0, 2e-2), #(0.75, 0.75, 0.0, 1e-1), ]: if b > a: a, b = b, a phi -= 90 a, b, phi = float(a), float(b), math.radians(phi) im = mi.getImage() x, y = 30, 40 # centre of object im[:] = bkgd axes = afwGeom.ellipses.Axes(a, b, phi, True) quad = afwGeom.ellipses.Quadrupole(axes) if False: a0, b0 = a, b pixellatedAxes = axes.convolve( afwGeom.ellipses.Quadrupole(1 / 6.0, 1 / 6.0)) a, b = pixellatedAxes.getA(), pixellatedAxes.getB() print a, b, a0, b0 sigma_xx, sigma_yy, sigma_xy = quad.getIxx(), quad.getIyy( ), quad.getIxy() ksize = 2 * int(4 * max(a, b)) + 1 c, s = math.cos(phi), math.sin(phi) sum, sumxx, sumxy, sumyy = 4 * [0.0] if False else 4 * [None] for dx in range(-ksize / 2, ksize / 2 + 1): for dy in range(-ksize / 2, ksize / 2 + 1): u, v = c * dx + s * dy, s * dx - c * dy I = 1000 * math.exp(-0.5 * ((u / a)**2 + (v / b)**2)) im[x + dx, y + dy] += I if sum is not None: sum += I sumxx += I * dx * dx sumxy += I * dx * dy sumyy += I * dy * dy if sum is not None: sumxx /= sum sumxy /= sum sumyy /= sum print "RHL %g %g %g" % (sumxx, sumyy, sumxy) if display: ds9.mtv(im) footprint = afwDetection.FootprintSet( im, afwDetection.Threshold(110)).getFootprints()[0] source = cat.addNew() source.setFootprint(footprint) source.set("centroid_x", footprint.getPeaks()[0].getCentroid().getX()) source.set("centroid_y", footprint.getPeaks()[0].getCentroid().getY()) plugin.measure(source, exp) if False: Ixx, Iyy, Ixy = source.getIxx(), source.getIyy( ), source.getIxy() A2 = 0.5 * (Ixx + Iyy) + math.sqrt((0.5 * (Ixx - Iyy))**2 + Ixy**2) B2 = 0.5 * (Ixx + Iyy) - math.sqrt((0.5 * (Ixx - Iyy))**2 + Ixy**2) print "I_xx: %.5f %.5f" % (Ixx, sigma_xx) print "I_xy: %.5f %.5f" % (Ixy, sigma_xy) print "I_yy: %.5f %.5f" % (Iyy, sigma_yy) print "A2, B2 = %.5f, %.5f" % (A2, B2) print source.getX(), source.getY(), x, y print source.getIxx(), sigma_xx, source.getIyy( ), sigma_yy, source.getIxy(), sigma_xy self.assertTrue( abs(x - source.getX()) < 1e-4, "%g v. %g" % (x, source.getX())) self.assertTrue( abs(y - source.getY()) < 1e-4, "%g v. %g" % (y, source.getY())) self.assertTrue( abs(source.getIxx() - sigma_xx) < tol * (1 + sigma_xx), "%g v. %g" % (sigma_xx, source.getIxx())) self.assertTrue( abs(source.getIxy() - sigma_xy) < tol * (1 + abs(sigma_xy)), "%g v. %g" % (sigma_xy, source.getIxy())) self.assertTrue( abs(source.getIyy() - sigma_yy) < tol * (1 + sigma_yy), "%g v. %g" % (sigma_yy, source.getIyy()))
def __call__(self, source, exposure): fp = source.getFootprint() peaks = fp.getPeaks() peaksF = [pk.getF() for pk in peaks] fbb = fp.getBBox() fmask = afwImage.MaskU(fbb) fmask.setXY0(fbb.getMinX(), fbb.getMinY()) afwDetect.setMaskFromFootprint(fmask, fp, 1) psf = exposure.getPsf() psfSigPix = psf.computeShape().getDeterminantRadius() psfFwhmPix = psfSigPix * self.sigma2fwhm subimage = afwImage.ExposureF(exposure, fbb, True) cpsf = deblendBaseline.CachingPsf(psf) # if fewer than 2 peaks, just return a copy of the source if len(peaks) < 2: return source.getTable().copyRecord(source) # make sure you only deblend 2 peaks; take the brighest and faintest speaks = [(p.getPeakValue(), p) for p in peaks] speaks.sort() dpeaks = [speaks[0][1], speaks[-1][1]] # and only set these peaks in the footprint (peaks is mutable) peaks.clear() for peak in dpeaks: peaks.append(peak) if True: # Call top-level deblend task fpres = deblendBaseline.deblend(fp, exposure.getMaskedImage(), psf, psfFwhmPix, log=self.log, psfChisqCut1=self.psfChisqCut1, psfChisqCut2=self.psfChisqCut2, psfChisqCut2b=self.psfChisqCut2b) else: # Call lower-level _fit_psf task # Prepare results structure fpres = deblendBaseline.PerFootprint() fpres.peaks = [] for pki, pk in enumerate(dpeaks): pkres = deblendBaseline.PerPeak() pkres.peak = pk pkres.pki = pki fpres.peaks.append(pkres) for pki, (pk, pkres, pkF) in enumerate(zip(dpeaks, fpres.peaks, peaksF)): self.log.logdebug('Peak %i' % pki) deblendBaseline._fitPsf( fp, fmask, pk, pkF, pkres, fbb, dpeaks, peaksF, self.log, cpsf, psfFwhmPix, subimage.getMaskedImage().getImage(), subimage.getMaskedImage().getVariance(), self.psfChisqCut1, self.psfChisqCut2, self.psfChisqCut2b) deblendedSource = source.getTable().copyRecord(source) deblendedSource.setParent(source.getId()) peakList = deblendedSource.getFootprint().getPeaks() peakList.clear() for i, peak in enumerate(fpres.peaks): if peak.psfFitFlux > 0: suffix = "pos" else: suffix = "neg" c = peak.psfFitCenter self.log.info("deblended.centroid.dipole.psf.%s %f %f" % (suffix, c[0], c[1])) self.log.info("deblended.chi2dof.dipole.%s %f" % (suffix, peak.psfFitChisq / peak.psfFitDof)) self.log.info("deblended.flux.dipole.psf.%s %f" % (suffix, peak.psfFitFlux * np.sum(peak.templateImage.getArray()))) peakList.append(peak.peak) return deblendedSource
def generate_mask(infile, outfile, mask_plane, pixels=None, columns=None, temp_mask_image=None): """ Generate a mask file for the specified pixels and columns. The amplifier geometry will be taken from infile. """ # Insert artificial signal into specified pixels and columns for # each segment. exptime = 1 gain = 1 geometry = makeAmplifierGeometry(infile) amps = imutils.allAmps(infile) ccd = CCD(exptime=exptime, gain=gain, geometry=geometry, amps=amps) # Account for prescan in x-coordinate since we want to mask # columns the full segment. prescan = geometry.prescan.getWidth() signal = 10 if pixels is None: pixels = {} for amp in pixels: imarr = ccd.segments[amp].image.getArray() for ix, iy in pixels[amp]: imarr[iy][ix + prescan] = signal if columns is None: columns = {} for amp in columns: imarr = ccd.segments[amp].image.getArray() for ix in columns[amp]: imarr[:, ix + prescan] = signal if temp_mask_image is None: temp_mask_image = tempfile.mkstemp(suffix='.fits', dir='.')[-1] fitsWriteto(ccd, temp_mask_image) # Use the afw code to create a mask file. try: afwImage.Mask.addMaskPlane(mask_plane) except AttributeError: afwImage.MaskU.addMaskPlane(mask_plane) # Loop over segments in the temporary file and add all pixels to # the mask with the inserted signal. with fits.open(infile) as hdus: hdus[0].header['MASKTYPE'] = mask_plane hdus[0].header['FILENAME'] = outfile maskedCCD = MaskedCCD(temp_mask_image) for amp in maskedCCD: threshold = afwDetect.Threshold(signal / 2. * exptime / gain) fp_set = afwDetect.FootprintSet(maskedCCD[amp], threshold) try: mask = afwImage.Mask(maskedCCD[amp].getDimensions()) except AttributeError: mask = afwImage.MaskU(maskedCCD[amp].getDimensions()) fp_set.setMask(mask, mask_plane) hdus[amp].data = mask.array # add mask plane keywords for key, value in mask.getMaskPlaneDict().items(): hdus[amp].header['MP_' + key] = value hdus.writeto(outfile, overwrite=True) os.remove(temp_mask_image)