Example #1
0
    def save_image(self, img, filename=None, floating_point=False, **kwargs):
        """Save the image to the given *filename* in geotiff_ format.
        `floating_point` allows the saving of
        'L' mode images in floating point format if set to True.

        .. _geotiff: http://trac.osgeo.org/geotiff/
        """
        raster = gdal.GetDriverByName("GTiff")

        filename = filename or self.get_filename(**img.info)

        # Update global GDAL options with these specific ones
        gdal_options = self.gdal_options.copy()
        for k in kwargs.keys():
            if k in self.GDAL_OPTIONS:
                gdal_options[k] = kwargs[k]

        floating_point = floating_point if floating_point is not None else self.floating_point

        if "alpha" in kwargs:
            raise ValueError(
                "Keyword 'alpha' is automatically set and should not be specified"
            )

        if floating_point:
            if img.mode != "L":
                raise ValueError(
                    "Image must be in 'L' mode for floating point geotiff saving"
                )
            if img.fill_value is None:
                LOG.warning(
                    "Image with floats cannot be transparent, so setting fill_value to 0"
                )
                fill_value = 0
            datasets = [img.channels[0].astype(np.float64)]
            fill_value = img.fill_value or [0]
            gformat = gdal.GDT_Float64
            opacity = 0
        else:
            nbits = int(gdal_options.get("nbits", "8"))
            if nbits > 16:
                dtype = np.uint32
                gformat = gdal.GDT_UInt32
            elif nbits > 8:
                dtype = np.uint16
                gformat = gdal.GDT_UInt16
            else:
                dtype = np.uint8
                gformat = gdal.GDT_Byte
            opacity = np.iinfo(dtype).max
            datasets, fill_value = img._finalize(dtype)

        LOG.debug("Saving to GeoTiff: %s", filename)

        g_opts = [
            "{0}={1}".format(k.upper(), str(v))
            for k, v in gdal_options.items()
        ]

        ensure_dir(filename)
        if img.mode == "L":
            if fill_value is not None:
                dst_ds = raster.Create(filename, img.width, img.height, 1,
                                       gformat, g_opts)
            else:
                g_opts.append("ALPHA=YES")
                dst_ds = raster.Create(filename, img.width, img.height, 2,
                                       gformat, g_opts)
            self._gdal_write_datasets(dst_ds, datasets, opacity, fill_value)
        elif img.mode == "LA":
            g_opts.append("ALPHA=YES")
            dst_ds = raster.Create(filename, img.width, img.height, 2, gformat,
                                   g_opts)
            self._gdal_write_datasets(dst_ds, datasets[:-1], datasets[1],
                                      fill_value)
        elif img.mode == "RGB":
            if fill_value is not None:
                dst_ds = raster.Create(filename, img.width, img.height, 3,
                                       gformat, g_opts)
            else:
                g_opts.append("ALPHA=YES")
                dst_ds = raster.Create(filename, img.width, img.height, 4,
                                       gformat, g_opts)

            self._gdal_write_datasets(dst_ds, datasets, opacity, fill_value)

        elif img.mode == "RGBA":
            g_opts.append("ALPHA=YES")
            dst_ds = raster.Create(filename, img.width, img.height, 4, gformat,
                                   g_opts)

            self._gdal_write_datasets(dst_ds, datasets[:-1], datasets[3],
                                      fill_value)
        else:
            raise NotImplementedError(
                "Saving to GeoTIFF using image mode %s is not implemented." %
                img.mode)

        # Create raster GeoTransform based on upper left corner and pixel
        # resolution ... if not overwritten by argument geotransform.
        if "area" not in img.info:
            LOG.warning("No 'area' metadata found in image")
        else:
            area = img.info["area"]
            try:
                geotransform = [
                    area.area_extent[0], area.pixel_size_x, 0,
                    area.area_extent[3], 0, -area.pixel_size_y
                ]
                dst_ds.SetGeoTransform(geotransform)
                srs = osr.SpatialReference()

                srs.ImportFromProj4(area.proj4_string)
                srs.SetProjCS(area.proj_id)
                try:
                    srs.SetWellKnownGeogCS(area.proj_dict['ellps'])
                except KeyError:
                    pass
                try:
                    # Check for epsg code.
                    srs.ImportFromEPSG(
                        int(area.proj_dict['init'].lower().split('epsg:')[1]))
                except (KeyError, IndexError):
                    pass
                srs = srs.ExportToWkt()
                dst_ds.SetProjection(srs)
            except AttributeError:
                LOG.warning(
                    "Can't save geographic information to geotiff, unsupported area type"
                )

        tags = self.tags.copy()
        if "start_time" in img.info:
            tags.update({
                'TIFFTAG_DATETIME':
                img.info["start_time"].strftime("%Y:%m:%d %H:%M:%S")
            })

        dst_ds.SetMetadata(tags, '')

        # Close the dataset
        dst_ds = None
Example #2
0
    def save_image(self, img, filename=None, dtype=None, fill_value=None,
                   floating_point=None, compute=True, **kwargs):
        """Save the image to the given ``filename`` in geotiff_ format.

        Note for faster output and reduced memory usage the ``rasterio``
        library must be installed. This writer currently falls back to
        using ``gdal`` directly, but that will be deprecated in the future.

        Args:
            img (xarray.DataArray): Data to save to geotiff.
            filename (str): Filename to save the image to. Defaults to
                ``filename`` passed during writer creation. Unlike the
                creation ``filename`` keyword argument, this filename does not
                get formatted with data attributes.
            dtype (numpy.dtype): Numpy data type to save the image as.
                Defaults to 8-bit unsigned integer (``np.uint8``). If the
                ``dtype`` argument is provided during writer creation then
                that will be used as the default.
            fill_value (int or float): Value to use where data values are
                NaN/null. If this is specified in the writer configuration
                file that value will be used as the default.
            floating_point (bool): Deprecated. Use ``dtype=np.float64``
                instead.
            compute (bool): Compute dask arrays and save the image
                immediately. If ``False`` then the return value can be passed
                to :func:`~satpy.writers.compute_writer_results` to do the
                computation. This is useful when multiple images may share
                input calculations where dask can benefit from not repeating
                them multiple times. Defaults to ``True`` in the writer by
                itself, but is typically passed as ``False`` by callers where
                calculations can be combined.

        .. _geotiff: http://trac.osgeo.org/geotiff/

        """
        filename = filename or self.get_filename(**img.data.attrs)

        # Update global GDAL options with these specific ones
        gdal_options = self.gdal_options.copy()
        for k in kwargs.keys():
            if k in self.GDAL_OPTIONS:
                gdal_options[k] = kwargs[k]
        if fill_value is None:
            # fall back to fill_value from configuration file
            fill_value = self.info.get('fill_value')

        if floating_point is not None:
            import warnings
            warnings.warn("'floating_point' is deprecated, use"
                          "'dtype=np.float64' instead.",
                          DeprecationWarning)
            dtype = np.float64
        dtype = dtype if dtype is not None else self.dtype
        if dtype is None:
            dtype = np.uint8

        if "alpha" in kwargs:
            raise ValueError(
                "Keyword 'alpha' is automatically set based on 'fill_value' "
                "and should not be specified")
        if np.issubdtype(dtype, np.floating):
            if img.mode != "L":
                raise ValueError("Image must be in 'L' mode for floating "
                                 "point geotiff saving")
            if fill_value is None:
                LOG.debug("Alpha band not supported for float geotiffs, "
                          "setting fill value to 'NaN'")
                fill_value = np.nan

        try:
            import rasterio  # noqa
            # we can use the faster rasterio-based save
            return img.save(filename, fformat='tif', fill_value=fill_value,
                            dtype=dtype, compute=compute, **gdal_options)
        except ImportError:
            LOG.warning("Using legacy/slower geotiff save method, install "
                        "'rasterio' for faster saving.")
            import warnings
            warnings.warn("Using legacy/slower geotiff save method with 'gdal'."
                          "This will be deprecated in the future. Install "
                          "'rasterio' for faster saving and future "
                          "compatibility.", PendingDeprecationWarning)

            # Map numpy data types to GDAL data types
            NP2GDAL = {
                np.float32: gdal.GDT_Float32,
                np.float64: gdal.GDT_Float64,
                np.uint8: gdal.GDT_Byte,
                np.uint16: gdal.GDT_UInt16,
                np.uint32: gdal.GDT_UInt32,
                np.int16: gdal.GDT_Int16,
                np.int32: gdal.GDT_Int32,
                np.complex64: gdal.GDT_CFloat32,
                np.complex128: gdal.GDT_CFloat64,
            }

            # force to numpy dtype object
            dtype = np.dtype(dtype)
            gformat = NP2GDAL[dtype.type]

            gdal_options['nbits'] = int(gdal_options.get('nbits',
                                                         dtype.itemsize * 8))
            datasets, mode = img._finalize(fill_value=fill_value, dtype=dtype)
            LOG.debug("Saving to GeoTiff: %s", filename)
            g_opts = ["{0}={1}".format(k.upper(), str(v))
                      for k, v in gdal_options.items()]

            ensure_dir(filename)
            delayed = self._create_file(filename, img, gformat, g_opts,
                                        datasets, mode)
            if compute:
                return delayed.compute()
            return delayed
Example #3
0
    def save_image(self, img, filename=None, dtype=None, fill_value=None,
                   floating_point=None, compute=True, **kwargs):
        """Save the image to the given *filename* in geotiff_ format.
        `floating_point` allows the saving of
        'L' mode images in floating point format if set to True.

        .. _geotiff: http://trac.osgeo.org/geotiff/
        """
        filename = filename or self.get_filename(**img.data.attrs)

        # Update global GDAL options with these specific ones
        gdal_options = self.gdal_options.copy()
        for k in kwargs.keys():
            if k in self.GDAL_OPTIONS:
                gdal_options[k] = kwargs[k]

        if floating_point is not None:
            import warnings
            warnings.warn("'floating_point' is deprecated, use"
                          "'dtype=np.float64' instead.",
                          DeprecationWarning)
            dtype = np.float64
        dtype = dtype if dtype is not None else self.dtype
        if dtype is None:
            dtype = np.uint8

        if "alpha" in kwargs:
            raise ValueError(
                "Keyword 'alpha' is automatically set based on 'fill_value' "
                "and should not be specified")
        if np.issubdtype(dtype, np.floating):
            if img.mode != "L":
                raise ValueError("Image must be in 'L' mode for floating "
                                 "point geotiff saving")
            if fill_value is None:
                LOG.debug("Alpha band not supported for float geotiffs, "
                          "setting fill value to 'NaN'")
                fill_value = np.nan

        try:
            import rasterio  # noqa
            # we can use the faster rasterio-based save
            return img.save(filename, fformat='tif', fill_value=fill_value,
                            dtype=dtype, compute=compute, **gdal_options)
        except ImportError:
            LOG.warning("Using legacy/slower geotiff save method, install "
                        "'rasterio' for faster saving.")
            # force to numpy dtype object
            dtype = np.dtype(dtype)
            gformat = NP2GDAL[dtype.type]

            gdal_options['nbits'] = int(gdal_options.get('nbits',
                                                         dtype.itemsize * 8))
            datasets, mode = img._finalize(fill_value=fill_value, dtype=dtype)
            LOG.debug("Saving to GeoTiff: %s", filename)
            g_opts = ["{0}={1}".format(k.upper(), str(v))
                      for k, v in gdal_options.items()]

            ensure_dir(filename)
            delayed = self._create_file(filename, img, gformat, g_opts,
                                        datasets, mode)
            if compute:
                return delayed.compute()
            return delayed
Example #4
0
    def save_image(self,
                   img,
                   filename=None,
                   dtype=None,
                   fill_value=None,
                   floating_point=None,
                   compute=True,
                   **kwargs):
        """Save the image to the given *filename* in geotiff_ format.
        `floating_point` allows the saving of
        'L' mode images in floating point format if set to True.

        .. _geotiff: http://trac.osgeo.org/geotiff/
        """
        filename = filename or self.get_filename(**img.data.attrs)

        # Update global GDAL options with these specific ones
        gdal_options = self.gdal_options.copy()
        for k in kwargs.keys():
            if k in self.GDAL_OPTIONS:
                gdal_options[k] = kwargs[k]

        if floating_point is not None:
            import warnings
            warnings.warn(
                "'floating_point' is deprecated, use"
                "'dtype=np.float64' instead.", DeprecationWarning)
            dtype = np.float64
        dtype = dtype if dtype is not None else self.dtype
        if dtype is None:
            dtype = np.uint8

        if "alpha" in kwargs:
            raise ValueError(
                "Keyword 'alpha' is automatically set based on 'fill_value' "
                "and should not be specified")
        if np.issubdtype(dtype, np.floating):
            if img.mode != "L":
                raise ValueError("Image must be in 'L' mode for floating "
                                 "point geotiff saving")
            if fill_value is None:
                LOG.debug("Alpha band not supported for float geotiffs, "
                          "setting fill value to 'NaN'")
                fill_value = np.nan

        try:
            import rasterio  # noqa
            # we can use the faster rasterio-based save
            return img.save(filename,
                            fformat='tif',
                            fill_value=fill_value,
                            dtype=dtype,
                            compute=compute,
                            **gdal_options)
        except ImportError:
            LOG.warning("Using legacy/slower geotiff save method, install "
                        "'rasterio' for faster saving.")
            # force to numpy dtype object
            dtype = np.dtype(dtype)
            gformat = NP2GDAL[dtype.type]

            gdal_options['nbits'] = int(
                gdal_options.get('nbits', dtype.itemsize * 8))
            datasets, mode = img._finalize(fill_value=fill_value, dtype=dtype)
            LOG.debug("Saving to GeoTiff: %s", filename)
            g_opts = [
                "{0}={1}".format(k.upper(), str(v))
                for k, v in gdal_options.items()
            ]

            ensure_dir(filename)
            delayed = self._create_file(filename, img, gformat, g_opts,
                                        datasets, mode)
            if compute:
                return delayed.compute()
            return delayed
Example #5
0
    def save_image(self, img, filename=None, floating_point=False, **kwargs):
        """Save the image to the given *filename* in geotiff_ format.
        `floating_point` allows the saving of
        'L' mode images in floating point format if set to True.

        .. _geotiff: http://trac.osgeo.org/geotiff/
        """
        raster = gdal.GetDriverByName("GTiff")

        filename = filename or self.get_filename(**img.info)

        # Update global GDAL options with these specific ones
        gdal_options = self.gdal_options.copy()
        for k in kwargs.keys():
            if k in self.GDAL_OPTIONS:
                gdal_options[k] = kwargs[k]

        floating_point = floating_point if floating_point is not None else self.floating_point

        if "alpha" in kwargs:
            raise ValueError(
                "Keyword 'alpha' is automatically set and should not be specified")

        if floating_point:
            if img.mode != "L":
                raise ValueError(
                    "Image must be in 'L' mode for floating point geotiff saving")
            if img.fill_value is None:
                LOG.warning(
                    "Image with floats cannot be transparent, so setting fill_value to 0")
                fill_value = 0
            datasets = [img.datasets[0].astype(np.float64)]
            fill_value = img.fill_value or [0]
            gformat = gdal.GDT_Float64
            opacity = 0
        else:
            nbits = int(gdal_options.get("nbits", "8"))
            if nbits > 16:
                dtype = np.uint32
                gformat = gdal.GDT_UInt32
            elif nbits > 8:
                dtype = np.uint16
                gformat = gdal.GDT_UInt16
            else:
                dtype = np.uint8
                gformat = gdal.GDT_Byte
            opacity = np.iinfo(dtype).max
            datasets, fill_value = img._finalize(dtype)

        LOG.debug("Saving to GeoTiff: %s", filename)

        g_opts = ["{0}={1}".format(k.upper(), str(v))
                  for k, v in self.gdal_options.items()]

        ensure_dir(filename)
        if img.mode == "L":
            if fill_value is not None:
                dst_ds = raster.Create(filename, img.width, img.height, 1,
                                       gformat, g_opts)
            else:
                g_opts.append("ALPHA=YES")
                dst_ds = raster.Create(filename, img.width, img.height, 2,
                                       gformat, g_opts)
            self._gdal_write_datasets(dst_ds, datasets, opacity, fill_value)
        elif img.mode == "LA":
            g_opts.append("ALPHA=YES")
            dst_ds = raster.Create(filename, img.width, img.height, 2, gformat,
                                   g_opts)
            self._gdal_write_datasets(dst_ds, datasets[:-1], datasets[1],
                                      fill_value)
        elif img.mode == "RGB":
            if fill_value is not None:
                dst_ds = raster.Create(filename, img.width, img.height, 3,
                                       gformat, g_opts)
            else:
                g_opts.append("ALPHA=YES")
                dst_ds = raster.Create(filename, img.width, img.height, 4,
                                       gformat, g_opts)

            self._gdal_write_datasets(dst_ds, datasets, opacity, fill_value)

        elif img.mode == "RGBA":
            g_opts.append("ALPHA=YES")
            dst_ds = raster.Create(filename, img.width, img.height, 4, gformat,
                                   g_opts)

            self._gdal_write_datasets(dst_ds, datasets[:-1], datasets[3],
                                      fill_value)
        else:
            raise NotImplementedError(
                "Saving to GeoTIFF using image mode %s is not implemented." %
                img.mode)

        # Create raster GeoTransform based on upper left corner and pixel
        # resolution ... if not overwritten by argument geotransform.
        if "area" not in img.info:
            LOG.warning("No 'area' metadata found in image")
        else:
            area = img.info["area"]
            try:
                geotransform = [area.area_extent[0], area.pixel_size_x, 0,
                                area.area_extent[3], 0, -area.pixel_size_y]
                dst_ds.SetGeoTransform(geotransform)
                srs = osr.SpatialReference()

                srs.ImportFromProj4(area.proj4_string)
                srs.SetProjCS(area.proj_id)
                try:
                    srs.SetWellKnownGeogCS(area.proj_dict['ellps'])
                except KeyError:
                    pass
                try:
                    # Check for epsg code.
                    srs.ImportFromEPSG(int(
                        area.proj_dict['init'].lower().split('epsg:')[1]))
                except (KeyError, IndexError):
                    pass
                srs = srs.ExportToWkt()
                dst_ds.SetProjection(srs)
            except AttributeError:
                LOG.warning(
                    "Can't save geographic information to geotiff, unsupported area type")

        tags = self.tags.copy()
        if "start_time" in img.info:
            tags.update({'TIFFTAG_DATETIME': img.info["start_time"].strftime(
                "%Y:%m:%d %H:%M:%S")})

        dst_ds.SetMetadata(tags, '')

        # Close the dataset

        dst_ds = None