From 5318516e555ac87fc4ed7e511e2886363f5b841e Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Wed, 7 Mar 2018 16:28:44 +0200 Subject: [PATCH 01/17] Fix mask checking in mask_source_lonlats() --- satpy/resample.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/satpy/resample.py b/satpy/resample.py index 6674d056fb..d978b47c60 100644 --- a/satpy/resample.py +++ b/satpy/resample.py @@ -483,6 +483,7 @@ def compute(self, data, fill_value=None, **kwargs): class NativeResampler(BaseResampler): + """Expand or reduce input datasets to be the same shape. If `expand=True` (default) input datasets are replicated in both @@ -492,6 +493,7 @@ class NativeResampler(BaseResampler): of the target area. """ + def resample(self, data, cache_dir=False, mask_area=False, **kwargs): # use 'mask_area' with a default of False. It wouldn't do anything. return super(NativeResampler, self).resample(data, @@ -673,7 +675,7 @@ def mask_source_lonlats(source_def, mask): # the data may have additional masked pixels # let's compare them to see if we can use the same area # assume lons and lats mask are the same - if mask and isinstance(source_geo_def, SwathDefinition): + if mask is not None and isinstance(source_geo_def, SwathDefinition): if np.issubsctype(mask.dtype, np.bool): # copy the source area and use it for the rest of the calculations LOG.debug("Copying source area to mask invalid dataset points") From 964e392efc2da2cf4b18e849ea2cbf0af6bab731 Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Wed, 7 Mar 2018 16:29:41 +0200 Subject: [PATCH 02/17] Add first try of xarray/daskifying DayNightCompositor --- satpy/composites/__init__.py | 110 +++++++++++++++-------------------- 1 file changed, 47 insertions(+), 63 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index aec5918790..acbaed096b 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -770,56 +770,50 @@ class DayNightCompositor(GenericCompositor): """A compositor that takes one composite on the night side, another on day side, and then blends them together.""" - def __call__(self, projectables, lim_low=85., lim_high=95., *args, - **kwargs): - if len(projectables) != 3: - raise ValueError("Expected 3 datasets, got %d" % - (len(projectables), )) - try: - day_data = projectables[0].copy() - night_data = projectables[1].copy() - coszen = np.cos(np.deg2rad(projectables[2])) - - coszen -= min(np.cos(np.deg2rad(lim_high)), - np.cos(np.deg2rad(lim_low))) - coszen /= np.abs(np.cos(np.deg2rad(lim_low)) - - np.cos(np.deg2rad(lim_high))) - coszen = np.clip(coszen, 0, 1) - - full_data = [] - - # Apply enhancements - day_data = enhance2dataset(day_data) - night_data = enhance2dataset(night_data) - - # Match dimensions to the data with more channels - # There are only 1-channel and 3-channel composites - if day_data.shape[0] > night_data.shape[0]: - night_data = np.ma.repeat(night_data, 3, 0) - elif day_data.shape[0] < night_data.shape[0]: - day_data = np.ma.repeat(day_data, 3, 0) - - for i in range(day_data.shape[0]): - day = day_data[i, :, :] - night = night_data[i, :, :] - - data = (1 - coszen) * np.ma.masked_invalid(night).filled(0) + \ - coszen * np.ma.masked_invalid(day).filled(0) - data = np.ma.array(data, mask=np.logical_and(night.mask, - day.mask), - copy=False) - data = Dataset(np.ma.masked_invalid(data), - copy=True, - **projectables[0].info) - full_data.append(data) - - res = super(DayNightCompositor, self).__call__((full_data[0], - full_data[1], - full_data[2]), - *args, **kwargs) + def __init__(self, lim_low=85., lim_high=95., *args, **kwargs): + """Collect custom configuration values. - except ValueError: - raise IncompatibleAreas + Args: + lim_low (float): lower limit of Sun zenith angle for the + blending of the given channels + lim_high (float): upper limit of Sun zenith angle for the + blending of the given channels + """ + self.lim_low = lim_low + self.lim_high = lim_high + super(DayNightCompositor, self).__init__(*args, **kwargs) + + def __call__(self, projectables, *args, **kwargs): + + day_data = projectables[0] + night_data = projectables[1] + + lim_low = np.cos(np.deg2rad(self.lim_low)) + lim_high = np.cos(np.deg2rad(self.lim_high)) + try: + coszen = xu.cos(xu.deg2rad(projectables[2])) + except IndexError: + from pyorbital.astronomy import cos_zen + LOG.debug("Computing sun zenith angles.") + lons, lats = day_data.attrs["area"].get_lonlats_dask(CHUNK_SIZE) + coszen = xr.DataArray(cos_zen(day_data.attrs["start_time"], + lons, lats), + dims=['y', 'x'], + coords=[day_data['y'], day_data['x']]) + # Calculate blending weights + coszen -= np.min((lim_high, lim_low)) + coszen /= np.abs(lim_low - lim_high) + coszen = coszen.clip(0, 1) + + # Apply enhancements to get images + day_data = enhance2dataset(day_data).clip(0.0, 1.0).fillna(0.0) + night_data = enhance2dataset(night_data).clip(0.0, 1.0).fillna(0.0) + + data = (1 - coszen) * night_data + coszen * day_data + data = data.where(data <= 0.0) + + res = super(DayNightCompositor, self).__call__((data, ), + **kwargs) return res @@ -979,21 +973,10 @@ def __call__(self, projectables, **kwargs): def enhance2dataset(dset): - """Apply enhancements to dataset *dset* and convert the image data - back to Dataset object.""" + """Apply enhancements to dataset *dset* and return the resulting data + array of the image.""" img = get_enhanced_image(dset) - - data = np.rollaxis(np.dstack(img.channels), axis=2) - mask = dset.mask - if mask.ndim < data.ndim: - mask = np.expand_dims(mask, 0) - mask = np.repeat(mask, 3, 0) - elif mask.ndim > data.ndim: - mask = mask[0, :, :] - data = Dataset(np.ma.masked_array(data, mask=mask), - copy=False, - **dset.info) - return data + return img.data class RatioSharpenedRGB(GenericCompositor): @@ -1079,6 +1062,7 @@ def __call__(self, datasets, optional_datasets=None, **info): class SelfSharpenedRGB(RatioSharpenedRGB): + """Sharpen RGB with ratio of a band with a strided-version of itself. Example: From d007e426d244bdb8d3ad9db2ada0fb1baed6bafc Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 08:05:54 +0200 Subject: [PATCH 03/17] Remove unnecesary, and harmful, masking --- satpy/composites/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index acbaed096b..0191a873ff 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -810,7 +810,6 @@ def __call__(self, projectables, *args, **kwargs): night_data = enhance2dataset(night_data).clip(0.0, 1.0).fillna(0.0) data = (1 - coszen) * night_data + coszen * day_data - data = data.where(data <= 0.0) res = super(DayNightCompositor, self).__call__((data, ), **kwargs) From 94a423805c4e1afa90abfd5ae0b3baa69e825117 Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 10:57:39 +0200 Subject: [PATCH 04/17] Add bands if diffent mode images are used with DayNightCompositor --- satpy/composites/__init__.py | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index 0191a873ff..dccb050c25 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -809,10 +809,19 @@ def __call__(self, projectables, *args, **kwargs): day_data = enhance2dataset(day_data).clip(0.0, 1.0).fillna(0.0) night_data = enhance2dataset(night_data).clip(0.0, 1.0).fillna(0.0) + # Adjust bands so that they match + # L/RGB -> RGB/RGB + # LA/RGB -> RGBA/RGBA + # RGB/RGBA -> RGBA/RGBA + day_data = add_bands(day_data, night_data['bands']) + night_data = add_bands(night_data, day_data['bands']) + data = (1 - coszen) * night_data + coszen * day_data - res = super(DayNightCompositor, self).__call__((data, ), - **kwargs) + # Split to separate bands so the mode is correct + data = [data.sel(bands=b) for b in data.bands] + + res = super(DayNightCompositor, self).__call__(data, **kwargs) return res @@ -978,6 +987,28 @@ def enhance2dataset(dset): return img.data +def add_bands(data, bands): + """Add bands so that they match *bands*""" + # Add R, G and B bands, remove L band + if 'L' in data.bands.data and 'R' in bands.data: + lum = data.sel(bands='L') + new_data = xr.concat((lum, lum, lum), dim='bands') + new_data['bands'] = ['R', 'G', 'B'] + new_data.attrs = data.attrs + data = new_data + # Add alpha band + if 'A' not in data.bands.data and 'A' in bands.data: + alpha = da.ones((data.sizes['y'], data.sizes['x']), + chunks=data.chunks) + new_data = [data.sel(bands=band) for band in data.bands.data] + new_data.append(alpha) + new_data = xr.concat(new_data) + new_data.attrs = data.attrs + data = new_data + + return data + + class RatioSharpenedRGB(GenericCompositor): def __init__(self, *args, **kwargs): From 3a51cc748e55b850da15f3c022c706c42bb722f0 Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 10:58:51 +0200 Subject: [PATCH 05/17] Move DayNightCompositor helper functions closer to it --- satpy/composites/__init__.py | 58 ++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index dccb050c25..945bc88095 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -826,6 +826,35 @@ def __call__(self, projectables, *args, **kwargs): return res +def enhance2dataset(dset): + """Apply enhancements to dataset *dset* and return the resulting data + array of the image.""" + img = get_enhanced_image(dset) + return img.data + + +def add_bands(data, bands): + """Add bands so that they match *bands*""" + # Add R, G and B bands, remove L band + if 'L' in data.bands.data and 'R' in bands.data: + lum = data.sel(bands='L') + new_data = xr.concat((lum, lum, lum), dim='bands') + new_data['bands'] = ['R', 'G', 'B'] + new_data.attrs = data.attrs + data = new_data + # Add alpha band + if 'A' not in data.bands.data and 'A' in bands.data: + alpha = da.ones((data.sizes['y'], data.sizes['x']), + chunks=data.chunks) + new_data = [data.sel(bands=band) for band in data.bands.data] + new_data.append(alpha) + new_data = xr.concat(new_data) + new_data.attrs = data.attrs + data = new_data + + return data + + class Airmass(GenericCompositor): def __call__(self, projectables, *args, **kwargs): @@ -980,35 +1009,6 @@ def __call__(self, projectables, **kwargs): return res -def enhance2dataset(dset): - """Apply enhancements to dataset *dset* and return the resulting data - array of the image.""" - img = get_enhanced_image(dset) - return img.data - - -def add_bands(data, bands): - """Add bands so that they match *bands*""" - # Add R, G and B bands, remove L band - if 'L' in data.bands.data and 'R' in bands.data: - lum = data.sel(bands='L') - new_data = xr.concat((lum, lum, lum), dim='bands') - new_data['bands'] = ['R', 'G', 'B'] - new_data.attrs = data.attrs - data = new_data - # Add alpha band - if 'A' not in data.bands.data and 'A' in bands.data: - alpha = da.ones((data.sizes['y'], data.sizes['x']), - chunks=data.chunks) - new_data = [data.sel(bands=band) for band in data.bands.data] - new_data.append(alpha) - new_data = xr.concat(new_data) - new_data.attrs = data.attrs - data = new_data - - return data - - class RatioSharpenedRGB(GenericCompositor): def __init__(self, *args, **kwargs): From 54637538e3d54f1cc6fa31ce8969ff3c1118076a Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 13:13:15 +0200 Subject: [PATCH 06/17] Fix adding alpha band to DataArray --- satpy/composites/__init__.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index 945bc88095..e6d6423c1e 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -844,11 +844,16 @@ def add_bands(data, bands): data = new_data # Add alpha band if 'A' not in data.bands.data and 'A' in bands.data: - alpha = da.ones((data.sizes['y'], data.sizes['x']), - chunks=data.chunks) new_data = [data.sel(bands=band) for band in data.bands.data] + # Create alpha band on top of a copy of the first "real" band + alpha = new_data[0].copy() + alpha.data = da.ones((data.sizes['y'], + data.sizes['x']), + chunks=new_data[0].chunks) + # Rename band to indicate it's alpha + alpha['bands'] = 'A' new_data.append(alpha) - new_data = xr.concat(new_data) + new_data = xr.concat(new_data, dim='bands') new_data.attrs = data.attrs data = new_data From daf64405df18493491f6cfbb71653860de9a1812 Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 13:52:38 +0200 Subject: [PATCH 07/17] Fix metadata handling for DayNightCompositor --- satpy/composites/__init__.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index e6d6423c1e..947d3356a2 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -806,8 +806,8 @@ def __call__(self, projectables, *args, **kwargs): coszen = coszen.clip(0, 1) # Apply enhancements to get images - day_data = enhance2dataset(day_data).clip(0.0, 1.0).fillna(0.0) - night_data = enhance2dataset(night_data).clip(0.0, 1.0).fillna(0.0) + day_data = enhance2dataset(day_data) + night_data = enhance2dataset(night_data) # Adjust bands so that they match # L/RGB -> RGB/RGB @@ -816,7 +816,12 @@ def __call__(self, projectables, *args, **kwargs): day_data = add_bands(day_data, night_data['bands']) night_data = add_bands(night_data, day_data['bands']) + # Get merged metadata + attrs = combine_metadata(day_data, night_data) + + # Blend the two images together data = (1 - coszen) * night_data + coszen * day_data + data.attrs = attrs # Split to separate bands so the mode is correct data = [data.sel(bands=b) for b in data.bands] @@ -829,8 +834,13 @@ def __call__(self, projectables, *args, **kwargs): def enhance2dataset(dset): """Apply enhancements to dataset *dset* and return the resulting data array of the image.""" + attrs = dset.attrs img = get_enhanced_image(dset) - return img.data + # Clip image data to interval [0.0, 1.0] and replace nan values + data = img.data.clip(0.0, 1.0).fillna(0.0) + data.attrs = attrs + + return data def add_bands(data, bands): @@ -840,12 +850,11 @@ def add_bands(data, bands): lum = data.sel(bands='L') new_data = xr.concat((lum, lum, lum), dim='bands') new_data['bands'] = ['R', 'G', 'B'] - new_data.attrs = data.attrs data = new_data # Add alpha band if 'A' not in data.bands.data and 'A' in bands.data: new_data = [data.sel(bands=band) for band in data.bands.data] - # Create alpha band on top of a copy of the first "real" band + # Create alpha band based on a copy of the first "real" band alpha = new_data[0].copy() alpha.data = da.ones((data.sizes['y'], data.sizes['x']), @@ -854,7 +863,6 @@ def add_bands(data, bands): alpha['bands'] = 'A' new_data.append(alpha) new_data = xr.concat(new_data, dim='bands') - new_data.attrs = data.attrs data = new_data return data From cc17908b4b0fbb19d5f9f25bbb0fe0fc161f544a Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Wed, 7 Mar 2018 16:28:44 +0200 Subject: [PATCH 08/17] Fix mask checking in mask_source_lonlats() --- satpy/resample.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/satpy/resample.py b/satpy/resample.py index 3e1d7eb22f..26bebdbaca 100644 --- a/satpy/resample.py +++ b/satpy/resample.py @@ -483,6 +483,7 @@ def compute(self, data, fill_value=None, **kwargs): class NativeResampler(BaseResampler): + """Expand or reduce input datasets to be the same shape. If `expand=True` (default) input datasets are replicated in both @@ -492,6 +493,7 @@ class NativeResampler(BaseResampler): of the target area. """ + def resample(self, data, cache_dir=False, mask_area=False, **kwargs): # use 'mask_area' with a default of False. It wouldn't do anything. return super(NativeResampler, self).resample(data, From c2abbd8b90650ad744a691d8d9d6c5ae506f1d4d Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Wed, 7 Mar 2018 16:29:41 +0200 Subject: [PATCH 09/17] Add first try of xarray/daskifying DayNightCompositor --- satpy/composites/__init__.py | 110 +++++++++++++++-------------------- 1 file changed, 47 insertions(+), 63 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index aec5918790..acbaed096b 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -770,56 +770,50 @@ class DayNightCompositor(GenericCompositor): """A compositor that takes one composite on the night side, another on day side, and then blends them together.""" - def __call__(self, projectables, lim_low=85., lim_high=95., *args, - **kwargs): - if len(projectables) != 3: - raise ValueError("Expected 3 datasets, got %d" % - (len(projectables), )) - try: - day_data = projectables[0].copy() - night_data = projectables[1].copy() - coszen = np.cos(np.deg2rad(projectables[2])) - - coszen -= min(np.cos(np.deg2rad(lim_high)), - np.cos(np.deg2rad(lim_low))) - coszen /= np.abs(np.cos(np.deg2rad(lim_low)) - - np.cos(np.deg2rad(lim_high))) - coszen = np.clip(coszen, 0, 1) - - full_data = [] - - # Apply enhancements - day_data = enhance2dataset(day_data) - night_data = enhance2dataset(night_data) - - # Match dimensions to the data with more channels - # There are only 1-channel and 3-channel composites - if day_data.shape[0] > night_data.shape[0]: - night_data = np.ma.repeat(night_data, 3, 0) - elif day_data.shape[0] < night_data.shape[0]: - day_data = np.ma.repeat(day_data, 3, 0) - - for i in range(day_data.shape[0]): - day = day_data[i, :, :] - night = night_data[i, :, :] - - data = (1 - coszen) * np.ma.masked_invalid(night).filled(0) + \ - coszen * np.ma.masked_invalid(day).filled(0) - data = np.ma.array(data, mask=np.logical_and(night.mask, - day.mask), - copy=False) - data = Dataset(np.ma.masked_invalid(data), - copy=True, - **projectables[0].info) - full_data.append(data) - - res = super(DayNightCompositor, self).__call__((full_data[0], - full_data[1], - full_data[2]), - *args, **kwargs) + def __init__(self, lim_low=85., lim_high=95., *args, **kwargs): + """Collect custom configuration values. - except ValueError: - raise IncompatibleAreas + Args: + lim_low (float): lower limit of Sun zenith angle for the + blending of the given channels + lim_high (float): upper limit of Sun zenith angle for the + blending of the given channels + """ + self.lim_low = lim_low + self.lim_high = lim_high + super(DayNightCompositor, self).__init__(*args, **kwargs) + + def __call__(self, projectables, *args, **kwargs): + + day_data = projectables[0] + night_data = projectables[1] + + lim_low = np.cos(np.deg2rad(self.lim_low)) + lim_high = np.cos(np.deg2rad(self.lim_high)) + try: + coszen = xu.cos(xu.deg2rad(projectables[2])) + except IndexError: + from pyorbital.astronomy import cos_zen + LOG.debug("Computing sun zenith angles.") + lons, lats = day_data.attrs["area"].get_lonlats_dask(CHUNK_SIZE) + coszen = xr.DataArray(cos_zen(day_data.attrs["start_time"], + lons, lats), + dims=['y', 'x'], + coords=[day_data['y'], day_data['x']]) + # Calculate blending weights + coszen -= np.min((lim_high, lim_low)) + coszen /= np.abs(lim_low - lim_high) + coszen = coszen.clip(0, 1) + + # Apply enhancements to get images + day_data = enhance2dataset(day_data).clip(0.0, 1.0).fillna(0.0) + night_data = enhance2dataset(night_data).clip(0.0, 1.0).fillna(0.0) + + data = (1 - coszen) * night_data + coszen * day_data + data = data.where(data <= 0.0) + + res = super(DayNightCompositor, self).__call__((data, ), + **kwargs) return res @@ -979,21 +973,10 @@ def __call__(self, projectables, **kwargs): def enhance2dataset(dset): - """Apply enhancements to dataset *dset* and convert the image data - back to Dataset object.""" + """Apply enhancements to dataset *dset* and return the resulting data + array of the image.""" img = get_enhanced_image(dset) - - data = np.rollaxis(np.dstack(img.channels), axis=2) - mask = dset.mask - if mask.ndim < data.ndim: - mask = np.expand_dims(mask, 0) - mask = np.repeat(mask, 3, 0) - elif mask.ndim > data.ndim: - mask = mask[0, :, :] - data = Dataset(np.ma.masked_array(data, mask=mask), - copy=False, - **dset.info) - return data + return img.data class RatioSharpenedRGB(GenericCompositor): @@ -1079,6 +1062,7 @@ def __call__(self, datasets, optional_datasets=None, **info): class SelfSharpenedRGB(RatioSharpenedRGB): + """Sharpen RGB with ratio of a band with a strided-version of itself. Example: From ac302b024981f0ec7b3fbd7c49183a574f9f3287 Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 08:05:54 +0200 Subject: [PATCH 10/17] Remove unnecesary, and harmful, masking --- satpy/composites/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index acbaed096b..0191a873ff 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -810,7 +810,6 @@ def __call__(self, projectables, *args, **kwargs): night_data = enhance2dataset(night_data).clip(0.0, 1.0).fillna(0.0) data = (1 - coszen) * night_data + coszen * day_data - data = data.where(data <= 0.0) res = super(DayNightCompositor, self).__call__((data, ), **kwargs) From fef2dc563183d49ad990d1997550d9c8caf93f99 Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 10:57:39 +0200 Subject: [PATCH 11/17] Add bands if diffent mode images are used with DayNightCompositor --- satpy/composites/__init__.py | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index 0191a873ff..dccb050c25 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -809,10 +809,19 @@ def __call__(self, projectables, *args, **kwargs): day_data = enhance2dataset(day_data).clip(0.0, 1.0).fillna(0.0) night_data = enhance2dataset(night_data).clip(0.0, 1.0).fillna(0.0) + # Adjust bands so that they match + # L/RGB -> RGB/RGB + # LA/RGB -> RGBA/RGBA + # RGB/RGBA -> RGBA/RGBA + day_data = add_bands(day_data, night_data['bands']) + night_data = add_bands(night_data, day_data['bands']) + data = (1 - coszen) * night_data + coszen * day_data - res = super(DayNightCompositor, self).__call__((data, ), - **kwargs) + # Split to separate bands so the mode is correct + data = [data.sel(bands=b) for b in data.bands] + + res = super(DayNightCompositor, self).__call__(data, **kwargs) return res @@ -978,6 +987,28 @@ def enhance2dataset(dset): return img.data +def add_bands(data, bands): + """Add bands so that they match *bands*""" + # Add R, G and B bands, remove L band + if 'L' in data.bands.data and 'R' in bands.data: + lum = data.sel(bands='L') + new_data = xr.concat((lum, lum, lum), dim='bands') + new_data['bands'] = ['R', 'G', 'B'] + new_data.attrs = data.attrs + data = new_data + # Add alpha band + if 'A' not in data.bands.data and 'A' in bands.data: + alpha = da.ones((data.sizes['y'], data.sizes['x']), + chunks=data.chunks) + new_data = [data.sel(bands=band) for band in data.bands.data] + new_data.append(alpha) + new_data = xr.concat(new_data) + new_data.attrs = data.attrs + data = new_data + + return data + + class RatioSharpenedRGB(GenericCompositor): def __init__(self, *args, **kwargs): From f65698776c0004731019e7850ef33caa10984ad1 Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 10:58:51 +0200 Subject: [PATCH 12/17] Move DayNightCompositor helper functions closer to it --- satpy/composites/__init__.py | 58 ++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index dccb050c25..945bc88095 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -826,6 +826,35 @@ def __call__(self, projectables, *args, **kwargs): return res +def enhance2dataset(dset): + """Apply enhancements to dataset *dset* and return the resulting data + array of the image.""" + img = get_enhanced_image(dset) + return img.data + + +def add_bands(data, bands): + """Add bands so that they match *bands*""" + # Add R, G and B bands, remove L band + if 'L' in data.bands.data and 'R' in bands.data: + lum = data.sel(bands='L') + new_data = xr.concat((lum, lum, lum), dim='bands') + new_data['bands'] = ['R', 'G', 'B'] + new_data.attrs = data.attrs + data = new_data + # Add alpha band + if 'A' not in data.bands.data and 'A' in bands.data: + alpha = da.ones((data.sizes['y'], data.sizes['x']), + chunks=data.chunks) + new_data = [data.sel(bands=band) for band in data.bands.data] + new_data.append(alpha) + new_data = xr.concat(new_data) + new_data.attrs = data.attrs + data = new_data + + return data + + class Airmass(GenericCompositor): def __call__(self, projectables, *args, **kwargs): @@ -980,35 +1009,6 @@ def __call__(self, projectables, **kwargs): return res -def enhance2dataset(dset): - """Apply enhancements to dataset *dset* and return the resulting data - array of the image.""" - img = get_enhanced_image(dset) - return img.data - - -def add_bands(data, bands): - """Add bands so that they match *bands*""" - # Add R, G and B bands, remove L band - if 'L' in data.bands.data and 'R' in bands.data: - lum = data.sel(bands='L') - new_data = xr.concat((lum, lum, lum), dim='bands') - new_data['bands'] = ['R', 'G', 'B'] - new_data.attrs = data.attrs - data = new_data - # Add alpha band - if 'A' not in data.bands.data and 'A' in bands.data: - alpha = da.ones((data.sizes['y'], data.sizes['x']), - chunks=data.chunks) - new_data = [data.sel(bands=band) for band in data.bands.data] - new_data.append(alpha) - new_data = xr.concat(new_data) - new_data.attrs = data.attrs - data = new_data - - return data - - class RatioSharpenedRGB(GenericCompositor): def __init__(self, *args, **kwargs): From acfc0860a359c0674f060a6d94ef10bd1569586f Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 13:13:15 +0200 Subject: [PATCH 13/17] Fix adding alpha band to DataArray --- satpy/composites/__init__.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index 945bc88095..e6d6423c1e 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -844,11 +844,16 @@ def add_bands(data, bands): data = new_data # Add alpha band if 'A' not in data.bands.data and 'A' in bands.data: - alpha = da.ones((data.sizes['y'], data.sizes['x']), - chunks=data.chunks) new_data = [data.sel(bands=band) for band in data.bands.data] + # Create alpha band on top of a copy of the first "real" band + alpha = new_data[0].copy() + alpha.data = da.ones((data.sizes['y'], + data.sizes['x']), + chunks=new_data[0].chunks) + # Rename band to indicate it's alpha + alpha['bands'] = 'A' new_data.append(alpha) - new_data = xr.concat(new_data) + new_data = xr.concat(new_data, dim='bands') new_data.attrs = data.attrs data = new_data From a072c9c5ccd6acc6104dc91b72714332447185bb Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Thu, 8 Mar 2018 13:52:38 +0200 Subject: [PATCH 14/17] Fix metadata handling for DayNightCompositor --- satpy/composites/__init__.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index e6d6423c1e..947d3356a2 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -806,8 +806,8 @@ def __call__(self, projectables, *args, **kwargs): coszen = coszen.clip(0, 1) # Apply enhancements to get images - day_data = enhance2dataset(day_data).clip(0.0, 1.0).fillna(0.0) - night_data = enhance2dataset(night_data).clip(0.0, 1.0).fillna(0.0) + day_data = enhance2dataset(day_data) + night_data = enhance2dataset(night_data) # Adjust bands so that they match # L/RGB -> RGB/RGB @@ -816,7 +816,12 @@ def __call__(self, projectables, *args, **kwargs): day_data = add_bands(day_data, night_data['bands']) night_data = add_bands(night_data, day_data['bands']) + # Get merged metadata + attrs = combine_metadata(day_data, night_data) + + # Blend the two images together data = (1 - coszen) * night_data + coszen * day_data + data.attrs = attrs # Split to separate bands so the mode is correct data = [data.sel(bands=b) for b in data.bands] @@ -829,8 +834,13 @@ def __call__(self, projectables, *args, **kwargs): def enhance2dataset(dset): """Apply enhancements to dataset *dset* and return the resulting data array of the image.""" + attrs = dset.attrs img = get_enhanced_image(dset) - return img.data + # Clip image data to interval [0.0, 1.0] and replace nan values + data = img.data.clip(0.0, 1.0).fillna(0.0) + data.attrs = attrs + + return data def add_bands(data, bands): @@ -840,12 +850,11 @@ def add_bands(data, bands): lum = data.sel(bands='L') new_data = xr.concat((lum, lum, lum), dim='bands') new_data['bands'] = ['R', 'G', 'B'] - new_data.attrs = data.attrs data = new_data # Add alpha band if 'A' not in data.bands.data and 'A' in bands.data: new_data = [data.sel(bands=band) for band in data.bands.data] - # Create alpha band on top of a copy of the first "real" band + # Create alpha band based on a copy of the first "real" band alpha = new_data[0].copy() alpha.data = da.ones((data.sizes['y'], data.sizes['x']), @@ -854,7 +863,6 @@ def add_bands(data, bands): alpha['bands'] = 'A' new_data.append(alpha) new_data = xr.concat(new_data, dim='bands') - new_data.attrs = data.attrs data = new_data return data From 78c1309fbb95de09bd45e8cc01b323a29dcd1ea2 Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Fri, 9 Mar 2018 13:05:49 +0200 Subject: [PATCH 15/17] Use data['bands'] instead of data.bands --- satpy/composites/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index 947d3356a2..c6ce9f3307 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -824,7 +824,7 @@ def __call__(self, projectables, *args, **kwargs): data.attrs = attrs # Split to separate bands so the mode is correct - data = [data.sel(bands=b) for b in data.bands] + data = [data.sel(bands=b) for b in data['bands']] res = super(DayNightCompositor, self).__call__(data, **kwargs) @@ -846,14 +846,14 @@ def enhance2dataset(dset): def add_bands(data, bands): """Add bands so that they match *bands*""" # Add R, G and B bands, remove L band - if 'L' in data.bands.data and 'R' in bands.data: + if 'L' in data['bands'].data and 'R' in bands.data: lum = data.sel(bands='L') new_data = xr.concat((lum, lum, lum), dim='bands') new_data['bands'] = ['R', 'G', 'B'] data = new_data # Add alpha band - if 'A' not in data.bands.data and 'A' in bands.data: - new_data = [data.sel(bands=band) for band in data.bands.data] + if 'A' not in data['bands'].data and 'A' in bands.data: + new_data = [data.sel(bands=band) for band in data['bands'].data] # Create alpha band based on a copy of the first "real" band alpha = new_data[0].copy() alpha.data = da.ones((data.sizes['y'], From 2961a2706636d7f1832f8fe978db97f6fdef3a4f Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Fri, 9 Mar 2018 13:33:00 +0200 Subject: [PATCH 16/17] Select lon and lat chunks so that it matches day_data --- satpy/composites/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index c6ce9f3307..6323e0bad2 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -795,7 +795,12 @@ def __call__(self, projectables, *args, **kwargs): except IndexError: from pyorbital.astronomy import cos_zen LOG.debug("Computing sun zenith angles.") - lons, lats = day_data.attrs["area"].get_lonlats_dask(CHUNK_SIZE) + # Get chunking that matches the data + try: + chunks = day_data.sel(bands=day_data['bands'][0]).chunks + except KeyError: + chunks = day_data.chunks + lons, lats = day_data.attrs["area"].get_lonlats_dask(chunks) coszen = xr.DataArray(cos_zen(day_data.attrs["start_time"], lons, lats), dims=['y', 'x'], From 184d74e23804a76ae7e346ec414df277a40843d2 Mon Sep 17 00:00:00 2001 From: Panu Lahtinen Date: Mon, 19 Mar 2018 10:51:56 +0200 Subject: [PATCH 17/17] Remove un-used "*args" from DayNightCompositor __init__() and __call__() --- satpy/composites/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/satpy/composites/__init__.py b/satpy/composites/__init__.py index 6323e0bad2..d6a201374b 100644 --- a/satpy/composites/__init__.py +++ b/satpy/composites/__init__.py @@ -770,7 +770,7 @@ class DayNightCompositor(GenericCompositor): """A compositor that takes one composite on the night side, another on day side, and then blends them together.""" - def __init__(self, lim_low=85., lim_high=95., *args, **kwargs): + def __init__(self, lim_low=85., lim_high=95., **kwargs): """Collect custom configuration values. Args: @@ -781,9 +781,9 @@ def __init__(self, lim_low=85., lim_high=95., *args, **kwargs): """ self.lim_low = lim_low self.lim_high = lim_high - super(DayNightCompositor, self).__init__(*args, **kwargs) + super(DayNightCompositor, self).__init__(**kwargs) - def __call__(self, projectables, *args, **kwargs): + def __call__(self, projectables, **kwargs): day_data = projectables[0] night_data = projectables[1]