示例#1
0
    def checkEmptyExposure(self, algorithm):
        """Check that we can persist an empty Exposure

        Parameters
        ----------
        algorithm : `lsst.afw.fits.ImageCompressionOptions.CompressionAlgorithm`
            Compression algorithm to try.
        """
        exp = lsst.afw.image.ExposureF(0, 0)
        degrees = lsst.geom.degrees
        cdMatrix = np.array([[1.0e-4, 0.0], [0.0, 1.0e-4]], dtype=float)
        exp.setWcs(
            lsst.afw.geom.makeSkyWcs(crval=lsst.geom.SpherePoint(
                0 * degrees, 0 * degrees),
                                     crpix=lsst.geom.Point2D(0.0, 0.0),
                                     cdMatrix=cdMatrix))
        imageOptions = lsst.afw.fits.ImageWriteOptions(
            ImageCompressionOptions(algorithm))
        maskOptions = lsst.afw.fits.ImageWriteOptions(
            exp.getMaskedImage().getMask())
        varianceOptions = lsst.afw.fits.ImageWriteOptions(
            ImageCompressionOptions(algorithm))
        with lsst.utils.tests.getTempFilePath(".fits") as filename:
            exp.writeFits(filename, imageOptions, maskOptions, varianceOptions)
            unpersisted = type(exp)(filename)
        self.assertEqual(unpersisted.getMaskedImage().getDimensions(),
                         lsst.geom.Extent2I(0, 0))
        self.assertEqual(unpersisted.getWcs(), exp.getWcs())
示例#2
0
    def testLossyFloatOurs(self):
        """Test lossy compression of floating-point images ourselves

        We do lossy compression by scaling first. We have full control over
        the scaling (multiple scaling algorithms), and we have access to our
        own masks when we do statistics.
        """
        classList = (lsst.afw.image.ImageF, lsst.afw.image.ImageD)
        algorithmList = ("GZIP", "GZIP_SHUFFLE", "RICE")
        bitpixList = (16, 32)
        quantizeList = (4.0, 10.0)
        for cls, algorithm, bitpix, quantize in itertools.product(
                classList, algorithmList, bitpixList, quantizeList):
            compression = ImageCompressionOptions(
                lsst.afw.fits.compressionAlgorithmFromString(algorithm),
                quantizeLevel=0.0)
            scaling = ImageScalingOptions(ImageScalingOptions.STDEV_BOTH,
                                          bitpix,
                                          quantizeLevel=quantize,
                                          fuzz=True)
            image = self.makeImage(cls)
            self.checkCompressedImage(cls,
                                      image,
                                      compression,
                                      scaling,
                                      atol=self.noise / quantize)
示例#3
0
def reduceToFits(obj):
    """Pickle to FITS

    Intended to be used by the ``__reduce__`` method of a class.

    Parameters
    ----------
    obj
        any object with a ``writeFits`` method taking a
        `~lsst.afw.fits.MemFileManager` and possibly an
        `~lsst.afw.fits.ImageWriteOptions`.

    Returns
    -------
    reduced : `tuple` [callable, `tuple`]
        a tuple in the format returned by `~object.__reduce__`
    """
    manager = MemFileManager()
    options = ImageWriteOptions(ImageCompressionOptions(ImageCompressionOptions.NONE))
    table = getattr(obj, 'table', None)
    if isinstance(table, lsst.afw.table.BaseTable):
        # table objects don't take `options`
        obj.writeFits(manager)
    else:
        # MaskedImage and Exposure both require options for each plane (image, mask, variance)
        if isinstance(obj, (lsst.afw.image.MaskedImage, lsst.afw.image.Exposure)):
            obj.writeFits(manager, options, options, options)
        else:
            obj.writeFits(manager, options)
    size = manager.getLength()
    data = manager.getData()
    return (unreduceFromFits, (obj.__class__, data, size))
示例#4
0
    def testQuantization(self):
        """Test that our quantization produces the same values as cfitsio

        Our quantization is more configurable (e.g., choice of scaling algorithm,
        specifying mask planes) and extensible (logarithmic, asinh scalings)
        than cfitsio's. However, cfitsio uses its own fuzz ("subtractive dithering")
        when reading the data, so if we don't want to add random values twice,
        we need to be sure that we're using the same random values. To check that,
        we write one image with our scaling+compression, and one with cfitsio's
        compression using exactly the BSCALE and dither seed we used for our own.
        That way, the two codes will quantize independently, and we can compare
        the results.
        """
        bscaleSet = 1.0
        bzeroSet = self.background - 10 * self.noise
        algorithm = ImageCompressionOptions.GZIP
        classList = (lsst.afw.image.ImageF, lsst.afw.image.ImageD)
        tilesList = ((4, 5), (0, 0), (0, 5), (4, 0), (0, 1))
        for cls, tiles in itertools.product(classList, tilesList):
            tiles = np.array(tiles, dtype=np.int64)
            compression = ImageCompressionOptions(algorithm, tiles, -bscaleSet)
            original = self.makeImage(cls)
            with lsst.utils.tests.getTempFilePath(self.extension) as filename:
                with lsst.afw.fits.Fits(filename, "w") as fits:
                    options = lsst.afw.fits.ImageWriteOptions(compression)
                    original.writeFits(fits, options)
                cfitsio = cls(filename)
                header = lsst.afw.fits.readMetadata(filename, 1)
                seed = header.getScalar("ZDITHER0")
                self.assertEqual(header.getScalar("BSCALE"), bscaleSet)

            compression = ImageCompressionOptions(algorithm, tiles, 0.0)
            scaling = ImageScalingOptions(ImageScalingOptions.MANUAL,
                                          32, [u"BAD"],
                                          bscale=bscaleSet,
                                          bzero=bzeroSet,
                                          fuzz=True,
                                          seed=seed)
            unpersisted = self.checkCompressedImage(cls,
                                                    original,
                                                    compression,
                                                    scaling,
                                                    atol=bscaleSet)
            oursDiff = unpersisted.getArray() - original.getArray()
            cfitsioDiff = cfitsio.getArray() - original.getArray()
            self.assertImagesAlmostEqual(oursDiff, cfitsioDiff, atol=0.0)
示例#5
0
 def testLosslessFloat(self):
     """Test lossless compression of floating-point image"""
     classList = (lsst.afw.image.ImageF, lsst.afw.image.ImageD)
     algorithmList = ("GZIP", "GZIP_SHUFFLE"
                      )  # Lossless float compression requires GZIP
     for cls, algorithm in itertools.product(classList, algorithmList):
         image = self.makeImage(cls)
         compression = ImageCompressionOptions(
             lsst.afw.fits.compressionAlgorithmFromString(algorithm))
         self.checkCompressedImage(cls, image, compression, atol=0.0)
示例#6
0
    def testLosslessInt(self):
        """Test lossless compression of integer image

        We deliberately don't test `lsst.afw.image.ImageL` because
        compression of LONGLONG images is unsupported by cfitsio.
        """
        classList = (lsst.afw.image.ImageU, lsst.afw.image.ImageI)
        algorithmList = ("GZIP", "GZIP_SHUFFLE", "RICE")
        for cls, algorithm in itertools.product(classList, algorithmList):
            compression = ImageCompressionOptions(
                lsst.afw.fits.compressionAlgorithmFromString(algorithm))
            image = self.makeImage(cls)
            self.checkCompressedImage(cls, image, compression, atol=0.0)
示例#7
0
    def testLongLong(self):
        """Test graceful failure when compressing ImageL

        We deliberately don't test `lsst.afw.image.ImageL` because
        compression of LONGLONG images is unsupported by cfitsio.
        """
        algorithmList = ("GZIP", "GZIP_SHUFFLE", "RICE")
        for algorithm in algorithmList:
            compression = ImageCompressionOptions(
                lsst.afw.fits.compressionAlgorithmFromString(algorithm))
            cls = lsst.afw.image.ImageL
            image = self.makeImage(cls)
            with self.assertRaises(lsst.afw.fits.FitsError):
                self.checkCompressedImage(cls, image, compression)
示例#8
0
 def doRoundTrip(self, image, compression=None, scaling=None):
     if compression is None:
         compression = dict(algorithm=ImageCompressionOptions.NONE)
     if scaling is None:
         scaling = dict(algorithm=ImageScalingOptions.NONE, bitpix=0)
     options = ImageWriteOptions(compression=ImageCompressionOptions(**compression),
                                 scaling=ImageScalingOptions(**scaling))
     isCompressed = (compression.get("algorithm", ImageCompressionOptions.NONE)
                     != ImageCompressionOptions.NONE)
     with lsst.utils.tests.getTempFilePath(f"_{type(image).__name__}.fits") as filename:
         image.writeFits(filename, options=options)
         readImage = type(image)(filename)
         with astropy.io.fits.open(filename) as hduList:
             hdu = hduList[1 if isCompressed else 0]
             if hdu.data.dtype.byteorder != '=':
                 hdu.data = hdu.data.byteswap().newbyteorder()
     return readImage, hdu
示例#9
0
    def testMask(self):
        """Test compression of mask

        We deliberately don't test PLIO compression (which is designed for
        masks) because our default mask type (32) has too much dynamic range
        for PLIO (limit of 24 bits).
        """
        for algorithm in ("GZIP", "GZIP_SHUFFLE", "RICE"):
            compression = ImageCompressionOptions(
                lsst.afw.fits.compressionAlgorithmFromString(algorithm))
            mask = self.makeMask()
            unpersisted = self.checkCompressedImage(lsst.afw.image.Mask,
                                                    mask,
                                                    compression,
                                                    atol=0.0)
            for mp in mask.getMaskPlaneDict():
                self.assertIn(mp, unpersisted.getMaskPlaneDict())
                unpersisted.getPlaneBitMask(mp)
示例#10
0
    def testLossyFloatCfitsio(self):
        """Test lossy compresion of floating-point images with cfitsio

        cfitsio does the compression, controlled through the 'quantizeLevel'
        parameter. Note that cfitsio doesn't have access to our masks when
        it does its statistics.
        """
        classList = (lsst.afw.image.ImageF, lsst.afw.image.ImageD)
        algorithmList = ("GZIP", "GZIP_SHUFFLE", "RICE")
        quantizeList = (4.0, 10.0)
        for cls, algorithm, quantizeLevel in itertools.product(
                classList, algorithmList, quantizeList):
            compression = ImageCompressionOptions(
                lsst.afw.fits.compressionAlgorithmFromString(algorithm),
                quantizeLevel=quantizeLevel)
            image = self.makeImage(cls)
            self.checkCompressedImage(cls,
                                      image,
                                      compression,
                                      atol=self.noise / quantizeLevel)