Skip to content

Commit b27e295

Browse files
committed
coco optimized
1 parent 59c81c2 commit b27e295

22 files changed

+297
-506
lines changed

superannotate/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@
7474
SANonExistingProjectNameException
7575
)
7676
from .input_converters.conversion import (
77-
coco_split_dataset, convert_platform, convert_project_type,
78-
export_annotation, import_annotation
77+
coco_split_dataset, convert_project_type, export_annotation,
78+
import_annotation
7979
)
8080
from .version import __version__
8181

superannotate/input_converters/conversion.py

Lines changed: 3 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@
77
from ..exceptions import SABaseException
88
from .export_from_sa_conversions import export_from_sa
99
from .import_to_sa_conversions import import_to_sa
10-
from .sa_conversion import (
11-
sa_convert_platform, sa_convert_project_type, split_coco
12-
)
13-
14-
AVAILABLE_PLATFORMS = ["Desktop", "Web"]
10+
from .sa_conversion import (sa_convert_project_type, split_coco)
1511

1612
ALLOWED_TASK_TYPES = [
1713
'panoptic_segmentation', 'instance_segmentation', 'keypoint_detection',
@@ -114,18 +110,6 @@ def _passes_sanity_checks(args):
114110
0, "Please enter valid task '%s'" % (ALLOWED_TASK_TYPES)
115111
)
116112

117-
if 'platform' in args:
118-
if args.platform not in AVAILABLE_PLATFORMS:
119-
raise SABaseException(
120-
0, "Please enter valid platform: 'Desktop' or 'Web'"
121-
)
122-
123-
if args.project_type == "Pixel" and args.platform == "Desktop":
124-
raise SABaseException(
125-
0,
126-
"Sorry, but Desktop Application doesn't support 'Pixel' projects."
127-
)
128-
129113

130114
def _passes_converter_sanity(args, direction):
131115
converter_values = (args.project_type, args.task)
@@ -153,7 +137,6 @@ def export_annotation(
153137
dataset_name,
154138
project_type="Vector",
155139
task="object_detection",
156-
platform="Web",
157140
):
158141
"""Converts SuperAnnotate annotation formate to the other annotation formats. Currently available (project_type, task) combinations for converter
159142
presented below:
@@ -189,8 +172,6 @@ def export_annotation(
189172
'instance_segmentation' 'Pixel' project_type converts instance masks and 'Vector' project_type generates bounding boxes and polygons from instance masks. Masks should be in the input folder if it is 'Pixel' project_type.
190173
'object_detection' converts objects from/to available annotation format
191174
:type task: str
192-
:param platform: SuperAnnotate has both 'Web' and 'Desktop' platforms. Choose from which one you are converting. (Default: "Web")
193-
:type platform: str
194175
195176
"""
196177

@@ -206,7 +187,6 @@ def export_annotation(
206187
dataset_name=dataset_name,
207188
project_type=project_type,
208189
task=task,
209-
platform=platform,
210190
)
211191

212192
_passes_sanity_checks(args)
@@ -222,7 +202,6 @@ def import_annotation(
222202
dataset_name='',
223203
project_type="Vector",
224204
task="object_detection",
225-
platform="Web",
226205
images_root='',
227206
images_extensions=['jpg']
228207
):
@@ -348,14 +327,10 @@ def import_annotation(
348327
'instance_segmentation' 'Pixel' project_type converts instance masks and 'Vector' project_type generates bounding boxes and polygons from instance masks. Masks should be in the input folder if it is 'Pixel' project_type.
349328
'object_detection' converts objects from/to available annotation format
350329
'vector_annotation' can be used to convert all annotations (point, ellipse, circule, cuboid and etc) to SuperAnnotate vector project.
351-
:param platform: SuperAnnotate has both 'Web' and 'Desktop' platforms. Choose to which platform you want convert. (Default: "Web")
352-
:type platform: str
353-
:param images_root: Additonal path to images directory in input_dir
354-
:type platform: str
355330
:param images_root: Additonal path to images directory in input_dir
356-
:type platform: str
331+
:type images_root: str
357332
:param image_extensions: List of image files xtensions in the images_root folder
358-
:type platform: list
333+
:type image_extensions: list
359334
360335
"""
361336

@@ -371,7 +346,6 @@ def import_annotation(
371346
dataset_name=dataset_name,
372347
project_type=project_type,
373348
task=task,
374-
platform=platform,
375349
images_root=images_root,
376350
images_extensions=images_extensions
377351
)
@@ -382,38 +356,6 @@ def import_annotation(
382356
import_to_sa(args)
383357

384358

385-
def convert_platform(input_dir, output_dir, input_platform):
386-
""" Converts SuperAnnotate input file structure from one platform too another.
387-
388-
:param input_dir: Path to the dataset folder that you want to convert.
389-
:type input_dir: str or PathLike
390-
:param output_dir: Path to the folder where you want to have converted files.
391-
:type output_dir: str or PathLike
392-
:param input_platform: Original platform format type
393-
:type input_platform: str
394-
395-
"""
396-
param_info = [
397-
(input_dir, 'input_dir', (str, Path)),
398-
(output_dir, 'output_dir', (str, Path)),
399-
(input_platform, 'input_platform', str),
400-
]
401-
for param in param_info:
402-
_type_sanity(param[0], param[1], param[2])
403-
404-
if input_platform not in AVAILABLE_PLATFORMS:
405-
raise SABaseException(
406-
0, "Please enter valid platform: 'Desktop' or 'Web'"
407-
)
408-
409-
if isinstance(input_dir, str):
410-
input_dir = Path(input_dir)
411-
if isinstance(output_dir, str):
412-
output_dir = Path(output_dir)
413-
414-
sa_convert_platform(input_dir, output_dir, input_platform)
415-
416-
417359
def convert_project_type(input_dir, output_dir):
418360
""" Converts SuperAnnotate 'Vector' project type to 'Pixel' or reverse.
419361

superannotate/input_converters/converters/baseStrategy.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,6 @@ def __init__(self, args):
218218
self.output_dir = args.output_dir
219219
self.task = args.task
220220
self.direction = args.direction
221-
self.platform = args.platform
222221
self.conversion_algorithm = CONVERSION_ALGORITHMS[self.direction][
223222
args.dataset_format][self.project_type][self.task]
224223

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import numpy as np
2+
3+
4+
def encode(bitmask):
5+
rle = _masktoRLE(bitmask)
6+
rle['counts'] = _toString(rle['counts'])
7+
return rle
8+
9+
10+
def decode(coco_dict):
11+
coco_dict['counts'] = _frString(coco_dict['counts'])
12+
return _maskfrRLE(coco_dict)
13+
14+
15+
def _masktoRLE(bitmask):
16+
shape = bitmask.shape
17+
bitmask = bitmask.T.flatten()
18+
N = len(bitmask)
19+
diff_index = np.where(np.array(bitmask[:N - 1]) - np.array(bitmask[1:]))[0]
20+
diff = np.array(diff_index[1:]) - np.array(diff_index[:-1])
21+
22+
counts = np.zeros(len(diff) + 3, dtype=np.int32)
23+
counts[1] = diff_index[0] + 1
24+
counts[2:-1] = diff
25+
counts[-1] = len(bitmask) - diff_index[-1] - 1
26+
27+
if bitmask[0] == 0:
28+
counts = counts[1:]
29+
30+
return {'counts': counts, 'size': list(shape)}
31+
32+
33+
def _maskfrRLE(rle):
34+
x = np.arange(len(rle['counts']), dtype=np.uint8) % 2
35+
bitmask = np.repeat(x, rle['counts'], axis=0)
36+
37+
return bitmask.reshape((rle['size'][1], rle['size'][0])).T
38+
39+
40+
def _toString(rle_counts):
41+
rle_string = ''
42+
for i, count in enumerate(rle_counts):
43+
if i > 2:
44+
count -= rle_counts[i - 2]
45+
46+
more = True
47+
while more:
48+
if count > 0:
49+
count_binary = bin(count)
50+
if len(count_binary[2:]) % 5 != 0:
51+
count_binary = '0b' + '0' * (5 - len(count_binary[2:]) %
52+
5) + count_binary[2:]
53+
else:
54+
count_binary = bin(((1 << 35) - 1) & count)
55+
56+
count = count >> 5
57+
last_bits = count_binary[-5:]
58+
59+
value = int(last_bits, 2)
60+
if last_bits[0] == '1':
61+
more = count != -1
62+
else:
63+
more = count != 0
64+
65+
if more:
66+
char = (value | 0x20) + 48
67+
else:
68+
char = value + 48
69+
70+
rle_string += chr(char)
71+
72+
return rle_string
73+
74+
75+
def _frString(rle_string):
76+
counts = []
77+
i = 0
78+
while i < len(rle_string):
79+
more = True
80+
k = 0
81+
count = 0
82+
while more:
83+
value = ord(rle_string[i]) - 48
84+
count |= (value & 0x1f) << 5 * k
85+
more = value & 0x20
86+
i += 1
87+
k += 1
88+
if not more and (value & 0x10):
89+
count |= -1 << 5 * k
90+
91+
if len(counts) > 2:
92+
count += counts[len(counts) - 2]
93+
94+
counts.append(count)
95+
96+
return counts

superannotate/input_converters/converters/coco_converters/coco_strategies.py

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from ..baseStrategy import baseStrategy
1212

13-
from ....common import id2rgb, dump_output
13+
from ....common import id2rgb, write_to_json
1414

1515

1616
class CocoBaseStrategy(baseStrategy):
@@ -164,14 +164,21 @@ def _create_sa_classes(self, json_path):
164164
hexcolor = "#%02x%02x%02x" % tuple(color)
165165
classes_dict = {
166166
'name': data["name"],
167-
'id': data["id"],
167+
# 'id': data["id"],
168168
'color': hexcolor,
169169
'attribute_groups': []
170170
}
171171
classes.append(classes_dict)
172172

173173
return classes
174174

175+
def to_sa_format(self):
176+
json_data = self.export_root / (self.dataset_name + ".json")
177+
sa_classes = self._create_sa_classes(json_data)
178+
(self.output_dir / 'classes').mkdir(parents=True, exist_ok=True)
179+
write_to_json(self.output_dir / 'classes' / 'classes.json', sa_classes)
180+
self.conversion_algorithm(json_data, self.output_dir)
181+
175182

176183
class CocoPanopticConverterStrategy(CocoBaseStrategy):
177184
def __init__(self, args):
@@ -226,12 +233,6 @@ def sa_to_output_format(self):
226233

227234
self.set_num_converted(len(jsons))
228235

229-
def to_sa_format(self):
230-
json_data = self.export_root / (self.dataset_name + ".json")
231-
sa_classes = self._create_sa_classes(json_data)
232-
sa_jsons = self.conversion_algorithm(json_data, self.output_dir)
233-
dump_output(self.output_dir, self.platform, sa_classes, sa_jsons)
234-
235236

236237
class CocoObjectDetectionStrategy(CocoBaseStrategy):
237238
def __init__(self, args):
@@ -305,12 +306,6 @@ def sa_to_output_format(self):
305306

306307
self.set_num_converted(len(jsons))
307308

308-
def to_sa_format(self):
309-
json_data = self.export_root / (self.dataset_name + ".json")
310-
sa_classes = self._create_sa_classes(json_data)
311-
sa_jsons = self.conversion_algorithm(json_data, self.output_dir)
312-
dump_output(self.output_dir, self.platform, sa_classes, sa_jsons)
313-
314309

315310
class CocoKeypointDetectionStrategy(CocoBaseStrategy):
316311
def __init__(self, args):
@@ -367,9 +362,3 @@ def sa_to_output_format(self):
367362
coco_json.write(json_data)
368363

369364
self.set_num_converted(len(out_json['images']))
370-
371-
def to_sa_format(self):
372-
json_data = self.export_root / (self.dataset_name + ".json")
373-
sa_classes = self._create_sa_classes(json_data)
374-
sa_jsons = self.conversion_algorithm(json_data, self.output_dir)
375-
dump_output(self.output_dir, self.platform, sa_classes, sa_jsons)

0 commit comments

Comments
 (0)