Skip to content

Commit

Permalink
add cast, floor and ceil algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentsarago committed Jan 7, 2025
1 parent 6fcd564 commit ce98003
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* move `rescale` and `color_formula` QueryParameters dependencies in `ImageRenderingParams` class **breaking change**
* handle image rescaling and color_formula within `titiler.core.utils.render_image` function **breaking change**
* add `render_func: Callable[..., Tuple[bytes, str]] = render_image` attribute in `TilerFactory` class
* add `castToInt`, `Floor`, `Ceil` algorithms

### titiler.application

Expand All @@ -32,6 +33,8 @@

* Updated WMTS Capabilities template to avoid inserting extra new lines (author @AndrewAnnex, https://github.com/developmentseed/titiler/pull/1052).
* Updated WMTS endpoint in titiler.mosaic and titiler.core to return layer bounds in coordinate ordering matching CRS order if WGS84 is not used (author @AndrewAnnex, https://github.com/developmentseed/titiler/pull/1052).
* Remove `python3.8` support (author @pratapvardhan, https://github.com/developmentseed/titiler/pull/1058)
* Add `python3.13` support (author @pratapvardhan, https://github.com/developmentseed/titiler/pull/1058)

## 0.19.2 (2024-11-28)

Expand Down
36 changes: 36 additions & 0 deletions src/titiler/core/tests/test_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,39 @@ def test_terrainrgb():
assert out.array.shape == (3, 256, 256)
assert out.array.dtype == "uint8"
assert out.array[0, 0, 0] is numpy.ma.masked


def test_ops():
"""test ops: cast, ceil and floor."""
arr = numpy.ma.MaskedArray(
numpy.random.randint(0, 5000, (1, 256, 256)).astype("float32"),
mask=numpy.zeros((1, 256, 256), dtype="bool"),
)
arr.data[0, 0, 0] = 1.6
arr.mask[0, 1:100, 1:100] = True

img = ImageData(arr)
assert img.array.dtype == numpy.float32

algo = default_algorithms.get("cast")()
out = algo(img)
assert out.array.shape == (1, 256, 256)
assert out.array.dtype == "uint8"
assert out.array[0, 0, 0] == 1
assert out.array[0, 1, 1] is numpy.ma.masked

assert img.array.dtype == numpy.float32
algo = default_algorithms.get("floor")()
out = algo(img)
assert out.array.shape == (1, 256, 256)
assert out.array.dtype == "uint8"
assert out.array[0, 0, 0] == 1
assert out.array[0, 1, 1] is numpy.ma.masked

assert img.array.dtype == numpy.float32
algo = default_algorithms.get("ceil")()
out = algo(img)
assert out.array.shape == (1, 256, 256)
assert out.array.dtype == "uint8"
assert out.array[0, 0, 0] == 2
assert out.array[0, 1, 1] is numpy.ma.masked
4 changes: 4 additions & 0 deletions src/titiler/core/titiler/core/algorithm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
from titiler.core.algorithm.base import BaseAlgorithm
from titiler.core.algorithm.dem import Contours, HillShade, TerrainRGB, Terrarium
from titiler.core.algorithm.index import NormalizedIndex
from titiler.core.algorithm.ops import CastToInt, Ceil, Floor

default_algorithms: Dict[str, Type[BaseAlgorithm]] = {
"hillshade": HillShade,
"contours": Contours,
"normalizedIndex": NormalizedIndex,
"terrarium": Terrarium,
"terrainrgb": TerrainRGB,
"cast": CastToInt,
"ceil": Ceil,
"floor": Floor,
}


Expand Down
2 changes: 2 additions & 0 deletions src/titiler/core/titiler/core/algorithm/dem.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

from titiler.core.algorithm.base import BaseAlgorithm

__all__ = ["HillShade", "Contours", "Terrarium", "TerrainRGB"]


class HillShade(BaseAlgorithm):
"""Hillshade."""
Expand Down
2 changes: 2 additions & 0 deletions src/titiler/core/titiler/core/algorithm/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

from titiler.core.algorithm.base import BaseAlgorithm

__all__ = ["NormalizedIndex"]


class NormalizedIndex(BaseAlgorithm):
"""Normalized Difference Index."""
Expand Down
82 changes: 82 additions & 0 deletions src/titiler/core/titiler/core/algorithm/ops.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""titiler.core.algorithm Ops."""

from typing import Sequence

import numpy
from rio_tiler.models import ImageData

from titiler.core.algorithm.base import BaseAlgorithm

__all__ = ["CastToInt", "Ceil", "Floor"]


class CastToInt(BaseAlgorithm):
"""Cast data to Integer."""

title: str = "Cast data to Integer"
description: str = "Cast data to Integer."

# metadata
output_dtype: str = "uint8"
output_min: Sequence[int] = [0]
output_max: Sequence[int] = [255]

def __call__(self, img: ImageData) -> ImageData:
"""Cast Data."""
return ImageData(
img.array.astype("uint8"),
assets=img.assets,
crs=img.crs,
bounds=img.bounds,
band_names=img.band_names,
metadata=img.metadata,
cutline_mask=img.cutline_mask,
)


class Ceil(BaseAlgorithm):
"""Round data to the smallest integer."""

title: str = "Round data to the smallest integer"
description: str = "Round data to the smallest integer."

# metadata
output_dtype: str = "uint8"
output_min: Sequence[int] = [0]
output_max: Sequence[int] = [255]

def __call__(self, img: ImageData) -> ImageData:
"""Cast Data."""
return ImageData(
numpy.ceil(img.array).astype("uint8"),
assets=img.assets,
crs=img.crs,
bounds=img.bounds,
band_names=img.band_names,
metadata=img.metadata,
cutline_mask=img.cutline_mask,
)


class Floor(BaseAlgorithm):
"""Round data to the largest integer."""

title: str = "Round data to the largest integer"
description: str = "Round data to the largest integer."

# metadata
output_dtype: str = "uint8"
output_min: Sequence[int] = [0]
output_max: Sequence[int] = [255]

def __call__(self, img: ImageData) -> ImageData:
"""Cast Data."""
return ImageData(
numpy.floor(img.array).astype("uint8"),
assets=img.assets,
crs=img.crs,
bounds=img.bounds,
band_names=img.band_names,
metadata=img.metadata,
cutline_mask=img.cutline_mask,
)

0 comments on commit ce98003

Please sign in to comment.