Skip to content

Commit 8db7782

Browse files
committed
coco converter new json
1 parent c1bd84c commit 8db7782

File tree

21 files changed

+310
-158
lines changed

21 files changed

+310
-158
lines changed

superannotate/input_converters/converters/coco_converters/coco_api.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import numpy as np
2+
import cv2
23

34

45
def encode(bitmask):
@@ -94,3 +95,47 @@ def _frString(rle_string):
9495
counts.append(count)
9596

9697
return counts
98+
99+
100+
def _area(bitmask):
101+
return np.sum(bitmask)
102+
103+
104+
def _toBbox(bitmask):
105+
contours, _ = cv2.findContours(
106+
bitmask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
107+
)
108+
segments = []
109+
for contour in contours:
110+
contour = contour.flatten().tolist()
111+
segments += contour
112+
113+
xmin = min(segments[::2])
114+
xmax = max(segments[::2])
115+
ymin = min(segments[1::2])
116+
ymax = max(segments[1::2])
117+
118+
return [xmin, ymin, xmax - xmin, ymax - ymin]
119+
120+
121+
def _merge(list_of_bitmask):
122+
shape = list_of_bitmask[0].shape
123+
final_bitmask = np.zeros(shape, dtype=np.uint8)
124+
for bitmask in list_of_bitmask:
125+
final_bitmask |= bitmask
126+
127+
return final_bitmask
128+
129+
130+
def _polytoMask(polygons, height, width):
131+
masks = []
132+
for polygon in polygons:
133+
polygon = np.round(polygon)
134+
bitmask = np.zeros((height, width)).astype(np.uint8)
135+
pts = np.array(
136+
[polygon[2 * i:2 * (i + 1)] for i in range(len(polygon) // 2)],
137+
dtype=np.int32
138+
)
139+
cv2.fillPoly(bitmask, [pts], 1)
140+
masks.append(bitmask)
141+
return masks

superannotate/input_converters/converters/coco_converters/coco_strategies.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,14 @@ def _prepare_single_image_commons_pixel(self, id_, json_path):
9595
)
9696
rm_len = len('___pixel.json')
9797

98-
sa_ann_json = json.load(open(json_path))
98+
sa_json = json.load(open(json_path))
99+
# sa_ann_json = json.load(open(json_path))
100+
sa_ann_json = sa_json['instances']
101+
99102
sa_bluemask_path = str(json_path)[:-rm_len] + '___save.png'
100103

101-
image_info = self.__make_image_info(json_path, id_, self.project_type)
104+
# image_info = self.__make_image_info(json_path, id_, self.project_type)
105+
image_info = self.__make_image_info(id_, sa_json['metadata'])
102106

103107
sa_bluemask_rgb = np.asarray(
104108
Image.open(sa_bluemask_path).convert('RGB'), dtype=np.uint32
@@ -117,20 +121,21 @@ def _prepare_single_image_commons_pixel(self, id_, json_path):
117121

118122
return res
119123

120-
def __make_image_info(self, json_path, id_, source_type):
121-
if source_type == 'Pixel':
122-
rm_len = len('___pixel.json')
123-
elif source_type == 'Vector':
124-
rm_len = len('___objects.json')
124+
# def __make_image_info(self, json_path, id_, source_type):
125+
# if source_type == 'Pixel':
126+
# rm_len = len('___pixel.json')
127+
# elif source_type == 'Vector':
128+
# rm_len = len('___objects.json')
125129

126-
image_path = str(json_path)[:-rm_len]
130+
# image_path = str(json_path)[:-rm_len]
127131

128-
img_width, img_height = Image.open(image_path).size
132+
# img_width, img_height = Image.open(image_path).size
133+
def __make_image_info(self, id_, sa_meta_json):
129134
image_info = {
130135
'id': id_,
131-
'file_name': Path(image_path).name,
132-
'height': img_height,
133-
'width': img_width,
136+
'file_name': sa_meta_json['name'],
137+
'height': sa_meta_json['height'],
138+
'width': sa_meta_json['width'],
134139
'license': 1
135140
}
136141

@@ -139,8 +144,12 @@ def __make_image_info(self, json_path, id_, source_type):
139144
def _prepare_single_image_commons_vector(self, id_, json_path):
140145
ImgCommons = namedtuple('ImgCommons', ['image_info', 'sa_ann_json'])
141146

142-
image_info = self.__make_image_info(json_path, id_, self.project_type)
143-
sa_ann_json = json.load(open(json_path))
147+
# sa_ann_json = json.load(open(json_path))
148+
sa_json = json.load(open(json_path))
149+
sa_ann_json = sa_json['instances']
150+
151+
# image_info = self.__make_image_info(json_path, id_, self.project_type)
152+
image_info = self.__make_image_info(id_, sa_json['metadata'])
144153

145154
res = ImgCommons(image_info, sa_ann_json)
146155

@@ -164,7 +173,6 @@ def _create_sa_classes(self, json_path):
164173
hexcolor = "#%02x%02x%02x" % tuple(color)
165174
classes_dict = {
166175
'name': data["name"],
167-
# 'id': data["id"],
168176
'color': hexcolor,
169177
'attribute_groups': []
170178
}
@@ -204,7 +212,7 @@ def sa_to_output_format(self):
204212
id_generator = self._make_id_generator()
205213

206214
jsons_gen = self.export_root.glob('*pixel.json')
207-
jsons = [path for path in jsons_gen]
215+
jsons = list(jsons_gen)
208216

209217
for id_, json_ in tqdm(enumerate(jsons, 1)):
210218
res = self._sa_to_coco_single(id_, json_, id_generator, cat_id_map)

superannotate/input_converters/converters/coco_converters/coco_to_sa_pixel.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
from .coco_api import (_maskfrRLE, decode)
1010

11-
from ..sa_json_helper import (_create_pixel_instance, _create_empty_sa_json)
11+
from ..sa_json_helper import (_create_pixel_instance, _create_sa_json)
1212

1313
from ....common import blue_color_generator, hex_to_rgb, id2rgb, write_to_json
1414

15-
logger = logging.getLogger("superannotate-python-sdk")
15+
logger = logging.getLogger("superannot-python-sdk")
1616

1717

1818
def annot_to_bitmask(annot):
@@ -27,14 +27,20 @@ def annot_to_bitmask(annot):
2727
def coco_panoptic_segmentation_to_sa_pixel(coco_path, output_dir):
2828
coco_json = json.load(open(coco_path))
2929
hex_colors = blue_color_generator(len(coco_json["categories"]))
30-
annotate_list = coco_json["annotations"]
3130

3231
cat_id_to_cat = {}
3332
for cat in coco_json['categories']:
3433
cat_id_to_cat[cat['id']] = cat['name']
3534

36-
for annotate in tqdm(annotate_list, "Converting annotations"):
37-
annot_name = Path(annotate["file_name"]).stem
35+
img_id_to_shape = {}
36+
for img in coco_json['images']:
37+
img_id_to_shape[str(img['id'])] = {
38+
'height': img['height'],
39+
'width': img['width']
40+
}
41+
42+
for annot in tqdm(coco_json["annotations"], "Converting annotations"):
43+
annot_name = Path(annot["file_name"]).stem
3844
img_cv = cv2.imread(str(output_dir / ("%s.png" % annot_name)))
3945
if img_cv is None:
4046
logger.warning(
@@ -47,7 +53,7 @@ def coco_panoptic_segmentation_to_sa_pixel(coco_path, output_dir):
4753
img = cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB)
4854
H, W, C = img.shape
4955
img = img.reshape((H * W, C))
50-
segments = annotate["segments_info"]
56+
segments = annot["segments_info"]
5157
hex_colors = blue_color_generator(len(segments))
5258

5359
sa_instances = []
@@ -64,7 +70,13 @@ def coco_panoptic_segmentation_to_sa_pixel(coco_path, output_dir):
6470
cv2.imwrite(str(output_dir / ("%s.jpg___save.png" % annot_name)), img)
6571

6672
file_name = "%s.jpg___pixel.json" % annot_name
67-
write_to_json(output_dir / file_name, sa_instances)
73+
sa_metadata = {
74+
'name': annot_name,
75+
'width': img_id_to_shape[str(annot['image_id'])]['width'],
76+
'height': img_id_to_shape[str(annot['image_id'])]['height']
77+
}
78+
json_template = _create_sa_json(sa_instances, metadata)
79+
write_to_json(output_dir / file_name, json_template)
6880
(output_dir / ("%s.png" % annot_name)).unlink()
6981

7082

@@ -119,14 +131,13 @@ def coco_instance_segmentation_to_sa_pixel(coco_path, output_dir):
119131
)
120132
sa_instances.append(sa_obj)
121133

122-
write_to_json(output_dir / file_name, sa_instances)
123-
# json_template['instance'] = sa_instances
124-
# json_template['metadata'] = {
125-
# 'name': images_dict['file_name'],
126-
# 'width': images_dict['shape'][1],
127-
# 'height': images_dict['shape'][0]
128-
# }
129-
# write_to_json(output_dir / file_name, json_template)
134+
sa_metadata = {
135+
'name': images_dict[id_]['file_name'],
136+
'width': images_dict[id_]['shape'][1],
137+
'height': images_dict[id_]['shape'][0]
138+
}
139+
json_template = _create_sa_json(sa_instances, sa_metadata)
140+
write_to_json(output_dir / file_name, json_template)
130141
cv2.imwrite(
131142
str(output_dir / ('%s___save.png' % annotations['file_name'])), mask
132143
)

superannotate/input_converters/converters/coco_converters/coco_to_sa_vector.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from .coco_api import (_maskfrRLE, decode)
1313

14-
from ..sa_json_helper import (_create_vector_instance, _create_empty_sa_json)
14+
from ..sa_json_helper import (_create_vector_instance, _create_sa_json)
1515

1616
from ....common import id2rgb, write_to_json
1717

@@ -36,7 +36,6 @@ def annot_to_polygon(annot):
3636

3737
def save_sa_jsons(coco_json, img_id_to_annot, output_dir):
3838
for img in tqdm(coco_json['images'], "Writing annotations to disk"):
39-
# json_template = _create_empty_sa_json()
4039
if 'file_name' in img:
4140
image_path = Path(img['file_name']).name
4241
else:
@@ -47,15 +46,14 @@ def save_sa_jsons(coco_json, img_id_to_annot, output_dir):
4746
else:
4847
sa_instances = img_id_to_annot[str(img['id'])]
4948
file_name = "%s___objects.json" % image_path
50-
write_to_json(output_dir / file_name, sa_instances)
51-
52-
# json_template['instance'] = sa_instances
53-
# json_template['metadata'] = {
54-
# 'name': image_path,
55-
# 'width': img['width'],
56-
# 'height': img['height']
57-
# }
58-
# write_to_json(output_dir / file_name, json_template)
49+
50+
sa_metadata = {
51+
'name': image_path,
52+
'width': img['width'],
53+
'height': img['height']
54+
}
55+
json_template = _create_sa_json(sa_instances, sa_metadata)
56+
write_to_json(output_dir / file_name, json_template)
5957

6058

6159
def coco_instance_segmentation_to_sa_vector(coco_path, output_dir):

superannotate/input_converters/converters/coco_converters/sa_pixel_to_coco.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import cv2 as cv
22
import numpy as np
33

4-
from ....pycocotools_sa import mask as cocomask
4+
from .coco_api import (encode, _toBbox, _area)
5+
# from ....pycocotools_sa import mask as cocomask
56

67

78
def __instance_object_commons_per_instance(
@@ -22,10 +23,13 @@ def __instance_object_commons_per_instance(
2223
contours, _ = cv.findContours(
2324
databytes, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE
2425
)
25-
coco_instance_mask = cocomask.encode(np.asfortranarray(instance_bitmask))
2626

27-
bbox = cocomask.toBbox(coco_instance_mask).tolist()
28-
area = int(cocomask.area(coco_instance_mask))
27+
# coco_instance_mask = cocomask.encode(np.asfortranarray(instance_bitmask))
28+
# coco_instance_mask = encode(instance_bitmask.astype(np.uint8))
29+
# bbox = cocomask.toBbox(coco_instance_mask).tolist()
30+
bbox = list(_toBbox(instance_bitmask.astype(np.uint8)))
31+
# area = int(cocomask.area(coco_instance_mask))
32+
area = int(_area(instance_bitmask.astype(np.uint8)))
2933
return (bbox, area, contours, category_id, anno_id)
3034

3135

@@ -92,11 +96,15 @@ def sa_pixel_to_coco_panoptic_segmentation(
9296
instance_bitmask = np.isin(flat_mask, parts)
9397
segment_id = next(id_generator)
9498
ann_mask[instance_bitmask] = segment_id
95-
coco_instance_mask = cocomask.encode(
96-
np.asfortranarray(instance_bitmask)
97-
)
98-
bbox = cocomask.toBbox(coco_instance_mask).tolist()
99-
area = int(cocomask.area(coco_instance_mask))
99+
# coco_instance_mask = cocomask.encode(
100+
# np.asfortranarray(instance_bitmask)
101+
# )
102+
# bbox = cocomask.toBbox(coco_instance_mask).tolist()
103+
# area = int(cocomask.area(coco_instance_mask))
104+
105+
# coco_instance_mask = encode(instance_bitmask.astype(np.uint8))
106+
bbox = list(_toBbox(instance_bitmask.astype(np.uint8)))
107+
area = int(_area(instance_bitmask.astype(np.uint8)))
100108

101109
segment_info = {
102110
'id': segment_id,

superannotate/input_converters/converters/coco_converters/sa_vector_to_coco.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import json
22
import logging
33

4+
from .coco_api import (encode, _toBbox, _merge, _area, _polytoMask)
5+
46
from ....pycocotools_sa import mask as cocomask
57

68
logger = logging.getLogger("superannotate-python-sdk")
@@ -80,12 +82,19 @@ def sa_vector_to_coco_instance_segmentation(
8082
for cat_id, polygons in polygon_group.items():
8183
anno_id = next(id_generator)
8284
try:
83-
masks = cocomask.frPyObjects(
85+
# masks = cocomask.frPyObjects(
86+
# polygons, image_info['height'], image_info['width']
87+
# )
88+
# mask = cocomask.merge(masks)
89+
# area = int(cocomask.area(mask))
90+
# bbox = cocomask.toBbox(mask).tolist()
91+
masks = _polytoMask(
8492
polygons, image_info['height'], image_info['width']
8593
)
86-
mask = cocomask.merge(masks)
87-
area = int(cocomask.area(mask))
88-
bbox = cocomask.toBbox(mask).tolist()
94+
mask = _merge(masks)
95+
area = int(_area(mask))
96+
bbox = list(_toBbox(mask))
97+
8998
annotation = make_annotation(
9099
cat_id, image_info['id'], bbox, polygons, area, anno_id
91100
)

0 commit comments

Comments
 (0)