Skip to content

Commit

Permalink
fix(LAB-3447): correct calculation of vertices in kili format
Browse files Browse the repository at this point in the history
  • Loading branch information
Sihem Tchabi authored and paulruelle committed Feb 4, 2025
1 parent a66486a commit 38af6d6
Showing 1 changed file with 62 additions and 17 deletions.
79 changes: 62 additions & 17 deletions src/kili/services/export/format/kili/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@

import json
from pathlib import Path
from typing import Callable, Dict, List
from typing import Callable, Dict, List, Optional, Union

from kili.services.export.exceptions import NotCompatibleInputType, NotCompatibleOptions
from kili.services.export.format.base import AbstractExporter
from kili.services.export.format.base import AbstractExporter, reverse_rotation_vertices
from kili.services.export.media.video import cut_video
from kili.services.types import Job


def _clean_json_response(asset: Dict):
if asset.get("latestLabel", {}) and asset["latestLabel"].get("jsonResponse", {}):
if "ROTATION_JOB" in asset["latestLabel"]["jsonResponse"]:
asset["latestLabel"]["jsonResponse"].pop("ROTATION_JOB")
if asset.get("labels"):
for label in asset["labels"]:
if label.get("jsonResponse", {}) and "ROTATION_JOB" in label["jsonResponse"]:
label["jsonResponse"].pop("ROTATION_JOB")
return asset


class KiliExporter(AbstractExporter):
"""Common code for Kili exporters."""

Expand Down Expand Up @@ -96,10 +107,10 @@ def _cut_video_assets(self, assets: List[Dict]) -> List[Dict]:
def process_and_save(self, assets: List[Dict], output_filename: Path) -> None:
"""Extract formatted annotations from labels and save the json in the buckets."""
clean_assets = self.preprocess_assets(assets)

if self.normalized_coordinates is False:
clean_assets = [self.convert_to_pixel_coords(asset) for asset in clean_assets]

if self.project["inputType"] != "LLM_RLHF":
for i, asset in enumerate(clean_assets):
clean_assets[i] = self.convert_to_pixel_coords(asset)
clean_assets[i] = _clean_json_response(asset)
return self._save_assets_export(
clean_assets,
output_filename,
Expand Down Expand Up @@ -131,11 +142,17 @@ def _scale_label_vertices(self, label: Dict, asset: Dict) -> None:
else False
)

rotation_val = 0
if "ROTATION_JOB" in label["jsonResponse"]:
rotation_val = label["jsonResponse"]["ROTATION_JOB"]["rotation"]

if self.project["inputType"] == "PDF":
self._scale_json_response_vertices(
label["jsonResponse"],
asset,
is_label_rotated,
rotation_val,
False,
_scale_normalized_vertices_pdf_annotation,
)

Expand All @@ -144,6 +161,8 @@ def _scale_label_vertices(self, label: Dict, asset: Dict) -> None:
label["jsonResponse"],
asset,
is_label_rotated,
rotation_val,
self.normalized_coordinates,
_scale_normalized_vertices_image_video_annotation,
)

Expand All @@ -154,6 +173,8 @@ def _scale_label_vertices(self, label: Dict, asset: Dict) -> None:
frame_resp,
asset,
is_label_rotated,
rotation_val,
self.normalized_coordinates,
_scale_normalized_vertices_image_video_annotation,
)

Expand All @@ -168,14 +189,16 @@ def _scale_json_response_vertices(
json_resp: Dict,
asset: Dict,
is_label_rotated: bool,
annotation_scaler: Callable[[Dict, Dict, bool], None],
rotation: int,
normalized_vertices: Optional[bool],
annotation_scaler: Callable[[Dict, Dict, bool, int, Union[bool, None]], None],
) -> None:
for job_name in json_resp:
if self._can_scale_vertices_for_job_name(job_name) and json_resp.get(job_name, {}).get(
"annotations"
):
for ann in json_resp[job_name]["annotations"]:
annotation_scaler(ann, asset, is_label_rotated)
annotation_scaler(ann, asset, is_label_rotated, rotation, normalized_vertices)

def _can_scale_vertices_for_job_name(self, job_name: str) -> bool:
return (
Expand Down Expand Up @@ -212,7 +235,11 @@ def _scale_all_vertices(object_, width: int, height: int):


def _scale_normalized_vertices_pdf_annotation(
annotation: Dict, asset: Dict, is_label_rotated: bool = False
annotation: Dict,
asset: Dict,
is_label_rotated: bool = False,
_rotation: int = 0,
_normalized_vertices: Union[bool, None] = False,
) -> None:
"""Scale normalized vertices of a PDF annotation.
Expand Down Expand Up @@ -265,31 +292,49 @@ def _scale_normalized_vertices_pdf_annotation(


def _scale_normalized_vertices_image_video_annotation(
annotation: Dict, asset: Dict, is_label_rotated: bool
annotation: Dict,
asset: Dict,
_is_label_rotated: bool,
rotation: int,
_normalized_vertices: Optional[bool],
) -> None:
"""Scale normalized vertices of an image/video object detection annotation."""
if "resolution" not in asset or asset["resolution"] is None:
if _normalized_vertices is False and ("resolution" not in asset or asset["resolution"] is None):
raise NotCompatibleOptions(
"Image and video labels export with absolute coordinates require `resolution` in the"
" asset. Please use `kili.update_properties_in_assets(resolution_array=...)` to update"
" the resolution of your asset.`"
)

width = asset["resolution"]["width"] if not is_label_rotated else asset["resolution"]["height"]
height = asset["resolution"]["height"] if not is_label_rotated else asset["resolution"]["width"]
width = asset["resolution"]["width"] if "resolution" in asset else 0
height = asset["resolution"]["height"] if "resolution" in asset else 0

# bbox, segmentation, polygons
if "boundingPoly" in annotation:
if "boundingPoly" in annotation and _normalized_vertices:
annotation["boundingPoly"] = [
{
**norm_vertices_dict, # keep the original normalizedVertices
"vertices": _scale_all_vertices(
norm_vertices_dict["normalizedVertices"], width=width, height=height
"normalizedVertices": reverse_rotation_vertices(
norm_vertices_dict["normalizedVertices"], rotation
),
}
for norm_vertices_dict in annotation["boundingPoly"]
]
return

if "boundingPoly" in annotation and _normalized_vertices is False:
annotation["boundingPoly"] = [
{
"normalizedVertices": reverse_rotation_vertices(
norm_vertices_dict["normalizedVertices"], rotation
),
"vertices": _scale_all_vertices(
reverse_rotation_vertices(norm_vertices_dict["normalizedVertices"], rotation),
width=width,
height=height,
),
}
for norm_vertices_dict in annotation["boundingPoly"]
]
# point jobs
if "point" in annotation:
annotation["pointPixels"] = _scale_all_vertices(
Expand Down

0 comments on commit 38af6d6

Please sign in to comment.