Skip to content

Commit

Permalink
🐛 Fix Rendering Annotations with Holes (#813)
Browse files Browse the repository at this point in the history
This PR adds correct rendering of annotations with holes.

Previously, annotations with holes would not be rendered. This PR fixes the issue.

![image](https://github.com/TissueImageAnalytics/tiatoolbox/assets/20169086/a6fb3576-9a58-4416-a676-e2d5d030bedc)

Previously an overlay like the above, with a geometry with holes in it, would not display.
  • Loading branch information
measty authored May 3, 2024
1 parent ec5a373 commit 8b0e1cf
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 21 deletions.
9 changes: 5 additions & 4 deletions tests/test_annotation_tilerendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
def cell_grid() -> list[Polygon]:
"""Generate a grid of fake cell boundary polygon annotations."""
return [
cell_polygon(((i + 0.5) * 100, (j + 0.5) * 100)) for i, j in np.ndindex(5, 5)
cell_polygon(((i + 0.5) * 100, (j + 0.5) * 100), radius=13)
for i, j in np.ndindex(5, 5)
]


Expand Down Expand Up @@ -168,7 +169,7 @@ def test_filter_by_expression(fill_store: Callable, tmp_path: Path) -> None:
tg = AnnotationTileGenerator(wsi.info, store, renderer, tile_size=256)
thumb = tg.get_thumb_tile()
_, num = label(np.array(thumb)[:, :, 1])
assert num == 25 # expect 25 cell objects, as the added one is too small
assert num == 25 # expect 25 cell objects


def test_zoomed_out_rendering(fill_store: Callable, tmp_path: Path) -> None:
Expand All @@ -190,7 +191,7 @@ def test_zoomed_out_rendering(fill_store: Callable, tmp_path: Path) -> None:

thumb = tg.get_tile(1, 0, 0)
_, num = label(np.array(thumb)[:, :, 1]) # default color is green
assert num == 25 # expect 25 cells in top left quadrant
assert num == 25 # expect 25 cells in top left quadrant (added one too small)


def test_decimation(fill_store: Callable, tmp_path: Path) -> None:
Expand Down Expand Up @@ -434,7 +435,7 @@ def test_unfilled_polys(fill_store: Callable, tmp_path: Path) -> None:
renderer = AnnotationRenderer(thickness=1)
tg = AnnotationTileGenerator(wsi.info, store, renderer, tile_size=256)
tile_outline = np.array(tg.get_tile(1, 0, 0))
tg.renderer.edge_thickness = -1
tg.renderer.thickness = -1
tile_filled = np.array(tg.get_tile(1, 0, 0))
# expect sum of filled polys to be much greater than sum of outlines
assert np.sum(tile_filled) > 2 * np.sum(tile_outline)
Expand Down
43 changes: 26 additions & 17 deletions tiatoolbox/utils/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,10 @@ def to_tile_coords(
Array of coordinates in tile space in the form [x, y].
"""
return ((np.reshape(coords, (-1, 2)) - top_left) / scale).astype(np.int32)
return [
((np.reshape(ring, (-1, 2)) - top_left) / scale).astype(np.int32)
for ring in coords
]

def get_color(
self: AnnotationRenderer,
Expand Down Expand Up @@ -756,19 +759,26 @@ def render_poly(
scale,
)
if self.thickness > -1:
cv2.drawContours(
cv2.polylines(
tile,
[cnt],
0,
col,
self.edge_thickness,
cnt,
isClosed=True,
color=col,
thickness=self.edge_thickness,
lineType=cv2.LINE_8,
)
else:
cv2.drawContours(tile, [cnt], 0, col, self.thickness, lineType=cv2.LINE_8)
cv2.fillPoly(tile, cnt, col)
if self.thickness == -1 and self.edge_thickness > 0:
edge_col = self.get_color(annotation, edge=True)
cv2.drawContours(tile, [cnt], 0, edge_col, 1, lineType=cv2.LINE_8)
cv2.polylines(
tile,
cnt,
isClosed=True,
color=edge_col,
thickness=1,
lineType=cv2.LINE_8,
)

def render_multipoly(
self: AnnotationRenderer,
Expand All @@ -782,7 +792,7 @@ def render_multipoly(
geoms = annotation.coords
for poly in geoms:
cnt = self.to_tile_coords(poly, top_left, scale)
cv2.drawContours(tile, [cnt], 0, col, self.thickness, lineType=cv2.LINE_8)
cv2.fillPoly(tile, cnt, col)

def render_pt(
self: AnnotationRenderer,
Expand Down Expand Up @@ -811,7 +821,7 @@ def render_pt(
annotation.coords,
top_left,
scale,
)[0],
)[0][0],
np.maximum(self.edge_thickness, 1),
col,
thickness=self.thickness,
Expand All @@ -838,15 +848,14 @@ def render_line(
"""
col = self.get_color(annotation, edge=False)
cnt = self.to_tile_coords(
list(annotation.coords),
top_left,
scale,
)
cv2.polylines(
tile,
[
self.to_tile_coords(
list(annotation.coords),
top_left,
scale,
),
],
[np.array(cnt)],
isClosed=False,
color=col,
thickness=3,
Expand Down

0 comments on commit 8b0e1cf

Please sign in to comment.