Skip to content

Commit f8410b7

Browse files
committed
remove cocoapi dependency
1 parent 562b529 commit f8410b7

File tree

5 files changed

+394
-322
lines changed

5 files changed

+394
-322
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import numpy as np
2+
import cv2
3+
4+
5+
def encode(bitmask):
6+
rle = _masktoRLE(bitmask)
7+
rle['counts'] = _toString(rle['counts'])
8+
return rle
9+
10+
11+
def decode(coco_dict):
12+
coco_dict['counts'] = _frString(coco_dict['counts'])
13+
return _maskfrRLE(coco_dict)
14+
15+
16+
def _masktoRLE(bitmask):
17+
shape = bitmask.shape
18+
bitmask = bitmask.T.flatten()
19+
N = len(bitmask)
20+
diff_index = np.where(np.array(bitmask[:N - 1]) - np.array(bitmask[1:]))[0]
21+
diff = np.array(diff_index[1:]) - np.array(diff_index[:-1])
22+
23+
counts = np.zeros(len(diff) + 3, dtype=np.int32)
24+
counts[1] = diff_index[0] + 1
25+
counts[2:-1] = diff
26+
counts[-1] = len(bitmask) - diff_index[-1] - 1
27+
28+
if bitmask[0] == 0:
29+
counts = counts[1:]
30+
31+
return {'counts': counts, 'size': list(shape)}
32+
33+
34+
def _maskfrRLE(rle):
35+
x = np.arange(len(rle['counts']), dtype=np.uint8) % 2
36+
bitmask = np.repeat(x, rle['counts'], axis=0)
37+
38+
return bitmask.reshape((rle['size'][1], rle['size'][0])).T
39+
40+
41+
def _toString(rle_counts):
42+
rle_string = ''
43+
for i, count in enumerate(rle_counts):
44+
if i > 2:
45+
count -= rle_counts[i - 2]
46+
47+
more = True
48+
while more:
49+
if count > 0:
50+
count_binary = bin(count)
51+
if len(count_binary[2:]) % 5 != 0:
52+
count_binary = '0b' + '0' * (5 - len(count_binary[2:]) %
53+
5) + count_binary[2:]
54+
else:
55+
count_binary = bin(((1 << 35) - 1) & count)
56+
57+
count = count >> 5
58+
last_bits = count_binary[-5:]
59+
60+
value = int(last_bits, 2)
61+
if last_bits[0] == '1':
62+
more = count != -1
63+
else:
64+
more = count != 0
65+
66+
if more:
67+
char = (value | 0x20) + 48
68+
else:
69+
char = value + 48
70+
71+
rle_string += chr(char)
72+
73+
return rle_string
74+
75+
76+
def _frString(rle_string):
77+
counts = []
78+
i = 0
79+
while i < len(rle_string):
80+
more = True
81+
k = 0
82+
count = 0
83+
while more:
84+
value = ord(rle_string[i]) - 48
85+
count |= (value & 0x1f) << 5 * k
86+
more = value & 0x20
87+
i += 1
88+
k += 1
89+
if not more and (value & 0x10):
90+
count |= -1 << 5 * k
91+
92+
if len(counts) > 2:
93+
count += counts[len(counts) - 2]
94+
95+
counts.append(count)
96+
97+
return counts
98+
99+
100+
def _area(bitmask):
101+
return np.sum(bitmask)
102+
103+
104+
def _toBbox(bitmask):
105+
y, x = np.where(bitmask)
106+
xmin = int(min(x))
107+
xmax = int(max(x))
108+
ymin = int(min(y))
109+
ymax = int(max(y))
110+
111+
return [xmin, ymin, xmax - xmin + 1, ymax - ymin + 1]
112+
113+
114+
def _merge(list_of_bitmask):
115+
shape = list_of_bitmask[0].shape
116+
final_bitmask = np.zeros(shape, dtype=np.uint8)
117+
for bitmask in list_of_bitmask:
118+
final_bitmask |= bitmask
119+
120+
return final_bitmask
121+
122+
123+
def _polytoMask(polygons, height, width):
124+
masks = []
125+
for polygon in polygons:
126+
polygon = np.array(polygon, dtype=np.uint16)
127+
pts = np.array(
128+
[polygon[2 * i:2 * (i + 1)] for i in range(len(polygon) // 2)],
129+
dtype=np.int32
130+
)
131+
bitmask = np.zeros((height, width)).astype(np.uint8)
132+
cv2.fillPoly(bitmask, [pts], 1)
133+
134+
masks.append(bitmask)
135+
return masks

superannotate/input_converters/converters/coco_converters/coco_to_sa_pixel.py

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,19 @@
66
import numpy as np
77
from tqdm import tqdm
88

9+
from .coco_api import (_maskfrRLE, decode)
10+
911
from ....common import blue_color_generator, hex_to_rgb, id2rgb
10-
from ....pycocotools_sa.coco import COCO
11-
from ....pycocotools_sa import mask as maskUtils
1212

1313
logger = logging.getLogger("superannotate-python-sdk")
1414

15+
def annot_to_bitmask(annot):
16+
if isinstance(annot['counts'], list):
17+
bitmask = _maskfrRLE(annot)
18+
elif isinstance(annot['counts'], str):
19+
bitmask = decode(annot)
1520

16-
def _rle_to_polygon(coco_json, annotation):
17-
coco = COCO(coco_json)
18-
binary_mask = coco.annToMask(annotation)
19-
contours, _ = cv2.findContours(
20-
binary_mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
21-
)
22-
segmentation = []
23-
24-
for contour in contours:
25-
contour = contour.flatten().tolist()
26-
if len(contour) > 4:
27-
segmentation.append(contour)
28-
if len(segmentation) == 0:
29-
continue
30-
return segmentation
31-
21+
return bitmask
3222

3323
def coco_panoptic_segmentation_to_sa_pixel(coco_path, images_path):
3424
coco_json = json.load(open(coco_path))
@@ -115,23 +105,8 @@ def coco_instance_segmentation_to_sa_pixel(coco_path, images_path):
115105
hexcolor = hexcolors[i]
116106
color = hex_to_rgb(hexcolor)
117107
if isinstance(annot['segmentation'], dict):
118-
if isinstance(annot['segmentation']['counts'], list):
119-
annot['segmentation'] = _rle_to_polygon(coco_path, annot)
120-
for segment in annot['segmentation']:
121-
bitmask = np.zeros((H, W)).astype(np.uint8)
122-
pts = np.array(
123-
[
124-
segment[2 * i:2 * (i + 1)]
125-
for i in range(len(segment) // 2)
126-
],
127-
dtype=np.int32
128-
)
129-
130-
cv2.fillPoly(bitmask, [pts], 1)
131-
mask[bitmask == 1] = list(color)[::-1] + [255]
132-
else:
133-
mask[maskUtils.decode(annot['segmentation']) == 1
134-
] = list(color)[::-1] + [255]
108+
bitmask = annot_to_bitmask(annot['segmentation'])
109+
mask[bitmask == 1] = list(color)[::-1] + [255]
135110
else:
136111
for segment in annot['segmentation']:
137112
bitmask = np.zeros((H, W)).astype(np.uint8)

0 commit comments

Comments
 (0)