def test_thumbnail_from_numpy_lookuptable(input_uint8_tif_2: Path): writer = FileWrite() outfile = Path(tempfile.gettempdir()) / "test-lookuptable.jpg" wofs_lookup = { 0: [150, 150, 110], # dry 1: [255, 255, 255], # nodata, 16: [119, 104, 87], # terrain 32: [89, 88, 86], # cloud_shadow 64: [216, 215, 214], # cloud 80: [242, 220, 180], # cloudy terrain 128: [79, 129, 189], # water 160: [51, 82, 119], # shady water 192: [186, 211, 242], # cloudy water } with rasterio.open(input_uint8_tif_2) as ds: input_geobox = GridSpec.from_rio(ds) data = ds.read(1) image_bytes = writer.create_thumbnail_singleband_from_numpy( input_data=data, input_geobox=input_geobox, lookup_table=wofs_lookup) with open(outfile, "wb") as jpeg_file: jpeg_file.write(image_bytes) assert_image(outfile, bands=3)
def test_thumbnail_bitflag(input_uint8_tif: Path): writer = FileWrite() outfile = Path(tempfile.gettempdir()) / "test-bitflag.jpg" water = 128 writer.create_thumbnail_singleband(input_uint8_tif, Path(outfile), bit=water) assert_image(outfile, bands=3)
def test_thumbnail_from_numpy_bitflag(input_uint8_tif: Path): writer = FileWrite() outfile = Path(tempfile.gettempdir()) / "test-bitflag.jpg" water = 128 with rasterio.open(input_uint8_tif) as ds: input_geobox = GridSpec.from_rio(ds) data = ds.read(1) image_bytes = writer.create_thumbnail_singleband_from_numpy( input_data=data, input_geobox=input_geobox, bit=water) with open(outfile, "wb") as jpeg_file: jpeg_file.write(image_bytes) assert_image(outfile, bands=3)
def write_thumbnail_singleband( self, measurement: str, bit: int = None, lookup_table: Dict[int, Tuple[int, int, int]] = None, kind: str = None, ): """ Write a singleband thumbnail out, taking in an input measurement and outputting a JPG with appropriate settings. Options are to EITHER Use a bit (int) as the value to scale from black to white to i.e., 0 will be BLACK and bit will be WHITE, with a linear scale between. OR Provide a lookuptable (dict) of int (key) [R, G, B] (value) fields to make the image with. """ thumb_path = self.names.thumbnail_name(self._work_path, kind=kind) _, image_path = self.measurements.get(measurement, (None, None)) if image_path is None: raise IncompleteDatasetError( ValidationMessage( Level.error, "missing_thumb_measurement", f"Thumbnail measurement is missing: no measurements called {measurement!r}. ", hint= f"Available measurements: {', '.join(self.measurements)}", )) FileWrite().create_thumbnail_singleband( image_path, thumb_path, bit, lookup_table, ) self._document_thumbnail(thumb_path, kind)
def test_thumbnail_lookuptable(input_uint8_tif_2: Path): writer = FileWrite() outfile = Path(tempfile.gettempdir()) / "test-lookuptable.jpg" wofs_lookup = { 0: [150, 150, 110], # dry 1: [255, 255, 255], # nodata, 16: [119, 104, 87], # terrain 32: [89, 88, 86], # cloud_shadow 64: [216, 215, 214], # cloud 80: [242, 220, 180], # cloudy terrain 128: [79, 129, 189], # water 160: [51, 82, 119], # shady water 192: [186, 211, 242], # cloudy water } writer.create_thumbnail_singleband(input_uint8_tif_2, Path(outfile), lookup_table=wofs_lookup) assert_image(outfile, bands=3)
def write_thumbnail( self, red: str, green: str, blue: str, resampling: Resampling = Resampling.average, static_stretch: Tuple[int, int] = None, percentile_stretch: Tuple[int, int] = (2, 98), scale_factor: int = 10, kind: str = None, ): """ Write a thumbnail for the dataset using the given measurements (specified by name) as r/g/b. (the measurements must already have been written.) A linear stretch is performed on the colour. By default this is a dynamic 2% stretch (the 2% and 98% percentile values of the input). The static_stretch parameter will override this with a static range of values. :param red: Name of measurement to put in red band :param green: Name of measurement to put in green band :param blue: Name of measurement to put in blue band :param kind: If you have multiple thumbnails, you can specify the 'kind' name to distinguish them (it will be put in the filename). Eg. GA's ARD has two thumbnails, one of kind ``nbar`` and one of ``nbart``. :param scale_factor: How many multiples smaller to make the thumbnail. :param percentile_stretch: Upper/lower percentiles to stretch by :param resampling: rasterio :class:`rasterio.enums.Resampling` method to use. :param static_stretch: Use a static upper/lower value to stretch by instead of dynamic stretch. """ thumb_path = self.names.thumbnail_name(self._work_path, kind=kind) measurements = dict( (name, (grid, path)) for grid, name, path in self._measurements.iter_paths() ) missing_measurements = {red, green, blue} - set(measurements) if missing_measurements: raise IncompleteDatasetError( ValidationMessage( Level.error, "missing_thumb_measurements", f"Thumbnail measurements are missing: no measurements called {missing_measurements!r}. ", hint=f"Available measurements: {', '.join(measurements)}", ) ) rgbs = [measurements[b] for b in (red, green, blue)] unique_grids: List[GridSpec] = list(set(grid for grid, path in rgbs)) if len(unique_grids) != 1: raise NotImplementedError( "Thumbnails can only currently be created from measurements of the same grid spec." ) grid = unique_grids[0] FileWrite().create_thumbnail( tuple(path for grid, path in rgbs), thumb_path, out_scale=scale_factor, resampling=resampling, static_stretch=static_stretch, percentile_stretch=percentile_stretch, input_geobox=grid, ) self._checksum.add_file(thumb_path) accessory_name = "thumbnail" if kind: accessory_name += f":{kind}" self.add_accessory_file(accessory_name, thumb_path)