Coverage for tests/test_image.py : 14%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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
48import lsst.pex.exceptions as pexExcept
50try:
51 afwdataDir = lsst.utils.getPackageDir("afwdata")
52except pexExcept.NotFoundError:
53 afwdataDir = None
55try:
56 type(display)
57except NameError:
58 display = False
61def makeRampImage(width, height, imgClass=afwImage.ImageF):
62 """Make a ramp image of the specified size and image class
64 Values start from 0 at the lower left corner and increase by 1 along rows
65 """
66 im = imgClass(width, height)
67 val = 0
68 for yInd in range(height):
69 for xInd in range(width):
70 im[xInd, yInd] = val
71 val += 1
72 return im
75class ImageTestCase(lsst.utils.tests.TestCase):
76 """A test case for Image"""
78 def setUp(self):
79 np.random.seed(1)
80 self.val1, self.val2 = 10, 100
81 self.image1 = afwImage.ImageF(lsst.geom.ExtentI(100, 200))
82 self.image1.set(self.val1)
83 self.image2 = afwImage.ImageF(self.image1.getDimensions())
84 self.image2.set(self.val2)
85 self.function = afwMath.PolynomialFunction2D(2)
86 self.function.setParameters(
87 list(range(self.function.getNParameters())))
89 def tearDown(self):
90 del self.image1
91 del self.image2
92 del self.function
94 def testArrays(self):
95 for cls in (afwImage.ImageU, afwImage.ImageI, afwImage.ImageF, afwImage.ImageD):
96 image1 = cls(lsst.geom.Extent2I(5, 6))
97 array1 = image1.getArray()
98 self.assertEqual(array1.shape[0], image1.getHeight())
99 self.assertEqual(array1.shape[1], image1.getWidth())
100 image2 = cls(array1, False)
101 self.assertEqual(array1.shape[0], image2.getHeight())
102 self.assertEqual(array1.shape[1], image2.getWidth())
103 image3 = afwImage.makeImageFromArray(array1)
104 self.assertEqual(array1.shape[0], image2.getHeight())
105 self.assertEqual(array1.shape[1], image2.getWidth())
106 self.assertEqual(type(image3), cls)
107 array2 = image1.array
108 np.testing.assert_array_equal(array1, array2)
109 array1[:, :] = np.random.uniform(low=0, high=10, size=array1.shape)
110 for j in range(image1.getHeight()):
111 for i in range(image1.getWidth()):
112 self.assertEqual(image1[i, j, afwImage.LOCAL], array1[j, i])
113 self.assertEqual(image2[i, j, afwImage.LOCAL], array1[j, i])
114 array3 = np.random.uniform(low=0, high=10,
115 size=array1.shape).astype(array1.dtype)
116 image1.array[:] = array3
117 np.testing.assert_array_equal(array1, array3)
118 image1.array[2:4, 3:] = 10
119 np.testing.assert_array_equal(array1[2:4, 3:], 10)
120 array4 = image1.array.copy()
121 array4 += 5
122 image1.array += 5
123 np.testing.assert_array_equal(image1.array, array4)
125 def testImagesOverlap(self):
126 dim = lsst.geom.Extent2I(10, 8)
127 # a set of bounding boxes, some of which overlap each other
128 # and some of which do not, and include the full image bounding box
129 bboxes = (
130 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), dim),
131 lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(3, 3)),
132 lsst.geom.Box2I(lsst.geom.Point2I(2, 2), lsst.geom.Extent2I(6, 4)),
133 lsst.geom.Box2I(lsst.geom.Point2I(4, 4), lsst.geom.Extent2I(6, 4)),
134 )
136 imageClasses = (afwImage.ImageF, afwImage.ImageD, afwImage.ImageI, afwImage.Mask)
138 for ImageClass1, ImageClass2 in itertools.product(imageClasses, imageClasses):
139 with self.subTest(ImageClass1=ImageClass1, ImageClass2=ImageClass2):
140 image1 = ImageClass1(dim)
141 self.assertTrue(afwImage.imagesOverlap(image1, image1))
143 image2 = ImageClass2(dim)
144 self.assertFalse(afwImage.imagesOverlap(image1, image2))
145 self.assertFalse(afwImage.imagesOverlap(image2, image1))
147 for bboxa, bboxb in itertools.product(bboxes, bboxes):
148 shouldOverlap = bboxa.overlaps(bboxb)
149 with self.subTest(bboxa=bboxa, bboxb=bboxb):
150 subim1a = ImageClass1(image1, bboxa)
151 subim1b = ImageClass1(image1, bboxb)
152 self.assertEqual(afwImage.imagesOverlap(subim1a, subim1b), shouldOverlap)
153 self.assertEqual(afwImage.imagesOverlap(subim1b, subim1a), shouldOverlap)
155 subim2b = ImageClass2(image2, bboxb)
156 self.assertFalse(afwImage.imagesOverlap(subim1a, subim2b))
157 self.assertFalse(afwImage.imagesOverlap(subim2b, subim1a))
159 def testInitializeImages(self):
160 val = 666
161 for ctor in (afwImage.ImageU, afwImage.ImageI, afwImage.ImageF, afwImage.ImageD):
162 im = ctor(10, 10, val)
163 self.assertEqual(im[0, 0], val)
165 im2 = ctor(lsst.geom.Box2I(lsst.geom.Point2I(0, 0),
166 lsst.geom.Extent2I(10, 10)), val)
167 self.assertEqual(im2[0, 0], val)
169 def testSetGetImages(self):
170 self.image1.setXY0(3, 4)
171 self.assertEqual(self.image1[0, 0, afwImage.LOCAL], self.val1)
172 self.assertEqual(self.image1[3, 4], self.val1)
173 self.image1[0, 0, afwImage.LOCAL] = 42.
174 self.assertEqual(self.image1[0, 0, afwImage.LOCAL], 42.)
175 self.assertEqual(self.image1[3, 4], 42.)
176 self.image1[3, 4] = self.val1
177 self.assertEqual(self.image1[0, 0, afwImage.LOCAL], self.val1)
178 self.assertEqual(self.image1[3, 4], self.val1)
180 def testAllocateLargeImages(self):
181 """Try to allocate a Very large image"""
182 bbox = lsst.geom.BoxI(lsst.geom.PointI(-1 << 30, -1 << 30),
183 lsst.geom.PointI(1 << 30, 1 << 30))
185 def tst():
186 afwImage.ImageF(bbox)
188 self.assertRaises(lsst.pex.exceptions.LengthError, tst)
190 def testAddImages(self):
191 self.image2 += self.image1
192 self.image1 += self.val1
194 self.assertEqual(self.image1[0, 0], 2*self.val1)
195 self.assertEqual(self.image2[0, 0], self.val1 + self.val2)
197 self.image1.set(self.val1)
198 self.image1 += self.function
200 for j in range(self.image1.getHeight()):
201 for i in range(self.image1.getWidth()):
202 self.assertEqual(self.image1[i, j],
203 self.val1 + self.function(i, j))
205 def testAssignWithBBox(self):
206 """Test assign(rhs, bbox) with non-empty bbox
207 """
208 for xy0 in (lsst.geom.Point2I(*val) for val in (
209 (0, 0),
210 (-100, 120), # an arbitrary value that is off the image
211 )):
212 destImDim = lsst.geom.Extent2I(5, 4)
213 srcImDim = lsst.geom.Extent2I(3, 2)
214 destIm = afwImage.ImageF(destImDim)
215 destIm.setXY0(xy0)
216 srcIm = makeRampImage(*srcImDim)
217 srcIm.setXY0(55, -33) # an arbitrary value that should be ignored
218 self.assertRaises(Exception, destIm.set, srcIm) # size mismatch
220 for validMin in (lsst.geom.Point2I(*val) for val in (
221 (0, 0),
222 (2, 0),
223 (0, 1),
224 (1, 2),
225 )):
226 # None to omit the argument
227 for origin in (None, afwImage.PARENT, afwImage.LOCAL):
228 destIm[:] = -1.0
229 bbox = lsst.geom.Box2I(validMin, srcIm.getDimensions())
230 if origin != afwImage.LOCAL:
231 bbox.shift(lsst.geom.Extent2I(xy0))
232 if origin is None:
233 destIm.assign(srcIm, bbox)
234 destImView = afwImage.ImageF(destIm, bbox)
235 else:
236 destIm.assign(srcIm, bbox, origin)
237 destImView = afwImage.ImageF(destIm, bbox, origin)
238 self.assertFloatsEqual(
239 destImView.getArray(), srcIm.getArray())
240 numPixNotAssigned = (destImDim[0] * destImDim[1]) - \
241 (srcImDim[0] * srcImDim[1])
242 self.assertEqual(
243 np.sum(destIm.getArray() < -0.5), numPixNotAssigned)
245 for badMin in (lsst.geom.Point2I(*val) + lsst.geom.Extent2I(xy0) for val in (
246 (-1, 0),
247 (3, 0),
248 (0, -1),
249 (1, 3),
250 )):
251 # None to omit the argument
252 for origin in (None, afwImage.PARENT, afwImage.LOCAL):
253 bbox = lsst.geom.Box2I(badMin, srcIm.getDimensions())
254 if origin != afwImage.LOCAL:
255 bbox.shift(lsst.geom.Extent2I(xy0))
256 if origin is None:
257 self.assertRaises(Exception, destIm.set, srcIm, bbox)
258 else:
259 self.assertRaises(
260 Exception, destIm.set, srcIm, bbox, origin)
262 def testAssignWithoutBBox(self):
263 """Test assign(rhs, [bbox]) with an empty bbox and with no bbox specified; both set all pixels
264 """
265 for xy0 in (lsst.geom.Point2I(*val) for val in (
266 (0, 0),
267 (-100, 120), # an arbitrary value that is off the image
268 )):
269 destImDim = lsst.geom.Extent2I(5, 4)
270 destIm = afwImage.ImageF(destImDim)
271 destIm.setXY0(xy0)
272 srcIm = makeRampImage(*destImDim)
273 srcIm.setXY0(55, -33) # an arbitrary value that should be ignored
275 destIm[:] = -1.0
276 destIm.assign(srcIm)
277 self.assertFloatsEqual(destIm.getArray(), srcIm.getArray())
279 destIm[:] = -1.0
280 destIm.assign(srcIm, lsst.geom.Box2I())
281 self.assertFloatsEqual(destIm.getArray(), srcIm.getArray())
283 def testAddScaledImages(self):
284 c = 10.0
285 self.image1.scaledPlus(c, self.image2)
287 self.assertEqual(self.image1[0, 0], self.val1 + c*self.val2)
289 def testSubtractImages(self):
290 self.image2 -= self.image1
291 self.image1 -= self.val1
293 self.assertEqual(self.image1[0, 0], 0)
294 self.assertEqual(self.image2[0, 0], self.val2 - self.val1)
296 self.image1.set(self.val1)
297 self.image1 -= self.function
299 for j in range(self.image1.getHeight()):
300 for i in range(self.image1.getWidth()):
301 self.assertEqual(self.image1[i, j],
302 self.val1 - self.function(i, j))
304 def testArithmeticImagesMismatch(self):
305 "Test arithmetic operations on Images of different sizes"
306 i1 = afwImage.ImageF(100, 100)
307 i1.set(100)
308 i2 = afwImage.ImageF(10, 10)
309 i2.set(10)
311 def tst1(i1, i2):
312 i1 -= i2
314 def tst2(i1, i2):
315 i1.scaledMinus(1.0, i2)
317 def tst3(i1, i2):
318 i1 += i2
320 def tst4(i1, i2):
321 i1.scaledPlus(1.0, i2)
323 def tst5(i1, i2):
324 i1 *= i2
326 def tst6(i1, i2):
327 i1.scaledMultiplies(1.0, i2)
329 def tst7(i1, i2):
330 i1 /= i2
332 def tst8(i1, i2):
333 i1.scaledDivides(1.0, i2)
335 tsts12 = [tst1, tst3, tst5, tst7]
336 for tst in tsts12:
337 self.assertRaises(lsst.pex.exceptions.LengthError, tst, i1, i2)
339 tsts21 = [tst2, tst4, tst6, tst8]
340 for tst in tsts21:
341 self.assertRaises(lsst.pex.exceptions.LengthError, tst, i2, i1)
343 def testSubtractScaledImages(self):
344 c = 10.0
345 self.image1.scaledMinus(c, self.image2)
347 self.assertEqual(self.image1[0, 0], self.val1 - c*self.val2)
349 def testMultiplyImages(self):
350 self.image2 *= self.image1
351 self.image1 *= self.val1
353 self.assertEqual(self.image1[0, 0], self.val1*self.val1)
354 self.assertEqual(self.image2[0, 0], self.val2*self.val1)
356 def testMultiplesScaledImages(self):
357 c = 10.0
358 self.image1.scaledMultiplies(c, self.image2)
360 self.assertEqual(self.image1[0, 0], self.val1 * c*self.val2)
362 def testDivideImages(self):
363 self.image2 /= self.image1
364 self.image1 /= self.val1
366 self.assertEqual(self.image1[0, 0], 1)
367 self.assertEqual(self.image2[0, 0], self.val2/self.val1)
369 def testDividesScaledImages(self):
370 c = 10.0
371 self.image1.scaledDivides(c, self.image2)
373 self.assertAlmostEqual(self.image1[0, 0], self.val1/(c*self.val2))
375 def testCopyConstructors(self):
376 dimage = afwImage.ImageF(self.image1, True) # deep copy
377 simage = afwImage.ImageF(self.image1) # shallow copy
379 self.image1 += 2 # should only change dimage
380 self.assertEqual(dimage[0, 0], self.val1)
381 self.assertEqual(simage[0, 0], self.val1 + 2)
383 def testGeneralisedCopyConstructors(self):
384 # these are generalised (templated) copy constructors in C++
385 imageU = self.image1.convertU()
386 imageF = imageU.convertF()
387 imageD = imageF.convertD()
389 self.assertEqual(imageU[0, 0], self.val1)
390 self.assertEqual(imageF[0, 0], self.val1)
391 self.assertEqual(imageD[0, 0], self.val1)
393 def checkImgPatch(self, img, x0=0, y0=0):
394 """Check that a patch of an image is correct; origin of patch is at (x0, y0)"""
396 self.assertEqual(img[x0 - 1, y0 - 1, afwImage.LOCAL], self.val1)
397 self.assertEqual(img[x0, y0, afwImage.LOCAL], 666)
398 self.assertEqual(img[x0 + 3, y0, afwImage.LOCAL], self.val1)
399 self.assertEqual(img[x0, y0 + 1, afwImage.LOCAL], 666)
400 self.assertEqual(img[x0 + 3, y0 + 1, afwImage.LOCAL], self.val1)
401 self.assertEqual(img[x0, y0 + 2, afwImage.LOCAL], self.val1)
403 def testOrigin(self):
404 """Check that we can set and read the origin"""
406 im = afwImage.ImageF(10, 20)
407 x0 = y0 = 0
409 self.assertEqual(im.getX0(), x0)
410 self.assertEqual(im.getY0(), y0)
411 self.assertEqual(im.getXY0(), lsst.geom.Point2I(x0, y0))
413 x0, y0 = 3, 5
414 im.setXY0(x0, y0)
415 self.assertEqual(im.getX0(), x0)
416 self.assertEqual(im.getY0(), y0)
417 self.assertEqual(im.getXY0(), lsst.geom.Point2I(x0, y0))
419 x0, y0 = 30, 50
420 im.setXY0(lsst.geom.Point2I(x0, y0))
421 self.assertEqual(im.getX0(), x0)
422 self.assertEqual(im.getY0(), y0)
423 self.assertEqual(im.getXY0(), lsst.geom.Point2I(x0, y0))
425 def testSubimages(self):
426 simage1 = afwImage.ImageF(
427 self.image1,
428 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(10, 5)),
429 afwImage.LOCAL)
431 simage = afwImage.ImageF(
432 simage1,
433 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(3, 2)),
434 afwImage.LOCAL
435 )
436 self.assertEqual(simage.getX0(), 2)
437 self.assertEqual(simage.getY0(), 2) # i.e. wrt self.image1
439 image2 = afwImage.ImageF(simage.getDimensions())
440 image2.set(666)
441 simage[:] = image2
442 del simage
443 del image2
445 self.checkImgPatch(self.image1, 2, 2)
446 self.checkImgPatch(simage1, 1, 1)
448 def testSubimages2(self):
449 """Test subimages when we've played with the (x0, y0) value"""
451 self.image1[9, 4] = 888
453 simage1 = afwImage.ImageF(
454 self.image1,
455 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(10, 5)),
456 afwImage.LOCAL
457 )
458 # reset origin; doesn't affect pixel coordinate systems
459 simage1.setXY0(lsst.geom.Point2I(0, 0))
461 simage = afwImage.ImageF(
462 simage1,
463 lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(3, 2)),
464 afwImage.LOCAL
465 )
466 self.assertEqual(simage.getX0(), 1)
467 self.assertEqual(simage.getY0(), 1)
469 image2 = afwImage.ImageF(simage.getDimensions())
470 image2.set(666)
471 simage[:] = image2
472 del simage
473 del image2
475 self.checkImgPatch(self.image1, 2, 2)
476 self.checkImgPatch(simage1, 1, 1)
478 def testBadSubimages(self):
479 def tst():
480 afwImage.ImageF(
481 self.image1,
482 lsst.geom.Box2I(lsst.geom.Point2I(1, -1), lsst.geom.Extent2I(10, 5)),
483 afwImage.LOCAL
484 )
486 self.assertRaises(lsst.pex.exceptions.LengthError, tst)
488 def testImageInitialisation(self):
489 dims = self.image1.getDimensions()
490 factory = self.image1.Factory
492 self.image1.set(666)
494 del self.image1 # tempt C++ to reuse the memory
495 self.image1 = factory(dims)
496 self.assertEqual(self.image1[10, 10], 0)
498 def testImageSlicesOrigin(self):
499 """Test image slicing, which generate sub-images using Box2I under the covers"""
500 im = afwImage.ImageF(10, 20)
501 im.setXY0(50, 100)
502 im[54, 110] = 10
503 im[-3:, -2:, afwImage.LOCAL] = 100
504 im[-2, -2, afwImage.LOCAL] = -10
505 sim = im[51:54, 106:110]
506 sim[:] = -1
507 im[50:54, 100:104] = im[2:6, 8:12, afwImage.LOCAL]
509 if display:
510 afwDisplay.Display(frame=1).mtv(im, title="testImageSlicesOrigin")
512 self.assertEqual(im[0, 6, afwImage.LOCAL], 0)
513 self.assertEqual(im[6, 17, afwImage.LOCAL], 0)
514 self.assertEqual(im[7, 18, afwImage.LOCAL], 100)
515 self.assertEqual(im[9, 19, afwImage.LOCAL], 100)
516 self.assertEqual(im[8, 18, afwImage.LOCAL], -10)
517 self.assertEqual(im[1, 6, afwImage.LOCAL], -1)
518 self.assertEqual(im[3, 9, afwImage.LOCAL], -1)
519 self.assertEqual(im[4, 10, afwImage.LOCAL], 10)
520 self.assertEqual(im[4, 9, afwImage.LOCAL], 0)
521 self.assertEqual(im[2, 2, afwImage.LOCAL], 10)
522 self.assertEqual(im[0, 0, afwImage.LOCAL], -1)
524 def testImageSliceFromBox(self):
525 """Test using a Box2I to index an Image"""
526 im = afwImage.ImageF(10, 20)
527 bbox = lsst.geom.BoxI(lsst.geom.PointI(1, 3), lsst.geom.PointI(6, 9))
528 im[bbox] = -1
530 if display:
531 afwDisplay.Display(frame=0).mtv(im, title="testImageSliceFromBox")
533 self.assertEqual(im[0, 6], 0)
534 self.assertEqual(im[1, 6], -1)
535 self.assertEqual(im[3, 9], -1)
537 def testImageSliceFromBoxOrigin(self):
538 """Test using a Box2I to index an Image"""
539 im = afwImage.ImageF(10, 20)
540 im.setXY0(50, 100)
541 bbox = lsst.geom.BoxI(lsst.geom.PointI(51, 103), lsst.geom.ExtentI(6, 7))
542 im[bbox] = -1
544 if display:
545 afwDisplay.Display(frame=2).mtv(im, title="testImageSliceFromBoxOrigin")
547 self.assertEqual(im[0, 6, afwImage.LOCAL], 0)
548 self.assertEqual(im[1, 6, afwImage.LOCAL], -1)
549 self.assertEqual(im[3, 9, afwImage.LOCAL], -1)
551 def testClone(self):
552 """Test that clone works properly"""
553 im = afwImage.ImageF(10, 20)
554 im[0, 0] = 100
556 im2 = im.clone() # check that clone with no arguments makes a deep copy
557 self.assertEqual(im.getDimensions(), im2.getDimensions())
558 self.assertEqual(im[0, 0], im2[0, 0])
559 im2[0, 0] += 100
560 self.assertNotEqual(im[0, 0], im2[0, 0]) # so it's a deep copy
562 im2 = im[0:3, 0:5].clone() # check that we can slice-then-clone
563 self.assertEqual(im2.getDimensions(), lsst.geom.ExtentI(3, 5))
564 self.assertEqual(im[0, 0], im2[0, 0])
565 im2[0, 0] += 10
566 self.assertNotEqual(float(im[0, 0]), float(im2[0, 0]))
568 def testString(self):
569 imageF = afwImage.ImageF(100, 100)
570 imageDSmall = afwImage.ImageD(2, 2)
571 imageISmall = afwImage.ImageI(2, 2)
572 imageU = afwImage.ImageU(100, 100)
574 # NumPy's string representation varies depending on the size of the
575 # array; we test both large and small.
576 self.assertIn(str(np.zeros((100, 100), dtype=imageF.dtype)), str(imageF))
577 self.assertIn(f"bbox={imageF.getBBox()}", str(imageF))
579 self.assertIn(str(np.zeros((2, 2), dtype=imageDSmall.dtype)), str(imageDSmall))
580 self.assertIn(str(np.zeros((2, 2), dtype=imageISmall.dtype)), str(imageISmall))
582 self.assertIn("ImageF=", repr(imageF))
583 self.assertIn("ImageU=", repr(imageU))
586class DecoratedImageTestCase(lsst.utils.tests.TestCase):
587 """A test case for DecoratedImage"""
589 def setUp(self):
590 np.random.seed(1)
591 self.val1, self.val2 = 10, 100
592 self.width, self.height = 200, 100
593 self.dimage1 = afwImage.DecoratedImageF(
594 lsst.geom.Extent2I(self.width, self.height)
595 )
596 self.dimage1.image.set(self.val1)
598 if afwdataDir is not None:
599 self.fileForMetadata = os.path.join(
600 afwdataDir, "data", "small_MI.fits")
601 self.trueMetadata = {"RELHUMID": 10.69}
603 def tearDown(self):
604 del self.dimage1
606 def testCreateDecoratedImage(self):
607 self.assertEqual(self.dimage1.getWidth(), self.width)
608 self.assertEqual(self.dimage1.getHeight(), self.height)
609 self.assertEqual(self.dimage1.image[0, 0], self.val1)
611 def testCreateDecoratedImageFromImage(self):
612 image = afwImage.ImageF(lsst.geom.Extent2I(self.width, self.height))
613 image[:] = self.dimage1.image
615 dimage = afwImage.DecoratedImageF(image)
616 self.assertEqual(dimage.getWidth(), self.width)
617 self.assertEqual(dimage.getHeight(), self.height)
618 self.assertEqual(dimage.image[0, 0], self.val1)
620 def testCopyConstructors(self):
621 dimage = afwImage.DecoratedImageF(self.dimage1, True) # deep copy
622 self.dimage1.image[0, 0] = 1 + 2*self.val1
623 self.assertEqual(dimage.image[0, 0], self.val1)
625 dimage = afwImage.DecoratedImageF(self.dimage1) # shallow copy
626 self.dimage1.image[0, 0] = 1 + 2*self.val1
627 self.assertNotEqual(dimage.image[0, 0], self.val1)
629 @unittest.skipIf(afwdataDir is None, "afwdata not setup")
630 def testReadFits(self):
631 """Test reading FITS files"""
633 hdus = {}
634 hdus["img"] = 1 # an S16 fits HDU
635 hdus["msk"] = 2 # an U8 fits HDU
636 hdus["var"] = 3 # an F32 fits HDU
638 # read as unsigned short
639 imgU = afwImage.DecoratedImageU(self.fileForMetadata, hdus["img"], allowUnsafe=True)
640 # read as float
641 imgF = afwImage.DecoratedImageF(self.fileForMetadata, hdus["img"])
643 self.assertEqual(imgU.getHeight(), 256)
644 self.assertEqual(imgF.image.getWidth(), 256)
645 self.assertEqual(imgU.image[0, 0, afwImage.LOCAL], imgF.image[0, 0, afwImage.LOCAL])
646 #
647 # Check the metadata
648 #
649 meta = self.trueMetadata
650 for k in meta.keys():
651 self.assertEqual(imgU.getMetadata().getAsDouble(k), meta[k])
652 self.assertEqual(imgF.getMetadata().getAsDouble(k), meta[k])
653 #
654 # Read an F32 image
655 #
656 # read as unsigned short
657 varU = afwImage.DecoratedImageF(self.fileForMetadata, hdus["var"])
658 # read as float
659 varF = afwImage.DecoratedImageF(self.fileForMetadata, hdus["var"])
661 self.assertEqual(varU.getHeight(), 256)
662 self.assertEqual(varF.image.getWidth(), 256)
663 self.assertEqual(varU.image[0, 0, afwImage.LOCAL], varF.image[0, 0, afwImage.LOCAL])
664 #
665 # Read a char image
666 #
667 maskImg = afwImage.DecoratedImageU(
668 self.fileForMetadata, hdus["msk"]).image # read a char file
670 self.assertEqual(maskImg.getHeight(), 256)
671 self.assertEqual(maskImg.getWidth(), 256)
672 self.assertEqual(maskImg[0, 0, afwImage.LOCAL], 1)
673 #
674 # Read a U16 image
675 #
676 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
677 imgU.writeFits(tmpFile)
679 afwImage.DecoratedImageF(tmpFile) # read as unsigned short
681 @unittest.skipIf(afwdataDir is None, "afwdata not setup")
682 def testWriteFits(self):
683 """Test writing FITS files"""
685 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
686 if self.fileForMetadata:
687 imgU = afwImage.DecoratedImageF(self.fileForMetadata)
688 else:
689 imgU = afwImage.DecoratedImageF()
691 self.dimage1.writeFits(tmpFile, imgU.getMetadata())
692 #
693 # Read it back
694 #
695 rimage = afwImage.DecoratedImageF(tmpFile)
697 self.assertEqual(self.dimage1.image[0, 0, afwImage.LOCAL],
698 rimage.image[0, 0, afwImage.LOCAL])
699 #
700 # Check that we wrote (and read) the metadata successfully
701 if self.fileForMetadata:
702 meta = self.trueMetadata
703 for k in meta.keys():
704 self.assertEqual(
705 rimage.getMetadata().getAsDouble(k), meta[k])
707 def testReadWriteXY0(self):
708 """Test that we read and write (X0, Y0) correctly"""
709 im = afwImage.ImageF(lsst.geom.Extent2I(10, 20))
711 x0, y0 = 1, 2
712 im.setXY0(x0, y0)
713 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile:
714 im.writeFits(tmpFile)
716 im2 = im.Factory(tmpFile)
718 self.assertEqual(im2.getX0(), x0)
719 self.assertEqual(im2.getY0(), y0)
721 @unittest.skipIf(afwdataDir is None, "afwdata not setup")
722 def testReadMetadata(self):
723 im = afwImage.DecoratedImageF(self.fileForMetadata)
725 meta = readMetadata(self.fileForMetadata)
726 self.assertIn("NAXIS1", meta.names())
727 self.assertEqual(im.getWidth(), meta.getScalar("NAXIS1"))
728 self.assertEqual(im.getHeight(), meta.getScalar("NAXIS2"))
730 def testTicket1040(self):
731 """ How to repeat from #1040"""
732 image = afwImage.ImageD(lsst.geom.Extent2I(6, 6))
733 image[2, 2] = 100
735 bbox = lsst.geom.Box2I(lsst.geom.Point2I(1, 1), lsst.geom.Extent2I(5, 5))
736 subImage = image.Factory(image, bbox)
737 subImageF = subImage.convertFloat()
739 if display:
740 afwDisplay.Display(frame=0).mtv(subImage, title="subImage")
741 afwDisplay.Display(frame=1).mtv(subImageF, title="converted subImage")
743 self.assertEqual(subImage[1, 1, afwImage.LOCAL], subImageF[1, 1, afwImage.LOCAL])
745 def testDM882(self):
746 """Test that we can write a dotted header unit to a FITS file. See DM-882."""
747 self.dimage1.getMetadata().add("A.B.C.D", 12345)
748 tempdir = tempfile.mkdtemp()
749 testfile = os.path.join(tempdir, "test.fits")
750 try:
751 self.dimage1.writeFits(testfile)
752 meta = readMetadata(testfile)
753 self.assertEqual(meta.getScalar("A.B.C.D"), 12345)
754 finally:
755 shutil.rmtree(tempdir)
757 def testLargeImage(self):
758 """Test that creating an extremely large image raises, rather than segfaulting. DM-89, -527."""
759 for imtype in (afwImage.ImageD, afwImage.ImageF, afwImage.ImageI, afwImage.ImageU):
760 self.assertRaises(lsst.pex.exceptions.LengthError,
761 imtype, 60000, 60000)
764def printImg(img):
765 print("%4s " % "", end=' ')
766 for c in range(img.getWidth()):
767 print("%7d" % c, end=' ')
768 print()
770 for r in range(img.getHeight() - 1, -1, -1):
771 print("%4d " % r, end=' ')
772 for c in range(img.getWidth()):
773 print("%7.1f" % float(img[c, r, afwImage.LOCAL]), end=' ')
774 print()
777class TestMemory(lsst.utils.tests.MemoryTestCase):
778 pass
781def setup_module(module):
782 lsst.utils.tests.init()
785if __name__ == "__main__": 785 ↛ 786line 785 didn't jump to line 786, because the condition on line 785 was never true
786 lsst.utils.tests.init()
787 unittest.main()