Coverage for tests/test_simpleShape.py: 28%
60 statements
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-31 04:36 -0700
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-31 04:36 -0700
1#
2# LSST Data Management System
3#
4# Copyright 2008-2017 AURA/LSST.
5#
6# This product includes software developed by the
7# LSST Project (http://www.lsst.org/).
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the LSST License Statement and
20# the GNU General Public License along with this program. If not,
21# see <https://www.lsstcorp.org/LegalNotices/>.
22#
23import unittest
25import numpy as np
27import lsst.utils.tests
28import lsst.geom
29import lsst.afw.geom.ellipses as el
30import lsst.afw.image
31from lsst.meas.extensions.simpleShape import SimpleShape
34class SimpleShapeTestCase(lsst.utils.tests.TestCase):
36 def setUp(self):
37 self.ellipseCores = [
38 el.Quadrupole(25.0, 25.0, 0.0),
39 el.Quadrupole(27.0, 22.0, -5.0),
40 el.Quadrupole(23.0, 28.0, 2.0),
41 ]
42 self.centers = [
43 lsst.geom.Point2D(0.0, 0.0),
44 lsst.geom.Point2D(2.0, 3.0),
45 lsst.geom.Point2D(-1.0, 2.5),
46 ]
47 for ellipseCore in self.ellipseCores:
48 ellipseCore.scale(2)
49 self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(-500, -500), lsst.geom.Point2I(50, 50))
50 self.xg, self.yg = np.meshgrid(
51 np.arange(self.bbox.getBeginX(), self.bbox.getEndX(), dtype=float),
52 np.arange(self.bbox.getBeginY(), self.bbox.getEndY(), dtype=float)
53 )
55 def evaluateGaussian(self, ellipse):
56 '''
57 Create an elliptical Guassian as a Numpy array. Does not normalize the Gaussian
58 '''
59 gt = ellipse.getGridTransform()
60 xt = gt[gt.XX] * self.xg + gt[gt.XY] * self.yg + gt[gt.X]
61 yt = gt[gt.YX] * self.xg + gt[gt.YY] * self.yg + gt[gt.Y]
62 return np.exp(-0.5 * (xt**2 + yt**2))
64 def buildImageAndMoments(self, dEllipseCore, dCenter, wEllipseCore, wCenter):
65 '''
66 Generates a elliptical Gaussian image from input ellipse (dEllipse)
67 and uses an elliptical Gaussian (wEllipse) to calculate the shape
68 of the generated image.
69 '''
70 dEllipse = el.Ellipse(dEllipseCore, dCenter)
71 image = lsst.afw.image.MaskedImageF(self.bbox)
72 image.getImage().getArray()[:, :] = self.evaluateGaussian(dEllipse)
73 wEllipse = el.Ellipse(wEllipseCore, wCenter)
74 result = SimpleShape.computeMoments(wEllipse, image)
75 return result
77 def testCorrectWeightedMoments(self):
78 '''
79 Test that the measured moments can be corrected for the fact that the measurement
80 contains information on the moments of the weight function used to make the
81 measurement. The results should only contain the objects shape and not the moments
82 used to make the measurement. This is a subset of the functionality in testNoNoiseGaussians.
83 Because the other test tests a broader scope, it is useful to have this test happen under
84 more restrictive conditions.
85 '''
86 for dEllipseCore in self.ellipseCores:
87 for dCenter in self.centers:
88 dEllipse = el.Ellipse(dEllipseCore, dCenter)
89 dArray = self.evaluateGaussian(dEllipse)
90 for wEllipseCore in self.ellipseCores:
91 for wCenter in self.centers:
92 wEllipse = el.Ellipse(wEllipseCore, wCenter)
93 wArray = self.evaluateGaussian(wEllipse)
94 product = dArray * wArray
95 i0 = np.sum(product)
96 ix = np.sum(product * self.xg) / i0
97 iy = np.sum(product * self.yg) / i0
98 ixx = np.sum(product * (self.xg - ix)**2) / i0
99 iyy = np.sum(product * (self.yg - iy)**2) / i0
100 ixy = np.sum(product * (self.xg - ix) * (self.yg - iy)) / i0
101 mEllipseCore = el.Quadrupole(ixx, iyy, ixy)
102 mCenter = lsst.geom.Point2D(ix, iy)
103 SimpleShape.correctWeightedMoments(wEllipseCore, mEllipseCore, mCenter)
104 self.assertFloatsAlmostEqual(mEllipseCore.getParameterVector(),
105 dEllipseCore.getParameterVector(),
106 rtol=1E-8, atol=1E-11)
108 def testNoNoiseGaussians(self):
109 '''
110 Test that shape moments can be actuately determined for Gaussian images with no noise
111 '''
112 for ellipseCore in self.ellipseCores:
113 for center in self.centers:
114 result = self.buildImageAndMoments(ellipseCore, center, ellipseCore, center)
115 self.assertFloatsAlmostEqual(result.ellipse.getParameterVector(),
116 ellipseCore.getParameterVector(),
117 rtol=3E-3, atol=1E-15)
118 self.assertFloatsAlmostEqual(np.array(result.center),
119 np.array(center),
120 rtol=1E-8, atol=1E-15)
123class TestMemory(lsst.utils.tests.MemoryTestCase):
124 pass
127def setup_module(module):
128 lsst.utils.tests.init()
131if __name__ == "__main__": 131 ↛ 132line 131 didn't jump to line 132, because the condition on line 131 was never true
132 lsst.utils.tests.init()
133 unittest.main()