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
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ dependencies = [
"filelock >= 3.0.0, < 4.0.0",
"pip-system-certs >= 4.0.0, < 5.0.0; platform_system=='Windows'",
"pyrate-limiter >= 3, < 4",
"kili-formats == 1.0.0"
"kili-formats == 1.0.1"
]
urls = { homepage = "https://github.com/kili-technology/kili-python-sdk" }

Expand Down Expand Up @@ -79,7 +79,7 @@ dev = [
"nbconvert",
"ipykernel",
# optional dependencies
"kili-formats[all] == 1.0.0",
"kili-formats[all] == 1.0.1",
"opencv-python >= 4.0.0, < 5.0.0",
"azure-storage-blob >= 12.0.0, < 13.0.0",
# optional dependencies gis
Expand All @@ -95,7 +95,7 @@ dev = [
all = [
# aggregate all optional deps without dev
"azure-storage-blob >= 12.0.0, < 13.0.0",
"kili-formats[all] == 1.0.0",
"kili-formats[all] == 1.0.1",
"opencv-python >= 4.0.0, < 5.0.0",
"Pillow >=9.0.0, <11.0.0",
"pyproj == 3.7.1",
Expand All @@ -108,20 +108,20 @@ cli = [
"tabulate >= 0.9.0, < 0.10.0"
]
coco = [
"kili-formats[coco] == 1.0.0"
"kili-formats[coco] == 1.0.1"
]
gis = [
"pyproj == 3.7.1",
"shapely >= 1.8, < 3"
]
image = [
"Pillow >=9.0.0, <11.0.0",
"kili-formats[image] == 1.0.0"
"kili-formats[image] == 1.0.1"
]
image-utils = ["opencv-python >= 4.0.0, < 5.0.0"]

video = [
"kili-formats[video] == 1.0.0"
"kili-formats[video] == 1.0.1"
]
yolo = [
"pyyaml >= 6.0, < 7.0"
Expand Down
16 changes: 12 additions & 4 deletions src/kili/services/export/format/geojson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,28 @@ def process_and_save(self, assets: list[dict], output_filename: Path) -> None:
" will be exported."
)

# Get json_interface for GIS-friendly property names
json_interface = self.project.get("jsonInterface")

for asset in tqdm(geotiff_assets, disable=self.disable_tqdm):
_process_asset(asset, labels_folder)
_process_asset(asset, labels_folder, json_interface, flatten_properties=True)

self.create_readme_kili_file(self.export_root_folder)
self.make_archive(self.export_root_folder, output_filename)

self.logger.warning(output_filename)


def _process_asset(asset: dict, labels_folder: Path) -> None:
def _process_asset(
asset: dict,
labels_folder: Path,
json_interface: dict | None = None,
flatten_properties: bool = False,
) -> None:
geojson_feature_collection = convert_from_kili_to_geojson_format(
asset["latestLabel"]["jsonResponse"]
asset["latestLabel"]["jsonResponse"], json_interface, flatten_properties
)
filepath = labels_folder / f'{asset["externalId"]}.geojson'
filepath = labels_folder / f"{asset['externalId']}.geojson"
filepath.parent.mkdir(parents=True, exist_ok=True)
with open(filepath, "w", encoding="utf-8") as file:
json.dump(geojson_feature_collection, file)
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
},
"id": "20230713142445256-28071",
"properties": {
"class": "BBox A",
"BBox job": "BBox A",
"kili": {
"type": "rectangle",
"categories": [{"name": "B_BOX_A"}],
"children": {},
"job": "BBOX_DETECTION_JOB",
"type": "rectangle",
}
},
},
"type": "Feature",
},
Expand All @@ -39,51 +41,59 @@
},
"id": "20230713142448596-95775",
"properties": {
"class": "BBox A",
"BBox job": "BBox A",
"kili": {
"type": "rectangle",
"categories": [{"name": "B_BOX_A"}],
"children": {},
"job": "BBOX_DETECTION_JOB",
"type": "rectangle",
}
},
},
"type": "Feature",
},
{
"geometry": {"coordinates": [4.398223125643078, 52.24806039693592], "type": "Point"},
"id": "20230713142454008-23856",
"properties": {
"class": "Point A",
"Point job": "Point A",
"kili": {
"type": "marker",
"categories": [{"name": "POINT_A"}],
"children": {},
"job": "POINT_DETECTION_JOB",
"type": "marker",
}
},
},
"type": "Feature",
},
{
"geometry": {"coordinates": [4.3710296361584255, 52.241662846365564], "type": "Point"},
"id": "20230713142503281-53174",
"properties": {
"class": "Point A",
"Point job": "Point A",
"kili": {
"type": "marker",
"categories": [{"name": "POINT_A"}],
"children": {},
"job": "POINT_DETECTION_JOB",
"type": "marker",
}
},
},
"type": "Feature",
},
{
"geometry": {"coordinates": [4.344001960634017, 52.24602952843428], "type": "Point"},
"id": "20230713142504544-36453",
"properties": {
"class": "Point A",
"Point job": "Point A",
"kili": {
"type": "marker",
"categories": [{"name": "POINT_A"}],
"children": {},
"job": "POINT_DETECTION_JOB",
"type": "marker",
}
},
},
"type": "Feature",
},
Expand All @@ -107,12 +117,14 @@
},
"id": "20230713142514505-569",
"properties": {
"class": "Polygon A",
"Polygon job": "Polygon A",
"kili": {
"type": "polygon",
"categories": [{"name": "POLYGON_A"}],
"children": {},
"job": "POLYGON_DETECTION_JOB",
"type": "polygon",
}
},
},
"type": "Feature",
},
Expand All @@ -131,12 +143,14 @@
},
"id": "20230713142520574-39224",
"properties": {
"class": "Polygon A",
"Polygon job": "Polygon A",
"kili": {
"type": "polygon",
"categories": [{"name": "POLYGON_A"}],
"children": {},
"job": "POLYGON_DETECTION_JOB",
"type": "polygon",
}
},
},
"type": "Feature",
},
Expand Down Expand Up @@ -165,12 +179,14 @@
},
"id": "20230713142557676-43208",
"properties": {
"class": "Line A",
"Line job": "Line A",
"kili": {
"type": "polyline",
"categories": [{"name": "LINE_A"}],
"children": {},
"job": "LINE_DETECTION_JOB",
"type": "polyline",
}
},
},
"type": "Feature",
},
Expand All @@ -188,12 +204,14 @@
},
"id": "20230713142603466-75106",
"properties": {
"class": "Line A",
"Line job": "Line A",
"kili": {
"type": "polyline",
"categories": [{"name": "LINE_A"}],
"children": {},
"job": "LINE_DETECTION_JOB",
"type": "polyline",
}
},
},
"type": "Feature",
},
Expand Down Expand Up @@ -917,12 +935,14 @@
},
"id": "20230713142654407-69669",
"properties": {
"class": "Segmentation A",
"Segmentation job": "Segmentation A",
"kili": {
"type": "semantic",
"categories": [{"name": "SEGMENTATION_A"}],
"children": {},
"job": "SEGMENTATION_JOB",
"type": "semantic",
}
},
},
"type": "Feature",
},
Expand Down
25 changes: 11 additions & 14 deletions tests/unit/utils/labels/test_geojson.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ def test_polygon_geojson():
{"x": 9.519223671685653, "y": 54.52470311233283},
]

first_polygon_vertices = first_annotation["boundingPoly"][0]["normalizedVertices"]
first_polygon_vertices = first_annotation["boundingPoly"][0][0]["normalizedVertices"]
assert len(first_polygon_vertices) == len(expected_first_polygon)

for i, point in enumerate(first_polygon_vertices):
Expand Down Expand Up @@ -336,19 +336,16 @@ def test_multipolygon_geojson():
assert "annotations" in response["multipolygons_job"]

annotations = response["multipolygons_job"]["annotations"]
# MultiPolygon should create multiple annotations with the same mid
assert len(annotations) == 2

# Check that both annotations have the same mid (indicating they're parts of the same multipolygon)
mids = [ann.get("mid") for ann in annotations]
assert len(set(mids)) == 1 # All should have the same mid

for annotation in annotations:
assert annotation["type"] == "semantic"
assert "boundingPoly" in annotation
assert "categories" in annotation
assert len(annotation["categories"]) == 1
assert annotation["categories"][0]["name"] == "multipolygon_category"
# MultiPolygon should create a single annotation with multiple polygons in boundingPoly
assert len(annotations) == 1

annotation = annotations[0]
assert annotation["type"] == "semantic"
assert "boundingPoly" in annotation
assert len(annotation["boundingPoly"]) == 2
assert "categories" in annotation
assert len(annotation["categories"]) == 1
assert annotation["categories"][0]["name"] == "multipolygon_category"

shutil.rmtree(temp_dir)

Expand Down