Models
ImageData¶
Reader methods returning image data (tile
, part
, feature
and preview
) return a data holding class: rio_tiler.models.ImageData
.
This class has helper methods like render
which forward internal data and mask to rio_tiler.utils.render
method, but also helps preserving geospatial information (bounds
and crs
) about the data.
Attributes¶
- array: image array (numpy.ma.MaskedArray)
- assets: assets list used to create the data array (list, optional)
- bounds: bounds of the data (rasterio.coords.BoundingBox, optional)
- crs: coordinate reference system for the data (rasterio.crs.CRS, optional)
- metadata: additional metadata (dict, optional)
- band_names: image band's names
- dataset_statistics: Dataset's min/max values (list of (min,max), optional)
- cutline_mask: array representing the mask for
feature
methods
import numpy
from rio_tiler.models import ImageData
d = numpy.zeros((3, 256, 256))
m = numpy.zeros((3, 256, 256), dtype="bool")
data = numpy.ma.MaskedArray(d, mask=m)
print(ImageData(data))
>>> ImageData(
array=masked_array(...),
assets=None,
bounds=None,
crs=None,
metadata={},
band_names=['b1', 'b2', 'b3'],
dataset_statistics=None,
cutline_mask=array(),
)
Properties¶
- width: number of column in the data array (int)
- height: number of row in the data array (int)
- count: number of bands in the data array (int)
- transform: Affine transform created from the bounds and crs (affine.Affine)
- data: Return data part of the masked array.
- mask: Return the mask part in form of rasterio dataset mask.
Methods¶
-
data_as_image(): Return the data array reshaped into an image processing/visualization software friendly order
import numpy from rio_tiler.models import ImageData d = numpy.zeros((3, 256, 256)) m = numpy.zeros((3, 256, 256), dtype="bool") data = numpy.ma.MaskedArray(d, mask=m) img = ImageData(data) print(img.data.shape) >>> (3, 256, 256) image = img.data_as_image() print(image.shape) >>> (256, 256, 3)
-
clip(): Clip data and mask to a bbox (in the ImageData CRS).
New in version 4.0.0
import numpy from rio_tiler.models import ImageData data = numpy.zeros((3, 1024, 1024), dtype="uint8") img = ImageData(data, crs="epsg:4326", bounds=(-180, -90, 180, 90)) img_c = img.clip((-100, -50, 100, 50)) assert img_c.count == 3 assert img_c.bounds == (-100, -50, 100, 50)
-
resize(): Resize data and mask.
New in version 4.0.0
import numpy from rio_tiler.models import ImageData data = numpy.zeros((3, 1024, 1024), dtype="uint8") img = ImageData(data) img_r = img.resize(256, 256) assert img_r.count == 3 assert img_r.width == 256 assert img_r.height == 256
-
post_process(): Apply rescaling or/and
color-operations
formula to the data array. Returns a new ImageData instance.import numpy from rio_tiler.models import ImageData data = numpy.random.randint(0, 3000, (3, 256, 256)) img = ImageData(data) print(img.data.dtype) >>> 'int64' print(img.data.max()) >>> 2999 # rescale the data from 0 -> 3000 to 0 -> 255 # by default rio-tiler will apply the same `in_range` for all the bands image = img.post_process(in_range=((0, 3000),)) # or provide range for each bands image = img.post_process(in_range=((0, 3000), (0, 1000), (0, 2000))) assert isinstance(image, ImageData) print(image.data.dtype) >>> 'uint8' print(image.data.max()) >>> 254 # rescale and apply color-operations formula image = img.post_process( in_range=((0, 3000),), color_formula="Gamma RGB 3.1", ) assert isinstance(image, ImageData)
-
statistics(): Return statistics from ImageData.
New in version 4.1.7
import numpy from rio_tiler.models import ImageData data = numpy.zeros((1, 256, 256), dtype="uint8") data[0, 0:10, 0:10] = 0 data[0, 10:11, 10:11] = 100 img = ImageData(data) stats = img.statistics(categorical=True) print(stats["b1"].min) >>> 0 print(stats["b1"].max) >>> 100 print(stats["b1"].majority) >>> 0 print(stats["b1"].minority) >>> 100 print(stats["b1"].unique) >>> 2.0
-
rescale(): linear rescaling of the data in place
New in version 3.1.5
import numpy from rio_tiler.models import ImageData data = numpy.random.randint(0, 3000, (3, 256, 256)) img = ImageData(data) print(img.data.dtype) >>> 'int64' print(img.data.max()) >>> 2999 # rescale and apply color-operations formula img.rescale(in_range=((0, 3000),),) print(img.data.max()) >>> 254 print(img.data.dtype) >>> 'uint8'
-
apply_color_formula(): Apply
color-operations
's color formula in placeNew in version 3.1.5
import numpy from rio_tiler.models import ImageData data = numpy.random.randint(0, 16000, (3, 256, 256)).astype("uint16") img = ImageData(data) print(img.data.dtype) >>> 'uint16' img.apply_color_formula("Gamma RGB 3.5") print(img.data.dtype) >>> 'uint8' print(img.data.max()) >>> 170
-
apply_colormap(): Apply colormap to the image data
New in version 4.1.6
import numpy from rio_tiler.models import ImageData cm = {0: (0, 0, 0, 255), 1: (255, 255, 255, 255)} im = ImageData(numpy.zeros((1, 256, 256), dtype="uint8")).apply_colormap(cm) assert im.data.shape == (3, 256, 256) assert im.data[:, 0, 0].tolist() == [0, 0, 0] assert im.mask[0, 0] == 255 assert im.mask.all()
-
apply_expression(): Apply band math expression
New in version 4.0
import numpy from rio_tiler.models import ImageData data = numpy.random.randint(0, 3000, (3, 256, 256)) img = ImageData(data) print(img.band_names) >>> ["b1", "b2", "b3"] # Defaults ratio = img.apply_expression("b1/b2") # Returns a new ImageData object assert isinstance(ratio, ImageData) print(ratio.band_names) >>> ["b1/b2"] print(ratio.data.shape) >>> (1, 256, 256)
-
render(): Render the data/mask to an image buffer (forward data and mask to rio_tiler.utils.render).
import numpy from rasterio.io import MemoryFile from rio_tiler.models import ImageData def get_meta(content): with MemoryFile(content) as mem: with mem.open() as dst: return dst.meta data = numpy.zeros((3, 256, 256), dtype="uint8") img = ImageData(data) # create a PNG image buf = img.render(img_format="png") print(get_meta(buf)) >>> { 'driver': 'PNG', 'dtype': 'uint8', 'nodata': None, 'width': 256, 'height': 256, 'count': 4, 'crs': None, 'transform': Affine(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) } # create a JPEG image buf = img.render(img_format="jpeg") print(get_meta(buf)) >>> { 'driver': 'JPEG', 'dtype': 'uint8', 'nodata': None, 'width': 256, 'height': 256, 'count': 3, 'crs': None, 'transform': Affine(1.0, 0.0, 0.0, 0.0, 1.0, 0.0) }
Note: Starting with rio-tiler==2.1
, when the output datatype is not valid for a driver (e.g float
for PNG
),
rio-tiler
will automatically rescale the data using the min/max
value for the datatype (ref: cogeotiff/rio-tiler!391).
PointData¶
New in version 4.0
Attributes¶
- array: image array (numpy.ma.MaskedArray)
- assets: assets list used to create the data array (list, optional)
- coordinates: Coordinates of the point (Tuple[float, float], optional)
- crs: coordinate reference system for the data (rasterio.crs.CRS, optional)
- metadata: additional metadata (dict, optional)
- band_names: values band's names
import numpy
from rio_tiler.models import PointData
d = numpy.zeros((3))
m = numpy.zeros((1), dtype="bool")
data = numpy.ma.MaskedArray(d, mask=m)
print(PointData(data))
>>> PointData(
array=masked_array(data=[0.0, 0.0, 0.0], mask=[False, False, False], fill_value=1e+20),
band_names=['b1', 'b2', 'b3'],
coordinates=None,
crs=None,
assets=None,
metadata={},
)
)
Properties¶
- count: number of bands in the data array (int)
- data: Return data part of the masked array.
- mask: Return the mask part in form of rasterio dataset mask.
Methods¶
- apply_expression(): Apply band math expression
import numpy
from rio_tiler.models import PointData
data = numpy.random.randint(0, 3000, (3))
pts = PointData(data)
print(pts.band_names)
>>> ["b1", "b2", "b3"] # Defaults
ratio = pts.apply_expression("b1/b2") # Returns a new PointData object
assert isinstance(ratio, PointData)
print(ratio.band_names)
>>> ["b1/b2"]
print(ratio.count)
>>> 1
Others¶
Readers methods returning metadata like results (info()
and statistics()
) return pydantic models to make sure the values are valids.
Info¶
from rio_tiler.io import Reader
from rio_tiler.models import Info
# Schema
print(Info.schema())
>>> {
"$defs": {
"BoundingBox": {
"maxItems": 4,
"minItems": 4,
"prefixItems": [
{
"title": "Left"
},
{
"title": "Bottom"
},
{
"title": "Right"
},
{
"title": "Top"
}
],
"type": "array"
}
},
"additionalProperties": true,
"description": "Dataset Info.",
"properties": {
"bounds": {
"$ref": "#/$defs/BoundingBox"
},
"crs": {
"title": "Crs",
"type": "string"
},
"band_metadata": {
"items": {
"maxItems": 2,
"minItems": 2,
"prefixItems": [
{
"type": "string"
},
{
"type": "object"
}
],
"type": "array"
},
"title": "Band Metadata",
"type": "array"
},
"band_descriptions": {
"items": {
"maxItems": 2,
"minItems": 2,
"prefixItems": [
{
"type": "string"
},
{
"type": "string"
}
],
"type": "array"
},
"title": "Band Descriptions",
"type": "array"
},
"dtype": {
"title": "Dtype",
"type": "string"
},
"nodata_type": {
"enum": [
"Alpha",
"Mask",
"Internal",
"Nodata",
"None"
],
"title": "Nodata Type",
"type": "string"
},
"colorinterp": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Colorinterp"
},
"scales": {
"anyOf": [
{
"items": {
"type": "number"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Scales"
},
"offsets": {
"anyOf": [
{
"items": {
"type": "number"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Offsets"
},
"colormap": {
"anyOf": [
{
"additionalProperties": {
"maxItems": 4,
"minItems": 4,
"prefixItems": [
{
"type": "integer"
},
{
"type": "integer"
},
{
"type": "integer"
},
{
"type": "integer"
}
],
"type": "array"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Colormap"
}
},
"required": [
"bounds",
"crs",
"band_metadata",
"band_descriptions",
"dtype",
"nodata_type"
],
"title": "Info",
"type": "object"
}
# Example
with Reader(
"http://oin-hotosm.s3.amazonaws.com/5a95f32c2553e6000ce5ad2e/0/10edab38-1bdd-4c06-b83d-6e10ac532b7d.tif"
) as src:
info = src.info()
print(info.nodata_type)
>>> "None"
print(info.model_dump_json(exclude_none=True))
>>> {
"bounds": [
683715.3266400001,
1718548.5702,
684593.2680000002,
1719064.90736
],
"crs": "http://www.opengis.net/def/crs/EPSG/0/32620",
"band_metadata": [
[
"b1",
{}
],
[
"b2",
{}
],
[
"b3",
{}
]
],
"band_descriptions": [
[
"b1",
""
],
[
"b2",
""
],
[
"b3",
""
]
],
"dtype": "uint8",
"nodata_type": "Mask",
"colorinterp": [
"red",
"green",
"blue"
],
"scales": [
1,
1,
1
],
"offsets": [
0,
0,
0
],
"driver": "GTiff",
"count": 3,
"width": 19836,
"height": 11666,
"overviews": [
2,
4,
8,
16,
32,
64
]
}
Note: starting with rio-tiler>=2.0.8
, additional metadata can be set (e.g. driver, count, width, height, overviews in Reader.info()
)
BandStatistics¶
from rio_tiler.io import Reader
from rio_tiler.models import BandStatistics
# Schema
print(BandStatistics.schema())
>>> {
"title": "BandStatistics",
"description": "Image statistics",
"type": "object",
"properties": {
"min": {
"title": "Min",
"type": "number"
},
"max": {
"title": "Max",
"type": "number"
},
"mean": {
"title": "Mean",
"type": "number"
},
"count": {
"title": "Count",
"type": "number"
},
"sum": {
"title": "Sum",
"type": "number"
},
"std": {
"title": "Std",
"type": "number"
},
"median": {
"title": "Median",
"type": "number"
},
"majority": {
"title": "Majority",
"type": "number"
},
"minority": {
"title": "Minority",
"type": "number"
},
"unique": {
"title": "Unique",
"type": "number"
},
"histogram": {
"title": "Histogram",
"type": "array",
"items": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "integer"
}
]
}
}
},
"valid_percent": {
"title": "Valid Percent",
"type": "number"
},
"masked_pixels": {
"title": "Masked Pixels",
"type": "number"
},
"valid_pixels": {
"title": "Valid Pixels",
"type": "number"
}
},
"required": [
"min",
"max",
"mean",
"count",
"sum",
"std",
"median",
"majority",
"minority",
"unique",
"histogram",
"valid_percent",
"masked_pixels",
"valid_pixels"
]
}
# Example
with Reader(
"http://oin-hotosm.s3.amazonaws.com/5a95f32c2553e6000ce5ad2e/0/10edab38-1bdd-4c06-b83d-6e10ac532b7d.tif"
) as src:
stats = src.statistics()
assert isinstance(stats["b1"], BandStatistics)
print(stats["b1"].min)
>>> 0.0
print(stats["b1"].model_dump_json(exclude_none=True))
>>> {
"min": 0,
"max": 255,
"mean": 93.16424226523633,
"count": 617472,
"sum": 57526311,
"std": 59.261322978176324,
"median": 94,
"majority": 0,
"minority": 253,
"unique": 256,
"histogram": [
[
100540,
43602,
87476,
112587,
107599,
73453,
43623,
21971,
15006,
11615
],
[
0,
25.5,
51,
76.5,
102,
127.5,
153,
178.5,
204,
229.5,
255
]
],
"valid_percent": 100,
"masked_pixels": 0,
"valid_pixels": 617472,
"percentile_2": 0,
"percentile_98": 228
}
Links¶
Attrs - Classes Without Boilerplate https://www.attrs.org/en/stable/
Pydantic - Define how data should be in pure, canonical python https://pydantic-docs.helpmanual.io