22Module for converting labelbox.com JSON exports to MS COCO format.
33"""
44
5- import json
65import datetime as dt
6+ import json
77import logging
8+ from typing import Any , Dict
9+
10+ from PIL import Image
11+ import requests
812from shapely import wkt
913from shapely .geometry import Polygon
10- import requests
11- from PIL import Image
1214
1315from labelbox .exceptions import UnknownFormatError
1416
@@ -25,15 +27,7 @@ def from_json(labeled_data, coco_output, label_format='WKT'):
2527 for data in label_data :
2628 # Download and get image name
2729 try :
28- image = {
29- "id" : data ['ID' ],
30- "file_name" : data ['Labeled Data' ],
31- "license" : None ,
32- "flickr_url" : data ['Labeled Data' ],
33- "coco_url" : data ['Labeled Data' ],
34- "date_captured" : None ,
35- }
36- _add_label (coco , image , data ['Label' ], label_format )
30+ add_label (coco , data ['ID' ], data ['Labeled Data' ], data ['Label' ], label_format )
3731 except requests .exceptions .MissingSchema as exc :
3832 logging .exception (exc )
3933 continue
@@ -45,31 +39,57 @@ def from_json(labeled_data, coco_output, label_format='WKT'):
4539 file_handle .write (json .dumps (coco ))
4640
4741
48- def make_coco_metadata (project_name , created_by ):
49- "Initializes COCO export data structure."
50- coco = {
51- 'info' : None ,
42+ def make_coco_metadata (project_name : str , created_by : str ) -> Dict [str , Any ]:
43+ """Initializes COCO export data structure.
44+
45+ Args:
46+ project_name: name of the project
47+ created_by: email of the project creator
48+
49+ Returns:
50+ The COCO export represented as a dictionary.
51+ """
52+ return {
53+ 'info' : {
54+ 'year' : dt .datetime .now (dt .timezone .utc ).year ,
55+ 'version' : None ,
56+ 'description' : project_name ,
57+ 'contributor' : created_by ,
58+ 'url' : 'labelbox.com' ,
59+ 'date_created' : dt .datetime .now (dt .timezone .utc ).isoformat ()
60+ },
5261 'images' : [],
5362 'annotations' : [],
5463 'licenses' : [],
5564 'categories' : []
5665 }
5766
58- coco ['info' ] = {
59- 'year' : dt .datetime .now (dt .timezone .utc ).year ,
60- 'version' : None ,
61- 'description' : project_name ,
62- 'contributor' : created_by ,
63- 'url' : 'labelbox.com' ,
64- 'date_created' : dt .datetime .now (dt .timezone .utc ).isoformat ()
65- }
66-
67- return coco
6867
69-
70- def _add_label (coco , image , labels , label_format ):
71- "Incrementally updates COCO export data structure with a new label."
72- response = requests .get (image ['coco_url' ], stream = True )
68+ def add_label (
69+ coco : Dict [str , Any ], label_id : str , image_url : str ,
70+ labels : Dict [str , Any ], label_format : str ):
71+ """Incrementally updates COCO export data structure with a new label.
72+
73+ Args:
74+ coco: The current COCO export, will be incrementally updated by this method.
75+ label_id: ID for the instance to write
76+ image_url: URL to download image file from
77+ labels: Labelbox formatted labels to use for generating annotation
78+ label_format: Format of the labeled data. Valid options are: "WKT" and
79+ "XY", default is "WKT".
80+
81+ Returns:
82+ The updated COCO export represented as a dictionary.
83+ """
84+ image = {
85+ "id" : label_id ,
86+ "file_name" : image_url ,
87+ "license" : None ,
88+ "flickr_url" : image_url ,
89+ "coco_url" : image_url ,
90+ "date_captured" : None ,
91+ }
92+ response = requests .get (image_url , stream = True )
7393 response .raw .decode_content = True
7494 image ['width' ], image ['height' ] = Image .open (response .raw ).size
7595
@@ -96,25 +116,29 @@ def _add_label(coco, image, labels, label_format):
96116 coco ['categories' ].append (category )
97117
98118 polygons = _get_polygons (label_format , label_data )
99-
100- for polygon in polygons :
101- segmentation = []
102- for x_val , y_val in polygon .exterior .coords :
103- segmentation .extend ([x_val , image ['height' ] - y_val ])
104-
105- annotation = {
106- "id" : len (coco ['annotations' ]) + 1 ,
107- "image_id" : image ['id' ],
108- "category_id" : category_id ,
109- "segmentation" : [segmentation ],
110- "area" : polygon .area , # float
111- "bbox" : [polygon .bounds [0 ], polygon .bounds [1 ],
112- polygon .bounds [2 ] - polygon .bounds [0 ],
113- polygon .bounds [3 ] - polygon .bounds [1 ]],
114- "iscrowd" : 0
115- }
116-
117- coco ['annotations' ].append (annotation )
119+ _append_polygons_as_annotations (coco , image , category_id , polygons )
120+
121+
122+ def _append_polygons_as_annotations (coco , image , category_id , polygons ):
123+ "Adds `polygons` as annotations in the `coco` export"
124+ for polygon in polygons :
125+ segmentation = []
126+ for x_val , y_val in polygon .exterior .coords :
127+ segmentation .extend ([x_val , image ['height' ] - y_val ])
128+
129+ annotation = {
130+ "id" : len (coco ['annotations' ]) + 1 ,
131+ "image_id" : image ['id' ],
132+ "category_id" : category_id ,
133+ "segmentation" : [segmentation ],
134+ "area" : polygon .area , # float
135+ "bbox" : [polygon .bounds [0 ], polygon .bounds [1 ],
136+ polygon .bounds [2 ] - polygon .bounds [0 ],
137+ polygon .bounds [3 ] - polygon .bounds [1 ]],
138+ "iscrowd" : 0
139+ }
140+
141+ coco ['annotations' ].append (annotation )
118142
119143
120144def _get_polygons (label_format , label_data ):
0 commit comments