Skip to content

Commit

Permalink
Adding functionality to reindex polygons
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasteuwen committed Aug 13, 2024
1 parent 8af648d commit d0a1ada
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 13 deletions.
58 changes: 47 additions & 11 deletions dlup/annotations_experimental.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def shape(
class WsiAnnotationsExperimental:
"""Class that holds all annotations for a specific image"""

def __init__(self, layers):
def __init__(self, layers: DlupGeometryContainer):
self._layers = layers
self._tags = []

Expand All @@ -151,7 +151,7 @@ def from_geojson(
_geojsons: Iterable[Any] = [pathlib.Path(geojsons)]

_geojsons = [geojsons] if not isinstance(geojsons, (tuple, list)) else geojsons
layers: list[DlupPolygon | DlupPoint] = []
geometries: list[DlupPolygon | DlupPoint] = []
for path in _geojsons:
path = pathlib.Path(path)
if not path.exists():
Expand All @@ -172,10 +172,10 @@ def from_geojson(
raise ValueError("Could not find label in the GeoJSON properties.")

_geometry = shape(x["geometry"], label=_label, color=_color)
layers += _geometry
geometries += _geometry

container = DlupGeometryContainer()
for layer in layers:
for layer in geometries:
if isinstance(layer, DlupPolygon):
container.add_polygon(layer)
elif isinstance(layer, DlupPoint):
Expand Down Expand Up @@ -210,18 +210,24 @@ def as_geojson(self) -> GeoJsonDict:

return data

def read_region(self, coordinates, scaling, size):
def read_region(self, coordinates: tuple[int, int], scaling: float, size: tuple[int, int]):
return self._layers.read_region(coordinates, scaling, size)

def scale(self, scaling: float) -> None:
"""Scale the annotations by a multiplication factor.
"""
Scale the annotations by a multiplication factor.
This operation will be performed in-place.
Parameters
----------
scaling : float
The scaling factor to apply to the annotations.
Notes
-----
This invalidates the R-tree. You could rebuild this manually using `.rebuild_rtree()`, or have the function
`read_region()` do it for you on-demand.
Returns
-------
None
Expand All @@ -230,31 +236,62 @@ def scale(self, scaling: float) -> None:

def set_offset(self, offset: tuple[float, float]) -> None:
"""Set the offset for the annotations. This operation will be performed in-place.
For example, if the offset is 1, 1, the annotations will be moved by 1 unit in the x and y direction.
Parameters
----------
offset : tuple[float, float]
The offset to apply to the annotations.
Notes
-----
This invalidates the R-tree. You could rebuild this manually using `.rebuild_rtree()`, or have the function
`read_region()` do it for you on-demand.
Returns
-------
None
"""
self._layers.set_offset(offset)

def rebuild_rtree(self):
"""
Rebuild the R-tree for the annotations. This operation will be performed in-place.
The R-tree is used for fast spatial queries on the annotations and is invalidated when the annotations are
modified. This function will rebuild the R-tree. Strictly speaking, this is not required as the R-tree will be
rebuilt on-demand when you invoke a `read_region()`. You could however do this if you want to avoid the `read_region()`
to do it for you the first time it runs.
"""

self._layers.rebuild_rtree()

def reindex_polygons(self, index_map: dict[str, int]):
"""
Reindex the polygons in the annotations. This operation will be performed in-place.
This is useful if you want to change the index of the polygons in the annotations.
This requires that the `.label` property on the polygons is set.
Parameters
----------
index_map : dict[str, int]
A dictionary that maps the label to the new index.
Returns
-------
None
"""
self._layers.reindex_polygons(index_map)

def filter_polygons(self, label: str) -> None:
"""Filter polygons in-place.
"""Filter polygons in-place.
Note
----
This will internally invalidate the R-tree. You could rebuild this manually using `.rebuild_rtree()`, or
have the function itself do this on-demand (typically when you invoke a `.read_region()`)
Parameters
----------
label : str
Expand All @@ -264,4 +301,3 @@ def filter_polygons(self, label: str) -> None:
for polygon in self._layers.polygons:
if polygon.label == label:
self._layers.remove_polygon(polygon)

16 changes: 14 additions & 2 deletions dlup/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,29 @@ def __init__(self, *args, **kwargs):
self.set_field(key, value)

@property
def label(self):
def label(self) -> str:
return self.get_field("label")

@label.setter
def label(self, value: str) -> None:
self.set_field("label", value)

@property
def index(self):
def index(self) -> int:
return self.get_field("index")

@index.setter
def index(self, value: int) -> None:
self.set_field("index", value)

@property
def color(self):
return self.get_field("color")

@color.setter
def color(self, value: str) -> None:
self.set_field("color", value)

def to_shapely(self):
if not SHAPELY_AVAILABLE:
raise ImportError(
Expand Down

0 comments on commit d0a1ada

Please sign in to comment.