#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2019 Satpy developers
#
# This file is part of satpy.
#
# satpy is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# satpy is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# satpy. If not, see <http://www.gnu.org/licenses/>.
"""Composite classes for the GLM instrument."""
import logging
import xarray as xr
from satpy.composites import GenericCompositor
from satpy.writers import get_enhanced_image
LOG = logging.getLogger(__name__)
[docs]
class HighlightCompositor(GenericCompositor):
"""Highlight pixels of a layer by an amount determined by a secondary layer.
The highlighting is applied per channel to either add or subtract an
intensity from the primary image. In the addition case, the code is
essentially doing::
highlight_factor = (highlight_data - min_highlight) / (max_highlight - min_highlight)
channel_result = primary_data + highlight_factor * max_factor
The ``max_factor`` is defined per channel and can be positive for an
additive effect, negative for a subtractive effect, or zero for no
effect.
"""
def __init__(self, name, min_highlight=0.0, max_highlight=10.0, # noqa: D417
max_factor=(0.8, 0.8, -0.8, 0), **kwargs):
"""Initialize composite with highlight factor options.
Args:
min_highlight (float): Minimum raw value of the "highlight" data
that will be used for linearly scaling the data along with
``max_highlight``.
max_highlight (float): Maximum raw value of the "highlight" data
that will be used for linearly scaling the data along with
``min_highlight``.
max_factor (tuple): Maximum effect that the highlight data can
have on each channel of the primary image data. This will be
multiplied by the linearly scaled highlight data and then
added or subtracted from the highlight channels. See class
docstring for more information. By default this is set to
``(0.8, 0.8, -0.8, 0)`` meaning the Red and Green channel
will be added to by at most 0.8, the Blue channel will be
subtracted from by at most 0.8 (resulting in yellow highlights),
and the Alpha channel will not be affected.
"""
self.min_highlight = min_highlight
self.max_highlight = max_highlight
self.max_factor = max_factor
super().__init__(name, **kwargs)
[docs]
@staticmethod
def _get_enhanced_background_data(background_layer):
img = get_enhanced_image(background_layer)
img.data = img.data.clip(0.0, 1.0)
img = img.convert("RGBA")
return img.data
[docs]
def _get_highlight_factor(self, highlight_data):
factor = (highlight_data - self.min_highlight) / (self.max_highlight - self.min_highlight)
factor = factor.where(factor.notnull(), 0)
return factor
[docs]
def _apply_highlight_effect(self, background_data, factor):
new_channels = []
for max_factor, band_name in zip(self.max_factor, "RGBA"):
new_channel = background_data.sel(bands=[band_name])
if max_factor != 0 or max_factor is not None:
new_channel = new_channel + factor * max_factor
new_channels.append(new_channel)
return new_channels
[docs]
def _update_attrs(self, new_data, background_layer, highlight_layer):
new_data.attrs = background_layer.attrs.copy()
new_data.attrs["units"] = 1
new_sensors = self._get_sensors((highlight_layer, background_layer))
new_data.attrs.update({
"sensor": new_sensors,
})
def __call__(self, projectables, optional_datasets=None, **attrs):
"""Create RGBA image with highlighted pixels."""
highlight_product, background_layer = self.match_data_arrays(projectables)
background_data = self._get_enhanced_background_data(background_layer)
# Adjust the colors of background by highlight layer
factor = self._get_highlight_factor(highlight_product)
new_channels = self._apply_highlight_effect(background_data, factor)
new_data = xr.concat(new_channels, dim="bands")
self._update_attrs(new_data, background_layer,
highlight_product)
return super(HighlightCompositor, self).__call__((new_data,), **attrs)