Coverage for tests/test_maskedImage.py: 12%
469 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-23 03:25 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-23 03:25 -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# (https://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 <https://www.gnu.org/licenses/>.
22"""
23Tests for MaskedImages
25Run with:
26 python test_maskedImage.py
27or
28 pytest test_maskedImage.py
29"""
31import itertools
32import os
33import unittest
35import numpy as np
37import lsst.utils
38import lsst.utils.tests
39import lsst.pex.exceptions
40import lsst.daf.base
41import lsst.geom
42import lsst.afw.image as afwImage
43import lsst.afw.math as afwMath
44import lsst.afw.display as afwDisplay
46try:
47 type(display)
48except NameError:
49 display = False
50afwDisplay.setDefaultMaskTransparency(75)
53def makeRampImage(width, height, imgClass=afwImage.MaskedImageF):
54 """Make a ramp image of the specified size and image class
56 Image values start from 0 at the lower left corner and increase by 1 along rows
57 Variance values equal image values + 100
58 Mask values equal image values modulo 8 bits (leaving plenty of unused values)
59 """
60 mi = imgClass(width, height)
61 image = mi.image
62 mask = mi.mask
63 variance = mi.variance
64 val = 0
65 for yInd in range(height):
66 for xInd in range(width):
67 image[xInd, yInd] = val
68 variance[xInd, yInd] = val + 100
69 mask[xInd, yInd] = val % 0x100
70 val += 1
71 return mi
74class MaskedImageTestCase(lsst.utils.tests.TestCase):
75 """A test case for MaskedImage"""
77 def setUp(self):
78 self.imgVal1, self.varVal1 = 100.0, 10.0
79 self.imgVal2, self.varVal2 = 200.0, 15.0
80 self.mimage = afwImage.MaskedImageF(100, 200)
82 self.mimage.image.set(self.imgVal1)
83 #
84 # Set center of mask to 0, with 2 pixel border set to EDGE
85 #
86 self.BAD = afwImage.Mask.getPlaneBitMask("BAD")
87 self.EDGE = afwImage.Mask.getPlaneBitMask("EDGE")
89 self.mimage.mask.set(self.EDGE)
90 centre = afwImage.Mask(
91 self.mimage.mask,
92 lsst.geom.Box2I(lsst.geom.Point2I(2, 2),
93 self.mimage.getDimensions() - lsst.geom.Extent2I(4)),
94 afwImage.LOCAL)
95 centre.set(0x0)
96 #
97 self.mimage.variance.set(self.varVal1)
98 #
99 # Second MaskedImage
100 #
101 self.mimage2 = afwImage.MaskedImageF(self.mimage.getDimensions())
102 self.mimage2.image.set(self.imgVal2)
103 self.mimage2.variance.set(self.varVal2)
104 #
105 # a Function2
106 #
107 self.function = afwMath.PolynomialFunction2D(2)
108 self.function.setParameters(
109 list(range(self.function.getNParameters())))
111 def tearDown(self):
112 del self.mimage
113 del self.mimage2
114 del self.function
116 # TODO DM-39935: remove this test when you remove getArrays()
117 def testArrays(self):
118 """
119 This method is testing that ``lsst.afw.image.MaskedImageF.getArrays()``
120 returns the proper image, mask, and variance.
121 """
122 image, mask, variance = self.mimage.getArrays()
123 self.assertFloatsEqual(self.mimage.image.getArray(), image)
124 self.assertFloatsEqual(self.mimage.mask.getArray(), mask)
125 self.assertFloatsEqual(self.mimage.variance.getArray(), variance)
126 mimage2 = afwImage.makeMaskedImageFromArrays(image, mask, variance)
127 self.assertEqual(type(mimage2), type(self.mimage))
129 def testProperties(self):
130 self.assertImagesEqual(self.mimage.image, self.mimage.image)
131 self.assertMasksEqual(self.mimage.mask, self.mimage.mask)
132 self.assertImagesEqual(self.mimage.variance, self.mimage.variance)
133 image2 = self.mimage.image.Factory(self.mimage.getDimensions())
134 image2.array[:] = 5.0
135 self.mimage.image = image2
136 self.assertImagesEqual(self.mimage.image, image2)
137 mask2 = self.mimage.mask.Factory(self.mimage.getDimensions())
138 mask2.array[:] = 0x4
139 self.mimage.mask = mask2
140 self.assertMasksEqual(self.mimage.mask, mask2)
141 var2 = self.mimage.image.Factory(self.mimage.getDimensions())
142 var2.array[:] = 3.0
143 self.mimage.variance = var2
144 self.assertImagesEqual(self.mimage.variance, var2)
146 def testSetGetValues(self):
147 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL],
148 (self.imgVal1, self.EDGE, self.varVal1))
150 self.assertEqual(self.mimage.mask[1, 1, afwImage.LOCAL], self.EDGE)
151 self.assertEqual(self.mimage.mask[2, 2, afwImage.LOCAL], 0x0)
153 def testImagesOverlap(self):
154 # make pairs of image, variance and mask planes
155 # using the same dimensions for each so we can mix and match
156 # while making masked images
157 dim = lsst.geom.Extent2I(10, 8)
158 # a set of bounding boxes, some of which overlap each other
159 # and some of which do not, and include the full image bounding box
160 bboxes = (
161 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), dim),
162 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(3, 3)),
163 lsst.geom.Box2I(lsst.geom.Point2I(2, 2), lsst.geom.Extent2I(6, 4)),
164 lsst.geom.Box2I(lsst.geom.Point2I(4, 4), lsst.geom.Extent2I(6, 4)),
165 )
166 masks = [afwImage.Mask(dim), afwImage.Mask(dim)]
167 variances = [afwImage.ImageF(dim), afwImage.ImageF(dim)]
168 imageClasses = (afwImage.ImageF, afwImage.ImageD, afwImage.ImageI, afwImage.ImageU)
169 for ImageClass1, ImageClass2 in itertools.product(imageClasses, imageClasses):
170 images = [ImageClass1(dim), ImageClass2(dim)]
171 for image1, mask1, variance1, image2, mask2, variance2 in itertools.product(
172 images, masks, variances, images, masks, variances):
173 with self.subTest(ImageClass1=str(ImageClass1), ImageClass2=str(ImageClass2),
174 image1=image1, mask1=mask1, variance1=variance1,
175 image2=image2, mask2=mask2, variance2=variance2):
176 shouldOverlap = (image1 is image2) or (mask1 is mask2) or (variance1 is variance2)
178 mi1 = afwImage.makeMaskedImage(image=image1, mask=mask1, variance=variance1)
179 mi2 = afwImage.makeMaskedImage(image=image2, mask=mask2, variance=variance2)
180 self.assertEqual(afwImage.imagesOverlap(mi1, mi2), shouldOverlap)
181 self.assertEqual(afwImage.imagesOverlap(mi2, mi1), shouldOverlap)
183 for bbox1, bbox2 in itertools.product(bboxes, bboxes):
184 with self.subTest(bbox1=bbox1, bbox2=bbox2):
185 subMi1 = afwImage.makeMaskedImage(image=type(image1)(image1, bbox1),
186 mask=afwImage.Mask(mask1, bbox1),
187 variance=afwImage.ImageF(variance1, bbox1))
188 subMi2 = afwImage.makeMaskedImage(image=type(image2)(image2, bbox2),
189 mask=afwImage.Mask(mask2, bbox2),
190 variance=afwImage.ImageF(variance2, bbox2))
191 subregionsShouldOverlap = shouldOverlap and bbox1.overlaps(bbox2)
192 self.assertEqual(afwImage.imagesOverlap(subMi1, subMi2), subregionsShouldOverlap)
193 self.assertEqual(afwImage.imagesOverlap(subMi2, subMi1), subregionsShouldOverlap)
195 def testMaskedImageFromImage(self):
196 w, h = 10, 20
197 dims = lsst.geom.Extent2I(w, h)
198 im, mask, var = afwImage.ImageF(dims), \
199 afwImage.Mask(dims), \
200 afwImage.ImageF(dims)
201 im.set(666)
203 maskedImage = afwImage.MaskedImageF(im, mask, var)
205 maskedImage = afwImage.makeMaskedImage(im, mask, var)
207 maskedImage = afwImage.MaskedImageF(im)
208 self.assertEqual(im.getDimensions(),
209 maskedImage.image.getDimensions())
210 self.assertEqual(im.getDimensions(),
211 maskedImage.mask.getDimensions())
212 self.assertEqual(im.getDimensions(),
213 maskedImage.variance.getDimensions())
215 self.assertEqual(maskedImage[0, 0, afwImage.LOCAL], (im[0, 0, afwImage.LOCAL], 0x0, 0.0))
217 def testMakeMaskedImageXY0(self):
218 """Test that makeMaskedImage sets XY0 correctly"""
219 im = afwImage.ImageF(200, 300)
220 xy0 = lsst.geom.PointI(10, 20)
221 im.setXY0(*xy0)
222 mi = afwImage.makeMaskedImage(im)
224 self.assertEqual(mi.image.getXY0(), xy0)
225 self.assertEqual(mi.mask.getXY0(), xy0)
226 self.assertEqual(mi.variance.getXY0(), xy0)
228 def testCopyMaskedImage(self):
229 """Test copy constructor"""
230 #
231 # shallow copy
232 #
233 mi = self.mimage.Factory(self.mimage, False)
235 val00 = self.mimage[0, 0, afwImage.LOCAL]
236 nval00 = (100, 0xff, -1) # the new value we'll set
237 self.assertNotEqual(val00, nval00)
239 self.assertEqual(mi[0, 0, afwImage.LOCAL], val00)
240 mi[0, 0, afwImage.LOCAL] = nval00
242 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], nval00)
243 self.assertEqual(mi[0, 0, afwImage.LOCAL], nval00)
244 mi[0, 0, afwImage.LOCAL] = val00 # reinstate initial value
245 #
246 # deep copy
247 #
248 mi = self.mimage.Factory(self.mimage, True)
250 self.assertEqual(mi[0, 0, afwImage.LOCAL], val00)
251 mi[0, 0, afwImage.LOCAL] = nval00
253 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], val00)
254 self.assertEqual(mi[0, 0, afwImage.LOCAL], nval00)
255 #
256 # Copy with change of Image type
257 #
258 mi = self.mimage.convertD()
260 self.assertEqual(mi[0, 0, afwImage.LOCAL], val00)
261 mi[0, 0, afwImage.LOCAL] = nval00
263 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], val00)
264 self.assertEqual(mi[0, 0, afwImage.LOCAL], nval00)
265 #
266 # Convert from U to F
267 #
268 mi = afwImage.MaskedImageU(lsst.geom.Extent2I(10, 20))
269 val00 = (10, 0x10, 1)
270 mi.set(val00)
271 self.assertEqual(mi[0, 0, afwImage.LOCAL], val00)
273 fmi = mi.convertF()
274 self.assertEqual(fmi[0, 0, afwImage.LOCAL], val00)
276 def testAddImages(self):
277 "Test addition"
278 # add an image
279 self.mimage2 += self.mimage
281 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], (self.imgVal1 + self.imgVal2, self.EDGE,
282 self.varVal1 + self.varVal2))
284 # Add an Image<int> to a MaskedImage<int>
285 mimage_i = afwImage.MaskedImageI(self.mimage2.getDimensions())
286 mimage_i.set(900, 0x0, 1000.0)
287 image_i = afwImage.ImageI(mimage_i.getDimensions(), 2)
289 mimage_i += image_i
291 self.assertEqual(mimage_i[0, 0, afwImage.LOCAL], (902, 0x0, 1000.0))
293 # add a scalar
294 self.mimage += self.imgVal1
296 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL],
297 (2*self.imgVal1, self.EDGE, self.varVal1))
299 self.assertEqual(self.mimage.mask[1, 1, afwImage.LOCAL], self.EDGE)
300 self.assertEqual(self.mimage.mask[2, 2, afwImage.LOCAL], 0x0)
302 # add a function
303 self.mimage.set(self.imgVal1, 0x0, 0.0)
304 self.mimage += self.function
306 for i, j in [(2, 3)]:
307 self.assertEqual(self.mimage.image[i, j, afwImage.LOCAL],
308 self.imgVal1 + self.function(i, j))
310 def testAddScaledImages(self):
311 "Test addition by a scaled MaskedImage"
312 # add an image
313 c = 10.0
314 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy
315 self.mimage2.scaledPlus(c, self.mimage)
316 #
317 # Now repeat calculation using a temporary
318 #
319 tmp = self.mimage.Factory(self.mimage, True)
320 tmp *= c
321 mimage2_copy += tmp
323 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], mimage2_copy[0, 0, afwImage.LOCAL])
325 def testAssignWithBBox(self):
326 """Test assign(rhs, bbox) with non-empty bbox
327 """
328 for xy0 in (lsst.geom.Point2I(*val) for val in (
329 (0, 0),
330 (-100, 120), # an arbitrary value that is off the image
331 )):
332 destMIDim = lsst.geom.Extent2I(5, 4)
333 srcMIDim = lsst.geom.Extent2I(3, 2)
334 destMI = afwImage.MaskedImageF(destMIDim)
335 destImage = destMI.image
336 destVariance = destMI.variance
337 destMask = destMI.mask
338 destMI.setXY0(xy0)
339 srcMI = makeRampImage(*srcMIDim)
340 srcMI.setXY0(55, -33) # an arbitrary value that should be ignored
341 self.assertRaises(Exception, destMI.set, srcMI) # size mismatch
343 for validMin in (lsst.geom.Point2I(*val) for val in (
344 (0, 0),
345 (2, 0),
346 (0, 1),
347 (1, 2),
348 )):
349 # None to omit the argument
350 for origin in (None, afwImage.PARENT, afwImage.LOCAL):
351 destImage[:] = -1.0
352 destVariance[:] = -1.0
353 destMask[:] = 0xFFFF
354 bbox = lsst.geom.Box2I(validMin, srcMI.getDimensions())
355 if origin != afwImage.LOCAL:
356 bbox.shift(lsst.geom.Extent2I(xy0))
357 if origin is None:
358 destMI.assign(srcMI, bbox)
359 destMIView = afwImage.MaskedImageF(destMI, bbox)
360 else:
361 destMI.assign(srcMI, bbox, origin)
362 destMIView = afwImage.MaskedImageF(destMI, bbox, origin)
363 self.assertMaskedImagesEqual(destMIView, srcMI)
364 numPixNotAssigned = (
365 destMIDim[0] * destMIDim[1]) - (srcMIDim[0] * srcMIDim[1])
366 self.assertEqual(
367 np.sum(destImage.getArray() < -0.5), numPixNotAssigned)
368 self.assertEqual(
369 np.sum(destVariance.getArray() < -0.5), numPixNotAssigned)
370 self.assertEqual(
371 np.sum(destMask.getArray() == 0xFFFF), numPixNotAssigned)
373 for badMin in (lsst.geom.Point2I(*val) + lsst.geom.Extent2I(xy0) for val in (
374 (-1, 0),
375 (3, 0),
376 (0, -1),
377 (1, 3),
378 )):
379 # None to omit the argument
380 for origin in (None, afwImage.PARENT, afwImage.LOCAL):
381 bbox = lsst.geom.Box2I(validMin, srcMI.getDimensions())
382 if origin != afwImage.LOCAL:
383 bbox.shift(lsst.geom.Extent2I(xy0))
384 if origin is None:
385 self.assertRaises(Exception, destMI.set, srcMI, bbox)
386 else:
387 self.assertRaises(
388 Exception, destMI.set, srcMI, bbox, origin)
390 def testAssignWithoutBBox(self):
391 """Test assign(rhs, [bbox]) with an empty bbox and with no bbox specified; both set all pixels
392 """
393 for xy0 in (lsst.geom.Point2I(*val) for val in (
394 (0, 0),
395 (-100, 120), # an arbitrary value that is off the image
396 )):
397 destMIDim = lsst.geom.Extent2I(5, 4)
398 destMI = afwImage.MaskedImageF(destMIDim)
399 destMI.setXY0(xy0)
400 destImage = destMI.image
401 destVariance = destMI.variance
402 destMask = destMI.mask
403 srcMI = makeRampImage(*destMIDim)
404 srcMI.setXY0(55, -33) # an arbitrary value that should be ignored
406 destImage[:] = -1.0
407 destVariance[:] = -1.0
408 destMask[:] = 0xFFFF
409 destMI.assign(srcMI)
410 self.assertMaskedImagesEqual(destMI, srcMI)
412 destImage[:] = -1.0
413 destVariance[:] = -1.0
414 destMask[:] = 0xFFFF
415 destMI.assign(srcMI, lsst.geom.Box2I())
416 self.assertMaskedImagesEqual(destMI, srcMI)
418 def testSubtractImages(self):
419 "Test subtraction"
420 # subtract an image
421 self.mimage2 -= self.mimage
422 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL],
423 (self.imgVal2 - self.imgVal1, self.EDGE, self.varVal2 + self.varVal1))
425 # Subtract an Image<int> from a MaskedImage<int>
426 mimage_i = afwImage.MaskedImageI(self.mimage2.getDimensions())
427 mimage_i.set(900, 0x0, 1000.0)
428 image_i = afwImage.ImageI(mimage_i.getDimensions(), 2)
430 mimage_i -= image_i
432 self.assertEqual(mimage_i[0, 0, afwImage.LOCAL], (898, 0x0, 1000.0))
434 # subtract a scalar
435 self.mimage -= self.imgVal1
436 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL], (0.0, self.EDGE, self.varVal1))
438 def testSubtractScaledImages(self):
439 "Test subtraction by a scaled MaskedImage"
440 # subtract a scaled image
441 c = 10.0
442 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy
443 self.mimage2.scaledMinus(c, self.mimage)
444 #
445 # Now repeat calculation using a temporary
446 #
447 tmp = self.mimage.Factory(self.mimage, True)
448 tmp *= c
449 mimage2_copy -= tmp
451 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], mimage2_copy[0, 0, afwImage.LOCAL])
453 def testArithmeticImagesMismatch(self):
454 "Test arithmetic operations on MaskedImages of different sizes"
455 i1 = afwImage.MaskedImageF(lsst.geom.Extent2I(100, 100))
456 i1.set(100)
457 i2 = afwImage.MaskedImageF(lsst.geom.Extent2I(10, 10))
458 i2.set(10)
460 def tst1(i1, i2):
461 i1 -= i2
463 def tst2(i1, i2):
464 i1.scaledMinus(1.0, i2)
466 def tst3(i1, i2):
467 i1 += i2
469 def tst4(i1, i2):
470 i1.scaledPlus(1.0, i2)
472 def tst5(i1, i2):
473 i1 *= i2
475 def tst6(i1, i2):
476 i1.scaledMultiplies(1.0, i2)
478 def tst7(i1, i2):
479 i1 /= i2
481 def tst8(i1, i2):
482 i1.scaledDivides(1.0, i2)
484 tsts12 = [tst1, tst3, tst5, tst7]
485 for tst in tsts12:
486 self.assertRaises(lsst.pex.exceptions.LengthError, tst, i1, i2)
488 tsts21 = [tst2, tst4, tst6, tst8]
489 for tst in tsts21:
490 self.assertRaises(lsst.pex.exceptions.LengthError, tst, i2, i1)
492 def testMultiplyImages(self):
493 """Test multiplication"""
494 # Multiply by a MaskedImage
495 self.mimage2 *= self.mimage
497 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL],
498 (self.imgVal2*self.imgVal1, self.EDGE,
499 self.varVal2*pow(self.imgVal1, 2) + self.varVal1*pow(self.imgVal2, 2)))
501 # Divide a MaskedImage<int> by an Image<int>; this divides the variance Image<float>
502 # by an Image<int> in C++
503 mimage_i = afwImage.MaskedImageI(self.mimage2.getDimensions())
504 mimage_i.set(900, 0x0, 1000.0)
505 image_i = afwImage.ImageI(mimage_i.getDimensions(), 2)
507 mimage_i *= image_i
509 self.assertEqual(mimage_i[0, 0, afwImage.LOCAL], (1800, 0x0, 4000.0))
511 # multiply by a scalar
512 self.mimage *= self.imgVal1
514 self.assertEqual(self.mimage[0, 0, afwImage.LOCAL],
515 (self.imgVal1*self.imgVal1, self.EDGE, self.varVal1*pow(self.imgVal1, 2)))
517 self.assertEqual(self.mimage.mask[1, 1, afwImage.LOCAL], self.EDGE)
518 self.assertEqual(self.mimage.mask[2, 2, afwImage.LOCAL], 0x0)
520 def testScaledMultiplyImages(self):
521 """Test multiplication by a scaled image"""
522 # Multiply by an image
523 c = 10.0
524 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy
525 self.mimage2.scaledMultiplies(c, self.mimage)
526 #
527 # Now repeat calculation using a temporary
528 #
529 tmp = self.mimage.Factory(self.mimage, True)
530 tmp *= c
531 mimage2_copy *= tmp
533 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], mimage2_copy[0, 0, afwImage.LOCAL])
535 def testDivideImages(self):
536 """Test division"""
537 # Divide by a MaskedImage
538 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy
539 mimage2_copy /= self.mimage
541 self.assertEqual(mimage2_copy.image[0, 0, afwImage.LOCAL],
542 self.imgVal2/self.imgVal1)
543 self.assertEqual(mimage2_copy.mask[0, 0, afwImage.LOCAL], self.EDGE)
544 self.assertAlmostEqual(mimage2_copy.variance[0, 0, afwImage.LOCAL],
545 (self.varVal2*pow(self.imgVal1, 2)
546 + self.varVal1*pow(self.imgVal2, 2))/pow(self.imgVal1, 4), 10)
547 # Divide by an Image (of the same type as MaskedImage.image)
548 mimage = self.mimage2.Factory(self.mimage2, True)
549 mimage /= mimage.image
551 self.assertEqual(mimage[0, 0, afwImage.LOCAL], (self.imgVal2 / self.imgVal2, 0x0, self.varVal2))
553 # Divide by an Image (of a different type from MaskedImage.image)
554 # this isn't supported from python (it's OK in C++)
555 if False:
556 mimage = self.mimage2.Factory(self.mimage2, True)
557 image = afwImage.ImageI(mimage.getDimensions(), 1)
558 mimage /= image
560 self.assertEqual(mimage[0, 0, afwImage.LOCAL],
561 (self.imgVal2, 0x0, self.varVal2))
563 # Divide a MaskedImage<int> by an Image<int>; this divides the variance Image<float>
564 # by an Image<int> in C++
565 mimage_i = afwImage.MaskedImageI(self.mimage2.getDimensions())
566 mimage_i.set(900, 0x0, 1000.0)
567 image_i = afwImage.ImageI(mimage_i.getDimensions(), 2)
569 mimage_i /= image_i
571 self.assertEqual(mimage_i[0, 0, afwImage.LOCAL], (450, 0x0, 250.0))
573 # divide by a scalar
574 self.mimage /= self.imgVal1
576 self.assertEqual(self.mimage.image[0, 0, afwImage.LOCAL],
577 self.imgVal1/self.imgVal1)
578 self.assertEqual(self.mimage.mask[0, 0, afwImage.LOCAL], self.EDGE)
579 self.assertAlmostEqual(self.mimage.variance[0, 0, afwImage.LOCAL],
580 self.varVal1/pow(self.imgVal1, 2), 9)
582 self.assertEqual(self.mimage.mask[1, 1, afwImage.LOCAL], self.EDGE)
583 self.assertEqual(self.mimage.mask[2, 2, afwImage.LOCAL], 0x0)
585 def testScaledDivideImages(self):
586 """Test division by a scaled image"""
587 # Divide by an image
588 c = 10.0
589 mimage2_copy = self.mimage2.Factory(self.mimage2, True) # make a copy
590 self.mimage2.scaledDivides(c, self.mimage)
591 #
592 # Now repeat calculation using a temporary
593 #
594 tmp = self.mimage.Factory(self.mimage, True)
595 tmp *= c
596 mimage2_copy /= tmp
598 self.assertEqual(self.mimage2[0, 0, afwImage.LOCAL], mimage2_copy[0, 0, afwImage.LOCAL])
600 def testCopyConstructors(self):
601 dimage = afwImage.MaskedImageF(self.mimage, True) # deep copy
602 simage = afwImage.MaskedImageF(self.mimage) # shallow copy
604 self.mimage += 2 # should only change dimage
605 self.assertEqual(dimage.image[0, 0, afwImage.LOCAL], self.imgVal1)
606 self.assertEqual(simage.image[0, 0, afwImage.LOCAL], self.imgVal1 + 2)
608 def checkImgPatch12(self, img, x0, y0):
609 """Check that a patch of an image is correct; origin of patch is at (x0, y0) in full image
610 N.b. This isn't a general routine! Works only for testSubimages[12]"""
612 self.assertEqual(img[x0 - 1, y0 - 1, afwImage.LOCAL],
613 (self.imgVal1, self.EDGE, self.varVal1))
614 self.assertEqual(img[x0, y0, afwImage.LOCAL], (666, self.BAD, 0))
615 self.assertEqual(img[x0 + 3, y0, afwImage.LOCAL],
616 (self.imgVal1, 0x0, self.varVal1))
617 self.assertEqual(img[x0, y0 + 1, afwImage.LOCAL], (666, self.BAD, 0))
618 self.assertEqual(img[x0 + 3, y0 + 1, afwImage.LOCAL],
619 (self.imgVal1, 0x0, self.varVal1))
620 self.assertEqual(img[x0, y0 + 2, afwImage.LOCAL],
621 (self.imgVal1, 0x0, self.varVal1))
623 def testOrigin(self):
624 """Check that we can set and read the origin"""
626 im = afwImage.MaskedImageF(lsst.geom.ExtentI(10, 20))
627 x0 = y0 = 0
629 self.assertEqual(im.getX0(), x0)
630 self.assertEqual(im.getY0(), y0)
631 self.assertEqual(im.getXY0(), lsst.geom.PointI(x0, y0))
633 x0, y0 = 3, 5
634 im.setXY0(x0, y0)
635 self.assertEqual(im.getX0(), x0)
636 self.assertEqual(im.getY0(), y0)
637 self.assertEqual(im.getXY0(), lsst.geom.PointI(x0, y0))
639 x0, y0 = 30, 50
640 im.setXY0(lsst.geom.Point2I(x0, y0))
641 self.assertEqual(im.getX0(), x0)
642 self.assertEqual(im.getY0(), y0)
643 self.assertEqual(im.getXY0(), lsst.geom.Point2I(x0, y0))
645 def testSubimages1(self):
646 smimage = afwImage.MaskedImageF(
647 self.mimage,
648 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(10, 5)),
649 afwImage.LOCAL
650 )
652 simage = afwImage.MaskedImageF(
653 smimage,
654 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(3, 2)),
655 afwImage.LOCAL
656 )
657 self.assertEqual(simage.getX0(), 2)
658 self.assertEqual(simage.getY0(), 2) # i.e. wrt self.mimage
660 mimage2 = afwImage.MaskedImageF(simage.getDimensions())
661 mimage2.image.set(666)
662 mimage2.mask.set(self.BAD)
663 simage[:] = mimage2
665 del simage
666 del mimage2
668 self.checkImgPatch12(self.mimage, 2, 2)
669 self.checkImgPatch12(smimage, 1, 1)
671 def testSubimages2(self):
672 """Test subimages when we've played with the (x0, y0) value"""
674 self.mimage[9, 4, afwImage.LOCAL] = (888, 0x0, 0)
676 smimage = afwImage.MaskedImageF(
677 self.mimage,
678 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(10, 5)),
679 afwImage.LOCAL
680 )
681 # reset origin; doesn't affect pixel coordinate systems
682 smimage.setXY0(lsst.geom.Point2I(0, 0))
684 simage = afwImage.MaskedImageF(
685 smimage, lsst.geom.Box2I(lsst.geom.Point2I(1, 1),
686 lsst.geom.Extent2I(3, 2)),
687 afwImage.LOCAL
688 )
689 self.assertEqual(simage.getX0(), 1)
690 self.assertEqual(simage.getY0(), 1)
692 mimage2 = afwImage.MaskedImageF(simage.getDimensions())
693 mimage2.set(666, self.BAD, 0.0)
694 simage[:] = mimage2
695 del simage
696 del mimage2
698 self.checkImgPatch12(self.mimage, 2, 2)
699 self.checkImgPatch12(smimage, 1, 1)
701 def checkImgPatch3(self, img, deep):
702 """Check that a patch of an image is correct; origin of patch is at (x0, y0) in full image
703 N.b. This isn't a general routine! Works only for testSubimages3"""
705 # Include deep in comparison so we can see which test fails
706 self.assertEqual(img[0, 0, afwImage.LOCAL] + (deep, ),
707 (100, 0x0, self.varVal1, deep))
708 self.assertEqual(img[10, 10, afwImage.LOCAL] + (deep, ),
709 (200, 0xf, self.varVal1, deep))
711 def testSubimages3(self):
712 """Test subimages when we've played with the (x0, y0) value"""
714 self.mimage.image[20, 20, afwImage.LOCAL] = 200
715 self.mimage.mask[20, 20, afwImage.LOCAL] = 0xf
717 for deep in (True, False):
718 mimage = self.mimage.Factory(
719 self.mimage,
720 lsst.geom.Box2I(lsst.geom.Point2I(10, 10),
721 lsst.geom.Extent2I(64, 64)),
722 afwImage.LOCAL,
723 deep)
724 mimage.setXY0(lsst.geom.Point2I(0, 0))
725 mimage2 = mimage.Factory(mimage)
727 if display:
728 afwDisplay.Display(frame=0).mtv(mimage2, title="testSubimages3")
730 self.checkImgPatch3(mimage2, deep)
732 def testSetCopiedMask(self):
733 """Check that we can set the Mask with a copied Mask"""
735 crMask = self.mimage.mask.Factory(self.mimage.mask, True)
736 msk = self.mimage.mask
737 msk |= crMask
738 del msk
740 def testVariance(self):
741 """Check that we can set the variance from the gain"""
742 gain = 2
744 var = self.mimage.variance
745 var[:] = self.mimage.image
746 var /= gain
748 def testTicket653(self):
749 """How-to-repeat for #653"""
750 # The original ticket read this file, but it doesn't reproduce for me,
751 # As I don't see how reading an exposure from disk could make a difference
752 # it's easier to just build an Image
753 if False:
754 im = afwImage.ImageF(os.path.join(
755 lsst.utils.getPackageDir("afwdata"), "med_img.fits"))
756 else:
757 im = afwImage.ImageF(lsst.geom.Extent2I(10, 10))
758 mi = afwImage.MaskedImageF(im)
759 afwImage.ExposureF(mi)
761 def testMaskedImageInitialisation(self):
762 dims = self.mimage.getDimensions()
763 factory = self.mimage.Factory
765 self.mimage.set(666)
767 del self.mimage # tempt C++ to reuse the memory
768 self.mimage = factory(dims)
769 self.assertEqual(self.mimage[10, 10, afwImage.LOCAL], (0, 0x0, 0))
771 del self.mimage
772 self.mimage = factory(lsst.geom.Extent2I(20, 20))
773 self.assertEqual(self.mimage[10, 10, afwImage.LOCAL], (0, 0x0, 0))
775 def testImageSlices(self):
776 """Test image slicing, which generate sub-images using Box2I under the covers"""
777 im = afwImage.MaskedImageF(10, 20)
778 im[4, 10] = (10, 0x2, 100)
779 im[-3:, -2:, afwImage.LOCAL] = 100
780 sim = im[1:4, 6:10]
781 nan = -666 # a real NaN != NaN so tests fail
782 sim[:] = (-1, 0x8, nan)
783 im[0:4, 0:4] = im[2:6, 8:12]
785 if display:
786 afwDisplay.Display(frame=1).mtv(im, title="testImageSlices")
788 self.assertEqual(im[0, 6, afwImage.LOCAL], (0, 0x0, 0))
789 self.assertEqual(im[6, 17, afwImage.LOCAL], (0, 0x0, 0))
790 self.assertEqual(im[7, 18, afwImage.LOCAL], (100, 0x0, 0))
791 self.assertEqual(im[9, 19, afwImage.LOCAL], (100, 0x0, 0))
792 self.assertEqual(im[1, 6, afwImage.LOCAL], (-1, 0x8, nan))
793 self.assertEqual(im[3, 9, afwImage.LOCAL], (-1, 0x8, nan))
794 self.assertEqual(im[4, 10, afwImage.LOCAL], (10, 0x2, 100))
795 self.assertEqual(im[4, 9, afwImage.LOCAL], (0, 0x0, 0))
796 self.assertEqual(im[2, 2, afwImage.LOCAL], (10, 0x2, 100))
797 self.assertEqual(im[0, 0, afwImage.LOCAL], (-1, 0x8, nan))
799 def testConversionToScalar(self):
800 """Test that even 1-pixel MaskedImages can't be converted to scalars"""
801 im = afwImage.MaskedImageF(10, 20)
803 # only single pixel images may be converted
804 self.assertRaises(TypeError, float, im)
805 # actually, can't convert (img, msk, var) to scalar
806 self.assertRaises(TypeError, float, im[0, 0])
808 def testString(self):
809 image = afwImage.MaskedImageF(100, 100)
810 self.assertIn("image=", str(image))
811 self.assertIn("mask=", str(image))
812 self.assertIn("variance=", str(image))
813 self.assertIn(str(np.zeros((100, 100), dtype=image.image.dtype)), str(image))
814 self.assertIn(str(np.zeros((100, 100), dtype=image.mask.dtype)), str(image))
815 self.assertIn(str(np.zeros((100, 100), dtype=image.variance.dtype)), str(image))
816 self.assertIn("bbox=%s"%str(image.getBBox()), str(image))
817 self.assertIn("maskPlaneDict=%s"%str(image.mask.getMaskPlaneDict()), str(image))
819 self.assertIn("MaskedImageF=(", repr(image))
822def printImg(img):
823 print("%4s " % "", end=' ')
824 for c in range(img.getWidth()):
825 print("%7d" % c, end=' ')
826 print()
828 for r in range(img.getHeight() - 1, -1, -1):
829 print("%4d " % r, end=' ')
830 for c in range(img.getWidth()):
831 print("%7.1f" % float(img[c, r, afwImage.LOCAL]), end=' ')
832 print()
835class TestMemory(lsst.utils.tests.MemoryTestCase):
836 pass
839def setup_module(module):
840 lsst.utils.tests.init()
843if __name__ == "__main__": 843 ↛ 844line 843 didn't jump to line 844, because the condition on line 843 was never true
844 lsst.utils.tests.init()
845 unittest.main()