Skip to content

Commit be1435d

Browse files
authored
[CVAT] Add polygons support (#2722)
* [Exchange Oracle] Adapt generate_jwt_token to be reused during development * [Exchange Oracle] Add polygon task type support * [Recording Oracle] Add initial polygon task type support * [Exchange Oracle] Fix get_auth_header in tests * [Exchange Oracle] Fix test_cannot_register_400_with_duplicated_address * [Recording Oracle] Fix linting issues * [Recording Oracle] Update development patches for recording oracle * [Recording Oracle] Add simple PolygonsDatasetComparator Currently, it just computes bounding box from the polyhon shape and uses it for comparison. This should be enough until we move to CVAT for validation. * [Exchange Oracle] Update local manifests on each request * [Recording Oracle] Fix linting * [Recording Oracle] Apply ruff format * [Exchange Oracle] Remove redundant session.commit() * Delete debug.py * [Exchange Oracle] Revert changes to `generate_jwt_token` * [Exchange Oracle] Revert changes to .gitignore
1 parent d98f8a5 commit be1435d

File tree

7 files changed

+48
-4
lines changed

7 files changed

+48
-4
lines changed

packages/examples/cvat/exchange-oracle/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@ __pycache__/
55
# Env file
66
.env
77
.python-version
8-

packages/examples/cvat/exchange-oracle/src/core/types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ class TaskTypes(str, Enum, metaclass=BetterEnumMeta):
4444
image_boxes = "image_boxes"
4545
image_boxes_from_points = "image_boxes_from_points"
4646
image_skeletons_from_boxes = "image_skeletons_from_boxes"
47+
image_polygons = "image_polygons"
4748

4849

4950
class CvatLabelTypes(str, Enum, metaclass=BetterEnumMeta):
5051
tag = "tag"
5152
points = "points"
5253
rectangle = "rectangle"
54+
polygon = "polygon"
5355

5456

5557
class OracleWebhookTypes(str, Enum, metaclass=BetterEnumMeta):

packages/examples/cvat/exchange-oracle/src/handlers/job_creation.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
TaskTypes.image_label_binary: CvatLabelTypes.tag,
4949
TaskTypes.image_points: CvatLabelTypes.points,
5050
TaskTypes.image_boxes: CvatLabelTypes.rectangle,
51+
TaskTypes.image_polygons: CvatLabelTypes.polygon,
5152
TaskTypes.image_boxes_from_points: CvatLabelTypes.rectangle,
5253
TaskTypes.image_skeletons_from_boxes: CvatLabelTypes.points,
5354
}
@@ -56,6 +57,7 @@
5657
TaskTypes.image_label_binary: "cvat_images",
5758
TaskTypes.image_points: "coco_person_keypoints",
5859
TaskTypes.image_boxes: "coco_instances",
60+
TaskTypes.image_polygons: "coco_instances",
5961
TaskTypes.image_boxes_from_points: "coco_instances",
6062
TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints",
6163
}
@@ -65,6 +67,7 @@
6567
TaskTypes.image_label_binary: "cvat_images",
6668
TaskTypes.image_points: "coco_instances",
6769
TaskTypes.image_boxes: "coco_instances",
70+
TaskTypes.image_polygons: "coco_instances",
6871
TaskTypes.image_boxes_from_points: "coco_instances",
6972
TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints",
7073
}
@@ -2499,6 +2502,7 @@ def create_task(escrow_address: str, chain_id: int) -> None:
24992502
TaskTypes.image_boxes,
25002503
TaskTypes.image_points,
25012504
TaskTypes.image_label_binary,
2505+
TaskTypes.image_polygons,
25022506
]:
25032507
builder_type = SimpleTaskBuilder
25042508
elif manifest.annotation.type in [TaskTypes.image_boxes_from_points]:

packages/examples/cvat/exchange-oracle/src/handlers/job_export.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
TaskTypes.image_label_binary: "CVAT for images 1.1",
2727
TaskTypes.image_points: "CVAT for images 1.1",
2828
TaskTypes.image_boxes: "COCO 1.0",
29+
TaskTypes.image_polygons: "COCO 1.0",
2930
TaskTypes.image_boxes_from_points: "COCO 1.0",
3031
TaskTypes.image_skeletons_from_boxes: "CVAT for images 1.1",
3132
}
@@ -160,6 +161,10 @@ class _BoxesTaskProcessor(_TaskProcessor):
160161
pass
161162

162163

164+
class _PolygonsTaskProcessor(_TaskProcessor):
165+
pass
166+
167+
163168
class _PointsTaskProcessor(_TaskProcessor):
164169
def _parse_dataset(self, ann_descriptor: FileDescriptor, dataset_dir: str) -> Dataset:
165170
annotation_utils.prepare_cvat_annotations_for_dm(dataset_dir)
@@ -586,6 +591,7 @@ def postprocess_annotations(
586591
processor_classes: dict[TaskTypes, type[_TaskProcessor]] = {
587592
TaskTypes.image_label_binary: _LabelsTaskProcessor,
588593
TaskTypes.image_boxes: _BoxesTaskProcessor,
594+
TaskTypes.image_polygons: _PolygonsTaskProcessor,
589595
TaskTypes.image_points: _PointsTaskProcessor,
590596
TaskTypes.image_boxes_from_points: _BoxesFromPointsTaskProcessor,
591597
TaskTypes.image_skeletons_from_boxes: _SkeletonsFromBoxesTaskProcessor,

packages/examples/cvat/recording-oracle/src/core/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Networks(int, Enum):
1313
class TaskTypes(str, Enum, metaclass=BetterEnumMeta):
1414
image_label_binary = "image_label_binary"
1515
image_points = "image_points"
16+
image_polygons = "image_polygons"
1617
image_boxes = "image_boxes"
1718
image_boxes_from_points = "image_boxes_from_points"
1819
image_skeletons_from_boxes = "image_skeletons_from_boxes"

packages/examples/cvat/recording-oracle/src/handlers/process_intermediate_results.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
BboxDatasetComparator,
3232
DatasetComparator,
3333
PointsDatasetComparator,
34+
PolygonsDatasetComparator,
3435
SkeletonDatasetComparator,
3536
TooFewGtError,
3637
)
@@ -42,6 +43,7 @@
4243

4344
DM_DATASET_FORMAT_MAPPING = {
4445
TaskTypes.image_label_binary: "cvat_images",
46+
TaskTypes.image_polygons: "coco_instances",
4547
TaskTypes.image_points: "coco_person_keypoints",
4648
TaskTypes.image_boxes: "coco_instances",
4749
TaskTypes.image_boxes_from_points: "coco_instances",
@@ -51,6 +53,7 @@
5153
DM_GT_DATASET_FORMAT_MAPPING = {
5254
TaskTypes.image_label_binary: "cvat_images",
5355
TaskTypes.image_points: "coco_instances", # we compare points against boxes
56+
TaskTypes.image_polygons: "coco_instances",
5457
TaskTypes.image_boxes: "coco_instances",
5558
TaskTypes.image_boxes_from_points: "coco_instances",
5659
TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints",
@@ -60,6 +63,7 @@
6063
DATASET_COMPARATOR_TYPE_MAP: dict[TaskTypes, type[DatasetComparator]] = {
6164
# TaskType.image_label_binary: TagDatasetComparator, # TODO: implement if support is needed
6265
TaskTypes.image_boxes: BboxDatasetComparator,
66+
TaskTypes.image_polygons: PolygonsDatasetComparator,
6367
TaskTypes.image_points: PointsDatasetComparator,
6468
TaskTypes.image_boxes_from_points: BboxDatasetComparator,
6569
TaskTypes.image_skeletons_from_boxes: SkeletonDatasetComparator,
@@ -199,7 +203,7 @@ def _validate_jobs(self):
199203
try:
200204
job_mean_accuracy = comparator.compare(gt_dataset, job_dataset)
201205
except TooFewGtError as e:
202-
job_results[job_cvat_id] = self.self.UNKNOWN_QUALITY
206+
job_results[job_cvat_id] = self.UNKNOWN_QUALITY
203207
rejected_jobs[job_cvat_id] = e
204208
continue
205209

@@ -271,7 +275,7 @@ def _put_gt_into_merged_dataset(
271275
"""
272276

273277
match manifest.annotation.type:
274-
case TaskTypes.image_boxes.value:
278+
case TaskTypes.image_boxes.value | TaskTypes.image_polygons.value:
275279
merged_dataset.update(gt_dataset)
276280
case TaskTypes.image_points.value:
277281
merged_label_cat: dm.LabelCategories = merged_dataset.categories()[
@@ -929,7 +933,12 @@ def process_intermediate_results( # noqa: PLR0912
929933
# actually validate jobs
930934

931935
task_type = manifest.annotation.type
932-
if task_type in [TaskTypes.image_label_binary, TaskTypes.image_boxes, TaskTypes.image_points]:
936+
if task_type in [
937+
TaskTypes.image_label_binary,
938+
TaskTypes.image_boxes,
939+
TaskTypes.image_polygons,
940+
TaskTypes.image_points,
941+
]:
933942
validator_type = _TaskValidator
934943
elif task_type == TaskTypes.image_boxes_from_points:
935944
validator_type = _BoxesFromPointsValidator

packages/examples/cvat/recording-oracle/src/validation/dataset_comparison.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,29 @@ def compare_sample_annotations(
183183
return matching_result, similarity_fn
184184

185185

186+
class PolygonsDatasetComparator(DatasetComparator):
187+
def compare_sample_annotations(
188+
self, gt_sample: dm.DatasetItem, ds_sample: dm.DatasetItem, *, similarity_threshold: float
189+
) -> tuple[MatchResult, SimilarityFunction]:
190+
similarity_fn = CachedSimilarityFunction(bbox_iou)
191+
192+
ds_boxes = [
193+
Bbox(*a.get_bbox(), a.label) for a in ds_sample.annotations if isinstance(a, dm.Polygon)
194+
]
195+
gt_boxes = [
196+
Bbox(*a.get_bbox(), a.label) for a in gt_sample.annotations if isinstance(a, dm.Polygon)
197+
]
198+
199+
matching_result = match_annotations(
200+
gt_boxes,
201+
ds_boxes,
202+
similarity=similarity_fn,
203+
min_similarity=similarity_threshold,
204+
)
205+
206+
return matching_result, similarity_fn
207+
208+
186209
_SkeletonInfo = list[str]
187210

188211

0 commit comments

Comments
 (0)