def setUp(self): """Create test data and mock pycoast/pydecorate.""" from trollimage.xrimage import XRImage from pyresample.geometry import AreaDefinition import xarray as xr import dask.array as da proj_dict = {'proj': 'lcc', 'datum': 'WGS84', 'ellps': 'WGS84', 'lon_0': -95., 'lat_0': 25, 'lat_1': 25, 'units': 'm', 'no_defs': True} self.area_def = AreaDefinition( 'test', 'test', 'test', proj_dict, 200, 400, (-1000., -1500., 1000., 1500.), ) self.orig_rgb_img = XRImage( xr.DataArray(da.arange(75., chunks=10).reshape(3, 5, 5) / 75., dims=('bands', 'y', 'x'), coords={'bands': ['R', 'G', 'B']}, attrs={'name': 'test_ds', 'area': self.area_def}) ) self.orig_l_img = XRImage( xr.DataArray(da.arange(25., chunks=10).reshape(5, 5) / 75., dims=('y', 'x'), attrs={'name': 'test_ds', 'area': self.area_def}) ) self.decorate = { 'decorate': [ {'logo': {'logo_path': '', 'height': 143, 'bg': 'white', 'bg_opacity': 255}}, {'text': { 'txt': 'TEST', 'align': {'top_bottom': 'bottom', 'left_right': 'right'}, 'font': '', 'font_size': 22, 'height': 30, 'bg': 'black', 'bg_opacity': 255, 'line': 'white'}}, {'scale': { 'colormap': greys, 'extend': False, 'width': 1670, 'height': 110, 'tick_marks': 5, 'minor_tick_marks': 1, 'cursor': [0, 0], 'bg':'white', 'title':'TEST TITLE OF SCALE', 'fontsize': 110, 'align': 'cc' }} ] } import_mock = mock.MagicMock() modules = {'pycoast': import_mock.pycoast, 'pydecorate': import_mock.pydecorate} self.module_patcher = mock.patch.dict('sys.modules', modules) self.module_patcher.start()
def setUp(self): """Create test data and mock pycoast/pydecorate.""" from trollimage.xrimage import XRImage from pyresample.geometry import AreaDefinition import xarray as xr import dask.array as da proj_dict = {'proj': 'lcc', 'datum': 'WGS84', 'ellps': 'WGS84', 'lon_0': -95., 'lat_0': 25, 'lat_1': 25, 'units': 'm', 'no_defs': True} self.area_def = AreaDefinition( 'test', 'test', 'test', proj_dict, 200, 400, (-1000., -1500., 1000., 1500.), ) self.orig_rgb_img = XRImage( xr.DataArray(da.arange(75., chunks=10).reshape(3, 5, 5) / 75., dims=('bands', 'y', 'x'), coords={'bands': ['R', 'G', 'B']}, attrs={'name': 'test_ds', 'area': self.area_def}) ) self.orig_l_img = XRImage( xr.DataArray(da.arange(25., chunks=10).reshape(5, 5) / 75., dims=('y', 'x'), attrs={'name': 'test_ds', 'area': self.area_def}) ) self.decorate = { 'decorate': [ {'logo': {'logo_path': '', 'height': 143, 'bg': 'white', 'bg_opacity': 255}}, {'text': { 'txt': 'TEST', 'align': {'top_bottom': 'bottom', 'left_right': 'right'}, 'font': '', 'font_size': 22, 'height': 30, 'bg': 'black', 'bg_opacity': 255, 'line': 'white'}} ] } self.contour_writer = mock.patch('pycoast.ContourWriterAGG') self.dec_writer = mock.patch('pydecorate.DecoratorAGG') self.cw = self.contour_writer.start() self.dw = self.dec_writer.start()
def to_image(dataset, copy=False, **kwargs): # Only add keywords if they are present for key in ["mode", "fill_value", "palette"]: if key in dataset.attrs: kwargs.setdefault(key, dataset.attrs[key]) dataset = dataset.squeeze() if dataset.ndim < 2: raise ValueError("Need at least a 2D array to make an image.") else: return XRImage(dataset)
def test_colormap_write(self): """Test writing an image with a colormap.""" from satpy.writers.geotiff import GeoTIFFWriter from trollimage.xrimage import XRImage from trollimage.colormap import spectral datasets = self._get_test_datasets() w = GeoTIFFWriter(base_dir=self.base_dir) # we'd have to customize enhancements to test this through # save_datasets. We'll use `save_image` as a workaround. img = XRImage(datasets[0]) img.palettize(spectral) w.save_image(img, keep_palette=True)
def test_write_rgba(): """Test saving an RGBA image.""" area = STEREOGRAPHIC_AREA fill_value = np.nan arr = create_hsv_color_disk(fill_value) attrs = dict([('platform_name', 'NOAA-18'), ('resolution', 1050), ('polarization', None), ('start_time', TIME - datetime.timedelta(minutes=55)), ('end_time', TIME - datetime.timedelta(minutes=50)), ('level', None), ('sensor', 'avhrr-3'), ('ancillary_variables', []), ('area', area), ('wavelength', None), ('optional_datasets', []), ('standard_name', 'overview'), ('name', 'overview'), ('prerequisites', [0.6, 0.8, 10.8]), ('optional_prerequisites', []), ('calibration', None), ('modifiers', None), ('mode', 'RGBA'), ('enhancement_history', [{'scale': np.array([1, 1, -1]), 'offset': np.array([0, 0, 1])}, {'scale': np.array([0.0266347, 0.03559078, 0.01329783]), 'offset': np.array([-0.02524969, -0.01996642, 3.8918446])}, {'gamma': 1.6}])]) kwargs = {'compute': True, 'fill_value': None, 'sat_id': 6300014, 'chan_id': 6500015, 'data_cat': 'PPRN', 'data_source': 'SMHI', 'nbits': 8} alpha = np.where(np.isnan(arr[0, :, :]), 0, 1) arr = np.nan_to_num(arr) arr = np.vstack((arr, alpha[np.newaxis, :, :])) data = da.from_array(arr.clip(0, 1), chunks=1024) data = xr.DataArray(data, coords={'bands': ['R', 'G', 'B', 'A']}, dims=[ 'bands', 'y', 'x'], attrs=attrs) img = XRImage(data) with tempfile.NamedTemporaryFile(delete=DELETE_FILES) as tmpfile: filename = tmpfile.name if not DELETE_FILES: print(filename) save(img, filename, data_is_scaled_01=True, **kwargs) tif = TiffFile(filename) res = tif[0].asarray() for idx in range(4): np.testing.assert_allclose(res[:, :, idx], np.round( np.nan_to_num(arr[idx, :, :]) * 255).astype(np.uint8)) np.testing.assert_allclose(res[:, :, 3] == 0, alpha == 0)
def _test_enhancement(self, func, data, expected, **kwargs): from trollimage.xrimage import XRImage pre_attrs = data.attrs img = XRImage(data) func(img, **kwargs) self.assertIsInstance(img.data.data, da.Array) self.assertListEqual(sorted(pre_attrs.keys()), sorted(img.data.attrs.keys()), "DataArray attributes were not preserved") np.testing.assert_allclose(img.data.values, expected, atol=1.e-6, rtol=0)
def test_cimss_true_color_contrast(self): """Test the cimss_true_color_contrast enhancement.""" from satpy.enhancements.abi import cimss_true_color_contrast from trollimage.xrimage import XRImage expected = np.array([[ [0., 0., 0.05261956, 0.13396146], [0.21530335, 0.29664525, 0.37798715, 0.45932905], [0.54067095, 0.62201285, 0.70335475, 0.78469665], [0.86603854, 0.94738044, 1., 1.], ]]) img = XRImage(self.da) cimss_true_color_contrast(img) np.testing.assert_almost_equal(img.data.compute(), expected)
def run_and_check_enhancement(func, data, expected, **kwargs): """Perform basic checks that apply to multiple tests.""" from trollimage.xrimage import XRImage pre_attrs = data.attrs img = XRImage(data) func(img, **kwargs) assert isinstance(img.data.data, da.Array) old_keys = set(pre_attrs.keys()) # It is OK to have "enhancement_history" added new_keys = set(img.data.attrs.keys()) - {"enhancement_history"} assert old_keys == new_keys np.testing.assert_allclose(img.data.values, expected, atol=1.e-6, rtol=0)
def palettize(img, min_out, max_out, min_in=0, max_in=1.0, colormap=None, alpha=True, **kwargs): """Apply a colormap to data and return the indices in to that colormap.""" import xarray as xr import dask.array as da from trollimage.xrimage import XRImage import trollimage.colormap as ticolormap from satpy import CHUNK_SIZE good_data_mask = kwargs['good_data_mask'] if img.ndim > 2: raise ValueError("Not sure how to palettize more than 2 dimensions") if colormap is None: raise ValueError("'colormap' is required for 'palettize' rescaling") elif not isinstance(colormap, ticolormap.Colormap): raise ValueError("Unknown 'colormap' type: %s", str(type(colormap))) dims = ('y', 'x') if img.ndim == 2 else ('y',) attrs = kwargs.get('attrs', {}) xrimg = XRImage( xr.DataArray(da.from_array(img, chunks=CHUNK_SIZE), dims=dims, attrs=attrs)) if alpha: # use colormap as is tmp_cmap = colormap # produce LA image xrimg = xrimg.convert(xrimg.mode + 'A') else: # the colormap has a value at 0 (first position) that represents # invalid data. We should palettize based on the colormap without # the 0 and then increment tmp_cmap = ticolormap.Colormap(*zip(colormap.values[1:], colormap.colors[1:])) tmp_cmap.set_range(min_in, max_in) xrimg.palettize(tmp_cmap) img_data = xrimg.data.values if alpha: # multiply alpha by the output size img_data[1, :, :] *= max_out else: # get the single band (L) img_data = img_data[0] # increment the indexes by 1 because the colormap has a 0 fill value img_data += 1 img_data[~good_data_mask] = 0 # our data values are now integers that can't be scaled to the output type # because they need to match the colormap return img_data
def _test_enhancement(self, func, data, expected, **kwargs): """Perform basic checks that apply to multiple tests.""" from trollimage.xrimage import XRImage pre_attrs = data.attrs img = XRImage(data) func(img, **kwargs) assert isinstance(img.data.data, da.Array) assert sorted(pre_attrs.keys()) == sorted( img.data.attrs.keys()), "DataArray attributes were not preserved" np.testing.assert_allclose(img.data.values, expected, atol=1.e-6, rtol=0)
def test_jma_true_color_reproduction(self): """Test the jma_true_color_reproduction enhancement.""" from trollimage.xrimage import XRImage from satpy.enhancements.ahi import jma_true_color_reproduction expected = [[[-109.98, 10.998, 131.976, 252.954, 373.932], [494.91, 615.888, 736.866, 857.844, 978.822]], [[-97.6, 9.76, 117.12, 224.48, 331.84], [439.2, 546.56, 653.92, 761.28, 868.64]], [[-94.27, 9.427, 113.124, 216.821, 320.518], [424.215, 527.912, 631.609, 735.306, 839.003]]] img = XRImage(self.rgb) jma_true_color_reproduction(img) np.testing.assert_almost_equal(img.data.compute(), expected)
def test_write_rgb_classified(): """Test saving a transparent RGB.""" area = STEREOGRAPHIC_AREA x_size, y_size = 1024, 1024 arr = np.zeros((3, y_size, x_size)) attrs = dict([('platform_name', 'NOAA-18'), ('resolution', 1050), ('polarization', None), ('start_time', TIME - datetime.timedelta(minutes=65)), ('end_time', TIME - datetime.timedelta(minutes=60)), ('level', None), ('sensor', 'avhrr-3'), ('ancillary_variables', []), ('area', area), ('wavelength', None), ('optional_datasets', []), ('standard_name', 'overview'), ('name', 'overview'), ('prerequisites', [0.6, 0.8, 10.8]), ('optional_prerequisites', []), ('calibration', None), ('modifiers', None), ('mode', 'P')]) kwargs = {'compute': True, 'fill_value': None, 'sat_id': 6300014, 'chan_id': 1700015, 'data_cat': 'PPRN', 'data_source': 'SMHI', 'nbits': 8} data1 = da.tile(da.repeat(da.arange(4, chunks=1024), 256), 256).reshape((1, 256, 1024)) datanan = da.ones((1, 256, 1024), chunks=1024) * 4 data2 = da.tile(da.repeat(da.arange(4, chunks=1024), 256), 512).reshape((1, 512, 1024)) data = da.concatenate((data1, datanan, data2), axis=1) data = xr.DataArray(data, coords={'bands': ['P']}, dims=['bands', 'y', 'x'], attrs=attrs) img = XRImage(data) with tempfile.NamedTemporaryFile(delete=DELETE_FILES) as tmpfile: filename = tmpfile.name if not DELETE_FILES: print(filename) save(img, filename, data_is_scaled_01=True, **kwargs) tif = TiffFile(filename) res = tif[0].asarray() for idx in range(3): np.testing.assert_allclose(res[:, :, idx], np.round( np.nan_to_num(arr[idx, :, :]) * 255).astype(np.uint8)) np.testing.assert_allclose(res[:, :, 3] == 0, np.isnan(arr[0, :, :]))
def to_image(dataset): """Convert ``dataset`` into a :class:`~trollimage.xrimage.XRImage` instance. Convert the ``dataset`` into an instance of the :class:`~trollimage.xrimage.XRImage` class. This function makes no other changes. To get an enhanced image, possibly with overlays and decoration, see :func:`~get_enhanced_image`. Args: dataset (xarray.DataArray): Data to be converted to an image. Returns: Instance of :class:`~trollimage.xrimage.XRImage`. """ dataset = dataset.squeeze() if dataset.ndim < 2: raise ValueError("Need at least a 2D array to make an image.") return XRImage(dataset)
def _pil_to_xrimage(img, adef, fill_value=None): """Convert PIL image to trollimage.xrimage.XRImage""" # Get image mode, width and height mode = img.mode width = img.width height = img.height # Convert to Numpy array img = np.array(img) # Get the minimum and maximum values of the input datatype min_val = np.iinfo(img.dtype).min max_val = np.iinfo(img.dtype).max img = img.reshape((height, width, len(mode))) # Reorder for XRImage img = np.rollaxis(img, 2, -3) # Remove alpha channel if fill_value is set if fill_value is not None: if 'A' in mode: mask = img[-1, :, :] == min_val # Remove alpha channel img = img[:-1, :, :] if np.any(mask): # Set fill_value for each channel for i in range(img.shape[0]): chan = img[i, :, :] chan[mask] = fill_value bands = BANDS[img.shape[0]] # Add image data to scene as xarray.DataArray img = xr.DataArray(img, dims=['bands', 'y', 'x']) img['bands'] = bands # Add area definition img.attrs['area'] = adef # Convert to XRImage img = XRImage(img) # Static stretch img.crude_stretch(min_val, max_val) return img
def add_scale(orig, dc, img, scale): """Add scale to an image using the pydecorate package. All the features of pydecorate's ``add_scale`` are available. See documentation of :doc:`pydecorate:index` for more info. """ LOG.info("Add scale to image.") dc.add_scale(**scale) arr = da.from_array(np.array(img) / 255.0, chunks=CHUNK_SIZE) new_data = xr.DataArray(arr, dims=['y', 'x', 'bands'], coords={'y': orig.data.coords['y'], 'x': orig.data.coords['x'], 'bands': list(img.mode)}, attrs=orig.data.attrs) return XRImage(new_data)
def test_write_rgb_with_a(): """Test saving a transparent RGB.""" from pyninjotiff.ninjotiff import save from pyninjotiff.tifffile import TiffFile area = FakeArea( { 'ellps': 'WGS84', 'lat_0': '90.0', 'lat_ts': '60.0', 'lon_0': '0.0', 'proj': 'stere' }, (-1000000.0, -4500000.0, 2072000.0, -1428000.0), 1024, 1024) x_size, y_size = 1024, 1024 arr = np.zeros((3, y_size, x_size)) radius = min(x_size, y_size) / 2.0 centre = x_size / 2, y_size / 2 for x in range(x_size): for y in range(y_size): rx = x - centre[0] ry = y - centre[1] s = ((x - centre[0])**2.0 + (y - centre[1])**2.0)**0.5 / radius if s <= 1.0: h = ((np.arctan2(ry, rx) / np.pi) + 1.0) / 2.0 rgb = colorsys.hsv_to_rgb(h, s, 1.0) arr[:, y, x] = np.array(rgb) else: arr[:, y, x] = np.nan attrs = dict([('platform_name', 'NOAA-18'), ('resolution', 1050), ('polarization', None), ('start_time', TIME - datetime.timedelta(minutes=55)), ('end_time', TIME - datetime.timedelta(minutes=50)), ('level', None), ('sensor', 'avhrr-3'), ('ancillary_variables', []), ('area', area), ('wavelength', None), ('optional_datasets', []), ('standard_name', 'overview'), ('name', 'overview'), ('prerequisites', [0.6, 0.8, 10.8]), ('optional_prerequisites', []), ('calibration', None), ('modifiers', None), ('mode', 'RGB'), ('enhancement_history', [{ 'scale': np.array([1, 1, -1]), 'offset': np.array([0, 0, 1]) }, { 'scale': np.array([0.0266347, 0.03559078, 0.01329783]), 'offset': np.array([-0.02524969, -0.01996642, 3.8918446]) }, { 'gamma': 1.6 }])]) kwargs = { 'compute': True, 'fill_value': None, 'sat_id': 6300014, 'chan_id': 6500015, 'data_cat': 'PPRN', 'data_source': 'SMHI', 'nbits': 8 } data = da.from_array(arr.clip(0, 1), chunks=1024) data = xr.DataArray(data, coords={'bands': ['R', 'G', 'B']}, dims=['bands', 'y', 'x'], attrs=attrs) from trollimage.xrimage import XRImage img = XRImage(data) with tempfile.NamedTemporaryFile(delete=DELETE_FILES) as tmpfile: filename = tmpfile.name if not DELETE_FILES: print(filename) save(img, filename, data_is_scaled_01=True, **kwargs) tif = TiffFile(filename) res = tif[0].asarray() for idx in range(3): np.testing.assert_allclose( res[:, :, idx], np.round(np.nan_to_num(arr[idx, :, :]) * 255).astype(np.uint8)) np.testing.assert_allclose(res[:, :, 3] == 0, np.isnan(arr[0, :, :]))
def add_overlay(orig, area, coast_dir, color=(0, 0, 0), width=0.5, resolution=None, level_coast=1, level_borders=1, fill_value=None): """Add coastline and political borders to image. Uses ``color`` for feature colors where ``color`` is a 3-element tuple of integers between 0 and 255 representing (R, G, B). .. warning:: This function currently loses the data mask (alpha band). ``resolution`` is chosen automatically if None (default), otherwise it should be one of: +-----+-------------------------+---------+ | 'f' | Full resolution | 0.04 km | | 'h' | High resolution | 0.2 km | | 'i' | Intermediate resolution | 1.0 km | | 'l' | Low resolution | 5.0 km | | 'c' | Crude resolution | 25 km | +-----+-------------------------+---------+ """ if area is None: raise ValueError("Area of image is None, can't add overlay.") from pycoast import ContourWriterAGG if isinstance(area, str): area = get_area_def(area) LOG.info("Add coastlines and political borders to image.") if resolution is None: x_resolution = ((area.area_extent[2] - area.area_extent[0]) / area.x_size) y_resolution = ((area.area_extent[3] - area.area_extent[1]) / area.y_size) res = min(x_resolution, y_resolution) if res > 25000: resolution = "c" elif res > 5000: resolution = "l" elif res > 1000: resolution = "i" elif res > 200: resolution = "h" else: resolution = "f" LOG.debug("Automagically choose resolution %s", resolution) if hasattr(orig, 'convert'): # image must be in RGB space to work with pycoast/pydecorate orig = orig.convert('RGBA' if orig.mode.endswith('A') else 'RGB') elif not orig.mode.startswith('RGB'): raise RuntimeError("'trollimage' 1.6+ required to support adding " "overlays/decorations to non-RGB data.") img = orig.pil_image(fill_value=fill_value) cw_ = ContourWriterAGG(coast_dir) cw_.add_coastlines(img, area, outline=color, resolution=resolution, width=width, level=level_coast) cw_.add_borders(img, area, outline=color, resolution=resolution, width=width, level=level_borders) arr = da.from_array(np.array(img) / 255.0, chunks=CHUNK_SIZE) new_data = xr.DataArray(arr, dims=['y', 'x', 'bands'], coords={'y': orig.data.coords['y'], 'x': orig.data.coords['x'], 'bands': list(img.mode)}, attrs=orig.data.attrs) return XRImage(new_data)
def _fake_get_enhanced_image(img, enhance=None, overlay=None, decorate=None): from trollimage.xrimage import XRImage return XRImage(img)
def add_overlay(orig, area, coast_dir, color=(0, 0, 0), width=0.5, resolution=None, level_coast=1, level_borders=1, fill_value=None, grid=None): """Add coastline, political borders and grid(graticules) to image. Uses ``color`` for feature colors where ``color`` is a 3-element tuple of integers between 0 and 255 representing (R, G, B). .. warning:: This function currently loses the data mask (alpha band). ``resolution`` is chosen automatically if None (default), otherwise it should be one of: +-----+-------------------------+---------+ | 'f' | Full resolution | 0.04 km | +-----+-------------------------+---------+ | 'h' | High resolution | 0.2 km | +-----+-------------------------+---------+ | 'i' | Intermediate resolution | 1.0 km | +-----+-------------------------+---------+ | 'l' | Low resolution | 5.0 km | +-----+-------------------------+---------+ | 'c' | Crude resolution | 25 km | +-----+-------------------------+---------+ ``grid`` is a dictionary with key values as documented in detail in pycoast eg. overlay={'grid': {'major_lonlat': (10, 10), 'write_text': False, 'outline': (224, 224, 224), 'width': 0.5}} Here major_lonlat is plotted every 10 deg for both longitude and latitude, no labels for the grid lines are plotted, the color used for the grid lines is light gray, and the width of the gratucules is 0.5 pixels. For grid if aggdraw is used, font option is mandatory, if not ``write_text`` is set to False:: font = aggdraw.Font('black', '/usr/share/fonts/truetype/msttcorefonts/Arial.ttf', opacity=127, size=16) """ if area is None: raise ValueError("Area of image is None, can't add overlay.") from pycoast import ContourWriterAGG if isinstance(area, str): area = get_area_def(area) LOG.info("Add coastlines and political borders to image.") if resolution is None: x_resolution = ((area.area_extent[2] - area.area_extent[0]) / area.x_size) y_resolution = ((area.area_extent[3] - area.area_extent[1]) / area.y_size) res = min(x_resolution, y_resolution) if res > 25000: resolution = "c" elif res > 5000: resolution = "l" elif res > 1000: resolution = "i" elif res > 200: resolution = "h" else: resolution = "f" LOG.debug("Automagically choose resolution %s", resolution) if hasattr(orig, 'convert'): # image must be in RGB space to work with pycoast/pydecorate orig = orig.convert('RGBA' if orig.mode.endswith('A') else 'RGB') elif not orig.mode.startswith('RGB'): raise RuntimeError("'trollimage' 1.6+ required to support adding " "overlays/decorations to non-RGB data.") img = orig.pil_image(fill_value=fill_value) cw_ = ContourWriterAGG(coast_dir) cw_.add_coastlines(img, area, outline=color, resolution=resolution, width=width, level=level_coast) cw_.add_borders(img, area, outline=color, resolution=resolution, width=width, level=level_borders) # Only add grid if major_lonlat is given. if grid and 'major_lonlat' in grid and grid['major_lonlat']: major_lonlat = grid.pop('major_lonlat') minor_lonlat = grid.pop('minor_lonlat', major_lonlat) cw_.add_grid(img, area, major_lonlat, minor_lonlat, **grid) arr = da.from_array(np.array(img) / 255.0, chunks=CHUNK_SIZE) new_data = xr.DataArray(arr, dims=['y', 'x', 'bands'], coords={ 'y': orig.data.coords['y'], 'x': orig.data.coords['x'], 'bands': list(img.mode) }, attrs=orig.data.attrs) return XRImage(new_data)
def test_write_rgb_tb(): """Test saving a non-trasparent RGB with thumbnails.""" from pyninjotiff.ninjotiff import save from pyninjotiff.tifffile import TiffFile area = FakeArea( { 'ellps': 'WGS84', 'lat_0': 90.0, 'lat_ts': 60.0, 'lon_0': 0.0, 'proj': 'stere' }, (-1000000.0, -4500000.0, 2072000.0, -1428000.0), 1024, 1024) x_size, y_size = 1024, 1024 arr = np.zeros((3, y_size, x_size)) radius = min(x_size, y_size) / 2.0 centre = x_size / 2, y_size / 2 for x in range(x_size): for y in range(y_size): rx = x - centre[0] ry = y - centre[1] s = ((x - centre[0])**2.0 + (y - centre[1])**2.0)**0.5 / radius if s <= 1.0: h = ((np.arctan2(ry, rx) / np.pi) + 1.0) / 2.0 rgb = colorsys.hsv_to_rgb(h, s, 1.0) arr[:, y, x] = np.array(rgb) attrs = dict([('platform_name', 'NOAA-18'), ('resolution', 1050), ('polarization', None), ('level', None), ('sensor', 'avhrr-3'), ('ancillary_variables', []), ('area', area), ('start_time', TIME - datetime.timedelta(minutes=45)), ('end_time', TIME - datetime.timedelta(minutes=40)), ('wavelength', None), ('optional_datasets', []), ('standard_name', 'overview'), ('name', 'overview'), ('prerequisites', [0.6, 0.8, 10.8]), ('optional_prerequisites', []), ('calibration', None), ('modifiers', None), ('mode', 'RGB'), ('enhancement_history', [{ 'scale': np.array([1, 1, -1]), 'offset': np.array([0, 0, 1]) }, { 'scale': np.array([0.0266347, 0.03559078, 0.01329783]), 'offset': np.array([-0.02524969, -0.01996642, 3.8918446]) }, { 'gamma': 1.6 }])]) kwargs = { 'compute': True, 'fill_value': None, 'sat_id': 6300014, 'chan_id': 6500015, 'data_cat': 'PPRN', 'data_source': 'SMHI', 'nbits': 8, 'tile_length': 256, 'tile_width': 256 } data = da.from_array(arr.clip(0, 1), chunks=1024) data = xr.DataArray(data, coords={'bands': ['R', 'G', 'B']}, dims=['bands', 'y', 'x'], attrs=attrs) from trollimage.xrimage import XRImage img = XRImage(data) with tempfile.NamedTemporaryFile(delete=DELETE_FILES) as tmpfile: filename = tmpfile.name if not DELETE_FILES: print(filename) save(img, filename, data_is_scaled_01=False, **kwargs) tif = TiffFile(filename) res = tif[0].asarray() assert (tif.pages[0].tags['tile_length'].value == 256) assert (tif.pages[1].tags['tile_length'].value == 128) assert (tif.pages[0].tags['tile_width'].value == 256) assert (tif.pages[1].tags['tile_width'].value == 128) assert (len(tif.pages) == 2) assert (tif.pages[0].shape == (1024, 1024, 4)) assert (tif.pages[1].shape == (512, 512, 4)) for idx in range(3): np.testing.assert_allclose( res[:, :, idx], np.round(arr[idx, :, :] * 255).astype(np.uint8)) tags = { 'new_subfile_type': 0, 'image_width': 1024, 'image_length': 1024, 'bits_per_sample': (8, 8, 8, 8), 'compression': 32946, 'photometric': 2, 'orientation': 1, 'samples_per_pixel': 4, 'planar_configuration': 1, 'software': b'tifffile/pytroll', 'datetime': b'2020:01:17 14:17:23', 'tile_width': 256, 'tile_length': 256, 'tile_offsets': (951, 24414, 77352, 126135, 141546, 206260, 272951, 318709, 349650, 413166, 475735, 519168, 547960, 570326, 615924, 666705), 'tile_byte_counts': (23463, 52938, 48783, 15411, 64714, 66691, 45758, 30941, 63516, 62569, 43433, 28792, 22366, 45598, 50781, 13371), 'extra_samples': 2, 'sample_format': (1, 1, 1, 1), 'model_pixel_scale': (0.026949458523585643, 0.027040118922685666, 0.0), 'model_tie_point': (0.0, 0.0, 0.0, -35.00279008179894, 73.3850622630575, 0.0), '40000': b'NINJO', '40001': 6300014, '40002': 1579264321, '40003': 1579267043, '40004': 6500015, '40005': 2, '40006': b'/tmp/tmpb4kn93qt', '40007': b'PPRN', '40008': b'', '40009': 24, '40010': b'SMHI', '40011': 1, '40012': 1024, '40013': 1, '40014': 1024, '40015': b'NPOL', '40016': -35.00278854370117, '40017': 24.72344398498535, '40018': 6378137.0, '40019': 6356752.5, '40021': 60.0, '40022': 0.0, '40023': 0.0, '40024': b'None', '40025': b'None', '40026': 0, '40027': 255, '40028': 1.0, '40029': 0.0, '40040': 0, '40041': 0, '40042': 1, '40043': 0, '50000': 0, 'fill_order': 1, 'rows_per_strip': 4294967295, 'resolution_unit': 2, 'predictor': 1, 'ycbcr_subsampling': 1, 'ycbcr_positioning': 1 } read_tags = tif.pages[0].tags assert (read_tags.keys() == tags.keys()) for key, val in tags.items(): if key in ['datetime', '40002', '40003', '40006']: continue assert (val == read_tags[key].value)
def _fake_get_enhanced_image(img): from trollimage.xrimage import XRImage return XRImage(img)
def to_image(dataset): dataset = dataset.squeeze() if dataset.ndim < 2: raise ValueError("Need at least a 2D array to make an image.") else: return XRImage(dataset)