|
4 | 4 | import copy |
5 | 5 | import geojson |
6 | 6 | import numpy as np |
| 7 | +import math |
7 | 8 | from fastlabel.const import AnnotationType |
8 | 9 |
|
9 | 10 | # COCO |
@@ -207,10 +208,75 @@ def _truncate(n, decimals=0) -> float: |
207 | 208 |
|
208 | 209 |
|
209 | 210 | 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) |
212 | 240 | return pascalvoc |
213 | 241 |
|
| 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 | + |
214 | 280 |
|
215 | 281 | # labelme |
216 | 282 |
|
@@ -388,58 +454,3 @@ def __get_pixel_coordinates(points: List[int or float]) -> List[int]: |
388 | 454 | new_points.append(int(prev_x + int(xdiff / mindiff * (i + 1)))) |
389 | 455 | new_points.append(int(prev_y + int(ydiff / mindiff * (i + 1)))) |
390 | 456 | 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 |
|
0 commit comments