Coverage for tests/test_multiband.py: 13%
570 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-15 02:45 -0700
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-15 02:45 -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([p.computeKernelImage().array for p in self.psfs])
595 self.exposure = MultibandExposure(image=mImage, mask=mMask, variance=mVariance,
596 psfs=self.psfs, filters=self.filters)
598 def tearDown(self):
599 del self.exposure
600 del self.psfs
601 del self.bbox
602 del self.imgValue
603 del self.maskValue
604 del self.varValue
605 # Reset the mask plane to the default
606 self.Mask.clearMaskPlaneDict()
607 for p in self.defaultMaskPlanes:
608 self.Mask.addMaskPlane(p)
609 del self.defaultMaskPlanes
611 def testConstructor(self):
612 exposures = self.exposure.singles
613 print(exposures[0].getPsf())
614 filters = self.exposure.filters
615 newExposure = MultibandExposure.fromExposures(filters, exposures)
616 for exposure in newExposure.singles:
617 self.assertIsNotNone(exposure.getPsf())
619 def testFilterSlicing(self):
620 _testMaskedImageFilters(self, self.exposure, ExposureF)
622 def testImageSlicing(self):
623 _testMaskedImageSlicing(self, self.exposure)
625 def testModification(self):
626 _testMaskedmageModification(self, self.exposure)
628 def testCopy(self):
629 _testMaskedImageCopy(self, self.exposure)
631 def testPsf(self):
632 psfImage = self.exposure.computePsfKernelImage().array
633 self.assertFloatsAlmostEqual(psfImage, self.psfImage)
635 newPsfs = [GaussianPsf(self.kernelSize, self.kernelSize, 1.0) for f in self.filters]
636 newPsfImage = [p.computeImage().array for p in newPsfs]
637 for psf, exposure in zip(newPsfs, self.exposure.singles):
638 exposure.setPsf(psf)
639 psfImage = self.exposure.computePsfKernelImage()
640 self.assertFloatsAlmostEqual(psfImage.array, newPsfImage)
642 psfImage = self.exposure.computePsfImage().array[0]
643 self.assertFloatsAlmostEqual(psfImage, self.exposure["G"].getPsf().computeImage().array)
646class MultibandFootprintTestCase(lsst.utils.tests.TestCase):
647 """
648 A test case for the Exposure Class
649 """
651 def setUp(self):
652 np.random.seed(1)
653 self.spans = SpanSet.fromShape(2, Stencil.CIRCLE)
654 self.footprint = Footprint(self.spans)
655 self.footprint.addPeak(3, 4, 10)
656 self.footprint.addPeak(8, 1, 2)
657 fp = Footprint(self.spans)
658 for peak in self.footprint.getPeaks():
659 fp.addPeak(peak["f_x"], peak["f_y"], peak["peakValue"])
660 self.peaks = fp.getPeaks()
661 self.bbox = self.footprint.getBBox()
662 self.filters = ("G", "R", "I")
663 singles = []
664 images = []
665 for n, f in enumerate(self.filters):
666 image = ImageF(self.spans.getBBox())
667 image.set(n)
668 images.append(image.array)
669 maskedImage = MaskedImageF(image)
670 heavy = makeHeavyFootprint(self.footprint, maskedImage)
671 singles.append(heavy)
672 self.image = np.array(images)
673 self.mFoot = MultibandFootprint(self.filters, singles)
675 def tearDown(self):
676 del self.spans
677 del self.footprint
678 del self.peaks
679 del self.bbox
680 del self.filters
681 del self.mFoot
682 del self.image
684 def verifyPeaks(self, peaks1, peaks2):
685 self.assertEqual(len(peaks1), len(peaks2))
686 for n in range(len(peaks1)):
687 pk1 = peaks1[n]
688 pk2 = peaks2[n]
689 # self.assertEqual(pk1["id"], pk2["id"])
690 self.assertEqual(pk1["f_x"], pk2["f_x"])
691 self.assertEqual(pk1["f_y"], pk2["f_y"])
692 self.assertEqual(pk1["i_x"], pk2["i_x"])
693 self.assertEqual(pk1["i_y"], pk2["i_y"])
694 self.assertEqual(pk1["peakValue"], pk2["peakValue"])
696 def testConstructor(self):
697 def projectSpans(radius, value, bbox, asArray):
698 ss = SpanSet.fromShape(radius, Stencil.CIRCLE, offset=(10, 10))
699 image = ImageF(bbox)
700 ss.setImage(image, value)
701 if asArray:
702 return image.array
703 else:
704 return image
706 def runTest(images, mFoot, peaks=self.peaks, footprintBBox=Box2I(Point2I(6, 6), Extent2I(9, 9))):
707 self.assertEqual(mFoot.getBBox(), footprintBBox)
708 try:
709 fpImage = np.array(images)[:, 1:-1, 1:-1]
710 except IndexError:
711 fpImage = np.array([img.array for img in images])[:, 1:-1, 1:-1]
712 # result = mFoot.getImage(fill=0).image.array
713 self.assertFloatsAlmostEqual(mFoot.getImage(fill=0).image.array, fpImage)
714 if peaks is not None:
715 self.verifyPeaks(mFoot.getPeaks(), peaks)
717 bbox = Box2I(Point2I(5, 5), Extent2I(11, 11))
718 xy0 = Point2I(5, 5)
720 images = np.array([projectSpans(n, 5-n, bbox, True) for n in range(2, 5)])
721 mFoot = MultibandFootprint.fromArrays(self.filters, images, xy0=xy0, peaks=self.peaks)
722 runTest(images, mFoot)
724 mFoot = MultibandFootprint.fromArrays(self.filters, images)
725 runTest(images, mFoot, None, Box2I(Point2I(1, 1), Extent2I(9, 9)))
727 images = [projectSpans(n, 5-n, bbox, False) for n in range(2, 5)]
728 mFoot = MultibandFootprint.fromImages(self.filters, images, peaks=self.peaks)
729 runTest(images, mFoot)
731 images = np.array([projectSpans(n, n, bbox, True) for n in range(2, 5)])
732 mFoot = MultibandFootprint.fromArrays(self.filters, images, peaks=self.peaks, xy0=bbox.getMin())
733 runTest(images, mFoot)
735 images = np.array([projectSpans(n, 5-n, bbox, True) for n in range(2, 5)])
736 thresh = [1, 2, 2.5]
737 mFoot = MultibandFootprint.fromArrays(self.filters, images, xy0=bbox.getMin(), thresh=thresh)
738 footprintBBox = Box2I(Point2I(8, 8), Extent2I(5, 5))
739 self.assertEqual(mFoot.getBBox(), footprintBBox)
741 fpImage = np.array(images)[:, 3:-3, 3:-3]
742 mask = np.all(fpImage <= np.array(thresh)[:, None, None], axis=0)
743 fpImage[:, mask] = 0
744 self.assertFloatsAlmostEqual(mFoot.getImage(fill=0).image.array, fpImage)
745 img = mFoot.getImage().image.array
746 img[~np.isfinite(img)] = 1.1
747 self.assertFloatsAlmostEqual(mFoot.getImage(fill=1.1).image.array, img)
749 def testSlicing(self):
750 self.assertIsInstance(self.mFoot["R"], HeavyFootprintF)
751 self.assertIsInstance(self.mFoot[:], MultibandFootprint)
753 self.assertEqual(self.mFoot["I"], self.mFoot["I"])
754 self.assertEqual(self.mFoot[:"I"].filters, ("G", "R"))
755 self.assertEqual(self.mFoot[:"I"].getBBox(), self.bbox)
756 self.assertEqual(self.mFoot[["G", "I"]].filters, ("G", "I"))
757 self.assertEqual(self.mFoot[["G", "I"]].getBBox(), self.bbox)
759 with self.assertRaises(TypeError):
760 self.mFoot["I", 4, 5]
761 self.mFoot["I", :, :]
762 with self.assertRaises(IndexError):
763 self.mFoot[:, :, :]
765 def testSpans(self):
766 self.assertEqual(self.mFoot.getSpans(), self.spans)
767 for footprint in self.mFoot.singles:
768 self.assertEqual(footprint.getSpans(), self.spans)
770 def testPeaks(self):
771 self.verifyPeaks(self.peaks, self.footprint.getPeaks())
772 for footprint in self.mFoot.singles:
773 self.verifyPeaks(footprint.getPeaks(), self.peaks)
776class TestMemory(lsst.utils.tests.MemoryTestCase):
777 pass
780def setup_module(module):
781 lsst.utils.tests.init()
784if __name__ == "__main__": 784 ↛ 785line 784 didn't jump to line 785, because the condition on line 784 was never true
785 lsst.utils.tests.init()
786 unittest.main()