Coverage for tests/test_image.py: 14%
498 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-19 04:54 -0700
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-19 04:54 -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 Images
25Run with:
26 python test_image.py
27or
28 pytest test_image.py
29"""
31import itertools
32import os.path
33import shutil
34import tempfile
35import unittest
37import numpy as np
39import lsst.utils
40import lsst.utils.tests
41import lsst.pex.exceptions
42import lsst.daf.base
43import lsst.geom
44import lsst.afw.image as afwImage
45import lsst.afw.math as afwMath
46from lsst.afw.fits import readMetadata
47import lsst.afw.display as afwDisplay
49try:
50 afwdataDir = lsst.utils.getPackageDir("afwdata")
51except LookupError:
52 afwdataDir = None
54try:
55 type(display)
56except NameError:
57 display = False
60def makeRampImage(width, height, imgClass=afwImage.ImageF):
61 """Make a ramp image of the specified size and image class
63 Values start from 0 at the lower left corner and increase by 1 along rows
64 """
65 im = imgClass(width, height)
66 val = 0
67 for yInd in range(height):
68 for xInd in range(width):
69 im[xInd, yInd] = val
70 val += 1
71 return im
74class ImageTestCase(lsst.utils.tests.TestCase):
75 """A test case for Image"""
77 def setUp(self):
78 np.random.seed(1)
79 self.val1, self.val2 = 10, 100
80 self.image1 = afwImage.ImageF(lsst.geom.ExtentI(100, 200))
81 self.image1.set(self.val1)
82 self.image2 = afwImage.ImageF(self.image1.getDimensions())
83 self.image2.set(self.val2)
84 self.function = afwMath.PolynomialFunction2D(2)
85 self.function.setParameters(
86 list(range(self.function.getNParameters())))
88 def tearDown(self):
89 del self.image1
90 del self.image2
91 del self.function
93 def testArrays(self):
94 for cls in (afwImage.ImageU, afwImage.ImageI, afwImage.ImageF, afwImage.ImageD):
95 image1 = cls(lsst.geom.Extent2I(5, 6))
96 array1 = image1.getArray()
97 self.assertEqual(array1.shape[0], image1.getHeight())
98 self.assertEqual(array1.shape[1], image1.getWidth())
99 image2 = cls(array1, False)
100 self.assertEqual(array1.shape[0], image2.getHeight())
101 self.assertEqual(array1.shape[1], image2.getWidth())
102 image3 = afwImage.makeImageFromArray(array1)
103 self.assertEqual(array1.shape[0], image2.getHeight())
104 self.assertEqual(array1.shape[1], image2.getWidth())
105 self.assertEqual(type(image3), cls)
106 array2 = image1.array
107 np.testing.assert_array_equal(array1, array2)
108 array1[:, :] = np.random.uniform(low=0, high=10, size=array1.shape)
109 for j in range(image1.getHeight()):
110 for i in range(image1.getWidth()):
111 self.assertEqual(image1[i, j, afwImage.LOCAL], array1[j, i])
112 self.assertEqual(image2[i, j, afwImage.LOCAL], array1[j, i])
113 array3 = np.random.uniform(low=0, high=10,
114 size=array1.shape).astype(array1.dtype)
115 image1.array[:] = array3
116 np.testing.assert_array_equal(array1, array3)
117 image1.array[2:4, 3:] = 10
118 np.testing.assert_array_equal(array1[2:4, 3:], 10)
119 array4 = image1.array.copy()
120 array4 += 5
121 image1.array += 5
122 np.testing.assert_array_equal(image1.array, array4)
124 def testImagesOverlap(self):
125 dim = lsst.geom.Extent2I(10, 8)
126 # a set of bounding boxes, some of which overlap each other
127 # and some of which do not, and include the full image bounding box
128 bboxes = (
129 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), dim),
130 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(3, 3)),
131 lsst.geom.Box2I(lsst.geom.Point2I(2, 2), lsst.geom.Extent2I(6, 4)),
132 lsst.geom.Box2I(lsst.geom.Point2I(4, 4), lsst.geom.Extent2I(6, 4)),
133 )
135 imageClasses = (afwImage.ImageF, afwImage.ImageD, afwImage.ImageI, afwImage.Mask)
137 for ImageClass1, ImageClass2 in itertools.product(imageClasses, imageClasses):
138 with self.subTest(ImageClass1=str(ImageClass1), ImageClass2=str(ImageClass2)):
139 image1 = ImageClass1(dim)
140 self.assertTrue(afwImage.imagesOverlap(image1, image1))
142 image2 = ImageClass2(dim)
143 self.assertFalse(afwImage.imagesOverlap(image1, image2))
144 self.assertFalse(afwImage.imagesOverlap(image2, image1))
146 for bboxa, bboxb in itertools.product(bboxes, bboxes):
147 shouldOverlap = bboxa.overlaps(bboxb)
148 with self.subTest(bboxa=bboxa, bboxb=bboxb):
149 subim1a = ImageClass1(image1, bboxa)
150 subim1b = ImageClass1(image1, bboxb)
151 self.assertEqual(afwImage.imagesOverlap(subim1a, subim1b), shouldOverlap)
152 self.assertEqual(afwImage.imagesOverlap(subim1b, subim1a), shouldOverlap)
154 subim2b = ImageClass2(image2, bboxb)
155 self.assertFalse(afwImage.imagesOverlap(subim1a, subim2b))
156 self.assertFalse(afwImage.imagesOverlap(subim2b, subim1a))
158 def testInitializeImages(self):
159 val = 666
160 for ctor in (afwImage.ImageU, afwImage.ImageI, afwImage.ImageF, afwImage.ImageD):
161 im = ctor(10, 10, val)
162 self.assertEqual(im[0, 0], val)
164 im2 = ctor(lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
165 lsst.geom.Extent2I(10, 10)), val)
166 self.assertEqual(im2[0, 0], val)
168 def testSetGetImages(self):
169 self.image1.setXY0(3, 4)
170 self.assertEqual(self.image1[0, 0, afwImage.LOCAL], self.val1)
171 self.assertEqual(self.image1[3, 4], self.val1)
172 self.image1[0, 0, afwImage.LOCAL] = 42.
173 self.assertEqual(self.image1[0, 0, afwImage.LOCAL], 42.)
174 self.assertEqual(self.image1[3, 4], 42.)
175 self.image1[3, 4] = self.val1
176 self.assertEqual(self.image1[0, 0, afwImage.LOCAL], self.val1)
177 self.assertEqual(self.image1[3, 4], self.val1)
179 def testAllocateLargeImages(self):
180 """Try to allocate a Very large image"""
181 bbox = lsst.geom.BoxI(lsst.geom.PointI(-1 << 30, -1 << 30),
182 lsst.geom.PointI(1 << 30, 1 << 30))
184 def tst():
185 afwImage.ImageF(bbox)
187 self.assertRaises(lsst.pex.exceptions.LengthError, tst)
189 def testAddImages(self):
190 self.image2 += self.image1
191 self.image1 += self.val1
193 self.assertEqual(self.image1[0, 0], 2*self.val1)
194 self.assertEqual(self.image2[0, 0], self.val1 + self.val2)
196 self.image1.set(self.val1)
197 self.image1 += self.function
199 for j in range(self.image1.getHeight()):
200 for i in range(self.image1.getWidth()):
201 self.assertEqual(self.image1[i, j],
202 self.val1 + self.function(i, j))
204 def testAssignWithBBox(self):
205 """Test assign(rhs, bbox) with non-empty bbox
206 """
207 for xy0 in (lsst.geom.Point2I(*val) for val in (
208 (0, 0),
209 (-100, 120), # an arbitrary value that is off the image
210 )):
211 destImDim = lsst.geom.Extent2I(5, 4)
212 srcImDim = lsst.geom.Extent2I(3, 2)
213 destIm = afwImage.ImageF(destImDim)
214 destIm.setXY0(xy0)
215 srcIm = makeRampImage(*srcImDim)
216 srcIm.setXY0(55, -33) # an arbitrary value that should be ignored
217 self.assertRaises(Exception, destIm.set, srcIm) # size mismatch
219 for validMin in (lsst.geom.Point2I(*val) for val in (
220 (0, 0),
221 (2, 0),
222 (0, 1),
223 (1, 2),
224 )):
225 # None to omit the argument
226 for origin in (None, afwImage.PARENT, afwImage.LOCAL):
227 destIm[:] = -1.0
228 bbox = lsst.geom.Box2I(validMin, srcIm.getDimensions())
229 if origin != afwImage.LOCAL:
230 bbox.shift(lsst.geom.Extent2I(xy0))
231 if origin is None:
232 destIm.assign(srcIm, bbox)
233 destImView = afwImage.ImageF(destIm, bbox)
234 else:
235 destIm.assign(srcIm, bbox, origin)
236 destImView = afwImage.ImageF(destIm, bbox, origin)
237 self.assertFloatsEqual(
238 destImView.getArray(), srcIm.getArray())
239 numPixNotAssigned = (destImDim[0] * destImDim[1]) - \
240 (srcImDim[0] * srcImDim[1])
241 self.assertEqual(
242 np.sum(destIm.getArray() < -0.5), numPixNotAssigned)
244 for badMin in (lsst.geom.Point2I(*val) + lsst.geom.Extent2I(xy0) for val in (
245 (-1, 0),
246 (3, 0),
247 (0, -1),
248 (1, 3),
249 )):
250 # None to omit the argument
251 for origin in (None, afwImage.PARENT, afwImage.LOCAL):
252 bbox = lsst.geom.Box2I(badMin, srcIm.getDimensions())
253 if origin != afwImage.LOCAL:
254 bbox.shift(lsst.geom.Extent2I(xy0))
255 if origin is None:
256 self.assertRaises(Exception, destIm.set, srcIm, bbox)
257 else:
258 self.assertRaises(
259 Exception, destIm.set, srcIm, bbox, origin)
261 def testAssignWithoutBBox(self):
262 """Test assign(rhs, [bbox]) with an empty bbox and with no bbox specified; both set all pixels
263 """
264 for xy0 in (lsst.geom.Point2I(*val) for val in (
265 (0, 0),
266 (-100, 120), # an arbitrary value that is off the image
267 )):
268 destImDim = lsst.geom.Extent2I(5, 4)
269 destIm = afwImage.ImageF(destImDim)
270 destIm.setXY0(xy0)
271 srcIm = makeRampImage(*destImDim)
272 srcIm.setXY0(55, -33) # an arbitrary value that should be ignored
274 destIm[:] = -1.0
275 destIm.assign(srcIm)
276 self.assertFloatsEqual(destIm.getArray(), srcIm.getArray())
278 destIm[:] = -1.0
279 destIm.assign(srcIm, lsst.geom.Box2I())
280 self.assertFloatsEqual(destIm.getArray(), srcIm.getArray())
282 def testAddScaledImages(self):
283 c = 10.0
284 self.image1.scaledPlus(c, self.image2)
286 self.assertEqual(self.image1[0, 0], self.val1 + c*self.val2)
288 def testSubtractImages(self):
289 self.image2 -= self.image1
290 self.image1 -= self.val1
292 self.assertEqual(self.image1[0, 0], 0)
293 self.assertEqual(self.image2[0, 0], self.val2 - self.val1)
295 self.image1.set(self.val1)
296 self.image1 -= self.function
298 for j in range(self.image1.getHeight()):
299 for i in range(self.image1.getWidth()):
300 self.assertEqual(self.image1[i, j],
301 self.val1 - self.function(i, j))
303 def testArithmeticImagesMismatch(self):
304 "Test arithmetic operations on Images of different sizes"
305 i1 = afwImage.ImageF(100, 100)
306 i1.set(100)
307 i2 = afwImage.ImageF(10, 10)
308 i2.set(10)
310 def tst1(i1, i2):
311 i1 -= i2
313 def tst2(i1, i2):
314 i1.scaledMinus(1.0, i2)
316 def tst3(i1, i2):
317 i1 += i2
319 def tst4(i1, i2):
320 i1.scaledPlus(1.0, i2)
322 def tst5(i1, i2):
323 i1 *= i2
325 def tst6(i1, i2):
326 i1.scaledMultiplies(1.0, i2)
328 def tst7(i1, i2):
329 i1 /= i2
331 def tst8(i1, i2):
332 i1.scaledDivides(1.0, i2)
334 tsts12 = [tst1, tst3, tst5, tst7]
335 for tst in tsts12:
336 self.assertRaises(lsst.pex.exceptions.LengthError, tst, i1, i2)
338 tsts21 = [tst2, tst4, tst6, tst8]
339 for tst in tsts21:
340 self.assertRaises(lsst.pex.exceptions.LengthError, tst, i2, i1)
342 def testSubtractScaledImages(self):
343 c = 10.0
344 self.image1.scaledMinus(c, self.image2)
346 self.assertEqual(self.image1[0, 0], self.val1 - c*self.val2)
348 def testMultiplyImages(self):
349 self.image2 *= self.image1
350 self.image1 *= self.val1
352 self.assertEqual(self.image1[0, 0], self.val1*self.val1)
353 self.assertEqual(self.image2[0, 0], self.val2*self.val1)
355 def testMultiplesScaledImages(self):
356 c = 10.0
357 self.image1.scaledMultiplies(c, self.image2)
359 self.assertEqual(self.image1[0, 0], self.val1 * c*self.val2)
361 def testDivideImages(self):
362 self.image2 /= self.image1
363 self.image1 /= self.val1
365 self.assertEqual(self.image1[0, 0], 1)
366 self.assertEqual(self.image2[0, 0], self.val2/self.val1)
368 def testDividesScaledImages(self):
369 c = 10.0
370 self.image1.scaledDivides(c, self.image2)
372 self.assertAlmostEqual(self.image1[0, 0], self.val1/(c*self.val2))
374 def testCopyConstructors(self):
375 dimage = afwImage.ImageF(self.image1, True) # deep copy
376 simage = afwImage.ImageF(self.image1) # shallow copy
378 self.image1 += 2 # should only change dimage
379 self.assertEqual(dimage[0, 0], self.val1)
380 self.assertEqual(simage[0, 0], self.val1 + 2)
382 def testGeneralisedCopyConstructors(self):
383 # these are generalised (templated) copy constructors in C++
384 imageU = self.image1.convertU()
385 imageF = imageU.convertF()
386 imageD = imageF.convertD()
388 self.assertEqual(imageU[0, 0], self.val1)
389 self.assertEqual(imageF[0, 0], self.val1)
390 self.assertEqual(imageD[0, 0], self.val1)
392 def checkImgPatch(self, img, x0=0, y0=0):
393 """Check that a patch of an image is correct; origin of patch is at (x0, y0)"""
395 self.assertEqual(img[x0 - 1, y0 - 1, afwImage.LOCAL], self.val1)
396 self.assertEqual(img[x0, y0, afwImage.LOCAL], 666)
397 self.assertEqual(img[x0 + 3, y0, afwImage.LOCAL], self.val1)
398 self.assertEqual(img[x0, y0 + 1, afwImage.LOCAL], 666)
399 self.assertEqual(img[x0 + 3, y0 + 1, afwImage.LOCAL], self.val1)
400 self.assertEqual(img[x0, y0 + 2, afwImage.LOCAL], self.val1)
402 def testOrigin(self):
403 """Check that we can set and read the origin"""
405 im = afwImage.ImageF(10, 20)
406 x0 = y0 = 0
408 self.assertEqual(im.getX0(), x0)
409 self.assertEqual(im.getY0(), y0)
410 self.assertEqual(im.getXY0(), lsst.geom.Point2I(x0, y0))
412 x0, y0 = 3, 5
413 im.setXY0(x0, y0)
414 self.assertEqual(im.getX0(), x0)
415 self.assertEqual(im.getY0(), y0)
416 self.assertEqual(im.getXY0(), lsst.geom.Point2I(x0, y0))
418 x0, y0 = 30, 50
419 im.setXY0(lsst.geom.Point2I(x0, y0))
420 self.assertEqual(im.getX0(), x0)
421 self.assertEqual(im.getY0(), y0)
422 self.assertEqual(im.getXY0(), lsst.geom.Point2I(x0, y0))
424 def testSubimages(self):
425 simage1 = afwImage.ImageF(
426 self.image1,
427 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(10, 5)),
428 afwImage.LOCAL)
430 simage = afwImage.ImageF(
431 simage1,
432 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(3, 2)),
433 afwImage.LOCAL
434 )
435 self.assertEqual(simage.getX0(), 2)
436 self.assertEqual(simage.getY0(), 2) # i.e. wrt self.image1
438 image2 = afwImage.ImageF(simage.getDimensions())
439 image2.set(666)
440 simage[:] = image2
441 del simage
442 del image2
444 self.checkImgPatch(self.image1, 2, 2)
445 self.checkImgPatch(simage1, 1, 1)
447 def testSubimages2(self):
448 """Test subimages when we've played with the (x0, y0) value"""
450 self.image1[9, 4] = 888
452 simage1 = afwImage.ImageF(
453 self.image1,
454 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(10, 5)),
455 afwImage.LOCAL
456 )
457 # reset origin; doesn't affect pixel coordinate systems
458 simage1.setXY0(lsst.geom.Point2I(0, 0))
460 simage = afwImage.ImageF(
461 simage1,
462 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(3, 2)),
463 afwImage.LOCAL
464 )
465 self.assertEqual(simage.getX0(), 1)
466 self.assertEqual(simage.getY0(), 1)
468 image2 = afwImage.ImageF(simage.getDimensions())
469 image2.set(666)
470 simage[:] = image2
471 del simage
472 del image2
474 self.checkImgPatch(self.image1, 2, 2)
475 self.checkImgPatch(simage1, 1, 1)
477 def testBadSubimages(self):
478 def tst():
479 afwImage.ImageF(
480 self.image1,
481 lsst.geom.Box2I(lsst.geom.Point2I(1, -1), lsst.geom.Extent2I(10, 5)),
482 afwImage.LOCAL
483 )
485 self.assertRaises(lsst.pex.exceptions.LengthError, tst)
487 def testImageInitialisation(self):
488 dims = self.image1.getDimensions()
489 factory = self.image1.Factory
491 self.image1.set(666)
493 del self.image1 # tempt C++ to reuse the memory
494 self.image1 = factory(dims)
495 self.assertEqual(self.image1[10, 10], 0)
497 def testImageSlicesOrigin(self):
498 """Test image slicing, which generate sub-images using Box2I under the covers"""
499 im = afwImage.ImageF(10, 20)
500 im.setXY0(50, 100)
501 im[54, 110] = 10
502 im[-3:, -2:, afwImage.LOCAL] = 100
503 im[-2, -2, afwImage.LOCAL] = -10
504 sim = im[51:54, 106:110]
505 sim[:] = -1
506 im[50:54, 100:104] = im[2:6, 8:12, afwImage.LOCAL]
508 if display:
509 afwDisplay.Display(frame=1).mtv(im, title="testImageSlicesOrigin")
511 self.assertEqual(im[0, 6, afwImage.LOCAL], 0)
512 self.assertEqual(im[6, 17, afwImage.LOCAL], 0)
513 self.assertEqual(im[7, 18, afwImage.LOCAL], 100)
514 self.assertEqual(im[9, 19, afwImage.LOCAL], 100)
515 self.assertEqual(im[8, 18, afwImage.LOCAL], -10)
516 self.assertEqual(im[1, 6, afwImage.LOCAL], -1)
517 self.assertEqual(im[3, 9, afwImage.LOCAL], -1)
518 self.assertEqual(im[4, 10, afwImage.LOCAL], 10)
519 self.assertEqual(im[4, 9, afwImage.LOCAL], 0)
520 self.assertEqual(im[2, 2, afwImage.LOCAL], 10)
521 self.assertEqual(im[0, 0, afwImage.LOCAL], -1)
523 def testImageSliceFromBox(self):
524 """Test using a Box2I to index an Image"""
525 im = afwImage.ImageF(10, 20)
526 bbox = lsst.geom.BoxI(lsst.geom.PointI(1, 3), lsst.geom.PointI(6, 9))
527 im[bbox] = -1
529 if display:
530 afwDisplay.Display(frame=0).mtv(im, title="testImageSliceFromBox")
532 self.assertEqual(im[0, 6], 0)
533 self.assertEqual(im[1, 6], -1)
534 self.assertEqual(im[3, 9], -1)
536 def testImageSliceFromBoxOrigin(self):
537 """Test using a Box2I to index an Image"""
538 im = afwImage.ImageF(10, 20)
539 im.setXY0(50, 100)
540 bbox = lsst.geom.BoxI(lsst.geom.PointI(51, 103), lsst.geom.ExtentI(6, 7))
541 im[bbox] = -1
543 if display:
544 afwDisplay.Display(frame=2).mtv(im, title="testImageSliceFromBoxOrigin")
546 self.assertEqual(im[0, 6, afwImage.LOCAL], 0)
547 self.assertEqual(im[1, 6, afwImage.LOCAL], -1)
548 self.assertEqual(im[3, 9, afwImage.LOCAL], -1)
550 def testClone(self):
551 """Test that clone works properly"""
552 im = afwImage.ImageF(10, 20)
553 im[0, 0] = 100
555 im2 = im.clone() # check that clone with no arguments makes a deep copy
556 self.assertEqual(im.getDimensions(), im2.getDimensions())
557 self.assertEqual(im[0, 0], im2[0, 0])
558 im2[0, 0] += 100
559 self.assertNotEqual(im[0, 0], im2[0, 0]) # so it's a deep copy
561 im2 = im[0:3, 0:5].clone() # check that we can slice-then-clone
562 self.assertEqual(im2.getDimensions(), lsst.geom.ExtentI(3, 5))
563 self.assertEqual(im[0, 0], im2[0, 0])
564 im2[0, 0] += 10
565 self.assertNotEqual(float(im[0, 0]), float(im2[0, 0]))
567 def testString(self):
568 imageF = afwImage.ImageF(100, 100)
569 imageDSmall = afwImage.ImageD(2, 2)
570 imageISmall = afwImage.ImageI(2, 2)
571 imageU = afwImage.ImageU(100, 100)
573 # NumPy's string representation varies depending on the size of the
574 # array; we test both large and small.
575 self.assertIn(str(np.zeros((100, 100), dtype=imageF.dtype)), str(imageF))
576 self.assertIn(f"bbox={imageF.getBBox()}", str(imageF))
578 self.assertIn(str(np.zeros((2, 2), dtype=imageDSmall.dtype)), str(imageDSmall))
579 self.assertIn(str(np.zeros((2, 2), dtype=imageISmall.dtype)), str(imageISmall))
581 self.assertIn("ImageF=", repr(imageF))
582 self.assertIn("ImageU=", repr(imageU))
585class DecoratedImageTestCase(lsst.utils.tests.TestCase):
586 """A test case for DecoratedImage"""
588 def setUp(self):
589 np.random.seed(1)
590 self.val1, self.val2 = 10, 100
591 self.width, self.height = 200, 100
592 self.dimage1 = afwImage.DecoratedImageF(
593 lsst.geom.Extent2I(self.width, self.height)
594 )
595 self.dimage1.image.set(self.val1)
597 if afwdataDir is not None:
598 self.fileForMetadata = os.path.join(
599 afwdataDir, "data", "small_MI.fits")
600 self.trueMetadata = {"RELHUMID": 10.69}
602 def tearDown(self):
603 del self.dimage1
605 def testCreateDecoratedImage(self):
606 self.assertEqual(self.dimage1.getWidth(), self.width)
607 self.assertEqual(self.dimage1.getHeight(), self.height)
608 self.assertEqual(self.dimage1.image[0, 0], self.val1)
610 def testCreateDecoratedImageFromImage(self):
611 image = afwImage.ImageF(lsst.geom.Extent2I(self.width, self.height))
612 image[:] = self.dimage1.image
614 dimage = afwImage.DecoratedImageF(image)
615 self.assertEqual(dimage.getWidth(), self.width)
616 self.assertEqual(dimage.getHeight(), self.height)
617 self.assertEqual(dimage.image[0, 0], self.val1)
619 def testCopyConstructors(self):
620 dimage = afwImage.DecoratedImageF(self.dimage1, True) # deep copy
621 self.dimage1.image[0, 0] = 1 + 2*self.val1
622 self.assertEqual(dimage.image[0, 0], self.val1)
624 dimage = afwImage.DecoratedImageF(self.dimage1) # shallow copy
625 self.dimage1.image[0, 0] = 1 + 2*self.val1
626 self.assertNotEqual(dimage.image[0, 0], self.val1)
628 @unittest.skipIf(afwdataDir is None, "afwdata not setup")
629 def testReadFits(self):
630 """Test reading FITS files"""
632 hdus = {}
633 hdus["img"] = 1 # an S16 fits HDU
634 hdus["msk"] = 2 # an U8 fits HDU
635 hdus["var"] = 3 # an F32 fits HDU
637 # read as unsigned short
638 imgU = afwImage.DecoratedImageU(self.fileForMetadata, hdus["img"], allowUnsafe=True)
639 # read as float
640 imgF = afwImage.DecoratedImageF(self.fileForMetadata, hdus["img"])
642 self.assertEqual(imgU.getHeight(), 256)
643 self.assertEqual(imgF.image.getWidth(), 256)
644 self.assertEqual(imgU.image[0, 0, afwImage.LOCAL], imgF.image[0, 0, afwImage.LOCAL])
645 #
646 # Check the metadata
647 #
648 meta = self.trueMetadata
649 for k in meta.keys():
650 self.assertEqual(imgU.getMetadata().getAsDouble(k), meta[k])
651 self.assertEqual(imgF.getMetadata().getAsDouble(k), meta[k])
652 #
653 # Read an F32 image
654 #
655 # read as unsigned short
656 varU = afwImage.DecoratedImageF(self.fileForMetadata, hdus["var"])
657 # read as float
658 varF = afwImage.DecoratedImageF(self.fileForMetadata, hdus["var"])
660 self.assertEqual(varU.getHeight(), 256)
661 self.assertEqual(varF.image.getWidth(), 256)
662 self.assertEqual(varU.image[0, 0, afwImage.LOCAL], varF.image[0, 0, afwImage.LOCAL])
663 #
664 # Read a char image
665 #
666 maskImg = afwImage.DecoratedImageU(
667 self.fileForMetadata, hdus["msk"]).image # read a char file
669 self.assertEqual(maskImg.getHeight(), 256)
670 self.assertEqual(maskImg.getWidth(), 256)
671 self.assertEqual(maskImg[0, 0, afwImage.LOCAL], 1)
672 #
673 # Read a U16 image
674 #
675 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
676 imgU.writeFits(tmpFile)
678 afwImage.DecoratedImageF(tmpFile) # read as unsigned short
680 @unittest.skipIf(afwdataDir is None, "afwdata not setup")
681 def testWriteFits(self):
682 """Test writing FITS files"""
684 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
685 if self.fileForMetadata:
686 imgU = afwImage.DecoratedImageF(self.fileForMetadata)
687 else:
688 imgU = afwImage.DecoratedImageF()
690 self.dimage1.writeFits(tmpFile, imgU.getMetadata())
691 #
692 # Read it back
693 #
694 rimage = afwImage.DecoratedImageF(tmpFile)
696 self.assertEqual(self.dimage1.image[0, 0, afwImage.LOCAL],
697 rimage.image[0, 0, afwImage.LOCAL])
698 #
699 # Check that we wrote (and read) the metadata successfully
700 if self.fileForMetadata:
701 meta = self.trueMetadata
702 for k in meta.keys():
703 self.assertEqual(
704 rimage.getMetadata().getAsDouble(k), meta[k])
706 def testReadWriteXY0(self):
707 """Test that we read and write (X0, Y0) correctly"""
708 im = afwImage.ImageF(lsst.geom.Extent2I(10, 20))
710 x0, y0 = 1, 2
711 im.setXY0(x0, y0)
712 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
713 im.writeFits(tmpFile)
715 im2 = im.Factory(tmpFile)
717 self.assertEqual(im2.getX0(), x0)
718 self.assertEqual(im2.getY0(), y0)
720 @unittest.skipIf(afwdataDir is None, "afwdata not setup")
721 def testReadMetadata(self):
722 im = afwImage.DecoratedImageF(self.fileForMetadata)
724 meta = readMetadata(self.fileForMetadata)
725 self.assertIn("NAXIS1", meta.names())
726 self.assertEqual(im.getWidth(), meta.getScalar("NAXIS1"))
727 self.assertEqual(im.getHeight(), meta.getScalar("NAXIS2"))
729 def testTicket1040(self):
730 """ How to repeat from #1040"""
731 image = afwImage.ImageD(lsst.geom.Extent2I(6, 6))
732 image[2, 2] = 100
734 bbox = lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(5, 5))
735 subImage = image.Factory(image, bbox)
736 subImageF = subImage.convertFloat()
738 if display:
739 afwDisplay.Display(frame=0).mtv(subImage, title="subImage")
740 afwDisplay.Display(frame=1).mtv(subImageF, title="converted subImage")
742 self.assertEqual(subImage[1, 1, afwImage.LOCAL], subImageF[1, 1, afwImage.LOCAL])
744 def testDM882(self):
745 """Test that we can write a dotted header unit to a FITS file. See DM-882."""
746 self.dimage1.getMetadata().add("A.B.C.D", 12345)
747 tempdir = tempfile.mkdtemp()
748 testfile = os.path.join(tempdir, "test.fits")
749 try:
750 self.dimage1.writeFits(testfile)
751 meta = readMetadata(testfile)
752 self.assertEqual(meta.getScalar("A.B.C.D"), 12345)
753 finally:
754 shutil.rmtree(tempdir)
756 def testLargeImage(self):
757 """Test that creating an extremely large image raises, rather than segfaulting. DM-89, -527."""
758 for imtype in (afwImage.ImageD, afwImage.ImageF, afwImage.ImageI, afwImage.ImageU):
759 self.assertRaises(lsst.pex.exceptions.LengthError,
760 imtype, 60000, 60000)
763def printImg(img):
764 print("%4s " % "", end=' ')
765 for c in range(img.getWidth()):
766 print("%7d" % c, end=' ')
767 print()
769 for r in range(img.getHeight() - 1, -1, -1):
770 print("%4d " % r, end=' ')
771 for c in range(img.getWidth()):
772 print("%7.1f" % float(img[c, r, afwImage.LOCAL]), end=' ')
773 print()
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()