def testIsNear(self): """Check isNear() method at 2pi wrap. This makes a call to angleCompare() [see next test], so it should fine, but it checks the inner workings of SatelliteTrail. """ drMax = 50.0 dThetaMax = 0.15 s1 = measArt.SatelliteTrail(r=1769.0,theta=0.017,width=29.88) s2 = measArt.SatelliteTrail(r=1769.0,theta=2.0*np.pi-0.001,width=29.88) s3 = measArt.SatelliteTrail(r=1769.0,theta=np.pi, width=29.88) s4 = measArt.SatelliteTrail(r=1700.0,theta=0.017, width=29.88) def compare(trail1, trail2, expect): comp = trail1.isNear(trail2, drMax=drMax, dThetaMax=dThetaMax) if expect: self.assertTrue(comp) else: self.assertFalse(comp) compare(s1, s1, True) compare(s2, s2, True) compare(s1, s2, True) compare(s2, s1, True) compare(s3, s1, False) compare(s3, s2, False) compare(s4, s1, False) compare(s4, s2, False)
def testImproveCluster(self): """Make sure scattered r,theta points convert in improvement algorithm""" np.random.seed(42) nx, ny = 512, 512 r, theta = 300, 0.4 trail = measArt.SatelliteTrail(r, theta) x, y = trail.trace(nx, ny) n = len(x) t = theta + 0.05*np.random.normal(size=n) niter = 2 rNew, tNew, _r, _x, _y = measArt.improveCluster(t, x, y) for i in range(niter-1): rNew, tNew, _r, _x, _y = measArt.improveCluster(tNew, x, y) rEst = rNew.mean() tEst = tNew.mean() # if you need to look at it if False: r0, theta0 = measArt.hesseForm(t-np.pi/2.0, x, y) fig = figure.Figure() can = FigCanvas(fig) ax = fig.add_subplot(111) ax.plot(theta0, r0, 'k.') ax.plot(tNew, rNew, '.r') ax.plot([tEst], [rEst], 'go') fig.savefig("improveCluster.png") self.assertLess(np.abs(rEst - r), 1.0) self.assertLess(np.abs(tEst - theta), 0.001)
def testShiftOrigin(self): """Verify trail origin shift works.""" # make a trail and shift the origin # be sure to shift enough so that we test the # reversal in theta when the sign of r changes. angle = np.pi/6.0 trail = measArt.SatelliteTrail(r=1000.0,theta=angle) delta = 500.0, 1000.0, 1500.0 for d in delta: # try x t = trail.shiftOrigin(d, 0.0) rExpected = trail.r - d*np.cos(angle) self.assertAlmostEquals(t.r, np.abs(rExpected)) tExpected = angle if rExpected >= 0 else angle + np.pi self.assertAlmostEquals(t.theta, tExpected) # and round-trip t2 = t.shiftOrigin(-d, 0.0) self.assertAlmostEquals(t2.r, trail.r) self.assertAlmostEquals(t2.theta, trail.theta) # try y t = trail.shiftOrigin(0.0, d) rExpected = trail.r - d*np.sin(angle) self.assertAlmostEquals(t.r, np.abs(rExpected)) tExpected = angle if rExpected >= 0 else angle + np.pi self.assertAlmostEquals(t.theta, tExpected) # and round-trip t2 = t.shiftOrigin(0.0, -d) self.assertAlmostEquals(t2.r, trail.r) self.assertAlmostEquals(t2.theta, trail.theta)
def testThetaAlignment(self): np.random.seed(42) ############################## # thetaAlignment # - Verify that pair-wise theta comparison works # It should check that a pair of points has the same local theta, and that matches the # theta based on their x,y coords. # - To test, generate random points, and then insert a real linear feature. # --> make sure we get back the linear feature points and not the random ones. n = 500 nx, ny = 512, 512 tolerance = 0.1 # start with random points x = nx*np.random.uniform(size=n) y = ny*np.random.uniform(size=n) t = 2.0*np.pi*np.random.uniform(size=n) known = np.zeros(n, dtype=bool) # append a line nLine = 100 r, theta = 300, 0.4 trail = measArt.SatelliteTrail(r, theta) _x, _y = trail.trace(nx, ny) if len(_x) > nLine: stride = len(_x)/nLine _x = _x[::stride] _y = _y[::stride] else: stride = 1 nLine = len(_x) x = np.append(x, _x) y = np.append(y, _y) # make sure the thetas pass tolerance... give them a scatter less than the limit. t = np.append(t, theta - np.pi/2.0 + 0.1*tolerance*np.random.uniform(size=nLine)) known = np.append(known, np.ones(nLine, dtype=bool)) # set ruthless limit=nLine/2 (normally 3 to 5) # It means a candidate is accepted only if it has this many statistically unexpected neighbours. isCand, newTheta = measArt.thetaAlignment(t, x, y, limit=int(0.5*nLine), tolerance=tolerance) # make sure we have the right number of hits self.assertEqual(isCand.sum(), nLine) # make sure they're for the right objects compare = known - isCand self.assertEqual(compare.sum(), 0)
def testHough(self): """ Test binning in r,theta.""" np.random.seed(42) nx, ny = 512, 512 r0, t0 = 300, 0.4 trail = measArt.SatelliteTrail(r0, t0) x, y = trail.trace(nx, ny) n = len(x) r = r0 + np.random.normal(size=n) t = t0 + 0.01*np.random.normal(size=n) rMax = (nx**2 + ny**2)**0.5 result = measArt.hesseBin(r, t, rMax=rMax) bin2d, rEdge, tEdge, rs, ts, idx = result # make sure we only got one hit self.assertEquals(len(rs), 1) self.assertEquals(len(ts), 1) # and that it has all our points self.assertEquals(idx[0].sum(), n) # And that it found the right answer self.assertClose(rs[0], r0, rtol=1.0e-2) self.assertClose(ts[0], t0, rtol=1.0e-2) # try the HoughTransform hough = measArt.HoughTransform(bins=200, thresh=40, rMax=rMax, maxResid=4.0, nIter=3) solutions = hough(t, x, y) # these should be better as they run improveCluster() internally self.assertEqual(len(solutions), 1) self.assertClose(solutions[0].r, r0, rtol=1.0e-3) self.assertClose(solutions[0].theta, t0, rtol=1.0e-3)
def testFindFake(self): """Test all the workings together. Add a fake and find it.""" np.random.seed(42) # make a fake trail in noise ... detect it. nx, ny = 512, 512 r1, t1 = 300, 0.4 r2, t2 = 200, 2.0*np.pi-0.2 trail1 = measArt.SatelliteTrail(r1, t1) trail2 = measArt.SatelliteTrail(r2, t2) # create an exposure with a PSF object mimg = afwImage.MaskedImageF(nx, ny) exposure = afwImage.ExposureF(mimg) seeing = 2.0 kx, ky = 15, 15 psf = measAlg.DoubleGaussianPsf(kx, ky, seeing/2.35) exposure.setPsf(psf) # Add two fake trails img = mimg.getImage().getArray() flux = 400.0 sigma = seeing prof = measArt.DoubleGaussianProfile(flux, sigma) width = 8*sigma trail1.insert(img, prof, width) trail2.insert(img, prof, width) # add noise on top of the trail rms = 20.0 noise = rms*np.random.normal(size=(nx, ny)) img += noise # create a finder and see what we get finder = measArt.SatelliteFinder() trailsFind = finder.getTrails(exposure, widths=[1.0]) # try a task config = measArt.HoughSatelliteConfig() config.narrow.eRange = 0.02 task = measArt.HoughSatelliteTask(config=config) trailsTask, runtime = task.process(exposure) # make sure both trails detected by finder and task self.assertEqual(len(trailsFind), 2) self.assertEqual(len(trailsTask), 2) # make sure we found the right ones! drMax = 5 dThetaMax = 0.1 for trails in trailsFind, trailsTask: found1 = trail1.isNear(trails[0], drMax, dThetaMax) or trail1.isNear(trails[1], drMax, dThetaMax) found2 = trail2.isNear(trails[0], drMax, dThetaMax) or trail2.isNear(trails[1], drMax, dThetaMax) self.assertTrue(found1) self.assertTrue(found2) fig = figure.Figure() can = FigCanvas(fig) ax = fig.add_subplot(111) ax.imshow(img, origin='lower', cmap='gray') for trail in trailsTask: x1, y1 = trail.trace(nx, ny, offset=10) x2, y2 = trail.trace(nx, ny, offset=-10) ax.plot(x1, y1, 'r-') ax.plot(x2, y2, 'r-') fig.savefig("fake.png")
def testTrails(self): """Test insert and measure""" ###################################### # start with a small constant profile trail # # - add it and see if we can measure it ###################################### nx, ny = 31, 31 value = 1.0 # the value to insert width = 2.1 # the width of the trail constProf = measArt.ConstantProfile(value, width) flux = 10.0 sigma = 2.0 # test both extremes of the DoubleGaussian gaussProf = measArt.DoubleGaussianProfile(flux, sigma, fWing=0.0) gaussProf2 = measArt.DoubleGaussianProfile(flux, 0.5*sigma, fWing=1.0) # vertical trail vFake = np.zeros((nx, ny)) vFake[:,nx//2-1:nx//2+2] += 1.0 # horizontal trail hFake = np.zeros((nx, ny)) hFake[ny//2-1:ny//2+2,:] += 1.0 for theta, fake in (0.0, vFake), (np.pi/2.0, hFake): # r,theta defining the trail r = nx//2 trail = measArt.SatelliteTrail(r, theta) # check the length leng = trail.length(nx, ny) self.assertEquals(leng, nx) measWidth = 10.0*width ################################### # insert the trail profiles = [ (constProf, nx*(int(width) + 1.0)), (gaussProf, nx*flux), (gaussProf2, nx*flux) ] for prof, expectedFlux in profiles: img = np.zeros((nx, ny)) trail.insert(img, prof, measWidth) # measure it measFlux = trail.measure(img, widthIn=measWidth) # centroid offset should be zero self.assertAlmostEquals(trail.center, 0.0) # flux should be same as returned value self.assertEquals(trail.flux, measFlux) self.assertAlmostEquals(trail.flux, expectedFlux, 4) # ConstProf should match the fake exactly img = np.zeros((nx, ny)) trail.insert(img, constProf, width+2.0) test = np.abs(img - fake) > 0.0 self.assertFalse(test.any())