Skip to content

Commit 0f905bc

Browse files
authored
Merge pull request #68 from fastlabel/feature/export-pascalvoc-switch-attr
fix pascal voc export
2 parents 6f33c15 + a41e7a9 commit 0f905bc

File tree

2 files changed

+69
-58
lines changed

2 files changed

+69
-58
lines changed

fastlabel/converters.py

Lines changed: 68 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import copy
55
import geojson
66
import numpy as np
7+
import math
78
from fastlabel.const import AnnotationType
89

910
# COCO
@@ -207,10 +208,75 @@ def _truncate(n, decimals=0) -> float:
207208

208209

209210
def to_pascalvoc(tasks: list) -> list:
210-
coco = to_coco(tasks)
211-
pascalvoc = __coco2pascalvoc(coco)
211+
pascalvoc = []
212+
for task in tasks:
213+
if task["height"] == 0 or task["width"] == 0:
214+
continue
215+
216+
pascal_objs = []
217+
data = [{"annotation": annotation}
218+
for annotation in task["annotations"]]
219+
with ThreadPoolExecutor(max_workers=8) as executor:
220+
results = executor.map(__get_pascalvoc_obj, data)
221+
222+
for result in results:
223+
if not result:
224+
continue
225+
pascal_objs.append(result)
226+
227+
voc = {
228+
"annotation": {
229+
"filename": task["name"],
230+
"size": {
231+
"width": task["width"],
232+
"height": task["height"],
233+
"depth": 3,
234+
},
235+
"segmented": 0,
236+
"object": pascal_objs
237+
}
238+
}
239+
pascalvoc.append(voc)
212240
return pascalvoc
213241

242+
def __get_pascalvoc_obj(data: dict) -> dict:
243+
annotation = data["annotation"]
244+
points = annotation["points"]
245+
annotation_type = annotation["type"]
246+
if annotation_type != AnnotationType.bbox.value and annotation_type != AnnotationType.polygon.value:
247+
return None
248+
if not points or len(points) == 0:
249+
return None
250+
if annotation_type == AnnotationType.bbox.value and (int(points[0]) == int(points[2]) or int(points[1]) == int(points[3])):
251+
return None
252+
bbox = __to_bbox(points)
253+
x = bbox[0]
254+
y = bbox[1]
255+
w = bbox[2]
256+
h = bbox[3]
257+
258+
return {
259+
"name": annotation["value"],
260+
"pose": "Unspecified",
261+
"truncated": __get_pascalvoc_tag_value(annotation, "truncated"),
262+
"occluded": __get_pascalvoc_tag_value(annotation, "occluded"),
263+
"difficult": __get_pascalvoc_tag_value(annotation, "difficult"),
264+
"bndbox": {
265+
"xmin": math.floor(x),
266+
"ymin": math.floor(y),
267+
"xmax": math.floor(x + w),
268+
"ymax": math.floor(y + h),
269+
},
270+
}
271+
272+
def __get_pascalvoc_tag_value(annotation: dict, target_tag_name: str) -> int:
273+
attributes = annotation["attributes"]
274+
if not attributes:
275+
return 0
276+
related_attr = next(
277+
(attribute for attribute in attributes if attribute["type"] == "switch" and attribute["key"] == target_tag_name), None)
278+
return int(related_attr["value"]) if related_attr else 0
279+
214280

215281
# labelme
216282

@@ -388,58 +454,3 @@ def __get_pixel_coordinates(points: List[int or float]) -> List[int]:
388454
new_points.append(int(prev_x + int(xdiff / mindiff * (i + 1))))
389455
new_points.append(int(prev_y + int(ydiff / mindiff * (i + 1))))
390456
return new_points
391-
392-
def __coco2pascalvoc(coco: dict) -> list:
393-
pascalvoc = []
394-
395-
for image in coco["images"]:
396-
397-
# Get objects
398-
objs = []
399-
for annotation in coco["annotations"]:
400-
if image["id"] != annotation["image_id"]:
401-
continue
402-
category = _get_category_by_id(
403-
coco["categories"], annotation["category_id"])
404-
405-
x = annotation["bbox"][0]
406-
y = annotation["bbox"][1]
407-
w = annotation["bbox"][2]
408-
h = annotation["bbox"][3]
409-
410-
obj = {
411-
"name": category["name"],
412-
"pose": "Unspecified",
413-
"truncated": 0,
414-
"difficult": 0,
415-
"bndbox": {
416-
"xmin": x,
417-
"ymin": y,
418-
"xmax": x + w,
419-
"ymax": y + h,
420-
},
421-
}
422-
objs.append(obj)
423-
424-
# get annotation
425-
voc = {
426-
"annotation": {
427-
"filename": image["file_name"],
428-
"size": {
429-
"width": image["width"],
430-
"height": image["height"],
431-
"depth": 3,
432-
},
433-
"segmented": 0,
434-
"object": objs
435-
}
436-
}
437-
pascalvoc.append(voc)
438-
439-
return pascalvoc
440-
441-
442-
def _get_category_by_id(categories: list, id_: str) -> str:
443-
category = [
444-
category for category in categories if category["id"] == id_][0]
445-
return category

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
setuptools.setup(
1010
name="fastlabel",
11-
version="0.11.1",
11+
version="0.11.2",
1212
author="eisuke-ueta",
1313
author_email="[email protected]",
1414
description="The official Python SDK for FastLabel API, the Data Platform for AI",

0 commit comments

Comments
 (0)