Coverage for tests/test_imageIo2.py: 25%
76 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-08-01 01:19 -0700
« prev ^ index » next coverage.py v6.4.2, created at 2022-08-01 01:19 -0700
1#
2# LSST Data Management System
3# Copyright 2008, 2009, 2010 LSST Corporation.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
23import unittest
25import numpy as np
26import astropy.io.fits
27import lsst.utils.tests
28from lsst.geom import Box2I, Point2I
29from lsst.afw.fits import ImageCompressionOptions, ImageScalingOptions, ImageWriteOptions
30import lsst.afw.image as afwImage
33class ImageIoTestCase(lsst.utils.tests.TestCase):
34 """A test case for Image FITS I/O"""
36 def assertImagesEqual(self, image, original):
37 self.assertEqual(image.getBBox(), original.getBBox())
38 super().assertImagesEqual(image, original)
40 def setUp(self):
41 # ImageL (uint64) is not supported by FITS standard, needs special tests
42 self.IntegerImages = (afwImage.ImageU, afwImage.ImageI)
43 self.FloatImages = (afwImage.ImageF, afwImage.ImageD)
44 self.bbox = Box2I(minimum=Point2I(3, 4), maximum=Point2I(9, 7))
46 def doRoundTrip(self, image, compression=None, scaling=None):
47 if compression is None:
48 compression = dict(algorithm=ImageCompressionOptions.NONE)
49 if scaling is None:
50 scaling = dict(algorithm=ImageScalingOptions.NONE, bitpix=0)
51 options = ImageWriteOptions(compression=ImageCompressionOptions(**compression),
52 scaling=ImageScalingOptions(**scaling))
53 isCompressed = (compression.get("algorithm", ImageCompressionOptions.NONE)
54 != ImageCompressionOptions.NONE)
55 with lsst.utils.tests.getTempFilePath(f"_{type(image).__name__}.fits") as filename:
56 image.writeFits(filename, options=options)
57 readImage = type(image)(filename)
58 with astropy.io.fits.open(filename) as hduList:
59 hdu = hduList[1 if isCompressed else 0]
60 if hdu.data.dtype.byteorder != '=':
61 hdu.data = hdu.data.byteswap().newbyteorder()
62 return readImage, hdu
64 def runRoundTripTest(self, cls, compression=None, scaling=None, addNaN=False, checkAstropy=True, rtol=0):
65 original = cls(self.bbox)
66 original.array[:, :] = np.random.randint(size=original.array.shape, low=1, high=255, dtype=np.uint8)
67 if addNaN:
68 original[5, 6] = np.nan
70 readImage, hdu = self.doRoundTrip(original, compression=compression, scaling=scaling)
71 self.assertImagesAlmostEqual(original, readImage, rtol=rtol, atol=0)
73 # Integer LSST images never have missing pixels; FITS floating-point images always use NaN
74 self.assertNotIn("BLANK", hdu.header.keys())
76 if checkAstropy:
77 # Compare to what astropy reads, to more-or-less check that we're not abusing FITS
78 hduImage = cls(hdu.data, deep=False, xy0=self.bbox.getMin())
79 self.assertImagesAlmostEqual(original, hduImage, rtol=rtol, atol=0)
81 def testIntegerUncompression(self):
82 """Test round-tripping integer images with no compression or scaling.
83 """
84 for cls in self.IntegerImages:
85 with self.subTest(cls=cls.__name__):
86 self.runRoundTripTest(cls)
88 def testIntegerCompression(self):
89 """Test round-tripping integer images with compression (and no scaling).
90 """
91 for cls in self.IntegerImages:
92 with self.subTest(cls=cls.__name__):
93 self.runRoundTripTest(cls, compression=dict(algorithm=ImageCompressionOptions.RICE))
95 def testUInt64(self):
96 """Test round-tripping uint64 images (ImageL).
98 uint64 is supported by a CFITSIO convention, not the FITS standard,
99 so we can't read them correctly with astropy or compression.
100 """
101 self.runRoundTripTest(afwImage.ImageL, checkAstropy=False)
103 def testFloatUncompressed(self):
104 """Test round-tripping floating-point images with no compression."""
105 for cls in self.FloatImages:
106 with self.subTest(cls=cls.__name__):
107 self.runRoundTripTest(cls, addNaN=True)
109 def testFloatCompressedLossless(self):
110 """Test round-tripping floating-point images with lossless compression."""
111 for cls in self.FloatImages:
112 with self.subTest(cls=cls.__name__):
113 self.runRoundTripTest(
114 cls,
115 compression=dict(algorithm=ImageCompressionOptions.GZIP, quantizeLevel=0),
116 addNaN=True
117 )
119 @unittest.skip("Fix deferred to DM-15644")
120 def testFloatCompressedRange(self):
121 """Test round-tripping floating-point images with lossy compression
122 and RANGE scaling."""
123 for cls in self.FloatImages:
124 with self.subTest(cls=cls.__name__):
125 self.runRoundTripTest(
126 cls,
127 compression=dict(algorithm=ImageCompressionOptions.GZIP, quantizeLevel=1),
128 scaling=dict(algorithm=ImageScalingOptions.RANGE, bitpix=32, fuzz=False),
129 addNaN=True,
130 checkAstropy=True
131 )
133 @unittest.skip("Fix deferred to DM-15644")
134 def testFloatCompressedManual(self):
135 """Test round-tripping floating-point images with lossy compression
136 and MANUAL scaling."""
137 for cls in self.FloatImages:
138 with self.subTest(cls=cls.__name__):
139 self.runRoundTripTest(
140 cls,
141 compression=dict(algorithm=ImageCompressionOptions.GZIP, quantizeLevel=1),
142 scaling=dict(algorithm=ImageScalingOptions.MANUAL, bitpix=32, fuzz=False,
143 bzero=3, bscale=2),
144 addNaN=True,
145 checkAstropy=True
146 )
149class TestMemory(lsst.utils.tests.MemoryTestCase):
150 pass
153def setup_module(module):
154 lsst.utils.tests.init()
157if __name__ == "__main__": 157 ↛ 158line 157 didn't jump to line 158, because the condition on line 157 was never true
158 lsst.utils.tests.init()
159 unittest.main()