Coverage for tests/test_multiband.py: 11%
570 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-06 04:03 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-06 04:03 -0700
1# This file is part of afw.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
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 GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
22"""
23Tests for Multiband objects
24"""
25import unittest
26import operator
28import numpy as np
30import lsst.utils
31import lsst.utils.tests
32from lsst.geom import Point2I, Box2I, Extent2I
33from lsst.afw.geom import SpanSet, Stencil
34from lsst.afw.detection import GaussianPsf, Footprint, makeHeavyFootprint, MultibandFootprint, HeavyFootprintF
35from lsst.afw.image import ImageF, Mask, MaskPixel, MaskedImage, ExposureF, MaskedImageF, LOCAL
36from lsst.afw.image import MultibandPixel, MultibandImage, MultibandMask, MultibandMaskedImage
37from lsst.afw.image import MultibandExposure
40def _testImageFilterSlicing(testCase, mImage, singleType, bbox, value):
41 """Test slicing by filters for image-like objects"""
42 testCase.assertIsInstance(mImage["R"], singleType)
43 testCase.assertIsInstance(mImage[:], type(mImage))
45 testCase.assertEqual(mImage["G", -1, -1, LOCAL], value)
46 testCase.assertEqual(mImage["G"].array.shape, (100, 200))
47 testCase.assertEqual(mImage[:"I"].array.shape, (2, 100, 200))
48 testCase.assertEqual(mImage[:"I"].filters, ("G", "R"))
49 testCase.assertEqual(mImage[:"I"].getBBox(), bbox)
50 testCase.assertEqual(mImage[["G", "I"]].array.shape, (2, 100, 200))
51 testCase.assertEqual(mImage[["G", "I"]].filters, ("G", "I"))
52 testCase.assertEqual(mImage[["G", "I"]].getBBox(), bbox)
54 testCase.assertEqual(mImage["G":"R"].filters, ("G",))
56 if "Z" in mImage.filters:
57 filterSlice = slice("R", "Z")
58 else:
59 filterSlice = slice("R", None)
60 testCase.assertEqual(mImage[filterSlice].filters, ("R", "I"))
61 testCase.assertEqual(mImage.filters, tuple(testCase.filters))
64def _testImageSlicing(testCase, mImage, gVal, rVal, iVal):
65 """Test slicing in the spatial dimensions for image-like objects"""
66 testCase.assertIsInstance(mImage[:, -1, -1, LOCAL], MultibandPixel)
67 testCase.assertEqual(mImage["G", -1, -1, LOCAL], gVal)
69 testCase.assertEqual(mImage[:, 1100:, 2025:].getBBox(), Box2I(Point2I(1100, 2025), Extent2I(100, 75)))
70 testCase.assertEqual(mImage[:, -20:-10, -10:-5, LOCAL].getBBox(),
71 Box2I(Point2I(1180, 2090), Extent2I(10, 5)))
72 testCase.assertEqual(mImage[:, :1100, :2050].getBBox(), Box2I(Point2I(1000, 2000), Extent2I(100, 50)))
73 coord = Point2I(1075, 2015)
74 bbox = Box2I(Point2I(1050, 2010), coord)
75 testCase.assertEqual(mImage[:, bbox].getBBox(), bbox)
76 testCase.assertEqual(mImage[:, 1010, 2010].getBBox().getMin(), Point2I(1010, 2010))
77 testCase.assertEqual(mImage[:, Point2I(1075, 2015)].getBBox().getMin(), coord)
79 testCase.assertEqual(mImage["G", 1100:, 2025:].getBBox(), Box2I(Point2I(1100, 2025), Extent2I(100, 75)))
80 testCase.assertEqual(mImage["R", -20:-10, -10:-5, LOCAL].getBBox(),
81 Box2I(Point2I(1180, 2090), Extent2I(10, 5)))
82 testCase.assertEqual(mImage["I", :1100, :2050].getBBox(), Box2I(Point2I(1000, 2000), Extent2I(100, 50)))
83 testCase.assertEqual(mImage["R", bbox].getBBox(), bbox)
84 testCase.assertEqual(mImage["I", 1010, 2010], iVal)
85 testCase.assertEqual(mImage["R", Point2I(1075, 2015)], rVal)
87 with testCase.assertRaises(TypeError):
88 mImage[:, 0]
89 with testCase.assertRaises(TypeError):
90 mImage[:, 10:]
91 with testCase.assertRaises(TypeError):
92 mImage[:, :10]
93 with testCase.assertRaises(TypeError):
94 mImage[:, :, 0]
97def _testImageModification(testCase, mImage1, mImage2, bbox1, bbox2, value1, value2):
98 """Test the image-like objects can be modified"""
99 mImage1[:"R", bbox2].array = value2
100 testCase.assertFloatsEqual(mImage1["G", bbox2].array, mImage2["G"].array)
101 testCase.assertFloatsEqual(mImage1["R"].array, value1)
102 mImage1.setXY0(Point2I(500, 150))
103 testCase.assertEqual(mImage1.getBBox(), Box2I(Point2I(500, 150), Extent2I(bbox1.getDimensions())))
105 mImage1["G"].array[:] = value2
106 testCase.assertFloatsEqual(mImage1["G"].array, value2)
107 testCase.assertFloatsEqual(mImage1.array[0], value2)
109 if "Z" in mImage1.filters:
110 filterSlice = slice("R", "Z")
111 else:
112 filterSlice = slice("R", None)
113 mImage1[filterSlice].array[:] = 7
114 testCase.assertFloatsEqual(mImage1["I"].array, 7)
115 newBBox = Box2I(Point2I(10000, 20000), mImage1.getBBox().getDimensions())
116 mImage1.setXY0(newBBox.getMin())
117 testCase.assertEqual(mImage1.getBBox(), newBBox)
118 for image in mImage1:
119 testCase.assertEqual(image.getBBox(), newBBox)
121 # Uncomment this test when DM-10781 is implemented
122 # offset = Extent2I(-9000, -18000)
123 # mImage1.shiftedBy(offset)
124 # newBBox = Box2I(Point2I(1000, 2000), newBBox.getDimensions())
125 # testCase.assertEqual(mImage1.getBBox(), newBBox)
126 # for image in mImage1:
127 # testCase.assertEqual(image.getBBox(), newBBox)
130def _testImageCopy(testCase, mImage1, value1, value2):
131 """Test copy and deep copy in image-like objects"""
132 mImage2 = mImage1.clone()
133 mImage2.setXY0(Point2I(11, 23))
134 testCase.assertEqual(mImage2.getBBox(), Box2I(Point2I(11, 23), Extent2I(200, 100)))
135 testCase.assertEqual(mImage1.getBBox(), Box2I(Point2I(1000, 2000), Extent2I(200, 100)))
136 testCase.assertTrue(np.all([s.getBBox() == mImage1.getBBox() for s in mImage1.singles]))
137 testCase.assertTrue(np.all([s.getBBox() == mImage2.getBBox() for s in mImage2.singles]))
138 mImage2.array[:] = 17
139 testCase.assertNotEqual(mImage1.array[0, 0, 0], 17)
141 mImage2.array[:] = value2
142 testCase.assertFloatsEqual(mImage1.array, value1)
143 testCase.assertFloatsEqual(mImage2.array, value2)
144 testCase.assertFloatsEqual(mImage1["G"].array, value1)
145 testCase.assertFloatsEqual(mImage2["G"].array, value2)
147 mImage2 = mImage1.clone(False)
148 mImage2.setXY0(Point2I(11, 23))
149 mImage2.array[:] = 17
150 testCase.assertFloatsEqual(mImage2.array, mImage1.array)
152 mImage2.array[:] = value2
153 testCase.assertFloatsEqual(mImage1.array, value2)
154 testCase.assertFloatsEqual(mImage2.array, value2)
155 testCase.assertFloatsEqual(mImage1["G"].array, value2)
156 testCase.assertFloatsEqual(mImage2["G"].array, value2)
159class MultibandPixelTestCase(lsst.utils.tests.TestCase):
160 """Test case for MultibandPixel
161 """
162 def setUp(self):
163 np.random.seed(1)
164 self.bbox = Point2I(101, 502)
165 self.filters = ["G", "R", "I", "Z", "Y"]
166 singles = np.arange(5, dtype=float)
167 self.pixel = MultibandPixel(self.filters, singles, self.bbox)
169 def tearDown(self):
170 del self.bbox
171 del self.filters
172 del self.pixel
174 def testFilterSlicing(self):
175 pixel = self.pixel
176 self.assertEqual(pixel["R"], 1.)
177 self.assertFloatsEqual(pixel.array, np.arange(5))
178 self.assertFloatsEqual(pixel.singles, np.arange(5))
179 self.assertFloatsEqual(pixel[["G", "I"]].array, [0, 2])
181 def testPixelBBoxModification(self):
182 pixel = self.pixel.clone()
183 otherPixel = pixel.clone()
184 pixel.getBBox().shift(Extent2I(9, -2))
185 self.assertEqual(pixel.getBBox().getMin(), Point2I(110, 500))
186 self.assertEqual(otherPixel.getBBox().getMin(), Point2I(101, 502))
188 pixel = self.pixel.clone()
189 otherPixel = pixel.clone(False)
190 pixel.getBBox().shift(Extent2I(9, -2))
191 self.assertEqual(pixel.getBBox().getMin(), Point2I(110, 500))
192 self.assertEqual(otherPixel.getBBox().getMin(), Point2I(110, 500))
194 def testPixelModification(self):
195 pixel = self.pixel
196 otherPixel = pixel.clone()
197 otherPixel.array = np.arange(10, 15)
198 self.assertFloatsEqual(otherPixel.array, np.arange(10, 15))
199 self.assertFloatsEqual(pixel.array, np.arange(0, 5))
202class MultibandImageTestCase(lsst.utils.tests.TestCase):
203 """Test case for MultibandImage"""
205 def setUp(self):
206 np.random.seed(1)
207 self.bbox1 = Box2I(Point2I(1000, 2000), Extent2I(200, 100))
208 self.filters = ["G", "R", "I", "Z", "Y"]
209 self.value1, self.value2 = 10, 100
210 images = [ImageF(self.bbox1, self.value1) for f in self.filters]
211 self.mImage1 = MultibandImage.fromImages(self.filters, images)
212 self.bbox2 = Box2I(Point2I(1100, 2025), Extent2I(30, 50))
213 images = [ImageF(self.bbox2, self.value2) for f in self.filters]
214 self.mImage2 = MultibandImage.fromImages(self.filters, images)
216 def tearDown(self):
217 del self.bbox1
218 del self.bbox2
219 del self.filters
220 del self.value1
221 del self.value2
222 del self.mImage1
223 del self.mImage2
225 def testFilterSlicing(self):
226 _testImageFilterSlicing(self, self.mImage1, ImageF, self.bbox1, self.value1)
228 def testImageSlicing(self):
229 _testImageSlicing(self, self.mImage1, self.value1, self.value1, self.value1)
231 def testImageModification(self):
232 _testImageModification(self, self.mImage1, self.mImage2, self.bbox1, self.bbox2,
233 self.value1, self.value2)
235 def testImageCopy(self):
236 _testImageCopy(self, self.mImage1, self.value1, 5.)
239class MultibandMaskTestCase(lsst.utils.tests.TestCase):
240 """A test case for Mask"""
242 def setUp(self):
243 np.random.seed(1)
244 self.filters = ["G", "R", "I"]
245 self.Mask = Mask[MaskPixel]
247 # Store the default mask planes for later use
248 maskPlaneDict = self.Mask().getMaskPlaneDict()
249 self.defaultMaskPlanes = sorted(maskPlaneDict, key=maskPlaneDict.__getitem__)
251 # reset so tests will be deterministic
252 self.Mask.clearMaskPlaneDict()
253 for p in ("BAD", "SAT", "INTRP", "CR", "EDGE"):
254 self.Mask.addMaskPlane(p)
256 self.BAD = self.Mask.getPlaneBitMask("BAD")
257 self.CR = self.Mask.getPlaneBitMask("CR")
258 self.EDGE = self.Mask.getPlaneBitMask("EDGE")
260 self.values1 = [self.BAD | self.CR, self.BAD | self.EDGE, self.BAD | self.CR | self.EDGE]
261 self.bbox = Box2I(Point2I(1000, 2000), Extent2I(200, 100))
262 singles = [self.Mask(self.bbox) for f in range(len(self.filters))]
263 for n in range(len(singles)):
264 singles[n].set(self.values1[n])
265 self.mMask1 = MultibandMask.fromMasks(self.filters, singles)
267 self.values2 = [self.EDGE, self.BAD, self.CR | self.EDGE]
268 singles = [self.Mask(self.bbox) for f in range(len(self.filters))]
269 for n in range(len(singles)):
270 singles[n].set(self.values2[n])
271 self.mMask2 = MultibandMask.fromMasks(self.filters, singles)
273 def tearDown(self):
274 del self.mMask1
275 del self.mMask2
276 del self.bbox
277 del self.values1
278 del self.values2
279 # Reset the mask plane to the default
280 self.Mask.clearMaskPlaneDict()
281 for p in self.defaultMaskPlanes:
282 self.Mask.addMaskPlane(p)
283 self.defaultMaskPlanes
285 def testInitializeMasks(self):
286 self.assertTrue(np.all([s.getBBox() == self.mMask1.getBBox() for s in self.mMask1.singles]))
287 self.assertTrue(np.all([s.array == self.values1[n] for n, s in enumerate(self.mMask1.singles)]))
289 def _bitOperator(self, op):
290 op(self.mMask2, self.mMask1)
291 for n, mask in enumerate(self.mMask1):
292 op(mask, self.values2[n])
294 self.assertFloatsEqual(self.mMask1.array, self.mMask2.array)
295 expect = np.empty_like(self.mMask1.array)
296 expect[:] = op(np.array(self.values1), np.array(self.values2))[:, None, None]
297 self.assertFloatsEqual(self.mMask1.array, expect)
299 def testOrMasks(self):
300 self._bitOperator(operator.ior)
302 def testAndMasks(self):
303 self._bitOperator(operator.iand)
305 def testXorMasks(self):
306 self._bitOperator(operator.ixor)
308 def testSetMask(self):
309 mMask = self.mMask1.clone()
310 mMask[:] = self.CR
311 self.assertFloatsEqual(mMask.array, self.CR)
312 mMask["G"] = self.EDGE
313 self.assertFloatsEqual(mMask["R":].array, self.CR)
314 self.assertFloatsEqual(mMask["G"].array, self.EDGE)
315 mMask["R":] = self.BAD
316 self.assertFloatsEqual(mMask["R":].array, self.BAD)
317 mMask["R", 1100, 2050] = self.CR | self.EDGE
318 self.assertEqual(mMask["R", 1100, 2050], self.CR | self.EDGE)
319 self.assertEqual(mMask["R", 1101, 2051], self.BAD)
321 def testMaskPlanes(self):
322 planes = self.mMask1.getMaskPlaneDict()
323 self.assertEqual(len(planes), self.mMask1.getNumPlanesUsed())
325 for k in sorted(planes.keys()):
326 self.assertEqual(planes[k], self.mMask1.getMaskPlane(k))
328 def testRemoveMaskPlane(self):
329 mMask = self.mMask1
330 # Add mask plane FOO and make sure it got added properly
331 mMask.addMaskPlane("FOO")
332 self.assertIn("FOO", mMask.getMaskPlaneDict())
333 self.assertIn("FOO", Mask().getMaskPlaneDict())
334 # Remove plane FOO, noting that removeMaskPlane removes it from the
335 # default, but each instance remembers the version of the mask
336 # dictionary that was current when it was created, so it will still
337 # be in the mMask dict.
338 mMask.removeMaskPlane("FOO")
339 self.assertIn("FOO", mMask.getMaskPlaneDict())
340 self.assertNotIn("FOO", Mask().getMaskPlaneDict())
342 def testRemoveAndClearMaskPlane(self):
343 mMask = self.mMask1
344 # Add mask plane FOO and test clearing it without removing plane from
345 # default dict
346 mMask.addMaskPlane("FOO")
347 mMask.removeAndClearMaskPlane("FOO")
348 self.assertNotIn("FOO", mMask.getMaskPlaneDict())
349 self.assertIn("FOO", Mask().getMaskPlaneDict())
350 # Now also remove it from default dict
351 mMask.addMaskPlane("FOO")
352 mMask.removeAndClearMaskPlane("FOO", removeFromDefault=True)
353 self.assertNotIn("FOO", mMask.getMaskPlaneDict())
354 self.assertNotIn("FOO", Mask().getMaskPlaneDict())
355 # Now remove and clear the EDGE mask plane and make sure all of the planes
356 # in the MultibandMask (i.e. the "singles") got updated accordingly
357 mMask.removeAndClearMaskPlane("EDGE", removeFromDefault=True)
358 self.assertNotIn("EDGE", mMask.getMaskPlaneDict())
359 self.assertNotIn("EDGE", Mask().getMaskPlaneDict())
360 # Assert that all mask planes were updated (i.e. having EDGE removed)
361 self.assertTrue(np.all([s.array == self.values1[n] & ~self.EDGE for
362 n, s in enumerate(mMask.singles)]))
364 def testFilterSlicing(self):
365 _testImageFilterSlicing(self, self.mMask1, Mask, self.bbox, self.values1[0])
367 def testImageSlicing(self):
368 _testImageSlicing(self, self.mMask1, *self.values1)
370 def testImageModification(self):
371 mMask1 = self.mMask1
372 value1 = self.CR
373 value2 = self.EDGE
374 mMask1[:] = value1
376 bbox2 = Box2I(Point2I(1100, 2025), Extent2I(30, 50))
377 singles = [self.Mask(bbox2) for f in range(len(self.filters))]
378 for n in range(len(singles)):
379 singles[n].set(value2)
380 mMask2 = MultibandMask.fromMasks(self.filters, singles)
382 _testImageModification(self, mMask1, mMask2, self.bbox, bbox2, value1, value2)
384 def testImageCopy(self):
385 mMask = self.mMask1
386 value1 = self.CR
387 value2 = self.EDGE
388 mMask[:] = value1
389 _testImageCopy(self, mMask, value1, value2)
392def _testMaskedImageFilters(testCase, maskedImage, singleType):
393 testCase.assertIsInstance(maskedImage["R"], singleType)
394 testCase.assertIsInstance(maskedImage.image["G"], ImageF)
395 testCase.assertIsInstance(maskedImage.mask["R"], Mask)
396 testCase.assertIsInstance(maskedImage.variance["I"], ImageF)
398 testCase.assertEqual(maskedImage["G"].image.array.shape, (100, 200))
399 testCase.assertEqual(maskedImage[:"I"].mask.array.shape, (2, 100, 200))
400 testCase.assertEqual(maskedImage[:"I"].filters, ("G", "R"))
401 testCase.assertEqual(maskedImage[:"I"].getBBox(), testCase.bbox)
402 testCase.assertEqual(maskedImage[["G", "I"]].getBBox(), testCase.bbox)
404 testCase.assertEqual(maskedImage.filters, tuple(testCase.filters))
407def _testMaskedImageSlicing(testCase, maskedImage):
408 subBox = Box2I(Point2I(1100, 2025), Extent2I(30, 50))
409 testCase.assertEqual(maskedImage[:, subBox].getBBox(), subBox)
410 testCase.assertEqual(maskedImage[:, subBox].image.getBBox(), subBox)
411 testCase.assertEqual(maskedImage[:, subBox].mask.getBBox(), subBox)
412 testCase.assertEqual(maskedImage[:, subBox].variance.getBBox(), subBox)
414 maskedPixel = maskedImage[:, 1100, 2025]
415 testCase.assertFloatsEqual(maskedPixel[0].array, np.array([10., 10., 10.]))
416 testCase.assertFloatsEqual(maskedPixel[1].array, np.array([1, 1, 1]))
417 testCase.assertFloatsAlmostEqual(maskedPixel[2].array, np.array([.01, .01, .01]), 1e-6)
419 newBox = Box2I(Point2I(100, 500), Extent2I(200, 100))
420 maskedImage.setXY0(newBox.getMin())
421 testCase.assertEqual(maskedImage.getBBox(), newBox)
422 testCase.assertEqual(maskedImage.image.getBBox(), newBox)
423 testCase.assertEqual(maskedImage.mask.getBBox(), newBox)
424 testCase.assertEqual(maskedImage.variance.getBBox(), newBox)
425 testCase.assertEqual(maskedImage["G"].getBBox(), newBox)
426 testCase.assertEqual(maskedImage["G"].image.getBBox(), newBox)
427 testCase.assertEqual(maskedImage["R"].mask.getBBox(), newBox)
428 testCase.assertEqual(maskedImage["I"].variance.getBBox(), newBox)
431def _testMaskedmageModification(testCase, maskedImage):
432 images = [ImageF(testCase.bbox, 10*testCase.imgValue) for f in testCase.filters]
433 mImage = MultibandImage.fromImages(testCase.filters, images)
434 maskedImage.image.array = mImage.array
435 testCase.assertFloatsEqual(maskedImage.image["G"].array, mImage.array[0])
436 testCase.assertFloatsEqual(maskedImage["G"].image.array, mImage.array[0])
438 singles = [testCase.Mask(testCase.bbox) for f in range(len(testCase.filters))]
439 for n in range(len(singles)):
440 singles[n].set(testCase.maskValue*2)
441 mMask = MultibandMask.fromMasks(testCase.filters, singles)
442 maskedImage.mask.array = mMask.array
443 testCase.assertFloatsEqual(maskedImage.mask["G"].array, mMask.array[0])
444 testCase.assertFloatsEqual(maskedImage["G"].mask.array, mMask.array[0])
446 images = [ImageF(testCase.bbox, .1 * testCase.varValue) for f in testCase.filters]
447 mVariance = MultibandImage.fromImages(testCase.filters, images)
448 maskedImage.variance.array = mVariance.array
449 testCase.assertFloatsEqual(maskedImage.variance["G"].array, mVariance.array[0])
450 testCase.assertFloatsEqual(maskedImage["G"].variance.array, mVariance.array[0])
452 subBox = Box2I(Point2I(1100, 2025), Extent2I(30, 50))
453 maskedImage.image[:, subBox].array = 12
454 testCase.assertFloatsEqual(maskedImage.image["G", subBox].array, 12)
455 testCase.assertFloatsEqual(maskedImage["G", subBox].image.array, 12)
456 maskedImage["R", subBox].image[:] = 15
457 testCase.assertFloatsEqual(maskedImage.image["R", subBox].array, 15)
458 testCase.assertFloatsEqual(maskedImage["R", subBox].image.array, 15)
460 maskedImage.mask[:, subBox].array = 64
461 testCase.assertFloatsEqual(maskedImage.mask["G", subBox].array, 64)
462 testCase.assertFloatsEqual(maskedImage["G", subBox].mask.array, 64)
463 maskedImage["R", subBox].mask[:] = 128
464 testCase.assertFloatsEqual(maskedImage.mask["R", subBox].array, 128)
465 testCase.assertFloatsEqual(maskedImage["R", subBox].mask.array, 128)
467 maskedImage.variance[:, subBox].array = 1e-6
468 testCase.assertFloatsEqual(maskedImage.variance["G", subBox].array, 1e-6)
469 testCase.assertFloatsEqual(maskedImage["G", subBox].variance.array, 1e-6)
470 maskedImage["R", subBox].variance[:] = 1e-7
471 testCase.assertFloatsEqual(maskedImage.variance["R", subBox].array, 1e-7)
472 testCase.assertFloatsEqual(maskedImage["R", subBox].variance.array, 1e-7)
475def _testMaskedImageCopy(testCase, maskedImage1):
476 maskedImage2 = maskedImage1.clone()
478 maskedImage2.setXY0(Point2I(11, 23))
479 testCase.assertEqual(maskedImage2.getBBox(), Box2I(Point2I(11, 23), Extent2I(200, 100)))
480 testCase.assertEqual(maskedImage1.getBBox(), Box2I(Point2I(1000, 2000), Extent2I(200, 100)))
481 testCase.assertTrue(np.all([img.getBBox() == maskedImage1.getBBox() for img in maskedImage1.image]))
482 testCase.assertTrue(np.all([img.getBBox() == maskedImage2.getBBox() for img in maskedImage2.image]))
484 maskedImage2.image.array = 1
485 testCase.assertFloatsEqual(maskedImage1.image.array, testCase.imgValue)
486 testCase.assertFloatsEqual(maskedImage2.image.array, 1)
487 testCase.assertFloatsEqual(maskedImage1["G"].image.array, testCase.imgValue)
488 testCase.assertFloatsEqual(maskedImage2["G"].image.array, 1)
490 maskedImage2 = maskedImage1.clone(False)
491 maskedImage2.image.array = 1
492 testCase.assertFloatsEqual(maskedImage1.image.array, 1)
493 testCase.assertFloatsEqual(maskedImage2.image.array, 1)
494 testCase.assertFloatsEqual(maskedImage1["G"].image.array, 1)
495 testCase.assertFloatsEqual(maskedImage2["G"].image.array, 1)
498class MultibandMaskedImageTestCase(lsst.utils.tests.TestCase):
499 """Test case for MultibandMaskedImage"""
501 def setUp(self):
502 np.random.seed(1)
503 self.bbox = Box2I(Point2I(1000, 2000), Extent2I(200, 100))
504 self.filters = ["G", "R", "I"]
506 self.imgValue = 10
507 images = [ImageF(self.bbox, self.imgValue) for f in self.filters]
508 mImage = MultibandImage.fromImages(self.filters, images)
510 self.Mask = Mask[MaskPixel]
511 # Store the default mask planes for later use
512 maskPlaneDict = self.Mask().getMaskPlaneDict()
513 self.defaultMaskPlanes = sorted(maskPlaneDict, key=maskPlaneDict.__getitem__)
515 # reset so tests will be deterministic
516 self.Mask.clearMaskPlaneDict()
517 for p in ("BAD", "SAT", "INTRP", "CR", "EDGE"):
518 self.Mask.addMaskPlane(p)
520 self.maskValue = self.Mask.getPlaneBitMask("BAD")
521 singles = [self.Mask(self.bbox) for f in range(len(self.filters))]
522 for n in range(len(singles)):
523 singles[n].set(self.maskValue)
524 mMask = MultibandMask.fromMasks(self.filters, singles)
526 self.varValue = 1e-2
527 images = [ImageF(self.bbox, self.varValue) for f in self.filters]
528 mVariance = MultibandImage.fromImages(self.filters, images)
530 self.maskedImage = MultibandMaskedImage(self.filters, image=mImage, mask=mMask, variance=mVariance)
532 def tearDown(self):
533 del self.maskedImage
534 del self.bbox
535 del self.imgValue
536 del self.maskValue
537 del self.varValue
538 # Reset the mask plane to the default
539 self.Mask.clearMaskPlaneDict()
540 for p in self.defaultMaskPlanes:
541 self.Mask.addMaskPlane(p)
542 del self.defaultMaskPlanes
544 def testFilterSlicing(self):
545 _testMaskedImageFilters(self, self.maskedImage, MaskedImage)
547 def testImageSlicing(self):
548 _testMaskedImageSlicing(self, self.maskedImage)
550 def testModification(self):
551 _testMaskedmageModification(self, self.maskedImage)
553 def testCopy(self):
554 _testMaskedImageCopy(self, self.maskedImage)
557class MultibandExposureTestCase(lsst.utils.tests.TestCase):
558 """
559 A test case for the Exposure Class
560 """
562 def setUp(self):
563 np.random.seed(1)
564 self.bbox = Box2I(Point2I(1000, 2000), Extent2I(200, 100))
565 self.filters = ["G", "R", "I"]
567 self.imgValue = 10
568 images = [ImageF(self.bbox, self.imgValue) for f in self.filters]
569 mImage = MultibandImage.fromImages(self.filters, images)
571 self.Mask = Mask[MaskPixel]
572 # Store the default mask planes for later use
573 maskPlaneDict = self.Mask().getMaskPlaneDict()
574 self.defaultMaskPlanes = sorted(maskPlaneDict, key=maskPlaneDict.__getitem__)
576 # reset so tests will be deterministic
577 self.Mask.clearMaskPlaneDict()
578 for p in ("BAD", "SAT", "INTRP", "CR", "EDGE"):
579 self.Mask.addMaskPlane(p)
581 self.maskValue = self.Mask.getPlaneBitMask("BAD")
582 singles = [self.Mask(self.bbox) for f in range(len(self.filters))]
583 for n in range(len(singles)):
584 singles[n].set(self.maskValue)
585 mMask = MultibandMask.fromMasks(self.filters, singles)
587 self.varValue = 1e-2
588 images = [ImageF(self.bbox, self.varValue) for f in self.filters]
589 mVariance = MultibandImage.fromImages(self.filters, images)
591 self.kernelSize = 51
592 self.psfs = [GaussianPsf(self.kernelSize, self.kernelSize, 4.0) for f in self.filters]
593 self.psfImage = np.array([
594 p.computeKernelImage(p.getAveragePosition()).array for p in self.psfs
595 ])
597 self.exposure = MultibandExposure(image=mImage, mask=mMask, variance=mVariance,
598 psfs=self.psfs, filters=self.filters)
600 def tearDown(self):
601 del self.exposure
602 del self.psfs
603 del self.bbox
604 del self.imgValue
605 del self.maskValue
606 del self.varValue
607 # Reset the mask plane to the default
608 self.Mask.clearMaskPlaneDict()
609 for p in self.defaultMaskPlanes:
610 self.Mask.addMaskPlane(p)
611 del self.defaultMaskPlanes
613 def testConstructor(self):
614 exposures = self.exposure.singles
615 print(exposures[0].getPsf())
616 filters = self.exposure.filters
617 newExposure = MultibandExposure.fromExposures(filters, exposures)
618 for exposure in newExposure.singles:
619 self.assertIsNotNone(exposure.getPsf())
621 def testFilterSlicing(self):
622 _testMaskedImageFilters(self, self.exposure, ExposureF)
624 def testImageSlicing(self):
625 _testMaskedImageSlicing(self, self.exposure)
627 def testModification(self):
628 _testMaskedmageModification(self, self.exposure)
630 def testCopy(self):
631 _testMaskedImageCopy(self, self.exposure)
633 def testPsf(self):
634 psfImage = self.exposure.computePsfKernelImage(self.exposure.getBBox().getCenter())
635 self.assertFloatsAlmostEqual(psfImage.array, self.psfImage)
637 newPsfs = [GaussianPsf(self.kernelSize, self.kernelSize, 1.0) for f in self.filters]
638 newPsfImage = [p.computeImage(p.getAveragePosition()).array for p in newPsfs]
639 for psf, exposure in zip(newPsfs, self.exposure.singles):
640 exposure.setPsf(psf)
641 psfImage = self.exposure.computePsfKernelImage(self.exposure.getBBox().getCenter())
642 self.assertFloatsAlmostEqual(psfImage.array, newPsfImage)
644 psfImage = self.exposure.computePsfImage(self.exposure.getBBox().getCenter())["G"]
645 self.assertFloatsAlmostEqual(
646 psfImage.array,
647 self.exposure["G"].getPsf().computeImage(
648 self.exposure["G"].getPsf().getAveragePosition()
649 ).array
650 )
653class MultibandFootprintTestCase(lsst.utils.tests.TestCase):
654 """
655 A test case for the Exposure Class
656 """
658 def setUp(self):
659 np.random.seed(1)
660 self.spans = SpanSet.fromShape(2, Stencil.CIRCLE)
661 self.footprint = Footprint(self.spans)
662 self.footprint.addPeak(3, 4, 10)
663 self.footprint.addPeak(8, 1, 2)
664 fp = Footprint(self.spans)
665 for peak in self.footprint.getPeaks():
666 fp.addPeak(peak["f_x"], peak["f_y"], peak["peakValue"])
667 self.peaks = fp.getPeaks()
668 self.bbox = self.footprint.getBBox()
669 self.filters = ("G", "R", "I")
670 singles = []
671 images = []
672 for n, f in enumerate(self.filters):
673 image = ImageF(self.spans.getBBox())
674 image.set(n)
675 images.append(image.array)
676 maskedImage = MaskedImageF(image)
677 heavy = makeHeavyFootprint(self.footprint, maskedImage)
678 singles.append(heavy)
679 self.image = np.array(images)
680 self.mFoot = MultibandFootprint(self.filters, singles)
682 def tearDown(self):
683 del self.spans
684 del self.footprint
685 del self.peaks
686 del self.bbox
687 del self.filters
688 del self.mFoot
689 del self.image
691 def verifyPeaks(self, peaks1, peaks2):
692 self.assertEqual(len(peaks1), len(peaks2))
693 for n in range(len(peaks1)):
694 pk1 = peaks1[n]
695 pk2 = peaks2[n]
696 # self.assertEqual(pk1["id"], pk2["id"])
697 self.assertEqual(pk1["f_x"], pk2["f_x"])
698 self.assertEqual(pk1["f_y"], pk2["f_y"])
699 self.assertEqual(pk1["i_x"], pk2["i_x"])
700 self.assertEqual(pk1["i_y"], pk2["i_y"])
701 self.assertEqual(pk1["peakValue"], pk2["peakValue"])
703 def testConstructor(self):
704 def projectSpans(radius, value, bbox, asArray):
705 ss = SpanSet.fromShape(radius, Stencil.CIRCLE, offset=(10, 10))
706 image = ImageF(bbox)
707 ss.setImage(image, value)
708 if asArray:
709 return image.array
710 else:
711 return image
713 def runTest(images, mFoot, peaks=self.peaks, footprintBBox=Box2I(Point2I(6, 6), Extent2I(9, 9))):
714 self.assertEqual(mFoot.getBBox(), footprintBBox)
715 try:
716 fpImage = np.array(images)[:, 1:-1, 1:-1]
717 except IndexError:
718 fpImage = np.array([img.array for img in images])[:, 1:-1, 1:-1]
719 # result = mFoot.getImage(fill=0).image.array
720 self.assertFloatsAlmostEqual(mFoot.getImage(fill=0).image.array, fpImage)
721 if peaks is not None:
722 self.verifyPeaks(mFoot.getPeaks(), peaks)
724 bbox = Box2I(Point2I(5, 5), Extent2I(11, 11))
725 xy0 = Point2I(5, 5)
727 images = np.array([projectSpans(n, 5-n, bbox, True) for n in range(2, 5)])
728 mFoot = MultibandFootprint.fromArrays(self.filters, images, xy0=xy0, peaks=self.peaks)
729 runTest(images, mFoot)
731 mFoot = MultibandFootprint.fromArrays(self.filters, images)
732 runTest(images, mFoot, None, Box2I(Point2I(1, 1), Extent2I(9, 9)))
734 images = [projectSpans(n, 5-n, bbox, False) for n in range(2, 5)]
735 mFoot = MultibandFootprint.fromImages(self.filters, images, peaks=self.peaks)
736 runTest(images, mFoot)
738 images = np.array([projectSpans(n, n, bbox, True) for n in range(2, 5)])
739 mFoot = MultibandFootprint.fromArrays(self.filters, images, peaks=self.peaks, xy0=bbox.getMin())
740 runTest(images, mFoot)
742 images = np.array([projectSpans(n, 5-n, bbox, True) for n in range(2, 5)])
743 thresh = [1, 2, 2.5]
744 mFoot = MultibandFootprint.fromArrays(self.filters, images, xy0=bbox.getMin(), thresh=thresh)
745 footprintBBox = Box2I(Point2I(8, 8), Extent2I(5, 5))
746 self.assertEqual(mFoot.getBBox(), footprintBBox)
748 fpImage = np.array(images)[:, 3:-3, 3:-3]
749 mask = np.all(fpImage <= np.array(thresh)[:, None, None], axis=0)
750 fpImage[:, mask] = 0
751 self.assertFloatsAlmostEqual(mFoot.getImage(fill=0).image.array, fpImage)
752 img = mFoot.getImage().image.array
753 img[~np.isfinite(img)] = 1.1
754 self.assertFloatsAlmostEqual(mFoot.getImage(fill=1.1).image.array, img)
756 def testSlicing(self):
757 self.assertIsInstance(self.mFoot["R"], HeavyFootprintF)
758 self.assertIsInstance(self.mFoot[:], MultibandFootprint)
760 self.assertEqual(self.mFoot["I"], self.mFoot["I"])
761 self.assertEqual(self.mFoot[:"I"].filters, ("G", "R"))
762 self.assertEqual(self.mFoot[:"I"].getBBox(), self.bbox)
763 self.assertEqual(self.mFoot[["G", "I"]].filters, ("G", "I"))
764 self.assertEqual(self.mFoot[["G", "I"]].getBBox(), self.bbox)
766 with self.assertRaises(TypeError):
767 self.mFoot["I", 4, 5]
768 self.mFoot["I", :, :]
769 with self.assertRaises(IndexError):
770 self.mFoot[:, :, :]
772 def testSpans(self):
773 self.assertEqual(self.mFoot.getSpans(), self.spans)
774 for footprint in self.mFoot.singles:
775 self.assertEqual(footprint.getSpans(), self.spans)
777 def testPeaks(self):
778 self.verifyPeaks(self.peaks, self.footprint.getPeaks())
779 for footprint in self.mFoot.singles:
780 self.verifyPeaks(footprint.getPeaks(), self.peaks)
783class TestMemory(lsst.utils.tests.MemoryTestCase):
784 pass
787def setup_module(module):
788 lsst.utils.tests.init()
791if __name__ == "__main__": 791 ↛ 792line 791 didn't jump to line 792, because the condition on line 791 was never true
792 lsst.utils.tests.init()
793 unittest.main()