def testConvolution(self): if scipy is None: print("Skipping convolution test; scipy could not be imported.") return e1 = ellipses.Ellipse(ellipses.Axes(10, 8, 0.3), geom.Point2D(1.5, 2.0)) e2 = ellipses.Ellipse(ellipses.Axes(12, 9, -0.5), geom.Point2D(-1.0, -0.25)) f1 = lsst.shapelet.ShapeletFunction(3, lsst.shapelet.HERMITE, e1) f2 = lsst.shapelet.ShapeletFunction(2, lsst.shapelet.LAGUERRE, e2) f1.getCoefficients()[:] = np.random.randn(*f1.getCoefficients().shape) f2.getCoefficients()[:] = np.random.randn(*f2.getCoefficients().shape) fc1, fc2 = self.checkConvolution(f1, f2) self.assertEqual(fc1.getBasisType(), lsst.shapelet.HERMITE) self.assertEqual(fc2.getBasisType(), lsst.shapelet.LAGUERRE) self.assertFloatsAlmostEqual(fc1.getEllipse().getParameterVector(), fc2.getEllipse().getParameterVector()) self.assertEqual(fc1.getOrder(), fc2.getOrder()) fc2.changeBasisType(lsst.shapelet.HERMITE) self.assertFloatsAlmostEqual(fc1.getCoefficients(), fc2.getCoefficients(), 1E-8)
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 = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(imwidth, imheight)) e1 = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), afwGeom.Point2D(x1, y1)) f1 = afwDetect.Footprint(e1,box) self.assertEqual(f1.getNpix(), circle_npix) e2 = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(radius, radius, 0), afwGeom.Point2D(x2, y2)) f2 = afwDetect.Footprint(e2,box) self.assertEqual(f2.getNpix(), circle_npix) initial = afwDetect.mergeFootprints(f1, f2) initial.setRegion(f2.getRegion()) # merge does not propagate the region self.assertEqual(initial_npix, initial.getNpix()) shrunk = afwDetect.shrinkFootprint(initial, nshrink, True) self.assertEqual(shrunk_npix, shrunk.getNpix()) if display: idImage = afwImage.ImageU(imwidth, imheight) for i, foot in enumerate([initial, shrunk]): print foot.getNpix() foot.insertIntoImage(idImage, i+1); ds9.mtv(idImage)
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 = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(1.5*radius, 2*radius, 0), afwGeom.Point2D(x0,y0)) foot = afwDetect.Footprint(ellipse, afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(imwidth, imheight))) self.assertNotEqual(afwDetect.shrinkFootprint(foot, nshrink, False), afwDetect.shrinkFootprint(foot, nshrink, True))
def testModel3(self): amplitude = 3.2 radius = 2.7 psfEllipse = ellipses.Quadrupole(2.3, 1.8, 0.6) psfAmplitude = 5.3 mgc = ms.GaussianComponent(amplitude, radius) shapelet = mgc.makeShapelet(ellipses.Ellipse(self.ellipse)) psf = ms.GaussianComponent(psfAmplitude, 1.0).makeShapelet( ellipses.Ellipse(psfEllipse)) shapelet = shapelet.convolve(psf) builder = ms.GaussianModelBuilder(self.x, self.y, amplitude, radius, psfEllipse, psfAmplitude) builder.update(self.ellipse) self.ellipse.scale(radius) ellipse = self.ellipse.convolve(psfEllipse) self.assertClose(builder.getModel(), amplitude * psfAmplitude * self.buildModel(ellipse)) z0 = builder.getModel() z1 = psfAmplitude * amplitude * self.buildModel(ellipse) z2 = self.evalShapelets(shapelet) self.assertClose(z0, z1) self.assertClose(z0, z2)
def testModel2(self): amplitude = 3.2 radius = 2.7 mgc = ms.GaussianComponent(amplitude, radius) shapelet = mgc.makeShapelet(ellipses.Ellipse(self.ellipse)) builder = ms.GaussianModelBuilder(self.x, self.y, amplitude, radius) builder.update(self.ellipse) self.ellipse.scale(radius) z0 = builder.getModel() z1 = amplitude * self.buildModel(self.ellipse) z2 = self.evalShapelets(shapelet) self.assertClose(z0, z1) self.assertClose(z0, z2)
def testFootprintFromCircle(self): """Create an elliptical Footprint""" ellipse = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(6, 6, 0), afwGeom.Point2D(9, 15)) foot = afwDetect.Footprint( ellipse, afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(20, 30))) idImage = afwImage.ImageU( afwGeom.Extent2I(foot.getRegion().getWidth(), foot.getRegion().getHeight())) idImage.set(0) foot.insertIntoImage(idImage, foot.getId()) if False: ds9.mtv(idImage, frame=2)
def setUp(self): np.random.seed(500) order = 4 self.ellipse = ellipses.Ellipse(ellipses.Axes(2.2, 0.8, 0.3), geom.Point2D(0.12, -0.08)) self.coefficients = np.random.randn(lsst.shapelet.computeSize(order)) self.x = np.random.randn(25) self.y = np.random.randn(25) self.bases = [ lsst.shapelet.BasisEvaluator(order, lsst.shapelet.HERMITE), lsst.shapelet.BasisEvaluator(order, lsst.shapelet.LAGUERRE), ] self.functions = [ lsst.shapelet.ShapeletFunction(order, lsst.shapelet.HERMITE, self.coefficients), lsst.shapelet.ShapeletFunction(order, lsst.shapelet.LAGUERRE, self.coefficients), ] for function in self.functions: function.setEllipse(self.ellipse)
def testTablePersistence(self): ellipse = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(8, 6, 0.25), afwGeom.Point2D(9,15)) fp1 = afwDetect.Footprint(ellipse) fp1.addPeak(6, 7, 2) fp1.addPeak(8, 9, 3) with utilsTests.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 testTablePersistence(self): ellipse = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(8, 6, 0.25), afwGeom.Point2D(9, 15)) fp1 = afwDetect.Footprint(ellipse) fp1.addPeak(6, 7, 2) fp1.addPeak(8, 9, 3) filename = "testFootprintTablePersistence.fits" fp1.writeFits(filename) fp2 = afwDetect.Footprint.readFits(filename) self.assertEqual(fp1.getArea(), fp2.getArea()) self.assertEqual(list(fp1.getSpans()), list(fp2.getSpans())) 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()) os.remove(filename)
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 = afwGeomEllipses.Ellipse( afwGeomEllipses.Axes(1.5 * radius, 2 * radius, 0), afwGeom.Point2D(x0, y0)) spanSet = afwGeom.SpanSet.fromShape(ellipse) foot = afwDetect.Footprint( spanSet, afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.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 = 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 testClipToNonzero(self): # create a circular footprint ellipse = afwGeomEllipses.Ellipse(afwGeomEllipses.Axes(6, 6, 0), afwGeom.Point2D(9, 15)) bb = afwGeom.Box2I(afwGeom.Point2I(0, 0), afwGeom.Extent2I(20, 30)) foot = afwDetect.Footprint(ellipse, bb) a0 = foot.getArea() plots = False if plots: import matplotlib matplotlib.use('Agg') import pylab as plt plt.clf() img = afwImage.ImageU(bb) foot.insertIntoImage(img, 1) ima = dict(interpolation='nearest', origin='lower', cmap='gray') plt.imshow(img.getArray(), **ima) plt.savefig('clipnz1.png') source = afwImage.ImageF(bb) source.getArray()[:, :] = 1. source.getArray()[:, 0:10] = 0. foot.clipToNonzero(source) foot.normalize() a1 = foot.getArea() self.assertLess(a1, a0) img = afwImage.ImageU(bb) foot.insertIntoImage(img, 1) self.assertTrue(np.all(img.getArray()[source.getArray() == 0] == 0)) if plots: plt.clf() plt.subplot(1, 2, 1) plt.imshow(source.getArray(), **ima) plt.subplot(1, 2, 2) plt.imshow(img.getArray(), **ima) plt.savefig('clipnz2.png') source.getArray()[:12, :] = 0. foot.clipToNonzero(source) foot.normalize() a2 = foot.getArea() self.assertLess(a2, a1) img = afwImage.ImageU(bb) foot.insertIntoImage(img, 1) self.assertTrue(np.all(img.getArray()[source.getArray() == 0] == 0)) if plots: plt.clf() plt.subplot(1, 2, 1) plt.imshow(source.getArray(), **ima) plt.subplot(1, 2, 2) img = afwImage.ImageU(bb) foot.insertIntoImage(img, 1) plt.imshow(img.getArray(), **ima) plt.savefig('clipnz3.png')
def measureKronInPython(self, objImg, xcen, ycen, nsigma, kfac, nIterForRadius, makeImage=None): """Measure the Kron quantities of an elliptical Gaussian in python. N.b. only works for XY0 == (0, 0) """ # # Measure moments using SDSS shape algorithm # # Note: this code was converted to the new meas_framework, but is not exercised. msConfig = makeMeasurementConfig(False, nsigma, nIterForRadius, kfac) center = afwGeom.Point2D(xcen, ycen) source = self.measureFree(objImg, center, msConfig) algMeta = source.getTable().getMetadata() self.assertTrue( algMeta.exists('ext_photometryKron_KronFlux_nRadiusForFlux')) Mxx = source.getIxx() Mxy = source.getIxy() Myy = source.getIyy() # # Calculate principal axes # Muu_p_Mvv = Mxx + Myy Muu_m_Mvv = math.sqrt((Mxx - Myy)**2 + 4 * Mxy**2) Muu = 0.5 * (Muu_p_Mvv + Muu_m_Mvv) Mvv = 0.5 * (Muu_p_Mvv - Muu_m_Mvv) theta = 0.5 * math.atan2(2 * Mxy, Mxx - Myy) a = math.sqrt(Muu) b = math.sqrt(Mvv) ab = a / b # # Get footprint # ellipse = afwEllipses.Ellipse( afwEllipses.Axes(nsigma * a, nsigma * b, theta), afwGeom.Point2D(xcen, ycen)) fpEllipse = afwDetection.Footprint(ellipse) sumI = 0.0 sumR = (0.38259771140356325 / ab * (1 + math.sqrt(2) * math.hypot(math.fmod(xcen, 1), math.fmod(ycen, 1))) * objImg.image[int(xcen), int(ycen), afwImage.LOCAL]) gal = objImg.image c, s = math.cos(theta), math.sin(theta) for sp in fpEllipse.getSpans(): y, x0, x1 = sp.getY(), sp.getX0(), sp.getX1() for x in range(x0, x1 + 1): dx, dy = x - xcen, y - ycen u = c * dx + s * dy v = -s * dx + c * dy r = math.hypot(u, v * ab) try: val = gal[x, y, afwImage.LOCAL] except Exception: continue sumI += val sumR += val * r R_K = sumR / sumI sumI = 0.0 for y in range(self.height): for x in range(self.width): dx, dy = x - xcen, y - ycen u = c * dx + s * dy v = -s * dx + c * dy if math.hypot(u / a, v / b) < kfac: sumI += gal[x, y, afwImage.LOCAL] return R_K, sumI, 0, False, False, False
def testSpanSetFromEllipse(self): axes = afwGeomEllipses.Axes(6, 6, 0) ellipse = afwGeomEllipses.Ellipse(axes, afwGeom.Point2D(5, 6)) spanSet = afwGeom.SpanSet.fromShape(ellipse) for ss, es in zip(spanSet, afwGeomEllipses.PixelRegion(ellipse)): self.assertEqual(ss, es)
def measureKronInPython(self, objImg, xcen, ycen, nsigma, kfac, nIterForRadius, makeImage=None): """Measure the Kron quantities of an elliptical Gaussian in python N.b. only works for XY0 == (0, 0) """ # # Measure moments using SDSS shape algorithm # msConfig = measAlg.SourceMeasurementConfig() if False: # requires #2546 msConfig.centroider = None msConfig.slots.centroid = None schema = afwTable.SourceTable.makeMinimalSchema() ms = msConfig.makeMeasureSources(schema) table = afwTable.SourceTable.make(schema) msConfig.slots.setupTable(table) source = table.makeRecord() fp = afwDetection.Footprint(objImg.getBBox()) source.setFootprint(fp) center = afwGeom.Point2D(xcen, ycen) ms.apply(source, objImg, center) Mxx = source.getIxx() Mxy = source.getIxy() Myy = source.getIyy() # # Calculate principal axes # Muu_p_Mvv = Mxx + Myy Muu_m_Mvv = math.sqrt((Mxx - Myy)**2 + 4*Mxy**2) Muu = 0.5*(Muu_p_Mvv + Muu_m_Mvv) Mvv = 0.5*(Muu_p_Mvv - Muu_m_Mvv) theta = 0.5*math.atan2(2*Mxy, Mxx - Myy) a = math.sqrt(Muu) b = math.sqrt(Mvv) ab = a/b # # Get footprint # ellipse = afwEllipses.Ellipse(afwEllipses.Axes(nsigma*a, nsigma*b, theta), afwGeom.Point2D(xcen - objImg.getX0(), ycen - objImg.getY0())) fpEllipse = afwDetection.Footprint(ellipse) sumI = 0.0 sumR = 0.38259771140356325/ab*(1 + math.sqrt(2)*math.hypot(math.fmod(xcen, 1), math.fmod(ycen, 1)))*\ objImg.getMaskedImage().getImage().get(int(xcen), int(ycen)) gal = objImg.getMaskedImage().getImage() c, s = math.cos(theta), math.sin(theta) for sp in fpEllipse.getSpans(): y, x0, x1 = sp.getY(), sp.getX0(), sp.getX1() for x in range(x0, x1 + 1): dx, dy = x - xcen, y - ycen u = c*dx + s*dy v = -s*dx + c*dy r = math.hypot(u, v*ab) try: val = gal.get(x, y) except: continue sumI += val sumR += val*r R_K = sumR/sumI sumI = 0.0 for y in range(self.height): for x in range(self.width): dx, dy = x - xcen, y - ycen u = c*dx + s*dy v = -s*dx + c*dy if math.hypot(u/a, v/b) < kfac: sumI += gal.get(x, y) return R_K, sumI, 0, False, False, False
def testShapeletApproximations(self): psf0 = lsst.shapelet.ShapeletFunction(0, lsst.shapelet.HERMITE, PSF_SIGMA) psf0.getCoefficients( )[:] = 1.0 / lsst.shapelet.ShapeletFunction.FLUX_FACTOR psf = lsst.shapelet.MultiShapeletFunction() psf.addComponent(psf0) psf.normalize() ellipse = el.Separable[el.Distortion, el.DeterminantRadius](E1, E2, GALAXY_RADIUS) for name, nComponents, maxRadius in PROFILES: # check1 is the multi-Gaussian approximation, as convolved and evaluated by GalSim, check1 = lsst.afw.image.ImageD( os.path.join("tests", "data", name + "-approx.fits")).getArray() xc = check1.shape[1] // 2 yc = check1.shape[0] // 2 xb = np.arange(check1.shape[1], dtype=float) - xc yb = np.arange(check1.shape[0], dtype=float) - yc xg, yg = np.meshgrid(xb, yb) basis = lsst.shapelet.RadialProfile.get(name).getBasis( nComponents, maxRadius) builder = lsst.shapelet.MatrixBuilderD.Factory( xg.ravel(), yg.ravel(), basis, psf)() image1 = np.zeros(check1.shape, dtype=float) matrix = image1.reshape(check1.size, 1) builder(matrix, el.Ellipse(ellipse)) self.assertFloatsAlmostEqual(check1, image1, plotOnFailure=False, rtol=5E-5, relTo=check1.max()) msf = basis.makeFunction( el.Ellipse(ellipse, lsst.afw.geom.Point2D(xc, yc)), np.array([1.0], dtype=float)) msf = msf.convolve(psf) image2 = np.zeros(check1.shape, dtype=float) msf.evaluate().addToImage(lsst.afw.image.ImageD(image2, False)) self.assertFloatsAlmostEqual(check1, image2, plotOnFailure=False, rtol=5E-5, relTo=check1.max()) if name == 'exp': # check2 is the exact profile, again by GalSim. # We only check exp against the exact profile. The other approximations are less # accurate, and we only really need to test one. The real measure of whether these # profiles are good enough is more complicated than what we can do in a unit test. check2 = lsst.afw.image.ImageD( os.path.join("tests", "data", name + "-exact.fits")).getArray() self.assertFloatsAlmostEqual(check2, image1, plotOnFailure=False, rtol=1E-3, relTo=check2.max()) if CHECK_COMPONENT_IMAGES: # This was once useful for debugging test failures, and may be again, but it's # redundant with the above and requires putting more check images in git, so # it's disabled by default. for n, sf in enumerate(msf.getComponents()): check = lsst.afw.image.ImageD( os.path.join("tests", "data", "%s-approx-%0d.fits" % (name, n))).getArray() image = np.zeros(check1.shape, dtype=float) sf.evaluate().addToImage( lsst.afw.image.ImageD(image, False)) self.assertFloatsAlmostEqual(check, image, plotOnFailure=False, rtol=5E-5, relTo=check1.max())