def setUp(self): # We create an image that has a ramp (unique values for each pixel), # with a single high pixel that allows for centering self.width, self.height = 50, 50 self.xcen, self.ycen = self.width // 2, self.height // 2 self.image = afwImage.ImageF(afwGeom.ExtentI(self.width, self.height)) for y in range(self.height): for x in range(self.width): self.image.set(x, y, self.width * y + x) self.image.set(self.xcen, self.ycen, 1234567.89) self.exp = afwImage.makeExposure(afwImage.makeMaskedImage(self.image)) self.exp.getMaskedImage().getVariance().set(1.0) scale = 0.2 / 3600 wcs = afwImage.makeWcs( afwCoord.Coord(0 * afwGeom.degrees, 0 * afwGeom.degrees), afwGeom.Point2D(self.xcen, self.ycen), scale, 0, 0, scale) self.exp.setWcs(wcs) if display: frame = 1 ds9.mtv(self.exp, frame=frame, title="Single pixel") # We will use a GaussianCentroid to tweak the center (it should not, for forced measurement) # and a NaiveFlux to measure the single pixel. We'll start offset from the high pixel, # so that a forced measurement should yield a flux of zero, while a measurement that was allowed to # center should yield a flux of unity. # Note that previous versions used NaiveCentroid, which was so nonrobust that it failed to get # right answer when the input value was round-tripped through Wcs and modified by ~1E-8. gaussianCentroid = measAlg.GaussianCentroidControl() naiveFlux = measAlg.NaiveFluxControl() naiveFlux.radius = 0.5 self.x, self.y = self.xcen - 1, self.ycen - 1 self.foot = afwDetection.Footprint(afwGeom.Point2I(self.x, self.y), 2) self.foot.addPeak(self.x, self.y, float("NaN")) schema = afwTable.SourceTable.makeMinimalSchema() msb = measAlg.MeasureSourcesBuilder() msb.addAlgorithm(naiveFlux) msb.setCentroider(gaussianCentroid) self.measurer = msb.build(schema) self.table = afwTable.SourceTable.make(schema) self.table.defineCentroid("centroid.gaussian") schemaF = afwTable.SourceTable.makeMinimalSchema() msbF = measAlg.MeasureSourcesBuilder("", True) msbF.addAlgorithm(naiveFlux) msbF.setCentroider(gaussianCentroid) self.measurerF = msbF.build(schemaF) self.tableF = afwTable.SourceTable.make(schemaF) self.tableF.defineCentroid("centroid.gaussian")
def testApertureMeasure(self): mi = afwImage.MaskedImageF(afwGeom.ExtentI(100, 200)) mi.set(10) # # Create our measuring engine # radii = (1.0, 5.0, 10.0) # radii to use fluxes = [50.0, 810.0, 3170.0] # corresponding correct fluxes control = measAlg.ApertureFluxControl() control.radii = radii exp = afwImage.makeExposure(mi) x0, y0 = 1234, 5678 exp.setXY0(afwGeom.Point2I(x0, y0)) schema = afwTable.SourceTable.makeMinimalSchema() mp = measAlg.MeasureSourcesBuilder().addAlgorithm(control).build( schema) table = afwTable.SourceTable.make(schema) source = table.makeRecord() mp.apply(source, exp, afwGeom.Point2D(30 + x0, 50 + y0)) measured = source[control.name] for i, f in enumerate(fluxes): self.assertEqual(f, measured[i])
def doMeasure(exposure, config): schema = afwTable.SourceTable.makeMinimalSchema() shapeFinder = algorithms.MeasureSourcesBuilder().addAlgorithm( config.makeControl()).build(schema) table = afwTable.SourceTable.make(schema) record = table.makeRecord() shapeFinder.apply(record, exposure, afwGeom.Point2D(0.0, 0.0)) return record
def do_testAstrometry(self, control, bkgd): """Test that we can instantiate and play with a centroiding algorithms""" x0, y0 = 12345, 54321 for imageFactory in ( afwImage.MaskedImageF, afwImage.MaskedImageD, ): im = imageFactory(afwGeom.ExtentI(100, 100)) im.setXY0(afwGeom.Point2I(x0, y0)) psf = testLib.makeTestPsf(im) exp = afwImage.makeExposure(im) exp.setPsf(psf) schema = afwTable.SourceTable.makeMinimalSchema() centroider = algorithms.MeasureSourcesBuilder().addAlgorithm( control).build(schema) #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- im.set(bkgd) x, y = 30, 20 im.set(x, y, (1010, )) table = afwTable.SourceTable.make(schema) table.defineCentroid(control.name) source = table.makeRecord() foot = afwDetection.Footprint(exp.getBBox()) source.setFootprint(foot) centroider.apply(source, exp, afwGeom.Point2D(x + x0, y + y0)) self.assertEqual(x + x0, source.getX()) self.assertEqual(y + y0, source.getY()) self.assertFalse(source.get(control.name + ".flags")) #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- im.set(bkgd) im.set(10, 20, (1010, )) im.set(10, 21, (1010, )) im.set(11, 20, (1010, )) im.set(11, 21, (1010, )) x, y = 10.5 + x0, 20.5 + y0 centroider.apply(source, exp, afwGeom.Point2D(x + 0.123, y - 0.123)) self.assertEqual(x, source.getX()) self.assertEqual(y, source.getY()) self.assertFalse(source.get(control.name + ".flags"))
def setUp(self): self.mi = afwImage.MaskedImageF(afwGeom.ExtentI(100, 100)) self.mi.set(0, 0x0, 1) self.exp = afwImage.makeExposure(self.mi) builder = measAlgorithms.MeasureSourcesBuilder() for conf in ( measAlgorithms.NaiveFluxConfig(radius=10.0), measAlgorithms.PsfFluxConfig(), measAlgorithms.SincFluxConfig(radius2=3.0), ): builder.addAlgorithm(conf.makeControl()) self.schema = afwTable.SourceTable.makeMinimalSchema() self.measurePhotom = builder.build(self.schema)
def setUp(self): # We create an image that has a ramp (unique values for each pixel), # with a single high pixel that allows for centering self.width, self.height = 50, 50 self.xcen, self.ycen = self.width // 2, self.height // 2 self.image = afwImage.ImageF(afwGeom.ExtentI(self.width, self.height)) for y in range(self.height): for x in range(self.width): self.image.set(x, y, self.width * y + x) self.image.set(self.xcen, self.ycen, 1234567.89) self.exp = afwImage.makeExposure(afwImage.makeMaskedImage(self.image)) self.exp.getMaskedImage().getVariance().set(1.0) scale = 0.2 / 3600 wcs = afwImage.makeWcs( afwCoord.Coord(0 * afwGeom.degrees, 0 * afwGeom.degrees), afwGeom.Point2D(self.xcen, self.ycen), scale, 0, 0, scale) self.exp.setWcs(wcs) if display: frame = 1 ds9.mtv(self.exp, frame=frame, title="Single pixel") # We will use a NaiveCentroid (peak over 3x3) to tweak the center (it should not, for forced # measurement) and a NaiveFlux to measure the single pixel. We'll start offset from the high pixel, # so that a forced measurement should yield a flux of zero, while a measurement that was allowed to # center should yield a flux of unity. naiveCentroid = measAlg.NaiveCentroidControl() naiveFlux = measAlg.NaiveFluxControl() naiveFlux.radius = 0.5 self.x, self.y = self.xcen - 1, self.ycen - 1 self.foot = afwDetection.Footprint(afwGeom.Point2I(self.x, self.y), 2) peak = afwDetection.Peak(self.x, self.y) self.foot.getPeaks().push_back(peak) schema = afwTable.SourceTable.makeMinimalSchema() msb = measAlg.MeasureSourcesBuilder() msb.addAlgorithm(naiveFlux) msb.setCentroider(naiveCentroid) self.measurer = msb.build(schema) self.table = afwTable.SourceTable.make(schema) self.table.defineCentroid("centroid.naive")
def testNaiveMeasure(self): mi = afwImage.MaskedImageF(afwGeom.ExtentI(100, 200)) mi.set(10) # # Create our measuring engine # exp = afwImage.makeExposure(mi) x0, y0 = 1234, 5678 exp.setXY0(afwGeom.Point2I(x0, y0)) control = measAlg.NaiveFluxControl() control.radius = 10.0 schema = afwTable.SourceTable.makeMinimalSchema() mp = measAlg.MeasureSourcesBuilder().addAlgorithm(control).build( schema) table = afwTable.SourceTable.make(schema) source = table.makeRecord() mp.apply(source, exp, afwGeom.Point2D(30 + x0, 50 + y0)) flux = 3170.0 self.assertEqual(source.get(control.name), flux)
def testMeasureCentroid(self): """Test that we can instantiate and play with SillyMeasureCentroid""" for imageFactory in ( afwImage.MaskedImageF, afwImage.MaskedImageD, ): im = imageFactory(afwGeom.ExtentI(100, 100)) exp = afwImage.makeExposure(im) control1 = testLib.SillyCentroidControl() control1.name = "silly1" control1.priority = 0.0 control1.param = 0 control2 = testLib.SillyCentroidControl() control2.name = "silly2" control2.priority = 1.0 control2.param = 1 control3 = testLib.SillyCentroidControl() control3.name = "silly3" control3.priority = 2.0 control3.param = 2 schema = afwTable.SourceTable.makeMinimalSchema() builder = algorithms.MeasureSourcesBuilder() builder.addAlgorithm(control1) builder.addAlgorithm(control2) builder.addAlgorithm(control3) centroider = builder.build(schema) table = afwTable.SourceTable.make(schema) source = table.makeRecord() x, y = 10, 20 centroider.apply(source, exp, afwGeom.Point2D(x, y)) table.defineCentroid(control1.name) self.assertEqual(x, source.getX() - 0) self.assertEqual(y, source.getY() - 0) table.defineCentroid(control2.name) self.assertEqual(x, source.getX() - 1) self.assertEqual(y, source.getY() - 1) table.defineCentroid(control3.name) self.assertEqual(x, source.getX() - 2) self.assertEqual(y, source.getY() - 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 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 testPixelFlags(self): width, height = 100, 100 mi = afwImage.MaskedImageF(width, height) exp = afwImage.makeExposure(mi) mi.getImage().set(0) mask = mi.getMask() sat = mask.getPlaneBitMask('SAT') interp = mask.getPlaneBitMask('INTRP') edge = mask.getPlaneBitMask('EDGE') bad = mask.getPlaneBitMask('BAD') mask.set(0) mask.set(20, 20, sat) mask.set(60, 60, interp) mask.set(40, 20, bad) mask.Factory( mask, afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(3, height))).set(edge) x0, y0 = 1234, 5678 exp.setXY0(afwGeom.Point2I(x0, y0)) control = measAlg.PixelFlagControl() schema = afwTable.SourceTable.makeMinimalSchema() mp = measAlg.MeasureSourcesBuilder().addAlgorithm(control).build( schema) table = afwTable.SourceTable.make(schema) allFlags = [ "flags.pixel.edge", "flags.pixel.bad", "flags.pixel.saturated.center", "flags.pixel.saturated.any", "flags.pixel.interpolated.center", "flags.pixel.interpolated.any", ] for x, y, setFlags in [ (1, 50, ["flags.pixel.edge"]), (40, 20, ["flags.pixel.bad"]), (20, 20, ["flags.pixel.saturated.center", "flags.pixel.saturated.any"]), (20, 22, ["flags.pixel.saturated.any"]), (60, 60, [ "flags.pixel.interpolated.center", "flags.pixel.interpolated.any" ]), (60, 62, ["flags.pixel.interpolated.any"]), (float("NAN"), 50, ["flags.pixel.edge"]), ]: source = table.makeRecord() foot = afwDetection.Footprint( afwGeom.Point2I(afwGeom.Point2D(x + x0, y + y0)), 5) source.setFootprint(foot) mp.apply(source, exp, afwGeom.Point2D(x + x0, y + y0)) for flag in allFlags: value = source.get(flag) if flag in setFlags: self.assertTrue( value, "Flag %s should be set for %f,%f" % (flag, x, y)) else: self.assertFalse( value, "Flag %s should not be set for %f,%f" % (flag, x, y))
def testPeakLikelihoodFlux(self): """Test measurement with PeakLikelihoodFlux """ # make mp: a flux measurer measControl = measAlg.PeakLikelihoodFluxControl() schema = afwTable.SourceTable.makeMinimalSchema() mp = measAlg.MeasureSourcesBuilder().addAlgorithm(measControl).build( schema) # make and measure a series of exposures containing just one star, approximately centered bbox = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(100, 101)) kernelWidth = 35 var = 100 fwhm = 3.0 sigma = fwhm / FwhmPerSigma convolutionControl = afwMath.ConvolutionControl() psf = measAlg.SingleGaussianPsf(kernelWidth, kernelWidth, sigma) psfKernel = psf.getLocalKernel() psfImage = psf.computeKernelImage() sumPsfSq = numpy.sum(psfImage.getArray()**2) psfSqArr = psfImage.getArray()**2 for flux in (1000, 10000): ctrInd = afwGeom.Point2I(50, 51) ctrPos = afwGeom.Point2D(ctrInd) kernelBBox = psfImage.getBBox(afwImage.PARENT) kernelBBox.shift(afwGeom.Extent2I(ctrInd)) # compute predicted flux error unshMImage = makeFakeImage(bbox, [ctrPos], [flux], fwhm, var) # filter image by PSF unshFiltMImage = afwImage.MaskedImageF( unshMImage.getBBox(afwImage.PARENT)) afwMath.convolve(unshFiltMImage, unshMImage, psfKernel, convolutionControl) # compute predicted flux = value of image at peak / sum(PSF^2) # this is a sanity check of the algorithm, as much as anything predFlux = unshFiltMImage.getImage().get(ctrInd[0], ctrInd[1]) / sumPsfSq self.assertLess(abs(flux - predFlux), flux * 0.01) # compute predicted flux error based on filtered pixels # = sqrt(value of filtered variance at peak / sum(PSF^2)^2) predFluxErr = math.sqrt(unshFiltMImage.getVariance().get( ctrInd[0], ctrInd[1])) / sumPsfSq # compute predicted flux error based on unfiltered pixels # = sqrt(sum(unfiltered variance * PSF^2)) / sum(PSF^2) # and compare to that derived from filtered pixels; # again, this is a test of the algorithm varView = afwImage.ImageF(unshMImage.getVariance(), kernelBBox) varArr = varView.getArray() unfiltPredFluxErr = math.sqrt(numpy.sum( varArr * psfSqArr)) / sumPsfSq self.assertLess(abs(unfiltPredFluxErr - predFluxErr), predFluxErr * 0.01) for fracOffset in (afwGeom.Extent2D(0, 0), afwGeom.Extent2D(0.2, -0.3)): adjCenter = ctrPos + fracOffset if fracOffset == (0, 0): maskedImage = unshMImage filteredImage = unshFiltMImage else: maskedImage = makeFakeImage(bbox, [adjCenter], [flux], fwhm, var) # filter image by PSF filteredImage = afwImage.MaskedImageF( maskedImage.getBBox(afwImage.PARENT)) afwMath.convolve(filteredImage, maskedImage, psfKernel, convolutionControl) exposure = afwImage.makeExposure(filteredImage) exposure.setPsf(psf) table = afwTable.SourceTable.make(schema) source = table.makeRecord() mp.apply(source, exposure, afwGeom.Point2D(*adjCenter)) measFlux = source.get(measControl.name) measFluxErr = source.get(measControl.name + ".err") self.assertFalse(source.get(measControl.name + ".flags")) self.assertLess(abs(measFlux - flux), flux * 0.003) self.assertLess(abs(measFluxErr - predFluxErr), predFluxErr * 0.2) # try nearby points and verify that the flux is smaller; # this checks that the sub-pixel shift is performed in the correct direction for dx in (-0.2, 0, 0.2): for dy in (-0.2, 0, 0.2): if dx == dy == 0: continue offsetCtr = afwGeom.Point2D(adjCenter[0] + dx, adjCenter[1] + dy) table = afwTable.SourceTable.make(schema) source = table.makeRecord() mp.apply(source, exposure, offsetCtr) offsetFlux = source.get(measControl.name) self.assertLess(offsetFlux, measFlux) # source so near edge of image that PSF does not overlap exposure should result in failure for edgePos in ( (1, 50), (50, 1), (50, bbox.getHeight() - 1), (bbox.getWidth() - 1, 50), ): table = afwTable.SourceTable.make(schema) source = table.makeRecord() mp.apply(source, exposure, afwGeom.Point2D(*edgePos)) self.assertTrue(source.get(measControl.name + ".flags")) # no PSF should result in failure: flags set noPsfExposure = afwImage.ExposureF(filteredImage) table = afwTable.SourceTable.make(schema) source = table.makeRecord() mp.apply(source, noPsfExposure, afwGeom.Point2D(*adjCenter)) self.assertTrue(source.get(measControl.name + ".flags"))
def testEllipticalGaussian(self): """Test measuring the properties of 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)) objImg.getMaskedImage().getVariance().set(1.0) del gal objImg.setXY0(afwGeom.Point2I(1234, 5678)) # # We need a PSF to be able to centroid well. Cf. #2540 # FWHM = 5 ksize = 25 # size of desired kernel objImg.setPsf( measAlg.DoubleGaussianPsf(ksize, ksize, FWHM / (2 * math.sqrt(2 * math.log(2))), 1, 0.1)) if display: frame = 0 ds9.mtv(objImg, frame=frame, title="Elliptical") self.assertAlmostEqual( 1.0, afwMath.makeStatistics(objImg.getMaskedImage().getImage(), afwMath.SUM).getValue() / flux) # # Test elliptical apertures # # msConfig = measAlg.SourceMeasurementConfig() msConfig.algorithms.names.add("flux.aperture.elliptical") radii = math.sqrt(a * b) * numpy.array([ 0.45, 1.0, 2.0, 3.0, 10.0, ]) msConfig.algorithms["flux.aperture.elliptical"].radii = radii schema = afwTable.SourceTable.makeMinimalSchema() ms = msConfig.makeMeasureSources(schema) table = afwTable.SourceTable.make(schema) msConfig.slots.setupTable(table) source = table.makeRecord() ss = afwDetection.FootprintSet(objImg.getMaskedImage(), afwDetection.Threshold(0.1)) fp = ss.getFootprints()[0] source.setFootprint(fp) center = fp.getPeaks()[0].getF() ms.apply(source, objImg, center) self.assertEqual(source.get("flux.aperture.elliptical.nProfile"), len(radii)) r0 = 0.0 if display: shape = source.getShape().clone() xy = afwGeom.ExtentD(source.getCentroid()) - afwGeom.ExtentD( objImg.getXY0()) ds9.dot("x", xcen, ycen, ctype=ds9.RED) ds9.dot("+", *xy, frame=frame) with ds9.Buffering(): for r, apFlux in zip(radii, source.get("flux.aperture.elliptical")): if display: # draw the inner and outer boundaries of the aperture shape.scale(r / shape.getDeterminantRadius()) ds9.dot(shape, *xy, frame=frame) trueFlux = flux * (math.exp(-r0**2 / (2 * a * b)) - math.exp(-r**2 / (2 * a * b))) if verbose: print "%5.2f %6.3f%%" % (r, 100 * ((trueFlux - apFlux) / flux)) self.assertAlmostEqual(trueFlux / flux, apFlux / flux, 5) r0 = r # # Now measure some annuli "by hand" (we'll repeat this will EllipticalAperture algorithm soon) # for r1, r2 in [ (0.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), ]: control = measAlg.SincFluxControl() control.radius1 = r1 control.radius2 = r2 control.angle = math.radians(theta) control.ellipticity = 1 - b / a schema = afwTable.SourceTable.makeMinimalSchema() mp = measAlg.MeasureSourcesBuilder().addAlgorithm(control).build( schema) table = afwTable.SourceTable.make(schema) source = table.makeRecord() 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) mp.apply(source, objImg, center) self.assertAlmostEqual( math.exp(-0.5 * (r1 / a)**2) - math.exp(-0.5 * (r2 / a)**2), source.get(control.name) / flux, 5) control = measAlg.GaussianFluxControl() schema = afwTable.SourceTable.makeMinimalSchema() mp = measAlg.MeasureSourcesBuilder().addAlgorithm(control).build( schema) table = afwTable.SourceTable.make(schema) source = table.makeRecord() objImg.setPsf(None) # no Psf mp.apply(source, objImg, center) # we haven't provided a PSF, so the built-in aperture correction won't work...but we'll get # a result anyway # Note that flags.psffactor==True sets flags=True IFF we attempt aperture corrections self.assertEqual(source.get(control.name + ".flags"), False) self.assertEqual(source.get(control.name + ".flags.psffactor"), True) gflux = source.get(control.name) err = gflux / flux - 1 if abs(err) > 1.5e-5: self.assertEqual(gflux, flux, ("%g, %g: error is %g" % (gflux, flux, err)))
def do_testmeasureShape(self): """Test that we can instantiate and play with a measureShape""" algorithmName = "shape.sdss" algorithmConfig = algorithms.SdssShapeConfig() 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) #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # # 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() bkgd = 100.0 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) algorithmConfig.background = bkgd schema = afwTable.SourceTable.makeMinimalSchema() shapeFinder = algorithms.MeasureSourcesBuilder()\ .addAlgorithm(algorithmConfig.makeControl())\ .build(schema) if display: ds9.mtv(im) table = afwTable.SourceTable.make(schema) table.defineShape(algorithmName) table.defineCentroid(algorithmName + ".centroid") source = table.makeRecord() center = afwGeom.Point2D(x, y) shapeFinder.apply(source, exp, center) 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) 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 showKernelMosaic(bbox, kernel, nx=7, ny=None, frame=None, title=None, showCenter=True, showEllipticity=True): """Show a mosaic of Kernel images. """ mos = displayUtils.Mosaic() x0 = bbox.getBeginX() y0 = bbox.getBeginY() width = bbox.getWidth() height = bbox.getHeight() if not ny: ny = int(nx*float(height)/width + 0.5) if not ny: ny = 1 schema = afwTable.SourceTable.makeMinimalSchema() control = measAlg.GaussianCentroidControl() centroider = measAlg.MeasureSourcesBuilder().addAlgorithm(control).build(schema) sdssShape = measAlg.SdssShapeControl() shaper = measAlg.MeasureSourcesBuilder().addAlgorithm(sdssShape).build(schema) table = afwTable.SourceTable.make(schema) table.defineCentroid(control.name) table.defineShape(sdssShape.name) centers = [] shapes = [] for iy in range(ny): for ix in range(nx): x = int(ix*(width-1)/(nx-1)) + x0 y = int(iy*(height-1)/(ny-1)) + y0 im = afwImage.ImageD(kernel.getDimensions()) ksum = kernel.computeImage(im, False, x, y) lab = "Kernel(%d,%d)=%.2f" % (x, y, ksum) if False else "" mos.append(im, lab) exp = afwImage.makeExposure(afwImage.makeMaskedImage(im)) w, h = im.getWidth(), im.getHeight() cen = afwGeom.PointD(w//2, h//2) src = table.makeRecord() foot = afwDet.Footprint(exp.getBBox()) src.setFootprint(foot) centroider.apply(src, exp, cen) centers.append((src.getX(), src.getY())) shaper.apply(src, exp, cen) shapes.append((src.getIxx(), src.getIxy(), src.getIyy())) mos.makeMosaic(frame=frame, title=title if title else "Model Kernel", mode=nx) if centers and frame is not None: i = 0 with ds9.Buffering(): for cen, shape in zip(centers, shapes): bbox = mos.getBBox(i); i += 1 xc, yc = cen[0] + bbox.getMinX(), cen[1] + bbox.getMinY() if showCenter: ds9.dot("+", xc, yc, ctype=ds9.BLUE, frame=frame) if showEllipticity: ixx, ixy, iyy = shape ds9.dot("@:%g,%g,%g" % (ixx, ixy, iyy), xc, yc, frame=frame, ctype=ds9.RED) return mos