Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the possibility to include scale and offset in geotiffs #948

Merged
merged 3 commits into from
Oct 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 16 additions & 4 deletions satpy/tests/writer_tests/test_geotiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
#
# You should have received a copy of the GNU General Public License along with
# satpy. If not, see <http://www.gnu.org/licenses/>.
"""Tests for the geotiff writer.
"""
"""Tests for the geotiff writer."""

import sys
import numpy as np

Expand Down Expand Up @@ -48,7 +48,7 @@ def tearDown(self):
pass

def _get_test_datasets(self):
"""Helper function to create a single test dataset."""
"""Create a single test dataset."""
import xarray as xr
import dask.array as da
from datetime import datetime
Expand Down Expand Up @@ -142,9 +142,21 @@ def test_tags(self):
called_tags = save_method.call_args[1]['tags']
self.assertDictEqual(called_tags, {'test1': 1, 'test2': 2})

def test_scale_offset(self):
"""Test tags being added."""
from satpy.writers.geotiff import GeoTIFFWriter
datasets = self._get_test_datasets()
w = GeoTIFFWriter(tags={'test1': 1}, base_dir=self.base_dir)
w.info['fill_value'] = 128
with mock.patch('satpy.writers.XRImage.save') as save_method:
save_method.return_value = None
w.save_datasets(datasets, tags={'test2': 2}, compute=False, include_scale_offset=True)
called_include = save_method.call_args[1]['include_scale_offset_tags']
self.assertTrue(called_include)


def suite():
"""The test suite for this writer's tests."""
"""Test suite for this writer's tests."""
loader = unittest.TestLoader()
mysuite = unittest.TestSuite()
mysuite.addTest(loader.loadTestsFromTestCase(TestGeoTIFFWriter))
Expand Down
4 changes: 4 additions & 0 deletions satpy/tests/writer_tests/test_ninjotiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ def __init__(self, data, mode):
self.data = data
self.mode = mode

def get_scaling_from_history(self):
"""Return dummy scale and offset."""
return xr.DataArray(1), xr.DataArray(0)


modules = {'pyninjotiff': mock.Mock(),
'pyninjotiff.ninjotiff': mock.Mock()}
Expand Down
18 changes: 12 additions & 6 deletions satpy/writers/geotiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
#
# You should have received a copy of the GNU General Public License along with
# satpy. If not, see <http://www.gnu.org/licenses/>.
"""GeoTIFF writer objects for creating GeoTIFF files from `Dataset` objects.

"""
"""GeoTIFF writer objects for creating GeoTIFF files from `Dataset` objects."""

import logging
import numpy as np
Expand Down Expand Up @@ -74,6 +72,7 @@ class GeoTIFFWriter(ImageWriter):
"copy_src_overviews",)

def __init__(self, dtype=None, tags=None, **kwargs):
"""Init the writer."""
super(GeoTIFFWriter, self).__init__(default_config_filename="writers/geotiff.yaml", **kwargs)
self.dtype = self.info.get("dtype") if dtype is None else dtype
self.tags = self.info.get("tags", None) if tags is None else tags
Expand All @@ -91,6 +90,7 @@ def __init__(self, dtype=None, tags=None, **kwargs):

@classmethod
def separate_init_kwargs(cls, kwargs):
"""Separate the init keyword args."""
# FUTURE: Don't pass Scene.save_datasets kwargs to init and here
init_kwargs, kwargs = super(GeoTIFFWriter, cls).separate_init_kwargs(
kwargs)
Expand All @@ -101,7 +101,9 @@ def separate_init_kwargs(cls, kwargs):
return init_kwargs, kwargs

def save_image(self, img, filename=None, dtype=None, fill_value=None,
compute=True, keep_palette=False, cmap=None, **kwargs):
compute=True, keep_palette=False, cmap=None, tags=None,
include_scale_offset=False,
**kwargs):
"""Save the image to the given ``filename`` in geotiff_ format.

Note for faster output and reduced memory usage the ``rasterio``
Expand Down Expand Up @@ -145,6 +147,9 @@ def save_image(self, img, filename=None, dtype=None, fill_value=None,
the index range of the palette
(ex. `cmap.set_range(0, len(colors))`).
tags (dict): Extra metadata to store in geotiff.
include_scale_offset (bool): Activate inclusion of scale and offset
factors in the geotiff to allow retrieving original values from
the pixel values. ``False`` by default.

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

Expand Down Expand Up @@ -181,10 +186,11 @@ def save_image(self, img, filename=None, dtype=None, fill_value=None,
cmap = create_colormap({'colors': img.palette})
cmap.set_range(0, len(img.palette) - 1)

tags = kwargs.get('tags', {})
if tags is None:
tags = {}
tags.update(self.tags)
return img.save(filename, fformat='tif', fill_value=fill_value,
dtype=dtype, compute=compute,
keep_palette=keep_palette, cmap=cmap,
tags=tags,
tags=tags, include_scale_offset_tags=include_scale_offset,
**gdal_options)
19 changes: 8 additions & 11 deletions satpy/writers/ninjotiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@

import pyninjotiff.ninjotiff as nt
from satpy.writers import ImageWriter
from trollimage.xrimage import invert_scale_offset


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -135,19 +136,15 @@ def save_image(self, img, filename=None, compute=True, **kwargs): # floating_po
or "ch_max_measurement_unit" not in kwargs
):
try:
history = img.data.attrs["enhancement_history"]
except KeyError:
logger.warning("Cannot find information on previous scaling for ninjo.")
scale, offset = img.get_scaling_from_history()
scale, offset = invert_scale_offset(scale, offset)
except ValueError as err:
logger.warning(str(err))
else:
if len(history) > 1:
raise NotImplementedError(
"Don't know how to process large enhancement_history yet"
)
try:
scale = history[0]["scale"]
offset = history[0]["offset"]
dmin = -offset / scale
dmax = (1 - offset) / scale
# Here we know that the data if the image is scaled between 0 and 1
dmin = offset
dmax = scale + offset
if dmin > dmax:
dmin, dmax = dmax, dmin
ch_min_measurement_unit, ch_max_measurement_unit = (
Expand Down
4 changes: 2 additions & 2 deletions satpy/writers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
#
# You should have received a copy of the GNU General Public License along with
# satpy. If not, see <http://www.gnu.org/licenses/>.
"""Writer utilities"""
"""Writer utilities."""


def flatten_dict(d, parent_key='', sep='_'):
"""Flatten a nested dictionary
"""Flatten a nested dictionary.

Based on https://stackoverflow.com/a/6027615/5703449
"""
Expand Down