Skip to content
26 changes: 26 additions & 0 deletions satpy/enhancements/contrast.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import logging
import typing
import warnings
from collections import namedtuple
from numbers import Number
from typing import Optional
Expand All @@ -38,6 +39,31 @@
LOG = logging.getLogger(__name__)


def warn_if_float_debug_otherwise(img, msg=""):
"""Perform no enhancement but emit a warning if data is floating point.

The warning message is specified by the ``msg`` keyword argument
and can be a format string. Keyword arguments for the message
formatting are taken from the underlying ``DataArray``s ``.attrs``
dictionary.

"""
formatted_msg = msg.format(**img.data.attrs)
if np.issubdtype(img.data.dtype, np.floating):
warnings.warn(formatted_msg, UserWarning, stacklevel=2)
else:
LOG.debug(formatted_msg)
return img


def stretch_if_floating(img, **kwargs):
"""Perform a regular linear stretch but warn about no other enhancement."""
# if np.issubdtype(img.data.dtype, np.floating):
# return stretch(img, **kwargs)
# return img
return stretch(img, **kwargs)


def stretch(img, **kwargs):
"""Perform stretch."""
return img.stretch(**kwargs)
Expand Down
12 changes: 9 additions & 3 deletions satpy/etc/enhancements/generic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
enhancements:
default:
operations:
- name: stretch
method: !!python/name:satpy.enhancements.contrast.stretch
kwargs: {stretch: linear}
- name: warn_no_predefined
method: !!python/name:satpy.enhancements.contrast.warn_if_float_debug_otherwise
kwargs:
# Satpy 1.0+
# msg: "No YAML enhancement found for {name!r}. Falling back to a dynamic linear stretch in case of floating point data, or no enhancement otherwise. See https://satpy.readthedocs.io/en/stable/enhancements.html for documentation on defining an enhancement."
msg: "No YAML enhancement found for {name!r}. Falling back to a dynamic linear stretch in case. In Satpy 1.0, non-floating data will no longer be scaled by this enhancement (ex. integer category products). See https://satpy.readthedocs.io/en/stable/enhancements.html for documentation on defining an enhancement."
- name: stretch
method: !!python/name:satpy.enhancements.contrast.stretch_if_floating
kwargs: {stretch: linear}
reflectance_default:
standard_name: toa_bidirectional_reflectance
operations:
Expand Down
4 changes: 2 additions & 2 deletions satpy/tests/compositor_tests/test_fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ def setUp(self):
a[:, 1, 0] = 0.3
a[:, 1, 1] = 0.4
a = da.from_array(a, a.shape)
self.data_a = xr.DataArray(a, attrs={"test": "a", "start_time": start_time},
self.data_a = xr.DataArray(a, attrs={"test": "a", "start_time": start_time, "name": "a"},
coords={"bands": bands}, dims=("bands", "y", "x"))
b = np.zeros((3, 2, 2), dtype=np.float32)
b[:, 0, 0] = np.nan
b[:, 0, 1] = 0.25
b[:, 1, 0] = 0.50
b[:, 1, 1] = 0.75
b = da.from_array(b, b.shape)
self.data_b = xr.DataArray(b, attrs={"test": "b", "start_time": start_time},
self.data_b = xr.DataArray(b, attrs={"test": "b", "start_time": start_time, "name": "b"},
coords={"bands": bands}, dims=("bands", "y", "x"))

sza = np.array([[80., 86.], [94., 100.]], dtype=np.float32)
Expand Down
1 change: 1 addition & 0 deletions satpy/tests/compositor_tests/test_resolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ def test_compositor(self):
# Three shades of grey
rgb_arr = np.array([1, 50, 100, 200, 1, 50, 100, 200, 1, 50, 100, 200])
rgb = xr.DataArray(rgb_arr.reshape((3, 2, 2)),
attrs={"name": "rgb"},
dims=["bands", "y", "x"], coords={"bands": ["R", "G", "B"]})
# 100 % luminance -> all result values ~1.0
lum = xr.DataArray(np.array([[100., 100.], [100., 100.]]),
Expand Down
4 changes: 2 additions & 2 deletions satpy/tests/enhancement_tests/test_enhancer.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def test_enhance_empty_config(self, test_configs_path):

from satpy.enhancements.enhancer import Enhancer, get_enhanced_image
ds = DataArray(np.arange(1, 11.).reshape((2, 5)),
attrs=dict(sensor="test_empty", mode="L"),
attrs=dict(sensor="test_empty", mode="L", name="1"),
dims=["y", "x"])
e = Enhancer()
assert e.enhancement_tree is not None
Expand All @@ -296,7 +296,7 @@ def test_enhance_with_sensor_no_entry(self, test_configs_path):

from satpy.enhancements.enhancer import Enhancer, get_enhanced_image
ds = DataArray(np.arange(1, 11.).reshape((2, 5)),
attrs=dict(sensor="test_sensor2", mode="L"),
attrs=dict(sensor="test_sensor2", mode="L", name="1"),
dims=["y", "x"])
e = Enhancer()
assert e.enhancement_tree is not None
Expand Down
127 changes: 69 additions & 58 deletions satpy/tests/enhancement_tests/test_stretching.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,61 +21,72 @@
from .utils import create_ch1, create_ch2, create_rgb, run_and_check_enhancement, run_and_check_enhancement_with_dtype


class TestEnhancementsStretching:
"""Class for testing enhancements in satpy.enhancements.contrast module."""

def setup_method(self):
"""Create test data used by every test."""
self.ch1 = create_ch1()
self.ch2 = create_ch2()
self.rgb = create_rgb()

@pytest.mark.parametrize("dtype", [np.float32, np.float64])
def test_cira_stretch(self, dtype):
"""Test applying the cira_stretch."""
from satpy.enhancements.contrast import cira_stretch

expected = np.array([[
[np.nan, -7.04045974, -7.04045974, 0.79630132, 0.95947296],
[1.05181359, 1.11651012, 1.16635571, 1.20691137, 1.24110186]]], dtype=dtype)
run_and_check_enhancement_with_dtype(cira_stretch, self.ch1.astype(dtype), expected)

def test_reinhard(self):
"""Test the reinhard algorithm."""
from satpy.enhancements.contrast import reinhard_to_srgb
expected = np.array([[[np.nan, 0., 0., 0.93333793, 1.29432402],
[1.55428709, 1.76572249, 1.94738635, 2.10848544, 2.25432809]],

[[np.nan, 0., 0., 0.93333793, 1.29432402],
[1.55428709, 1.76572249, 1.94738635, 2.10848544, 2.25432809]],

[[np.nan, 0., 0., 0.93333793, 1.29432402],
[1.55428709, 1.76572249, 1.94738635, 2.10848544, 2.25432809]]])
run_and_check_enhancement(reinhard_to_srgb, self.rgb, expected)

def test_piecewise_linear_stretch(self):
"""Test the piecewise_linear_stretch enhancement function."""
from satpy.enhancements.contrast import piecewise_linear_stretch
expected = np.array([[
[np.nan, 0., 0., 0.44378, 0.631734],
[0.737562, 0.825041, 0.912521, 1., 1.]]])
run_and_check_enhancement(piecewise_linear_stretch,
self.ch2 / 100.0,
expected,
xp=[0., 25., 55., 100., 255.],
fp=[0., 90., 140., 175., 255.],
reference_scale_factor=255,
)

def test_btemp_threshold(self):
"""Test applying the cira_stretch."""
from satpy.enhancements.contrast import btemp_threshold

expected = np.array([[
[np.nan, 0.946207, 0.892695, 0.839184, 0.785672],
[0.73216, 0.595869, 0.158745, -0.278379, -0.715503]]])
run_and_check_enhancement(btemp_threshold, self.ch1, expected,
min_in=-200, max_in=500, threshold=350)

def tearDown(self):
"""Clean up."""
def test_default_enhancement_warning():
"""Test that the default enhancement warns for floating point data."""
from trollimage.xrimage import XRImage

from satpy.enhancements.contrast import warn_if_float_debug_otherwise

ch1 = create_ch1()
ch1.attrs["name"] = "NAME"
img = XRImage(ch1)

with pytest.warns(UserWarning, match="TEST NAME"):
warn_if_float_debug_otherwise(img, msg="TEST {name}")


@pytest.mark.parametrize("dtype", [np.float32, np.float64])
def test_cira_stretch(dtype):
"""Test applying the cira_stretch."""
from satpy.enhancements.contrast import cira_stretch

ch1 = create_ch1()
expected = np.array([[
[np.nan, -7.04045974, -7.04045974, 0.79630132, 0.95947296],
[1.05181359, 1.11651012, 1.16635571, 1.20691137, 1.24110186]]], dtype=dtype)
run_and_check_enhancement_with_dtype(cira_stretch, ch1.astype(dtype), expected)


def test_reinhard():
"""Test the reinhard algorithm."""
from satpy.enhancements.contrast import reinhard_to_srgb

rgb = create_rgb()
expected = np.array([[[np.nan, 0., 0., 0.93333793, 1.29432402],
[1.55428709, 1.76572249, 1.94738635, 2.10848544, 2.25432809]],

[[np.nan, 0., 0., 0.93333793, 1.29432402],
[1.55428709, 1.76572249, 1.94738635, 2.10848544, 2.25432809]],

[[np.nan, 0., 0., 0.93333793, 1.29432402],
[1.55428709, 1.76572249, 1.94738635, 2.10848544, 2.25432809]]])
run_and_check_enhancement(reinhard_to_srgb, rgb, expected)


def test_piecewise_linear_stretch():
"""Test the piecewise_linear_stretch enhancement function."""
from satpy.enhancements.contrast import piecewise_linear_stretch

ch2 = create_ch2()
expected = np.array([[
[np.nan, 0., 0., 0.44378, 0.631734],
[0.737562, 0.825041, 0.912521, 1., 1.]]])
run_and_check_enhancement(piecewise_linear_stretch,
ch2 / 100.0,
expected,
xp=[0., 25., 55., 100., 255.],
fp=[0., 90., 140., 175., 255.],
reference_scale_factor=255,
)


def test_btemp_threshold():
"""Test applying the cira_stretch."""
from satpy.enhancements.contrast import btemp_threshold

ch1 = create_ch1()
expected = np.array([[
[np.nan, 0.946207, 0.892695, 0.839184, 0.785672],
[0.73216, 0.595869, 0.158745, -0.278379, -0.715503]]])
run_and_check_enhancement(btemp_threshold, ch1, expected,
min_in=-200, max_in=500, threshold=350)
4 changes: 3 additions & 1 deletion satpy/tests/writer_tests/test_core/test_compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ def test_group_results_by_output_file(tmp_path):
fake_area = create_area_def("sargasso", 4326, resolution=1, width=x, height=x, center=(0, 0))
fake_scene = make_fake_scene(
{
"dragon_top_height": (dat := xr.DataArray(dims=("y", "x"), data=da.arange(x * x).reshape((x, x)))),
"dragon_top_height": (dat := xr.DataArray(
dims=("y", "x"),
data=da.arange(float(x * x)).reshape((x, x)))),
"penguin_bottom_height": dat,
"kraken_depth": dat,
},
Expand Down
Loading