def _fig8Test(self, x1, y1, x2, y2): # Construct a "figure of 8" consisting of two circles touching at the # centre of an image, then demonstrate that it shrinks correctly. # (Helper method for tests below.) radius = 3 imwidth, imheight = 100, 100 nshrink = 1 # These are the correct values for footprint sizes given the paramters # above. circle_npix = 29 initial_npix = circle_npix * 2 - 1 # touch at one pixel shrunk_npix = 26 box = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(imwidth, imheight)) e1 = afwGeom.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), lsst.geom.Point2D(x1, y1)) spanSet1 = afwGeom.SpanSet.fromShape(e1) f1 = afwDetect.Footprint(spanSet1, box) self.assertEqual(f1.getArea(), circle_npix) e2 = afwGeom.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), lsst.geom.Point2D(x2, y2)) spanSet2 = afwGeom.SpanSet.fromShape(e2) f2 = afwDetect.Footprint(spanSet2, box) self.assertEqual(f2.getArea(), circle_npix) initial = afwDetect.mergeFootprints(f1, f2) initial.setRegion( f2.getRegion()) # merge does not propagate the region self.assertEqual(initial_npix, initial.getArea()) shrunk = afwDetect.Footprint().assign(initial) shrunk.erode(nshrink) self.assertEqual(shrunk_npix, shrunk.getArea()) if display: idImage = afwImage.ImageU(imwidth, imheight) for i, foot in enumerate([initial, shrunk]): print(foot.getArea()) foot.spans.setImage(idImage, i + 1) afwDisplay.Display(frame=1).mtv(idImage, title=self._testMethodName + " image")
def testFootprintFromCircle(self): """Create an elliptical Footprint""" ellipse = afwGeom.Ellipse(afwGeomEllipses.Axes(6, 6, 0), lsst.geom.Point2D(9, 15)) spanSet = afwGeom.SpanSet.fromShape(ellipse) foot = afwDetect.Footprint(spanSet, lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(20, 30))) idImage = afwImage.ImageU( lsst.geom.Extent2I(foot.getRegion().getWidth(), foot.getRegion().getHeight())) idImage.set(0) foot.spans.setImage(idImage, foot.getId()) if False: ds9.mtv(idImage, frame=2)
def testTablePersistence(self): ellipse = afwGeom.Ellipse(afwGeomEllipses.Axes(8, 6, 0.25), lsst.geom.Point2D(9, 15)) fp1 = afwDetect.Footprint(afwGeom.SpanSet.fromShape(ellipse)) fp1.addPeak(6, 7, 2) fp1.addPeak(8, 9, 3) with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: fp1.writeFits(tmpFile) fp2 = afwDetect.Footprint.readFits(tmpFile) self.assertEqual(fp1.getArea(), fp2.getArea()) self.assertEqual(list(fp1.getSpans()), list(fp2.getSpans())) # can't use Peak operator== for comparison because it compares IDs, not positions/values self.assertEqual(len(fp1.getPeaks()), len(fp2.getPeaks())) for peak1, peak2 in zip(fp1.getPeaks(), fp2.getPeaks()): self.assertEqual(peak1.getIx(), peak2.getIx()) self.assertEqual(peak1.getIy(), peak2.getIy()) self.assertEqual(peak1.getFx(), peak2.getFx()) self.assertEqual(peak1.getFy(), peak2.getFy()) self.assertEqual(peak1.getPeakValue(), peak2.getPeakValue())
def testFootprintFromEllipse(self): """Create an elliptical Footprint""" cen = lsst.geom.Point2D(23, 25) a, b, theta = 25, 15, 30 ellipse = afwGeom.Ellipse( afwGeomEllipses.Axes(a, b, math.radians(theta)), cen) spanSet = afwGeom.SpanSet.fromShape(ellipse) foot = afwDetect.Footprint( spanSet, lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(50, 60))) idImage = afwImage.ImageU( lsst.geom.Extent2I(foot.getRegion().getWidth(), foot.getRegion().getHeight())) idImage.set(0) foot.spans.setImage(idImage, 42) if display: disp = afwDisplay.Display(frame=2) disp.mtv(idImage, title=self._testMethodName + " image") afwDisplay.utils.drawFootprint(foot, frame=2) shape = foot.getShape() shape.scale(2) # <r^2> = 1/2 for a disk disp.dot(shape, *cen, ctype=afwDisplay.RED) shape = foot.getShape() shape.scale(2) # <r^2> = 1/2 for a disk disp.dot(shape, *cen, ctype=afwDisplay.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, f"a: {a:g} vs. {axes.getA():g}") self.assertLess(abs(b - axes.getB()), 0.02, f"b: {b:g} va. {axes.getB():g}") self.assertLess( abs(theta - math.degrees(axes.getTheta())), 0.2, f"theta: {theta:g} vs. {math.degrees(axes.getTheta()):g}")
def testShrinkIsoVsManhattan(self): # Demonstrate that isotropic and Manhattan shrinks are different. radius = 8 imwidth, imheight = 100, 100 x0, y0 = imwidth // 2, imheight // 2 nshrink = 4 ellipse = afwGeom.Ellipse( afwGeomEllipses.Axes(1.5 * radius, 2 * radius, 0), lsst.geom.Point2D(x0, y0)) spanSet = afwGeom.SpanSet.fromShape(ellipse) foot = afwDetect.Footprint( spanSet, lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(imwidth, imheight))) footIsotropic = afwDetect.Footprint() footIsotropic.assign(foot) foot.erode(nshrink, afwGeom.Stencil.MANHATTAN) footIsotropic.erode(nshrink) self.assertNotEqual(foot, footIsotropic)
def testFootprintFromEllipse(self): """Create an elliptical Footprint""" cen = afwGeom.Point2D(23, 25) a, b, theta = 25, 15, 30 ellipse = afwGeom.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 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(lsst.geom.ExtentI(width, height)) a, b, theta = float(10), float(5), 20 instFlux = 1e4 I0 = instFlux / (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[x, y, afwImage.LOCAL] = 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() / instFlux) # # Now measure some annuli # 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), ]: 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) center = lsst.geom.Point2D(xcen, ycen) # this tests tests a sync algorithm with an inner and outer radius # since that is no longer available from the ApertureFluxAlgorithm, # we will calculate the two and subtract. axes = afwGeom.ellipses.Axes(r2, r2 * (1 - b / a), math.radians(theta)) ellipse = afwGeom.Ellipse(axes, center) result2 = measBase.ApertureFluxAlgorithm.computeSincFlux( objImg.getMaskedImage(), ellipse) axes = afwGeom.ellipses.Axes(r1, r1 * (1 - b / a), math.radians(theta)) ellipse = afwGeom.Ellipse(axes, center) result1 = measBase.ApertureFluxAlgorithm.computeSincFlux( objImg.getMaskedImage(), ellipse) self.assertAlmostEqual( math.exp(-0.5 * (r1 / a)**2) - math.exp(-0.5 * (r2 / a)**2), (result2.instFlux - result1.instFlux) / instFlux, 4)
def main(): ######################################################################## # command line arguments and options ######################################################################## parser = optparse.OptionParser(usage=__doc__) # parser.add_option("-a", "--aa", dest="aa", type=float, # default=1.0, help="default=%default") opts, args = parser.parse_args() if len(args) == 0: r1, r2, dr = 3.0, 3.0, 0.5 elif len(args) == 3: r1, r2, dr = list(map(float, args)) else: parser.print_help() sys.exit(1) # make a list of radii to compute the growthcurve points radius = [] nR = int((r2 - r1) / dr + 1) for iR in range(nR): radius.append(r1 + iR * dr) # make an image big enough to hold the largest requested aperture xwidth = 2 * (0 + 128) ywidth = xwidth # initializations sigmas = [1.5, 2.5] # the Gaussian widths of the psfs we'll use nS = len(sigmas) alg = measBase.PsfFluxAlgorithm schema = afwTable.SourceTable.makeMinimalSchema() schema.addField("centroid_x", type=float) schema.addField("centroid_y", type=float) plugin = alg(measBase.PsfFluxControl(), "test", schema) cat = afwTable.SourceCatalog(schema) cat.defineCentroid("centroid") print("# sig rad Naive Sinc Psf") for iS in range(nS): sigma = sigmas[iS] # make a Gaussian star to measure gauss = afwMath.GaussianFunction2D(sigma, sigma) kernel = afwMath.AnalyticKernel(xwidth, ywidth, gauss) kimg = afwImage.ImageD(kernel.getDimensions()) kernel.computeImage(kimg, False) kimg *= 100.0 mimg = afwImage.MaskedImageF( kimg.convertFloat(), afwImage.Mask(kimg.getDimensions(), 0x0), afwImage.ImageF(kimg.getDimensions(), 0.0)) exposure = afwImage.ExposureF(mimg) # loop over all the radii in the growthcurve for iR in range(nR): psfH = int(2.0 * (r2 + 2.0)) + 1 psfW = int(2.0 * (r2 + 2.0)) + 1 # this test uses a single Gaussian instead of the original double gaussian psf = afwDet.GaussianPsf(psfW, psfH, sigma) # get the aperture fluxes for Naive and Sinc methods axes = afwGeom.ellipses.Axes(radius[iR], radius[iR], math.radians(0)) center = afwGeom.Point2D(0, 0) ellipse = afwGeom.Ellipse(axes, center) resultSinc = measBase.ApertureFluxAlgorithm.computeSincFlux( mimg.getImage(), ellipse) resultNaive = measBase.ApertureFluxAlgorithm.computeNaiveFlux( mimg.getImage(), ellipse) source = cat.addNew() source["centroid_x"] = 0 source["centroid_y"] = 0 exposure.setPsf(psf) plugin.measure(source, exposure) fluxNaive = resultNaive.flux fluxSinc = resultSinc.flux fluxPsf = source["test_flux"] # get the exact flux for the theoretical smooth PSF # rpsf = RGaussian(sigma, a, radius[iR], aptaper) # *** not sure how to integrate a python functor *** print("%.2f %.2f %.3f %.3f %.3f" % (sigma, radius[iR], fluxNaive, fluxSinc, fluxPsf))
def testSpanSetFromEllipse(self): axes = afwGeomEllipses.Axes(6, 6, 0) ellipse = afwGeom.Ellipse(axes, afwGeom.Point2D(5, 6)) spanSet = afwGeom.SpanSet.fromShape(ellipse) for ss, es in zip(spanSet, afwGeomEllipses.PixelRegion(ellipse)): self.assertEqual(ss, es)