def drawLabels(self, labels=None, frame=None): """Draw the list labels at the corners of each panel. If labels is None, use the ones specified by Mosaic.append()""" if frame is None: return if not labels: labels = self.labels if not labels: return if len(labels) != self.nImage: raise RuntimeError, ("You provided %d labels for %d panels" % (len(labels), self.nImage)) with ds9.Buffering(): for i in range(len(labels)): if labels[i]: label, ctype = labels[i], None try: label, ctype = label except: pass if not label: continue ds9.dot(str(label), self.getBBox(i).getMinX(), self.getBBox(i).getMinY(), frame=frame, ctype=ctype)
def testLinearRamp(self): """Fit a ramp""" binsize = 1 ramp, rampCoeffs, xVec, yVec = self.makeRamp(binsize) # # Add a (labelled) bad value # ramp.set(ramp.getWidth() // 2, ramp.getHeight() // 2, (0, 0x1, np.nan)) if display: ds9.mtv(ramp, title="Input", frame=0) # # Here's the range that the approximation should be valid (and also the # bbox of the image returned by getImage) # bbox = afwGeom.BoxI( afwGeom.PointI(0, 0), afwGeom.PointI(binsize * ramp.getWidth() - 1, binsize * ramp.getHeight() - 1) ) order = 3 # 1 would be enough to fit the ramp actrl = afwMath.ApproximateControl(afwMath.ApproximateControl.CHEBYSHEV, order) approx = afwMath.makeApproximate(xVec, yVec, ramp, bbox, actrl) for i, aim in enumerate([approx.getImage(), approx.getMaskedImage().getImage()]): if i == 0 and display: ds9.mtv(aim, title="interpolated", frame=1) with ds9.Buffering(): for x in xVec: for y in yVec: ds9.dot("+", x, y, size=0.4, frame=1) for x, y in aim.getBBox().getCorners(): self.assertEqual(aim.get(x, y), rampCoeffs[0] + rampCoeffs[1] * x + rampCoeffs[1] * y)
def view(cat=None, exp=None, tract=None, patch=None, ID=None, coords=None, filter='I', frame=0, scale="zscale",\ zoom="to fit", trans=80, draw_ells=True, maxsep=None, shape_model='shape.hsm.moments', pcolor=ds9.GREEN, ccolor=ds9.RED): if cat is None: assert (tract is not None) and (patch is not None), 'if no cat is given, must give tract and patch' exp = butler.get("deepCoadd_calexp", tract=tract, patch=patch, filter='HSC-'+filter, immediate=True) cat = butler.get("deepCoadd_meas", tract=tract, patch=patch, filter='HSC-'+filter, immediate=True) else: assert exp is not None, 'if cat is given, must also give exp' x0, y0 = exp.getXY0() settings = {'scale':scale, 'zoom': zoom, 'mask' : 'transparency %d' %(trans)} ds9.mtv(exp, frame=frame, settings=settings) ######################################################### # maxsep is used if you only want to draw ellipses around # objects within a distance maxsep from a candidate ######################################################### if maxsep is not None: if ID is not None: obj = cat.find(ID) ra0, dec0 = obj.getRa().asDegrees(), obj.getDec().asDegrees() else: ra0, dec0 = coords ra, dec = cat.get('coord.ra')*180./np.pi, cat.get('coord.dec')*180./np.pi seps = angsep(ra0, dec0, ra, dec) cut = seps < maxsep cat = cat[seps < maxsep].copy(deep=True) if draw_ells: with ds9.Buffering(): for i,source in enumerate(cat): ellcolor = pcolor if source.get('parent')==0 else ccolor ixx, ixy, iyy = [source.get(shape_model+_x) for _x in ['.xx', '.xy', '.yy']] symbol = "@:{ixx},{ixy},{iyy}".format(ixx=ixx, ixy=ixy, iyy=iyy) ds9.dot(symbol, source.getX()-x0, source.getY()-y0, ctype=ellcolor, frame=frame)
def showStandards(standardStarSet, exp, frame, countsMin=None, flagMask=None, rmsMax=None, ctype=ds9.RED): """Show all the standards that are visible on this exposure If countsMin is not None, only show brighter Sources If flagMask is not None, ignore sources that have (flags & ~flagMask) != 0 """ wcs = exp.getWcs() width, height = exp.getMaskedImage().getWidth(), exp.getMaskedImage().getHeight() for s in standardStarSet: x,y = wcs.skyToPixel(s.getRaDec()) if x < 0 or x >= width or y < 0 or y >= height: continue counts = s.getPsfFlux() if counts < countsMin and countsMin is not None: continue if flagMask is not None: if (s.getFlagForDetection() & ~flagMask) != 0: continue rms = math.sqrt(s.getIxx() + s.getIyy()) if rmsMax is not None and rms > rmsMax: continue if False: pt = "%.1f" % (rms) else: pt = "+" ds9.dot(pt, x, y, frame=frame, ctype=ctype)
def main(expName, config, display=False): exp = afwImage.ExposureF(expName) # Assume exposure is bias-subtracted, CCD-assembled, has variance and mask plane. # If not, put code here to fix what's lacking. bg, bgSubExp = estimateBackground(exp, config.background, subtract=True) detection = SourceDetectionTask(config=config.detection) detResults = detection.detectFootprints(bgSubExp, sigma=config.psfSigma) fpSet = detResults.positive print "Found %d positive footprints" % len(fpSet.getFootprints()) if display: print "Displaying results..." import lsst.afw.display.ds9 as ds9 frame = 1 ds9.mtv(bgSubExp, frame=frame, title="Background-subtracted exposure") with ds9.Buffering(): for fp in fpSet.getFootprints(): peakList = fp.getPeaks() for p in peakList: ds9.dot("x", p.getFx(), p.getFy(), frame=frame) # XXX Work with footprints here psf = measAlg.SingleGaussianPsf(config.psfSize, config.psfSize, config.psfSigma) exp.setPsf(psf) cosmicray(exp, config.cosmicray, display=display)
def main(rootDir, visit, ccd, frame=1, title="", scale="zscale", zoom="to fit", trans=60, useEllipse=False): # make a butler and specify your dataId butler = dafPersist.Butler(rootDir) dataId = {'visit': visit, 'ccd':ccd} # get the exposure from the butler exposure = butler.get('calexp', dataId) # put the settings in a dict object and call ds9.mtv() settings = {'scale':scale, 'zoom': zoom, 'mask' : 'transparency %d' %(trans)} ds9.mtv(exposure, frame=frame, title=title, settings=settings) # now get the source catalog and overplot the points sources = butler.get('src', dataId) with ds9.Buffering(): for i,source in enumerate(sources): color = ds9.RED size = 5.0 if useEllipse: # show an ellipse symbol symbol = "@:{ixx},{ixy},{iyy}".format(ixx=source.getIxx(), ixy=source.getIxy(), iyy=source.getIyy()) else: # just a simple point (symbols +, x, *, o are all accepted) symbol = "o" ds9.dot(symbol, source.getX(), source.getY(), ctype=color, size=size, frame=frame, silent=True)
def testFootprintFromEllipse(self): """Create an elliptical Footprint""" cen = afwGeom.Point2D(23, 25) a, b, theta = 25, 15, 30 ellipse = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(a, b, math.radians(theta)), cen) foot = afwDetect.Footprint(ellipse, afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(50, 60))) idImage = afwImage.ImageU(afwGeom.Extent2I(foot.getRegion().getWidth(), foot.getRegion().getHeight())) idImage.set(0) foot.insertIntoImage(idImage, foot.getId()) if display: ds9.mtv(idImage, frame=2) displayUtils.drawFootprint(foot, frame=2) shape = foot.getShape() shape.scale(2) # <r^2> = 1/2 for a disk ds9.dot(shape, *cen, frame=2, ctype=ds9.RED) shape = foot.getShape() shape.scale(2) # <r^2> = 1/2 for a disk ds9.dot(shape, *cen, frame=2, ctype=ds9.MAGENTA) axes = afwGeom.ellipses.Axes(foot.getShape()) axes.scale(2) # <r^2> = 1/2 for a disk self.assertEqual(foot.getCentroid(), cen) self.assertTrue(abs(a - axes.getA()) < 0.15, "a: %g v. %g" % (a, axes.getA())) self.assertTrue(abs(b - axes.getB()) < 0.02, "b: %g v. %g" % (b, axes.getB())) self.assertTrue(abs(theta - math.degrees(axes.getTheta())) < 0.2, "theta: %g v. %g" % (theta, math.degrees(axes.getTheta())))
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"))
def showCamera(camera, imageSource=SynthesizeCcdImage(), imageFactory=afwImage.ImageU, frame=None, overlay=True, bin=1): """Show a Camera on ds9 (with the specified frame); if overlay show the IDs and amplifier boundaries If imageSource is provided its getImage method will be called to return a CCD image (e.g. a cameraGeom.GetCcdImage object); if it is "", an image will be created based on the properties of the detectors""" if imageSource is None: cameraImage = None elif isinstance(imageSource, GetCcdImage): cameraImage = makeImageFromCamera(camera, imageSource, bin=bin, imageFactory=imageFactory) else: cameraImage = imageSource if cameraImage: ds9.mtv(cameraImage, frame=frame, title=camera.getId().getName()) for det in camera: raft = cameraGeom.cast_Raft(det) center = camera.getCenterPixel() + afwGeom.Extent2D(raft.getCenterPixel()) if overlay: bbox = raft.getAllPixels() ds9.dot(raft.getId().getName(), center[0]/bin, center[1]/bin, frame=frame) showRaft(raft, None, frame=frame, overlay=overlay, raftOrigin=center - afwGeom.makeExtentD(raft.getAllPixels().getWidth()/2, raft.getAllPixels().getHeight()/2), bin=bin)
def plotPeaks(fps, ctype): if fps is None: return with ds9.Buffering(): for fp in fps.getFootprints(): for pp in fp.getPeaks(): ds9.dot("+", pp.getFx() - x0, pp.getFy() - y0, ctype=ctype)
def run(display=False): # # Create the task # config = CalibrateTask.ConfigClass() config.initialPsf.pixelScale = 0.185 # arcsec per pixel config.initialPsf.fwhm = 1.0 config.astrometry.retarget(MyAstrometryTask) calibrateTask = CalibrateTask(config=config) # # Process the data # exposure = loadData(config.initialPsf.pixelScale) result = calibrateTask.run(exposure) exposure0, exposure = exposure, result.exposure sources = result.sources if display: # display on ds9 (see also --debug argparse option) frame = 1 ds9.mtv(exposure, frame=frame) with ds9.Buffering(): for s in sources: xy = s.getCentroid() ds9.dot('+', *xy, ctype=ds9.CYAN if s.get("flags_negative") else ds9.GREEN, frame=frame)
def main(rootDir, visit, ccd, frame=1, title="", scale="zscale", zoom="to fit", trans=60, useEllipse=False): # butler を開き読み込みたいデータの dataId を指定する butler = dafPersist.Butler(rootDir) dataId = {'visit': visit, 'ccd':ccd} # butler から一次処理済データを読み込む exposure = butler.get('calexp', dataId) # 読み込みたい天体情報を設定し、ds9.mtv() を読み込む settings = {'scale':scale, 'zoom': zoom, 'mask' : 'transparency %d' %(trans)} ds9.mtv(exposure, frame=frame, title=title, settings=settings) # 天体カタログを取得し、データ点を重ねて表示する sources = butler.get('src', dataId) with ds9.Buffering(): for i,source in enumerate(sources): color = ds9.RED size = 5.0 if useEllipse: # 楕円体のシンボルで表示 symbol = "@:{ixx},{ixy},{iyy}".format(ixx=source.getIxx(), ixy=source.getIxy(), iyy=source.getIyy()) else: # シンプルなシンボルで表示(例えば、 +, x, *, o が使える) symbol = "o" ds9.dot(symbol, source.getX(), source.getY(), ctype=color, size=size, frame=frame, silent=True)
def detectSources(exposure, threshold, psf=None): """Detect sources above positiveThreshold in the provided exposure returning the sourceList """ if not psf: FWHM = 5 psf = algorithms.createPSF("DoubleGaussian", 15, 15, FWHM/(2*math.sqrt(2*math.log(2)))) # # Subtract background # mi = exposure.getMaskedImage() bctrl = afwMath.BackgroundControl(afwMath.NATURAL_SPLINE); bctrl.setNxSample(int(mi.getWidth()/256) + 1); bctrl.setNySample(int(mi.getHeight()/256) + 1); backobj = afwMath.makeBackground(mi.getImage(), bctrl) img = mi.getImage(); img -= backobj.getImageF(); del img if display: ds9.mtv(exposure) ds = detectFootprints(exposure, threshold) objects = ds.getFootprints() # # Time to actually measure # measPipelineDir = lsst.utils.getPackageDir('meas_pipeline') moPolicy = policy.Policy.createPolicy(os.path.join(measPipelineDir, "policy", "MeasureSources.paf")) moPolicy = moPolicy.getPolicy("measureObjects") measureSources = algorithms.makeMeasureSources(exposure, moPolicy, psf) sourceList = afwDetection.SourceSet() for i in range(len(objects)): source = afwDetection.Source() sourceList.append(source) source.setId(i) source.setFlagForDetection(source.getFlagForDetection() | algorithms.Flags.BINNED1); try: measureSources.apply(source, objects[i]) except Exception: pass if source.getFlagForDetection() & algorithms.Flags.EDGE: continue if display: xc, yc = source.getXAstrom() - mi.getX0(), source.getYAstrom() - mi.getY0() if False: ds9.dot("%.1f %d" % (source.getPsfFlux(), source.getId()), xc, yc+1) ds9.dot("+", xc, yc, size=1) return sourceList
def main(rootDir, visit, ccd, filter=None, frame=1, title="", scale="zscale", zoom="to fit", trans=60, useEllipse=False, maskOnly=False): if ccd.find(",") < 0: ccd = int(ccd) pipeVersion = dafPersist.eupsVersions.EupsVersions().versions['hscPipe'] if StrictVersion(pipeVersion) >= StrictVersion('3.9.0'): coaddData = "deepCoadd_calexp" coaddCat = "meas" else: coaddData = "deepCoadd" coaddCat = "src" print "Read in %s image"%coaddData # make a butler and specify your dataId butler = dafPersist.Butler(rootDir) if filter: dataId = {'tract': visit, 'patch':ccd, 'filter': filter} exposure = butler.get(coaddData, dataId, immediate=True) butlerTarget='deepCoadd_' sources = butler.get(butlerTarget + coaddCat, dataId) else: dataId = {'visit': visit, 'ccd':ccd} exposure = butler.get("calexp", dataId, immediate=True) butlerTarget="" sources = butler.get(butlerTarget + 'src', dataId) # put the settings in a dict object and call ds9.mtv() settings = {'scale':scale, 'zoom': zoom, 'mask' : 'transparency %d' %(trans)} ds9.setMaskPlaneColor('FAKE', color=ds9.CYAN) if not maskOnly: ds9.mtv(exposure, frame=frame, title=title, settings=settings) else: msk = exposure.getMaskedImage().getMask() msk &= msk.getPlaneBitMask('FAKE') ds9.mtv(msk, frame=frame, title=title, settings=settings) with ds9.Buffering(): print len(sources) x0, y0 = exposure.getXY0() print x0, y0 for i,source in enumerate(sources): color = ds9.RED size = 5.0 if useEllipse: # show an ellipse symbol symbol = "@:{ixx},{ixy},{iyy}".format(ixx=source.getIxx(), ixy=source.getIxy(), iyy=source.getIyy()) else: # just a simple point (symbols +, x, *, o are all accepted) symbol = "o" ds9.dot(symbol, source.getX()-x0, source.getY()-y0, ctype=color, size=size, frame=frame, silent=True)
def selectPsfSources(exposure, matches, psfPolicy): """Get a list of suitable stars to construct a PSF.""" import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = lsstDebug.Info(__name__).displayExposure # display the Exposure + spatialCells # # Unpack policy # kernelSize = psfPolicy.get("kernelSize") borderWidth = psfPolicy.get("borderWidth") sizePsfCellX = psfPolicy.get("sizeCellX") sizePsfCellY = psfPolicy.get("sizeCellY") # mi = exposure.getMaskedImage() if display and displayExposure: frame = 0 ds9.mtv(mi, frame=frame, title="PSF candidates") psfCellSet = afwMath.SpatialCellSet(mi.getBBox(), sizePsfCellX, sizePsfCellY) psfStars = [] for val in matches: ref, source = val[0:2] if not (ref.getFlagForDetection() & measAlg.Flags.STAR) or \ (source.getFlagForDetection() & measAlg.Flags.BAD): continue try: cand = measAlg.makePsfCandidate(source, mi) # # The setXXX methods are class static, but it's convenient to call them on # an instance as we don't know Exposure's pixel type (and hence cand's exact type) if cand.getWidth() == 0: cand.setBorderWidth(borderWidth) cand.setWidth(kernelSize + 2*borderWidth) cand.setHeight(kernelSize + 2*borderWidth) im = cand.getMaskedImage().getImage() max = afwMath.makeStatistics(im, afwMath.MAX).getValue() if not numpy.isfinite(max): continue psfCellSet.insertCandidate(cand) if display and displayExposure: ds9.dot("+", source.getXAstrom() - mi.getX0(), source.getYAstrom() - mi.getY0(), size=4, frame=frame, ctype=ds9.CYAN) ds9.dot("o", source.getXAstrom() - mi.getX0(), source.getYAstrom() - mi.getY0(), size=4, frame=frame, ctype=ds9.CYAN) except Exception: continue source.setFlagForDetection(source.getFlagForDetection() | measAlg.Flags.STAR) psfStars += [source] return psfStars, psfCellSet
def DrawStat(stat, zoom_to_point = False): # if stat.ellipse_b == 0: # ds9.zoom(22, stat.centroid_x,stat.centroid_y, 0) # use to zoom to a single point argstring = "@:"+str(4*stat.ellipse_Ixx)+','+str(4*stat.ellipse_Ixy)+','+str(4*stat.ellipse_Iyy) #multiply by four just to make it more exaggerated otherwise they all look like cirlces ds9.dot(argstring,stat.centroid_x,stat.centroid_y) #ellipse around the centroid ds9.dot("x",stat.centroid_x,stat.centroid_y)# cross on the peak displayUtils.drawBBox(stat.BBox, borderWidth=0.5) # border to fully encompass the bbox and no more if zoom_to_point: ds9.zoom(22, stat.centroid_x,stat.centroid_y, 0) # use to zoom to a single point print 'length (diag,px) = %s, length (3D,true,um) = %s, flux = %s, npix = %s, dedx = %s' %(stat.diagonal_length_pixels, stat.length_true_um, stat.flux, stat.npix, stat.de_dx)
def check(self, psfFwhm=0.5, flux=1000.0): """Check that we can measure convolved fluxes We create an image with a Gaussian PSF and a single point source. Measurements of the point source should match expectations for a Gaussian of the known sigma and known aperture radius. @param psfFwhm: PSF FWHM in arcsec @param flux: source flux in ADU """ bbox = afwGeom.Box2I(afwGeom.Point2I(12345, 6789), afwGeom.Extent2I(200, 300)) # We'll only achieve the target accuracy if the pixel scale is rather smaller than Gaussians # involved. Otherwise it's important to consider the convolution with the pixel grid, and we're # not doing that here. scale = 0.1*afwGeom.arcseconds exposure, center = makeExposure(bbox, scale, psfFwhm, flux) msConfig = measAlg.SourceMeasurementConfig() msConfig.algorithms.names.add("flux.convolved") values = [ii/scale.asArcseconds() for ii in (0.6, 0.8, 1.0, 1.2)] msConfig.algorithms["flux.convolved"].seeing = values msConfig.algorithms["flux.convolved"].radius = values schema = afwTable.SourceTable.makeMinimalSchema() ms = msConfig.makeMeasureSources(schema) table = afwTable.SourceTable.make(schema) msConfig.slots.setupTable(table) source = table.makeRecord() ss = afwDetection.FootprintSet(exposure.getMaskedImage(), afwDetection.Threshold(0.1)) fp = ss.getFootprints()[0] source.setFootprint(fp) ms.apply(source, exposure, center) if display: ds9.mtv(exposure, frame=frame) ds9.dot("x", center.getX() - exposure.getX0(), center.getY() - exposure.getY0(), frame=frame) import pdb;pdb.set_trace() self.assertFalse(source.get("flux.convolved.flag")) # algorithm succeeded for ii, seeing in enumerate(msConfig.algorithms["flux.convolved"].seeing): deconvolve = seeing < psfFwhm/scale.asArcseconds() self.assertTrue(source.get("flux.convolved.%d.deconv" % ii) == deconvolve) if deconvolve: # Not worth checking anything else continue for jj, radius in enumerate(msConfig.algorithms["flux.convolved"].radius): sigma = seeing/SIGMA_TO_FWHM expected = flux*(1.0 - math.exp(-0.5*(radius/sigma)**2)) name = "flux.convolved.%d.%d" % (ii, jj) self.assertClose(expected, source.get(name), rtol=1.0e-3) self.assertFalse(source.get(name + ".flags")) self.assertGreater(source.get(name + ".err"), 0)
def testFootprintsMeasure(self): """Check that we can measure the objects in a detectionSet""" xcentroid = [10.0, 14.0, 9.0] ycentroid = [8.0, 11.5061728, 14.0] flux = [51.0, 101.0, 20.0] wflux = [51.0, 101.0, 20.0] ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10), "DETECTED") if display: ds9.mtv(self.mi, frame=0) ds9.mtv(self.mi.getVariance(), frame=1) measureSourcesConfig = algorithms.SourceMeasurementConfig() measureSourcesConfig.algorithms["flux.naive"].radius = 3.0 measureSourcesConfig.algorithms.names = ["centroid.naive", "shape.sdss", "flux.psf", "flux.naive"] measureSourcesConfig.slots.centroid = "centroid.naive" measureSourcesConfig.slots.psfFlux = "flux.psf" measureSourcesConfig.slots.apFlux = "flux.naive" measureSourcesConfig.slots.modelFlux = None measureSourcesConfig.slots.instFlux = None measureSourcesConfig.slots.calibFlux = None measureSourcesConfig.validate() schema = afwTable.SourceTable.makeMinimalSchema() ms = measureSourcesConfig.makeMeasureSources(schema) catalog = afwTable.SourceCatalog(schema) measureSourcesConfig.slots.setupTable(catalog.getTable()) ds.makeSources(catalog) sigma = 1e-10; psf = algorithms.DoubleGaussianPsf(11, 11, sigma) # i.e. a single pixel self.exposure.setPsf(psf) for i, source in enumerate(catalog): ms.applyWithPeak(source, self.exposure) xc, yc = source.getX() - self.mi.getX0(), source.getY() - self.mi.getY0() if display: ds9.dot("+", xc, yc) self.assertAlmostEqual(source.getX(), xcentroid[i], 6) self.assertAlmostEqual(source.getY(), ycentroid[i], 6) self.assertEqual(source.getApFlux(), flux[i]) self.assertAlmostEqual(source.getApFluxErr(), math.sqrt(29), 6) # 29 pixels in 3pixel circular ap. # We're using a delta-function PSF, so the psfFlux should be the pixel under the centroid, # iff the object's centred in the pixel if xc == int(xc) and yc == int(yc): self.assertAlmostEqual(source.getPsfFlux(), self.exposure.getMaskedImage().getImage().get(int(xc + 0.5), int(yc + 0.5))) self.assertAlmostEqual(source.getPsfFluxErr(), self.exposure.getMaskedImage().getVariance().get(int(xc + 0.5), int(yc + 0.5)))
def makeAndMeasure(self, measureKron, a, b, theta, dx=0.0, dy=0.0, nsigma=6, kfac=2, nIterForRadius=1, xcen=None, ycen=None, makeImage=True, apCorrValue=None, # if a numeric value, use as the constant value of aperture correction ): """Make and measure an elliptical Gaussian""" if xcen is None: xcen = 0.5*self.width + dx if ycen is None: ycen = 0.5*self.height + dy # # Make the object # if a < b: a, b = b, a theta += 90 if self.objImg is None: makeImage = True if makeImage: self.objImg = makeGalaxy(self.width, self.height, self.flux, a, b, theta, dx, dy, afwGeom.Point2I(10, 10), xcen=xcen, ycen=ycen) if display: ds9.mtv(self.objImg, frame=ds9Frame, title="%g %g" % (a, b)) doApplyApCorr = "noButWarn" if apCorrValue != None: addApCorrMap(self.objImg, apCorrValue) doApplyApCorr = "yes" if display: if not makeImage: ds9.erase(frame=ds9Frame) ds9.dot("+", xcen - self.objImg.getX0(), ycen - self.objImg.getY0(), size=1, ctype=ds9.RED, frame=ds9Frame) ds9.pan(xcen - self.objImg.getX0(), ycen - self.objImg.getY0(), frame=ds9Frame) c, s = math.cos(math.radians(theta)), math.sin(math.radians(theta)) # N.b. add 1/12 in quadrature to allow for pixellisation ds9.dot("@:%f,%f,%f" % (nsigma**2*((a**2 + 1/12.0)*c**2 + (b**2 + 1/12.0)*s**2), nsigma**2*(a**2 - b**2)*c*s, nsigma**2*((a**2 + 1/12.0)*s**2 + (b**2 + 1/12.0)*c**2)), xcen - self.objImg.getX0(), ycen - self.objImg.getY0(), size=1, ctype=ds9.RED, frame=ds9Frame, silent=True) # # Do the measuring # FWHM = 5 ksize = 25 # size of desired kernel self.objImg.setPsf(measAlg.DoubleGaussianPsf(ksize, ksize, FWHM/(2*math.sqrt(2*math.log(2))), 1, 0.1)) return measureKron(self.objImg, xcen, ycen, nsigma, kfac, nIterForRadius, doApplyApCorr)
def DrawStatFromScratch(stat, bgsubtract): metadata_filename = '/home/mmmerlin/useful/herring_bone.fits' image = AssembleImage(stat.filename, metadata_filename, bgsubtract) print "track at %s,%s in %s"%(stat.centroid_x,stat.centroid_y,stat.filename) ds9.mtv(image) # exit() argstring = "@:"+str(4*stat.ellipse_Ixx)+','+str(4*stat.ellipse_Ixy)+','+str(4*stat.ellipse_Iyy) #multiply by four just to make it more exaggerated otherwise they all look like cirlces ds9.dot(argstring,stat.centroid_x,stat.centroid_y) #ellipse around the centroid ds9.dot("x",stat.centroid_x,stat.centroid_y)# cross on the peak displayUtils.drawBBox(stat.BBox, borderWidth=0.5) # border to fully encompass the bbox and no more ds9.zoom(22, stat.centroid_x,stat.centroid_y, 0) # use to zoom to a single point
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 showSourceSet(sSet, xy0=(0, 0), frame=0, ctype=ds9.GREEN, symb="+", size=2): """Draw the (XAstrom, YAstrom) positions of a set of Sources. Image has the given XY0""" with ds9.Buffering(): for s in sSet: xc, yc = s.getXAstrom() - xy0[0], s.getYAstrom() - xy0[1] if symb == "id": ds9.dot(str(splitId(s.getId(), True)["objId"]), xc, yc, frame=frame, ctype=ctype, size=size) else: ds9.dot(symb, xc, yc, frame=frame, ctype=ctype, size=size)
def showPsfSpatialCells(exposure, cellSet, showBadCandidates, frame=1): maUtils.showPsfSpatialCells(exposure, cellSet, symb="o", ctype=ds9.CYAN, ctypeUnused=ds9.YELLOW, size=4, frame=frame) for cell in cellSet.getCellList(): for cand in cell.begin(not showBadCandidates): # maybe include bad candidates cand = measAlg.cast_PsfCandidateF(cand) status = cand.getStatus() ds9.dot('+', *cand.getSource().getCentroid(), frame=frame, ctype=ds9.GREEN if status == afwMath.SpatialCellCandidate.GOOD else ds9.YELLOW if status == afwMath.SpatialCellCandidate.UNKNOWN else ds9.RED)
def checkPeaks(self, dwidth=0, dheight=0, frame=3): """Check that we got the peaks right""" feet = self.fs.getFootprints() # # Check that we found all the peaks # self.assertEqual(sum([len(f.getPeaks()) for f in feet]), sum([len(f.getPeaks()) for f in feet])) if display: ds9.mtv(self.im, frame=frame) with ds9.Buffering(): for i, foot in enumerate(feet): for p in foot.getPeaks(): ds9.dot("+", p.getIx(), p.getIy(), size=0.4, frame=frame) if i < len(self.peaks): for trueX, trueY, peakVal in self.peaks[i]: ds9.dot("x", trueX, trueY, size=0.4, ctype=ds9.RED, frame=frame) for i, foot in enumerate(feet): npeak = None # # Peaks that touch the edge are handled differently, as only the single highest/lowest pixel # is treated as a Peak # if dwidth != 0 or dheight != 0: if ( foot.getBBox().getMinX() == 0 or foot.getBBox().getMaxX() == self.im.getWidth() - 1 or foot.getBBox().getMinY() == 0 or foot.getBBox().getMaxY() == self.im.getHeight() - 1 ): npeak = 1 if npeak is None: npeak = len(self.peaks[i]) if npeak != len(foot.getPeaks()): print "RHL", foot.repr() # print "RHL", [(p.repr().split(":")[0], p.getIx(), p.getIy()) for p in foot.getPeaks()] print "RHL", [(p.getId(), p.getIx(), p.getIy()) for p in foot.getPeaks()] print "RHL", [p[0:2] for p in self.peaks[i]] self.assertEqual(len(foot.getPeaks()), npeak) for j, p in enumerate(foot.getPeaks()): trueX, trueY, peakVal = self.peaks[i][j] if (p.getIx(), p.getIy()) != (trueX, trueY): print "RHL", [(pp.getId(), pp.getIx(), pp.getIy()) for pp in foot.getPeaks()] print "RHL", [pp[0:2] for pp in self.peaks[i]] self.assertEqual((p.getIx(), p.getIy()), (trueX, trueY))
def testDrawing(self): """Test drawing lines and glyphs""" ds9.erase() exp = afwImage.ExposureF(300, 350) ds9.mtv(exp, title="parent") # tells display0 about the image's xy0 with ds9.Buffering(): ds9.dot('o', 200, 220) vertices = [(200, 220), (210, 230), (224, 230), (214, 220), (200, 220)] ds9.line(vertices, ctype=ds9.CYAN) ds9.line(vertices[:-1], symbs="+x+x", size=3)
def testFootprintsMeasure(self): """Check that we can measure the objects in a detectionSet""" xcentroid = [10.0, 14.0, 9.0] ycentroid = [8.0, 11.5061728, 14.0] flux = [51.0, 101.0, 20.0] ds = afwDetection.FootprintSet(self.mi, afwDetection.Threshold(10), "DETECTED") if display: ds9.mtv(self.mi, frame=0) ds9.mtv(self.mi.getVariance(), frame=1) measureSourcesConfig = measBase.SingleFrameMeasurementConfig() measureSourcesConfig.algorithms["base_CircularApertureFlux"].radii = [3.0] measureSourcesConfig.algorithms.names = ["base_NaiveCentroid", "base_SdssShape", "base_PsfFlux", "base_CircularApertureFlux"] measureSourcesConfig.slots.centroid = "base_NaiveCentroid" measureSourcesConfig.slots.psfFlux = "base_PsfFlux" measureSourcesConfig.slots.apFlux = "base_CircularApertureFlux_3_0" measureSourcesConfig.slots.modelFlux = None measureSourcesConfig.slots.instFlux = None measureSourcesConfig.slots.calibFlux = None schema = afwTable.SourceTable.makeMinimalSchema() task = measBase.SingleFrameMeasurementTask(schema, config=measureSourcesConfig) measCat = afwTable.SourceCatalog(schema) # now run the SFM task with the test plugin sigma = 1e-10 psf = algorithms.DoubleGaussianPsf(11, 11, sigma) # i.e. a single pixel self.exposure.setPsf(psf) task.run(measCat, self.exposure) for i, source in enumerate(measCat): xc, yc = source.getX() - self.mi.getX0(), source.getY() - self.mi.getY0() if display: ds9.dot("+", xc, yc) self.assertAlmostEqual(source.getX(), xcentroid[i], 6) self.assertAlmostEqual(source.getY(), ycentroid[i], 6) self.assertEqual(source.getApFlux(), flux[i]) self.assertAlmostEqual(source.getApFluxErr(), math.sqrt(29), 6) # 29 pixels in 3pixel circular ap. # We're using a delta-function PSF, so the psfFlux should be the pixel under the centroid, # iff the object's centred in the pixel if xc == int(xc) and yc == int(yc): self.assertAlmostEqual(source.getPsfFlux(), self.exposure.getMaskedImage().getImage().get(int(xc + 0.5), int(yc + 0.5))) self.assertAlmostEqual(source.getPsfFluxErr(), self.exposure.getMaskedImage().getVariance().get(int(xc + 0.5), int(yc + 0.5)))
def showAstrometry(exposure, wcs, allMatches, useMatches, frame=0, title=None, pause=False): """Show results of astrometry fitting @param exposure: Image to display @param wcs: Astrometric solution @param allMatches: List of all astrometric matches (including rejects) @param useMatches: List of used astrometric matches @param frame: Frame number for display @param title: Title for display @param pause: Pause to allow viewing of the display and optional debugging? """ import lsst.afw.display.ds9 as ds9 ds9.mtv(exposure, frame=frame, title=title) useIndices = set(m.second.getId() for m in useMatches) radii = [] with ds9.Buffering(): for i, m in enumerate(allMatches): x, y = m.second.getX(), m.second.getY() pix = wcs.skyToPixel(m.first.getCoord()) isUsed = m.second.getId() in useIndices if isUsed: radii.append(numpy.hypot(pix[0] - x, pix[1] - y)) color = ds9.YELLOW if isUsed else ds9.RED ds9.dot("+", x, y, size=10, frame=frame, ctype=color) ds9.dot("x", pix[0], pix[1], size=10, frame=frame, ctype=color) radii = numpy.array(radii) print "<dr> = %.4g +- %.4g pixels [%d/%d matches]" % (radii.mean(), radii.std(), len(useMatches), len(allMatches)) if pause: import sys while True: try: reply = raw_input("Debugging? [p]db [q]uit; any other key to continue... ").strip() except EOFError: reply = "" reply = reply.split() if len(reply) > 1: reply, _ = reply[0], reply[1:] if reply == "p": import pdb;pdb.set_trace() elif reply == "q": sys.exit(1) else: break
def showPeaks(im=None, fs=None, frame=0): """Show the image and peaks""" if frame is None: return if im: ds9.mtv(im, frame=frame) if fs: with ds9.Buffering(): # turn on buffering of ds9's slow "region" writes for foot in fs.getFootprints(): for p in foot.getPeaks(): ds9.dot("+", p.getIx(), p.getIy(), size=0.4, ctype=ds9.RED, frame=frame)
def DEBUG(image, footprintset): ds9.mtv(image) for footprint in footprintset: from lsst.afw.image.imageLib import MaskedImageF masked_imaged = MaskedImageF(image) heavy_footprint = afwDetect.HeavyFootprintF(footprint, masked_imaged) stat = GetTrackStats(heavy_footprint, image, False) argstring = "@:"+str(4*stat.ellipse_Ixx)+','+str(4*stat.ellipse_Ixy)+','+str(4*stat.ellipse_Iyy) #multiply by four just to make it more exaggerated otherwise they all look like cirlces ds9.dot(argstring,stat.centroid_x,stat.centroid_y) #ellipse around the centroid ds9.dot("x",stat.centroid_x,stat.centroid_y)# cross on the peak displayUtils.drawBBox(stat.BBox, borderWidth=0.5) # border to fully encompass the bbox and no more
def showMedpict(fileName="events.dat", events=None, image=None): medpictEvents = ras.readEventFile(fileName) # # Look for events that medpict missed # if events: x = np.empty(len(medpictEvents)) y = np.empty(len(medpictEvents)) for i, ev in enumerate(medpictEvents): x[i] = ev.x y[i] = ev.y for ev in events: if events: d = np.hypot(x - ev.x, y - ev.y) dmin = np.min(d) if dmin > 0: print "medpict missed:", " ".join([str(_) for _ in zip(x[d == dmin], y[d == dmin])]) ds9.dot("o", ev.x, ev.y, size=5, ctype=ds9.GREEN) if False: ds9.pan(ev.x, ev.y) ds9.flush() import pdb; pdb.set_trace() # # Look for events that the DM stack missed # if events: x = np.empty(len(events)) y = np.empty(len(events)) for i, ev in enumerate(events): x[i] = ev.x y[i] = ev.y with ds9.Buffering(): for ev in medpictEvents: if events: d = np.hypot(x - ev.x, y - ev.y) dmin = np.min(d) if dmin > 0: print "DM missed:", " ".join([str(_) for _ in zip(x[d == dmin], y[d == dmin])]) ds9.dot("o", ev.x, ev.y, size=5, ctype=ds9.RED) if False: ds9.pan(ev.x, ev.y) ds9.flush() import pdb; pdb.set_trace()
def showImage(self, image, sources, title, frame): """Display an image Images are only displayed if 'display' is turned on. @param image: Image to display @param sources: Sources to mark on the display @param title: Title to give frame @param frame: Frame on which to display """ if not display: return ds9.mtv(image, title=title, frame=frame) with ds9.Buffering(): for s in sources: center = s.getCentroid() ds9.dot("o", center.getX(), center.getY(), frame=frame)
def testText(self): """Test drawing text""" ds9.erase() exp = afwImage.ExposureF(300, 350) ds9.mtv(exp, title="parent") # tells display0 about the image's xy0 with ds9.Buffering(): ds9.dot('hello', 200, 200) ds9.dot('hello', 200, 210, size=1.25) ds9.dot('hello', 200, 220, size=3, fontFamily="times") ds9.dot('hello', 200, 230, fontFamily="helvetica bold italic")
def drawFootprint(foot, borderWidth=0.5, origin=None, XY0=None, frame=None, ctype=None, bin=1, peaks=False, symb="+", size=0.4, ctypePeak=None): """Draw an afwDetection::Footprint on a ds9 frame with the specified ctype. Include an extra borderWidth pixels If origin is present, it's Added to the Footprint; if XY0 is present is Subtracted from the Footprint If peaks is True, also show the object's Peaks using the specified symbol and size and ctypePeak All Footprint coordinates are divided by bin, as is right and proper for overlaying on a binned image """ if XY0: if origin: raise RuntimeError("You may not specify both origin and XY0") origin = (-XY0[0], -XY0[1]) with ds9.Buffering(): borderWidth /= bin for s in foot.getSpans(): y, x0, x1 = s.getY(), s.getX0(), s.getX1() if origin: x0 += origin[0]; x1 += origin[0] y += origin[1] x0 /= bin; x1 /= bin; y /= bin ds9.line([(x0 - borderWidth, y - borderWidth), (x0 - borderWidth, y + borderWidth), (x1 + borderWidth, y + borderWidth), (x1 + borderWidth, y - borderWidth), (x0 - borderWidth, y - borderWidth), ], frame=frame, ctype=ctype) if peaks: for p in foot.getPeaks(): x, y = p.getIx(), p.getIy() if origin: x += origin[0]; y += origin[1] x /= bin; y /= bin ds9.dot(symb, x, y, size=size, ctype=ctypePeak, frame=frame)
def createFakeSource(x, y, catalog, exposure, threshold=0.1): """Create a fake source at the given x/y centroid location. Parameters ---------- x,y : `int` The x and y centroid coordinates to place the image at. catalog : `lsst.afw.table.SourceCatalog` The catalog to add the new source to. exposure : `lsst.afw.image.Exposure` The exposure to add the source to. threshold : `float`, optional The footprint threshold for identifying the source. Returns ------- source : `lsst.afw.table.SourceRecord` The created source record that was added to ``catalog``. """ source = catalog.addNew() source['centroid_x'] = x source['centroid_y'] = y exposure.getMaskedImage().getImage()[x, y] = 1.0 fpSet = afwDet.FootprintSet(exposure.getMaskedImage(), afwDet.Threshold(threshold), "DETECTED") if display: ds9.mtv(exposure, frame=1) for fp in fpSet.getFootprints(): for peak in fp.getPeaks(): ds9.dot("x", peak.getIx(), peak.getIy(), frame=1) # There might be multiple footprints; only the one around x,y should go in the source found = False for fp in fpSet.getFootprints(): if fp.contains(afwGeom.Point2I(x, y)): found = True break # We cannot continue if the the created source wasn't found. assert found, "Unable to find central peak in footprint: faulty test" source.setFootprint(fp) return source
def showPsfSpatialCells(exposure, cellSet, showBadCandidates, frame=1): maUtils.showPsfSpatialCells(exposure, cellSet, symb="o", ctype=ds9.CYAN, ctypeUnused=ds9.YELLOW, size=4, frame=frame) for cell in cellSet.getCellList(): for cand in cell.begin( not showBadCandidates): # maybe include bad candidates status = cand.getStatus() ds9.dot( '+', *cand.getSource().getCentroid(), frame=frame, ctype=ds9.GREEN if status == afwMath.SpatialCellCandidate.GOOD else ds9.YELLOW if status == afwMath.SpatialCellCandidate.UNKNOWN else ds9.RED)
def showPeaks(im=None, fs=None, frame=0): """Show the image and peaks""" if frame is None: return if im: ds9.mtv(im, frame=frame) if fs: with ds9.Buffering( ): # turn on buffering of ds9's slow "region" writes for foot in fs.getFootprints(): for p in foot.getPeaks(): ds9.dot("+", p.getIx(), p.getIy(), size=0.4, ctype=ds9.RED, frame=frame)
def displayDipoles(self, exposure, sources): """!Display debugging information on the detected dipoles @param exposure Image the dipoles were measured on @param sources The set of diaSources that were measured""" import lsstDebug display = lsstDebug.Info(__name__).display displayDiaSources = lsstDebug.Info(__name__).displayDiaSources maskTransparency = lsstDebug.Info(__name__).maskTransparency if not maskTransparency: maskTransparency = 90 ds9.setMaskTransparency(maskTransparency) ds9.mtv(exposure, frame=lsstDebug.frame) if display and displayDiaSources: with ds9.Buffering(): for source in sources: cenX, cenY = source.get("ipdiffim_DipolePsfFlux_centroid") if np.isinf(cenX) or np.isinf(cenY): cenX, cenY = source.getCentroid() isdipole = source.get("classification.dipole") if isdipole and np.isfinite(isdipole): # Dipole ctype = "green" else: # Not dipole ctype = "red" ds9.dot("o", cenX, cenY, size=2, ctype=ctype, frame=lsstDebug.frame) negCenX = source.get("ip_diffim_PsfDipoleFlux_neg_centroid_x") negCenY = source.get("ip_diffim_PsfDipoleFlux_neg_centroid_y") posCenX = source.get("ip_diffim_PsfDipoleFlux_pos_centroid_x") posCenY = source.get("ip_diffim_PsfDipoleFlux_pos_centroid_y") if (np.isinf(negCenX) or np.isinf(negCenY) or np.isinf(posCenX) or np.isinf(posCenY)): continue ds9.line([(negCenX, negCenY), (posCenX, posCenY)], ctype="yellow", frame=lsstDebug.frame) lsstDebug.frame += 1
def showStandards(standardStarSet, exp, frame, countsMin=None, flagMask=None, rmsMax=None, ctype=ds9.RED): """Show all the standards that are visible on this exposure If countsMin is not None, only show brighter Sources If flagMask is not None, ignore sources that have (flags & ~flagMask) != 0 """ wcs = exp.getWcs() width, height = exp.getMaskedImage().getWidth(), exp.getMaskedImage( ).getHeight() for s in standardStarSet: x, y = wcs.skyToPixel(s.getRaDec()) if x < 0 or x >= width or y < 0 or y >= height: continue counts = s.getPsfFlux() if counts < countsMin and countsMin is not None: continue if flagMask is not None: if (s.getFlagForDetection() & ~flagMask) != 0: continue rms = math.sqrt(s.getIxx() + s.getIyy()) if rmsMax is not None and rms > rmsMax: continue if False: pt = "%.1f" % (rms) else: pt = "+" ds9.dot(pt, x, y, frame=frame, ctype=ctype)
def testLinearRamp(self): """Fit a ramp""" binsize = 1 ramp, rampCoeffs, xVec, yVec = self.makeRamp(binsize) # # Add a (labelled) bad value # ramp.set(ramp.getWidth() // 2, ramp.getHeight() // 2, (0, 0x1, np.nan)) if display: ds9.mtv(ramp, title="Input", frame=0) # # Here's the range that the approximation should be valid (and also the # bbox of the image returned by getImage) # bbox = afwGeom.BoxI( afwGeom.PointI(0, 0), afwGeom.PointI(binsize * ramp.getWidth() - 1, binsize * ramp.getHeight() - 1)) order = 3 # 1 would be enough to fit the ramp actrl = afwMath.ApproximateControl( afwMath.ApproximateControl.CHEBYSHEV, order) approx = afwMath.makeApproximate(xVec, yVec, ramp, bbox, actrl) for i, aim in enumerate([ approx.getImage(), approx.getMaskedImage().getImage(), ]): if i == 0 and display: ds9.mtv(aim, title="interpolated", frame=1) with ds9.Buffering(): for x in xVec: for y in yVec: ds9.dot('+', x, y, size=0.4, frame=1) for x, y in aim.getBBox().getCorners(): self.assertEqual( aim.get(x, y), rampCoeffs[0] + rampCoeffs[1] * x + rampCoeffs[1] * y)
def assess(self, cand, kFn1, bgFn1, kFn2, bgFn2, frame0): tmi = cand.getTemplateMaskedImage() smi = cand.getScienceMaskedImage() im1 = afwImage.ImageD(kFn1.getDimensions()) kFn1.computeImage(im1, False, afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) fk1 = afwMath.FixedKernel(im1) bg1 = bgFn1(afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) d1 = ipDiffim.convolveAndSubtract(tmi, smi, fk1, bg1) #### im2 = afwImage.ImageD(kFn2.getDimensions()) kFn2.computeImage(im2, False, afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) fk2 = afwMath.FixedKernel(im2) bg2 = bgFn2(afwImage.indexToPosition(int(cand.getXCenter())), afwImage.indexToPosition(int(cand.getYCenter()))) d2 = ipDiffim.convolveAndSubtract(tmi, smi, fk2, bg2) if display: ds9.mtv(tmi, frame=frame0+0) ds9.dot("Cand %d" % (cand.getId()), 0, 0, frame=frame0+0) ds9.mtv(smi, frame=frame0+1) ds9.mtv(im1, frame=frame0+2) ds9.mtv(d1, frame=frame0+3) ds9.mtv(im2, frame=frame0+4) ds9.mtv(d2, frame=frame0+5) pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "Full Spatial Model") self.stats(cand.getId(), d1) pexLog.Trace("lsst.ip.diffim.JackknifeResampleKernel", 1, "N-1 Spatial Model") self.stats(cand.getId(), d2)
def testFootprintFromEllipse(self): """Create an elliptical Footprint""" cen = afwGeom.Point2D(23, 25) a, b, theta = 25, 15, 30 ellipse = afwGeomEllipses.Ellipse( afwGeomEllipses.Axes(a, b, math.radians(theta)), cen) spanSet = afwGeom.SpanSet.fromShape(ellipse) foot = afwDetect.Footprint( spanSet, afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(50, 60))) idImage = afwImage.ImageU( afwGeom.Extent2I(foot.getRegion().getWidth(), foot.getRegion().getHeight())) idImage.set(0) foot.spans.setImage(idImage, foot.getId()) if display: ds9.mtv(idImage, frame=2) displayUtils.drawFootprint(foot, frame=2) shape = foot.getShape() shape.scale(2) # <r^2> = 1/2 for a disk ds9.dot(shape, *cen, frame=2, ctype=ds9.RED) shape = foot.getShape() shape.scale(2) # <r^2> = 1/2 for a disk ds9.dot(shape, *cen, frame=2, ctype=ds9.MAGENTA) axes = afwGeom.ellipses.Axes(foot.getShape()) axes.scale(2) # <r^2> = 1/2 for a disk self.assertEqual(foot.getCentroid(), cen) self.assertLess(abs(a - axes.getA()), 0.15, "a: %g v. %g" % (a, axes.getA())) self.assertLess(abs(b - axes.getB()), 0.02, "b: %g v. %g" % (b, axes.getB())) self.assertLess( abs(theta - math.degrees(axes.getTheta())), 0.2, "theta: %g v. %g" % (theta, math.degrees(axes.getTheta())))
def displayCutout(subImage, origin=None, catSubImage=None, frame=0): """ Display a subImage. If catSubImage is not None then the centroids of the records in the catalog are also displayed, this catalog is meant to be the catalog of records in the subImage's bounding box. """ ds9.mtv(subImage, frame=frame) if origin is not None and catSubImage is not None: for s in catSubImage: centroid = s.getCentroid() - origin if s.get('deblend.nchild') == 0: ds9.dot('+', centroid[0], centroid[1], ctype=ds9.GREEN, frame=frame) else: ds9.dot('+', centroid[0], centroid[1], ctype=ds9.RED, frame=frame) if s.getParent() == 0: ds9.dot('o', centroid[0], centroid[1], ctype=ds9.CYAN, frame=frame)
def run(display=False): exposure = loadData() schema = afwTable.SourceTable.makeMinimalSchema() # # Create the detection and measurement Tasks # config = SourceDetectionTask.ConfigClass() config.reEstimateBackground = False detectionTask = SourceDetectionTask(config=config, schema=schema) config = SingleFrameMeasurementTask.ConfigClass() # Use the minimum set of plugins required. config.plugins.names.clear() for plugin in [ "base_SdssCentroid", "base_SdssShape", "base_CircularApertureFlux", "base_PixelFlags" ]: config.plugins.names.add(plugin) config.plugins["base_CircularApertureFlux"].radii = [7.0] # Use of the PSF flux is hardcoded in secondMomentStarSelector config.slots.psfFlux = "base_CircularApertureFlux_7_0" measureTask = SingleFrameMeasurementTask(schema, config=config) # # Create the measurePsf task # config = MeasurePsfTask.ConfigClass() psfDeterminer = config.psfDeterminer.apply() psfDeterminer.config.sizeCellX = 128 psfDeterminer.config.sizeCellY = 128 psfDeterminer.config.spatialOrder = 1 psfDeterminer.config.nEigenComponents = 3 measurePsfTask = MeasurePsfTask(config=config, schema=schema) # # Create the output table # tab = afwTable.SourceTable.make(schema) # # Process the data # sources = detectionTask.run(tab, exposure, sigma=2).sources measureTask.measure(exposure, sources) result = measurePsfTask.run(exposure, sources) psf = result.psf cellSet = result.cellSet if display: # display on ds9 (see also --debug argparse option) frame = 1 ds9.mtv(exposure, frame=frame) with ds9.Buffering(): for s in sources: xy = s.getCentroid() ds9.dot('+', *xy, frame=frame) if s.get("calib.psf.candidate"): ds9.dot('x', *xy, ctype=ds9.YELLOW, frame=frame) if s.get("calib.psf.used"): ds9.dot('o', *xy, size=4, ctype=ds9.RED, frame=frame)
def testGetImage(self): """Test returning a realisation of the dgPsf""" xcen = self.psf.getKernel().getWidth()//2 ycen = self.psf.getKernel().getHeight()//2 stamps = [] trueCenters = [] for x, y in ([10, 10], [9.4999, 10.4999], [10.5001, 10.5001]): fx, fy = x - int(x), y - int(y) if fx >= 0.5: fx -= 1.0 if fy >= 0.5: fy -= 1.0 im = self.psf.computeImage(afwGeom.Point2D(x, y)).convertF() stamps.append(im.Factory(im, True)) trueCenters.append([xcen + fx, ycen + fy]) if display: mos = displayUtils.Mosaic() # control mosaics ds9.mtv(mos.makeMosaic(stamps)) for i in range(len(trueCenters)): bbox = mos.getBBox(i) ds9.dot("+", bbox.getMinX() + xcen, bbox.getMinY() + ycen, ctype = ds9.RED, size = 1) ds9.dot("+", bbox.getMinX() + trueCenters[i][0], bbox.getMinY() + trueCenters[i][1]) ds9.dot("%.2f, %.2f" % (trueCenters[i][0], trueCenters[i][1]), bbox.getMinX() + xcen, bbox.getMinY() + 2)
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"))
def showFrames(mos, frame0=1, R=23, subtractSky=True): visits = sorted(position.keys()) frame = frame0 - 1 for v in visits: frame += 1 xc, yc = position[v] xc -= mos[v].getX0() yc -= mos[v].getY0() im = mos[v] if subtractSky: im = im.clone() im[2121:2230, 590:830] = np.nan # QE for this chip is bad ima = im.getArray() im[:] -= np.percentile(ima, 25) ds9.mtv(im, title=v, frame=frame) ds9.dot("o", xc, yc, size=R, frame=frame, ctype=ds9.GREEN if yc < mos[v].getHeight() else ds9.RED)
def testSetIntegerOffset(self): """Test that we can offset by positive and negative amounts""" self.inImage.set(50, 50, 400) if False and display: frame = 0 ds9.mtv(self.inImage, frame=frame) ds9.pan(50, 50, frame=frame) ds9.dot("+", 50, 50, frame=frame) for algorithm in ("lanczos5", "bilinear", "nearest"): for delta in [-0.49, 0.51]: for dx, dy in [(2, 3), (-2, 3), (-2, -3), (2, -3)]: outImage = afwMath.offsetImage(self.inImage, dx + delta, dy + delta, algorithm) if False and display: frame += 1 ds9.mtv(outImage, frame=frame) ds9.pan(50, 50, frame=frame) ds9.dot("+", 50 + dx + delta - outImage.getX0(), 50 + dy + delta - outImage.getY0(), frame=frame)
def testMeasureCentroid(self): """Test that we can instantiate and play with a measureCentroid""" exposure = afwImage.makeExposure(self.mi) self.ds.makeSources(self.ssMeasured) ID = 1 for s in self.ssMeasured: s.setId(ID) ID += 1 foot = s.getFootprint() bbox = foot.getBBox() xc = (bbox.getMinX() + bbox.getMaxX()) // 2 yc = (bbox.getMinY() + bbox.getMaxY()) // 2 self.centroider.apply(s, exposure, afwGeom.Point2D(xc, yc)) if display: ds9.dot("x", c.getX(), c.getY(), ctype=ds9.GREEN) # # OK, we've measured all the sources. Compare positions with Dave Monet's values # # FIXME: this test will fail until source matching in afw is updated to use afw/table mat = afwTable.matchXy(self.ssTruth, self.ssMeasured, 1.0) #self.assertEqual(ID, len(mat)) # we matched all the input sources eps = 6e-6 # offset in pixels between measured centroid and the Truth for match in mat: dx = match[0].getX() - match[1].getX() dy = match[0].getY() - match[1].getY() good = True if math.hypot(dx, dy) < eps else False if not good: msg = "Star at (%.1f, %.1f): (dx, dy) = %g, %g)" % \ (match[0].getXAstrom(), match[0].getYAstrom(), dx, dy) if True: print msg else: self.assertTrue(good, msg)
def displaySources(self, exposure, matches, reserved, frame=1): """Display sources we'll use for photocal Sources that will be actually used will be green. Sources reserved from the fit will be red. Parameters ---------- exposure : `lsst.afw.image.ExposureF` Exposure to display. matches : `list` of `lsst.afw.table.RefMatch` Matches used for photocal. reserved : `numpy.ndarray` of type `bool` Boolean array indicating sources that are reserved. frame : `int` Frame number for display. """ ds9.mtv(exposure, frame=frame, title="photocal") with ds9.Buffering(): for mm, rr in zip(matches, reserved): x, y = mm.second.getCentroid() ctype = ds9.RED if rr else ds9.GREEN ds9.dot("o", x, y, size=4, frame=frame, ctype=ctype)
def testMeasureCentroid(self): """Test that we can instantiate and play with a measureCentroid""" exposure = afwImage.makeExposure(self.mi) self.ds.makeSources(self.ssMeasured) ID = 1 self.task.run(self.ssMeasured, exposure) for s in self.ssMeasured: s.setId(ID) ID += 1 foot = s.getFootprint() bbox = foot.getBBox() xc = (bbox.getMinX() + bbox.getMaxX()) // 2 yc = (bbox.getMinY() + bbox.getMaxY()) // 2 if display: ds9.dot("x", xc, yc, ctype=ds9.GREEN) # # OK, we've measured all the sources. Compare positions with Dave Monet's values # mat = afwTable.matchXy(self.ssTruth, self.ssMeasured, 1.0) self.assertEqual(ID, len(mat)) # we matched all the input sources # offset in pixels between measured centroid and the Truth eps = 6e-6 for match in mat: dx = match[0].getX() - match[1].getX() dy = match[0].getY() - match[1].getY() good = True if math.hypot(dx, dy) < eps else False if not good: msg = "Star at (%.1f, %.1f): (dx, dy) = %g, %g)" % \ (match[0].getXAstrom(), match[0].getYAstrom(), dx, dy) if True: print(msg) else: self.assertTrue(good, msg)
def run(display=False): exposure = loadData() schema = afwTable.SourceTable.makeMinimalSchema() # # Create the detection task # config = SourceDetectionTask.ConfigClass() config.thresholdPolarity = "both" config.background.isNanSafe = True config.thresholdValue = 3 detectionTask = SourceDetectionTask(config=config, schema=schema) # # And the measurement Task # config = SingleFrameMeasurementTask.ConfigClass() config.algorithms.names = ["base_SdssCentroid", "base_SdssShape", "base_CircularApertureFlux"] config.algorithms["base_CircularApertureFlux"].radii = [1, 2, 4, 8, 16] # pixels config.slots.instFlux = None config.slots.modelFlux = None config.slots.psfFlux = None algMetadata = dafBase.PropertyList() measureTask = SingleFrameMeasurementTask(schema, algMetadata=algMetadata, config=config) radii = algMetadata.get("base_CircularApertureFlux_radii") # # Create the output table # tab = afwTable.SourceTable.make(schema) # # Process the data # result = detectionTask.run(tab, exposure) sources = result.sources print("Found %d sources (%d +ve, %d -ve)" % (len(sources), result.fpSets.numPos, result.fpSets.numNeg)) measureTask.run(sources, exposure) if display: # display on ds9 (see also --debug argparse option) frame = 1 ds9.mtv(exposure, frame=frame) with ds9.Buffering(): for s in sources: xy = s.getCentroid() ds9.dot('+', *xy, ctype=ds9.CYAN if s.get("flags.negative") else ds9.GREEN, frame=frame) ds9.dot(s.getShape(), *xy, ctype=ds9.RED, frame=frame) for i in range(s.get("flux.aperture.nProfile")): ds9.dot('o', *xy, size=radii[i], ctype=ds9.YELLOW, frame=frame)
def showPsfSpatialCells(exposure, psfCellSet, nMaxPerCell=-1, showChi2=False, showMoments=False, symb=None, ctype=None, ctypeUnused=None, ctypeBad=None, size=2, frame=None): """Show the SpatialCells. If symb is something that ds9.dot understands (e.g. "o"), the top nMaxPerCell candidates will be indicated with that symbol, using ctype and size""" with ds9.Buffering(): origin = [-exposure.getMaskedImage().getX0(), -exposure.getMaskedImage().getY0()] for cell in psfCellSet.getCellList(): displayUtils.drawBBox(cell.getBBox(), origin=origin, frame=frame) if nMaxPerCell < 0: nMaxPerCell = 0 i = 0 goodies = ctypeBad is None for cand in cell.begin(goodies): if nMaxPerCell > 0: i += 1 cand = algorithmsLib.cast_PsfCandidateF(cand) xc, yc = cand.getXCenter() + origin[0], cand.getYCenter() + origin[1] if i > nMaxPerCell: if not ctypeUnused: continue color = ctypeBad if cand.isBad() else ctype if symb: if i > nMaxPerCell: ct = ctypeUnused else: ct = ctype ds9.dot(symb, xc, yc, frame=frame, ctype=ct, size=size) source = cand.getSource() if showChi2: rchi2 = cand.getChi2() if rchi2 > 1e100: rchi2 = numpy.nan ds9.dot("%d %.1f" % (splitId(source.getId(), True)["objId"], rchi2), xc - size, yc - size - 4, frame=frame, ctype=color, size=2) if showMoments: ds9.dot("%.2f %.2f %.2f" % (source.getIxx(), source.getIxy(), source.getIyy()), xc-size, yc + size + 4, frame=frame, ctype=color, size=size)
def measureKron(self, objImg, xcen, ycen, nsigma, kfac, nIterForRadius): """Measure Kron quantities using the C++ code""" # # Now measure things # center = afwGeom.Point2D(xcen, ycen) msConfig = makeSourceMeasurementConfig(nsigma, nIterForRadius, kfac) source = measureFree(objImg, center, msConfig) R_K = source.get("flux.kron.radius") flux_K = source.get("flux.kron") fluxErr_K = source.get("flux.kron.err") flags_K = source.get("flux.kron.flags") if not flags_K: # Forced measurement on the same image should produce exactly the same result forced = measureForced(objImg, source, objImg.getWcs(), msConfig) for field in ("flux.kron", "flux.kron.err", "flux.kron.radius", "flux.kron.flags"): try: if np.isnan(source.get(field)): self.assertTrue(np.isnan(forced.get(field))) else: self.assertClose(source.get(field), forced.get(field), rtol=1.0e-6, atol=None) except AssertionError: print "Failed:", field, source.get(field), forced.get(field) raise if display: xc, yc = xcen - objImg.getX0(), ycen - objImg.getY0() ds9.dot("x", xc, yc, ctype=ds9.MAGENTA, size=1, frame=ds9Frame) displayUtils.drawFootprint(source.getFootprint(), XY0=objImg.getXY0()) shape = source.getShape() if True: # nsigma*shape, the radius used to estimate R_K shape = shape.clone() shape.scale(source.get("flux.kron.radiusForRadius")/shape.getDeterminantRadius()) ds9.dot(shape, xc, yc, ctype=ds9.MAGENTA, frame=ds9Frame) # Show R_K shape = shape.clone() for r, ct in [(R_K, ds9.BLUE), (R_K*kfac, ds9.CYAN),]: shape.scale(r/shape.getDeterminantRadius()) ds9.dot(shape, xc, yc, ctype=ct, frame=ds9Frame) return R_K, flux_K, fluxErr_K, flags_K, \ source.get("flux.kron.flags.radius"), source.get("flux.kron.flags.smallRadius")
def testDistortedImage(self): detector = self.detector psfSigma = 1.5 stars = plantSources(self.x0, self.y0, self.nx, self.ny, self.sky, self.nObj, psfSigma, detector) expos, starXy = stars[0], stars[1] # add some faint round galaxies ... only slightly bigger than the psf gxy = plantSources(self.x0, self.y0, self.nx, self.ny, self.sky, 10, 1.07*psfSigma, detector) mi = expos.getMaskedImage() mi += gxy[0].getMaskedImage() gxyXy = gxy[1] kwid = 15 #int(10*psfSigma) + 1 psf = measAlg.SingleGaussianPsf(kwid, kwid, psfSigma) expos.setPsf(psf) expos.setDetector(detector) ######################## # try without distorter expos.setDetector(self.flatDetector) print "Testing PSF selection *without* distortion" sourceList = self.detectAndMeasure(expos) psfCandidateList = self.starSelector.run(expos, sourceList).psfCandidates ######################## # try with distorter expos.setDetector(self.detector) print "Testing PSF selection *with* distortion" sourceList = self.detectAndMeasure(expos) psfCandidateListCorrected = self.starSelector.run(expos, sourceList).psfCandidates def countObjects(candList): nStar, nGxy = 0, 0 for c in candList: s = c.getSource() x, y = s.getX(), s.getY() for xs,ys in starXy: if abs(x-xs) < 2.0 and abs(y-ys) < 2.0: nStar += 1 for xg,yg in gxyXy: if abs(x-xg) < 2.0 and abs(y-yg) < 2.0: nGxy += 1 return nStar, nGxy nstar, ngxy = countObjects(psfCandidateList) nstarC, ngxyC = countObjects(psfCandidateListCorrected) print "uncorrected nStar, nGxy: ", nstar, "/", len(starXy)," ", ngxy, '/', len(gxyXy) print "dist-corrected nStar, nGxy: ", nstarC, '/', len(starXy)," ", ngxyC, '/', len(gxyXy) ######################## # display if display: iDisp = 1 ds9.mtv(expos, frame=iDisp) size = 40 for c in psfCandidateList: s = c.getSource() ixx, iyy, ixy = size*s.getIxx(), size*s.getIyy(), size*s.getIxy() ds9.dot("@:%g,%g,%g" % (ixx, ixy, iyy), s.getX(), s.getY(), frame=iDisp, ctype=ds9.RED) size *= 2.0 for c in psfCandidateListCorrected: s = c.getSource() ixx, iyy, ixy = size*s.getIxx(), size*s.getIyy(), size*s.getIxy() ds9.dot("@:%g,%g,%g" % (ixx, ixy, iyy), s.getX(), s.getY(), frame=iDisp, ctype=ds9.GREEN) # we shouldn't expect to get all available stars without distortion correcting self.assertLess(nstar, len(starXy)) # here we should get all of them, occassionally 1 or 2 might get missed self.assertGreaterEqual(nstarC, 0.95*len(starXy)) # no contamination by small gxys self.assertEqual(ngxyC, 0)
def testEllipticalGaussian(self): """Test measuring elliptical aperture mags for an elliptical Gaussian""" width, height = 200, 200 xcen, ycen = 0.5 * width, 0.5 * height # # Make the object # gal = afwImage.ImageF(afwGeom.ExtentI(width, height)) a, b, theta = float(10), float(5), 20 flux = 1e4 I0 = flux / (2 * math.pi * a * b) c, s = math.cos(math.radians(theta)), math.sin(math.radians(theta)) for y in range(height): for x in range(width): dx, dy = x - xcen, y - ycen u = c * dx + s * dy v = -s * dx + c * dy val = I0 * math.exp(-0.5 * ((u / a)**2 + (v / b)**2)) if val < 0: val = 0 gal.set(x, y, val) objImg = afwImage.makeExposure(afwImage.makeMaskedImage(gal)) del gal if display: frame = 0 ds9.mtv(objImg, frame=frame, title="Elliptical") self.assertAlmostEqual( 1.0, afwMath.makeStatistics(objImg.getMaskedImage().getImage(), afwMath.SUM).getValue() / flux) # # Now measure some annuli # sincConfig = measAlgorithms.SincFluxConfig(radius1=0.0, radius2=0.0, angle=math.radians(theta), ellipticity=(1 - b / a)) for r1, r2 in [ (0., 0.45 * a), (0.45 * a, 1.0 * a), (1.0 * a, 2.0 * a), (2.0 * a, 3.0 * a), (3.0 * a, 5.0 * a), (3.0 * a, 10.0 * a), ]: sincConfig.radius1 = r1 sincConfig.radius2 = r2 schema = afwTable.SourceTable.makeMinimalSchema() mp = measAlgorithms.MeasureSourcesBuilder().addAlgorithm( sincConfig.makeControl()).build(schema) if display: # draw the inner and outer boundaries of the aperture Mxx = 1 Myy = (b / a)**2 mxx, mxy, myy = c**2 * Mxx + s**2 * Myy, c * s * ( Mxx - Myy), s**2 * Mxx + c**2 * Myy for r in (r1, r2): ds9.dot("@:%g,%g,%g" % (r**2 * mxx, r**2 * mxy, r**2 * myy), xcen, ycen, frame=frame) table = afwTable.SourceTable.make(schema) source = table.makeRecord() center = afwGeom.Point2D(xcen, ycen) mp.apply(source, objImg, center) self.assertAlmostEqual( math.exp(-0.5 * (r1 / a)**2) - math.exp(-0.5 * (r2 / a)**2), source["flux.sinc"] / flux, 5)
def selectStars(self, exposure, sourceCat, matches=None): """!Return a list of PSF candidates that represent likely stars A list of PSF candidates may be used by a PSF fitter to construct a PSF. \param[in] exposure the exposure containing the sources \param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog) \param[in] matches astrometric matches; ignored by this star selector \return an lsst.pipe.base.Struct containing: - starCat catalog of selected stars (a subset of sourceCat) """ import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = lsstDebug.Info( __name__).displayExposure # display the Exposure + spatialCells plotMagSize = lsstDebug.Info( __name__).plotMagSize # display the magnitude-size relation dumpData = lsstDebug.Info( __name__).dumpData # dump data to pickle file? detector = exposure.getDetector() pixToTanXYTransform = None if detector is not None: tanSys = detector.makeCameraSys(TAN_PIXELS) pixToTanXYTransform = detector.getTransformMap().get(tanSys) # # Look at the distribution of stars in the magnitude-size plane # flux = sourceCat.get(self.config.sourceFluxField) xx = numpy.empty(len(sourceCat)) xy = numpy.empty_like(xx) yy = numpy.empty_like(xx) for i, source in enumerate(sourceCat): Ixx, Ixy, Iyy = source.getIxx(), source.getIxy(), source.getIyy() if pixToTanXYTransform: p = afwGeom.Point2D(source.getX(), source.getY()) linTransform = pixToTanXYTransform.linearizeForwardTransform( p).getLinear() m = Quadrupole(Ixx, Iyy, Ixy) m.transform(linTransform) Ixx, Iyy, Ixy = m.getIxx(), m.getIyy(), m.getIxy() xx[i], xy[i], yy[i] = Ixx, Ixy, Iyy width = numpy.sqrt(0.5 * (xx + yy)) bad = reduce(lambda x, y: numpy.logical_or(x, sourceCat.get(y)), self.config.badFlags, False) bad = numpy.logical_or(bad, flux < self.config.fluxMin) bad = numpy.logical_or(bad, numpy.logical_not(numpy.isfinite(width))) bad = numpy.logical_or(bad, numpy.logical_not(numpy.isfinite(flux))) bad = numpy.logical_or(bad, width < self.config.widthMin) bad = numpy.logical_or(bad, width > self.config.widthMax) if self.config.fluxMax > 0: bad = numpy.logical_or(bad, flux > self.config.fluxMax) good = numpy.logical_not(bad) if not numpy.any(good): raise RuntimeError( "No objects passed our cuts for consideration as psf stars") mag = -2.5 * numpy.log10(flux[good]) width = width[good] # # Look for the maximum in the size histogram, then search upwards for the minimum that separates # the initial peak (of, we presume, stars) from the galaxies # if dumpData: import os import pickle as pickle _ii = 0 while True: pickleFile = os.path.expanduser( os.path.join("~", "widths-%d.pkl" % _ii)) if not os.path.exists(pickleFile): break _ii += 1 with open(pickleFile, "wb") as fd: pickle.dump(mag, fd, -1) pickle.dump(width, fd, -1) centers, clusterId = _kcenters( width, nCluster=4, useMedian=True, widthStdAllowed=self.config.widthStdAllowed) if display and plotMagSize: fig = plot( mag, width, centers, clusterId, magType=self.config.sourceFluxField.split(".")[-1].title(), marker="+", markersize=3, markeredgewidth=None, ltype=':', clear=True) else: fig = None clusterId = _improveCluster( width, centers, clusterId, nsigma=self.config.nSigmaClip, widthStdAllowed=self.config.widthStdAllowed) if display and plotMagSize: plot(mag, width, centers, clusterId, marker="x", markersize=3, markeredgewidth=None, clear=False) stellar = (clusterId == 0) # # We know enough to plot, if so requested # frame = 0 if fig: if display and displayExposure: ds9.mtv(exposure.getMaskedImage(), frame=frame, title="PSF candidates") global eventHandler eventHandler = EventHandler(fig.get_axes()[0], mag, width, sourceCat.getX()[good], sourceCat.getY()[good], frames=[frame]) fig.show() while True: try: reply = input("continue? [c h(elp) q(uit) p(db)] ").strip() except EOFError: reply = None if not reply: reply = "c" if reply: if reply[0] == "h": print("""\ We cluster the points; red are the stellar candidates and the other colours are other clusters. Points labelled + are rejects from the cluster (only for cluster 0). At this prompt, you can continue with almost any key; 'p' enters pdb, and 'h' prints this text If displayExposure is true, you can put the cursor on a point and hit 'p' to see it in ds9. """) elif reply[0] == "p": import pdb pdb.set_trace() elif reply[0] == 'q': sys.exit(1) else: break if display and displayExposure: mi = exposure.getMaskedImage() with ds9.Buffering(): for i, source in enumerate(sourceCat): if good[i]: ctype = ds9.GREEN # star candidate else: ctype = ds9.RED # not star ds9.dot("+", source.getX() - mi.getX0(), source.getY() - mi.getY0(), frame=frame, ctype=ctype) starCat = SourceCatalog(sourceCat.table) goodSources = [s for g, s in zip(good, sourceCat) if g] for isStellar, source in zip(stellar, goodSources): if isStellar: starCat.append(source) return Struct(starCat=starCat, )
def selectStars(self, exposure, catalog, matches=None): """Return a list of PSF candidates that represent likely stars A list of PSF candidates may be used by a PSF fitter to construct a PSF. @param[in] exposure: the exposure containing the sources @param[in] catalog: a SourceCatalog containing sources that may be stars @param[in] matches: astrometric matches; ignored by this star selector @return psfCandidateList: a list of PSF candidates. """ import lsstDebug display = lsstDebug.Info(__name__).display displayExposure = lsstDebug.Info( __name__).displayExposure # display the Exposure + spatialCells plotMagSize = lsstDebug.Info( __name__).plotMagSize # display the magnitude-size relation dumpData = lsstDebug.Info( __name__).dumpData # dump data to pickle file? # create a log for my application logger = pexLogging.Log(pexLogging.getDefaultLog(), "meas.algorithms.objectSizeStarSelector") detector = exposure.getDetector() distorter = None xy0 = afwGeom.Point2D(0, 0) if not detector is None: cPix = detector.getCenterPixel() detSize = detector.getSize() xy0.setX(cPix.getX() - int(0.5 * detSize.getMm()[0])) xy0.setY(cPix.getY() - int(0.5 * detSize.getMm()[1])) distorter = detector.getDistortion() # # Look at the distribution of stars in the magnitude-size plane # flux = catalog.get(self._sourceFluxField) xx = numpy.empty(len(catalog)) xy = numpy.empty_like(xx) yy = numpy.empty_like(xx) for i, source in enumerate(catalog): Ixx, Ixy, Iyy = source.getIxx(), source.getIxy(), source.getIyy() if distorter: xpix, ypix = source.getX() + xy0.getX(), source.getY( ) + xy0.getY() p = afwGeom.Point2D(xpix, ypix) m = distorter.undistort(p, geomEllip.Quadrupole(Ixx, Iyy, Ixy), detector) Ixx, Ixy, Iyy = m.getIxx(), m.getIxy(), m.getIyy() xx[i], xy[i], yy[i] = Ixx, Ixy, Iyy width = numpy.sqrt(xx + yy) bad = reduce(lambda x, y: numpy.logical_or(x, catalog.get(y)), self._badFlags, False) bad = numpy.logical_or(bad, flux < self._fluxMin) bad = numpy.logical_or(bad, numpy.logical_not(numpy.isfinite(width))) bad = numpy.logical_or(bad, numpy.logical_not(numpy.isfinite(flux))) bad = numpy.logical_or(bad, width < self._widthMin) bad = numpy.logical_or(bad, width > self._widthMax) if self._fluxMax > 0: bad = numpy.logical_or(bad, flux > self._fluxMax) good = numpy.logical_not(bad) if not numpy.any(good): raise RuntimeError( "No objects passed our cuts for consideration as psf stars") mag = -2.5 * numpy.log10(flux[good]) width = width[good] # # Look for the maximum in the size histogram, then search upwards for the minimum that separates # the initial peak (of, we presume, stars) from the galaxies # if dumpData: import os, cPickle as pickle _ii = 0 while True: pickleFile = os.path.expanduser( os.path.join("~", "widths-%d.pkl" % _ii)) if not os.path.exists(pickleFile): break _ii += 1 with open(pickleFile, "wb") as fd: pickle.dump(mag, fd, -1) pickle.dump(width, fd, -1) centers, clusterId = _kcenters(width, nCluster=4, useMedian=True) if display and plotMagSize and pyplot: fig = plot(mag, width, centers, clusterId, marker="+", markersize=3, markeredgewidth=None, ltype=':', clear=True) else: fig = None clusterId = _improveCluster(width, centers, clusterId) if display and plotMagSize and pyplot: plot(mag, width, centers, clusterId, marker="x", markersize=3, markeredgewidth=None) stellar = (clusterId == 0) # # We know enough to plot, if so requested # frame = 0 if fig: if display and displayExposure: ds9.mtv(exposure.getMaskedImage(), frame=frame, title="PSF candidates") global eventHandler eventHandler = EventHandler(fig.get_axes()[0], mag, width, catalog.getX()[good], catalog.getY()[good], frames=[frame]) fig.show() #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- while True: try: reply = raw_input( "continue? [c h(elp) q(uit) p(db)] ").strip() except EOFError: reply = "y" if reply: if reply[0] == "h": print """\ We cluster the points; red are the stellar candidates and the other colours are other clusters. Points labelled + are rejects from the cluster (only for cluster 0). At this prompt, you can continue with almost any key; 'p' enters pdb, and 'h' prints this text If displayExposure is true, you can put the cursor on a point and hit 'p' to see it in ds9. """ elif reply[0] == "p": import pdb pdb.set_trace() elif reply[0] == 'q': sys.exit(1) else: break if display and displayExposure: mi = exposure.getMaskedImage() with ds9.Buffering(): for i, source in enumerate(catalog): if good[i]: ctype = ds9.GREEN # star candidate else: ctype = ds9.RED # not star ds9.dot("+", source.getX() - mi.getX0(), source.getY() - mi.getY0(), frame=frame, ctype=ctype) # # Time to use that stellar classification to generate psfCandidateList # with ds9.Buffering(): psfCandidateList = [] for isStellar, source in zip( stellar, [s for g, s in zip(good, catalog) if g]): if not isStellar: continue try: psfCandidate = algorithmsLib.makePsfCandidate( source, exposure) # The setXXX methods are class static, but it's convenient to call them on # an instance as we don't know Exposure's pixel type # (and hence psfCandidate's exact type) if psfCandidate.getWidth() == 0: psfCandidate.setBorderWidth(self._borderWidth) psfCandidate.setWidth(self._kernelSize + 2 * self._borderWidth) psfCandidate.setHeight(self._kernelSize + 2 * self._borderWidth) im = psfCandidate.getMaskedImage().getImage() vmax = afwMath.makeStatistics(im, afwMath.MAX).getValue() if not numpy.isfinite(vmax): continue psfCandidateList.append(psfCandidate) if display and displayExposure: ds9.dot("o", source.getX() - mi.getX0(), source.getY() - mi.getY0(), size=4, frame=frame, ctype=ds9.CYAN) except Exception as err: logger.log( pexLogging.Log.INFO, "Failed to make a psfCandidate from source %d: %s" % (source.getId(), err)) return psfCandidateList
def testBasics(self): bbox = afwGeom.Box2I(afwGeom.Point2I(256, 100), afwGeom.Extent2I(128, 127)) minCounts = 2000 maxCounts = 20000 starSigma = 1.5 numX = 4 numY = 4 coordList = self.makeCoordList( bbox=bbox, numX=numX, numY=numY, minCounts=minCounts, maxCounts=maxCounts, sigma=starSigma, ) kwid = 11 sky = 2000 addPoissonNoise = True exposure = plantSources(bbox=bbox, kwid=kwid, sky=sky, coordList=coordList, addPoissonNoise=addPoissonNoise) if display: ds9.mtv(exposure) schema = afwTable.SourceTable.makeMinimalSchema() config = SourceDetectionTask.ConfigClass() config.reEstimateBackground = False config.thresholdPolarity = 'both' detection = SourceDetectionTask(config=config, schema=schema) algMetadata = dafBase.PropertyList() measurement = SourceMeasurementTask(schema=schema, algMetadata=algMetadata) table = afwTable.SourceTable.make(schema) detections = detection.makeSourceCatalog(table, exposure) sources = detections.sources fpSets = detections.fpSets self.assertEqual(len(sources), numX * numY) self.assertEqual(fpSets.numPos, numX * numY / 2) self.assertEqual(fpSets.numNeg, numX * numY / 2) measurement.run(sources, exposure) nGoodCent = 0 nGoodShape = 0 for s in sources: cent = s.getCentroid() shape = s.getShape() if cent[0] == cent[0] and cent[1] == cent[1]: nGoodCent += 1 if (shape.getIxx() == shape.getIxx() and shape.getIyy() == shape.getIyy() and shape.getIxy() == shape.getIxy()): nGoodShape += 1 if display: xy = cent[0] - exposure.getX0(), cent[1] - exposure.getY0() ds9.dot('+', *xy) ds9.dot(shape, *xy, ctype=ds9.RED) self.assertEqual(nGoodCent, numX * numY) self.assertEqual(nGoodShape, numX * numY)
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