Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to the [Nucleus Python Client](https://github.com/scaleapi/n
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.10.2](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.10.2) - 2022-04-22

### Fixed
- Polygon and bounding box matching uses Shapely again providing faster evaluations

## [0.10.1](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.10.1) - 2022-04-21

### Added
Expand Down
7 changes: 2 additions & 5 deletions nucleus/metrics/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@

from nucleus.prediction import PredictionList

from .polygon_utils import (
BoxOrPolygonAnnoOrPred,
polygon_annotation_to_geometry,
)
from .polygon_utils import BoxOrPolygonAnnoOrPred, polygon_annotation_to_shape


def polygon_area_filter(
polygons: List[BoxOrPolygonAnnoOrPred], min_area: float, max_area: float
) -> List[BoxOrPolygonAnnoOrPred]:
filter_fn = (
lambda polygon: min_area
<= polygon_annotation_to_geometry(polygon).signed_area
<= polygon_annotation_to_shape(polygon)
<= max_area
)
return list(filter(filter_fn, polygons))
Expand Down
198 changes: 0 additions & 198 deletions nucleus/metrics/geometry.py

This file was deleted.

32 changes: 13 additions & 19 deletions nucleus/metrics/polygon_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

import numpy as np
from scipy.optimize import linear_sum_assignment
from shapely.geometry import Polygon

from nucleus.annotation import BoxAnnotation, PolygonAnnotation
from nucleus.prediction import BoxPrediction, PolygonPrediction

from .base import ScalarResult
from .errors import PolygonAnnotationTypeError
from .geometry import GeometryPolygon, polygon_intersection_area

BoxOrPolygonPrediction = TypeVar(
"BoxOrPolygonPrediction", BoxPrediction, PolygonPrediction
Expand All @@ -27,33 +27,31 @@
)


def polygon_annotation_to_geometry(
def polygon_annotation_to_shape(
annotation: BoxOrPolygonAnnotation,
) -> GeometryPolygon:
) -> Polygon:
if isinstance(annotation, BoxAnnotation):
xmin = annotation.x - annotation.width / 2
xmax = annotation.x + annotation.width / 2
ymin = annotation.y - annotation.height / 2
ymax = annotation.y + annotation.height / 2
points = [(xmin, ymin), (xmax, ymin), (xmax, ymax), (xmin, ymax)]
return GeometryPolygon(points=points, is_rectangle=True)
elif isinstance(annotation, PolygonAnnotation):
return GeometryPolygon(
points=[(point.x, point.y) for point in annotation.vertices],
is_rectangle=False,
return Polygon(
[(xmin, ymin), (xmax, ymin), (xmax, ymax), (xmin, ymax)]
)
elif isinstance(annotation, PolygonAnnotation):
return Polygon([(point.x, point.y) for point in annotation.vertices])
else:
raise PolygonAnnotationTypeError()


def _iou(annotation: GeometryPolygon, prediction: GeometryPolygon) -> float:
intersection = polygon_intersection_area(annotation, prediction)
def _iou(annotation: Polygon, prediction: Polygon) -> float:
intersection = annotation.intersection(prediction).area
union = annotation.area + prediction.area - intersection
return intersection / max(union, sys.float_info.epsilon)


def _iou_matrix(
annotations: List[GeometryPolygon], predictions: List[GeometryPolygon]
annotations: List[Polygon], predictions: List[Polygon]
) -> np.ndarray:
iou_matrix = np.empty((len(predictions), len(annotations)))
for i, prediction in enumerate(predictions):
Expand All @@ -80,13 +78,9 @@ def _iou_assignments_for_same_reference_id(
len(reference_ids) <= 1
), "Expected annotations and predictions to have same reference ID."

# Convert annotation and predictions to GeometryPolygon objects
polygon_annotations = list(
map(polygon_annotation_to_geometry, annotations)
)
polygon_predictions = list(
map(polygon_annotation_to_geometry, predictions)
)
# Convert annotation and predictions to shapely.geometry.Polygon objects
polygon_annotations = list(map(polygon_annotation_to_shape, annotations))
polygon_predictions = list(map(polygon_annotation_to_shape, predictions))

# Compute IoU matrix and set IoU values below the threshold to 0.
iou_matrix = _iou_matrix(polygon_annotations, polygon_predictions)
Expand Down
Loading