-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathpycococreatortool_teeth.py
184 lines (155 loc) · 6.1 KB
/
pycococreatortool_teeth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/usr/bin/env python3
import re
import datetime
import numpy as np
from itertools import groupby
from skimage import measure
from PIL import Image
from pycocotools import mask
import json
import os
from skimage.color import rgb2gray, gray2rgb
from skimage.io import imread, imshow, imsave
import cv2
INFO = {
'description': 'TEETH DATASET',
'url' : 'https://github.com/gil.../',
'version': '0.1.0',
'year': 2018,
'contributor': 'IvisionLab',
'date_created': datetime.datetime.utcnow().isoformat(' ')
}
LICENSES = [{
'id': 1,
'name': 'Attribution-NonCommercial-ShareAlike License',
'url': 'http://creativecommons.org/licenses/by-nc-sa/2.0/'
}]
CATEGORIES = [{"supercategory": "teeth","id": 1,"name": "tooth"}]
convert = lambda text: int(text) if text.isdigit() else text.lower()
natrual_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ]
def resize_binary_mask(array, new_size):
image = Image.fromarray(array.astype(np.uint8)*255)
image = image.resize(new_size)
return np.asarray(image).astype(np.bool_)
def close_contour(contour):
if not np.array_equal(contour[0], contour[-1]):
contour = np.vstack((contour, contour[0]))
return contour
def binary_mask_to_rle(binary_mask):
rle = {'counts': [], 'size': list(binary_mask.shape)}
counts = rle.get('counts')
for i, (value, elements) in enumerate(groupby(binary_mask.ravel(order='F'))):
if i == 0 and value == 1:
counts.append(0)
counts.append(len(list(elements)))
return rle
def binary_mask_to_polygon(binary_mask, tolerance=0):
"""Converts a binary mask to COCO polygon representation
Args:
binary_mask: a 2D binary numpy array where '1's represent the object
tolerance: Maximum distance from original points of polygon to approximated
polygonal chain. If tolerance is 0, the original coordinate array is returned.
"""
polygons = []
# pad mask to close contours of shapes which start and end at an edge
padded_binary_mask = np.pad(binary_mask, pad_width=1, mode='constant', constant_values=0)
contours = measure.find_contours(padded_binary_mask, 0.5)
contours = np.subtract(contours, 1)
for contour in contours:
contour = close_contour(contour)
contour = measure.approximate_polygon(contour, tolerance)
if len(contour) < 3:
continue
contour = np.flip(contour, axis=1)
segmentation = contour.ravel().tolist()
# after padding and subtracting 1 we may get -0.5 points in our segmentation
segmentation = [0 if i < 0 else i for i in segmentation]
polygons.append(segmentation)
return polygons
def get_teeth_masks(img_fullpath):
image = imread(img_fullpath)
image_gray = rgb2gray(image)
image = gray2rgb(image)
ret, thresh = cv2.threshold(image_gray, 0, 255, 0)
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
annotations = []
for id_contourn in range(len(contours)):
img_cont = np.zeros(image.shape, dtype=image.dtype)
cv2.drawContours(img_cont, contours, id_contourn, (255,255,255), -1)
bimask = np.zeros(img_cont.shape[0:2], dtype=np.uint8)
bimask = img_cont[:,:, 0]
bimask = Image.fromarray(bimask)
bimask = np.asarray(bimask.convert('1')).astype(np.uint8)
annotations.append(bimask)
return annotations
def get_teeth_masks_test(img_fullpath):
image = imread(img_fullpath)
image_gray = rgb2gray(image)
image = gray2rgb(image)
ret, thresh = cv2.threshold(image_gray, 0, 255, 0)
annotations = []
bimask = np.zeros(image_gray.shape[0:2], dtype=np.uint8)
image_gray[image_gray > thresh] = 255
bimask = image_gray
bimask = Image.fromarray(bimask)
bimask = np.asarray(bimask.convert('1')).astype(np.uint8)
annotations.append(bimask)
return annotations
def create_image_info(image_id, file_name, image_size,
date_captured=datetime.datetime.utcnow().isoformat(' '),
license_id=1, coco_url="", flickr_url=""):
dict_images = {
"id": image_id,
"file_name": file_name,
"width": image_size[1],
"height": image_size[0],
"date_captured": date_captured,
"license": license_id,
"coco_url": coco_url,
"flickr_url": flickr_url,
}
return dict_images
def create_annotation_info(annotation_id, image_id, binary_mask,
class_id, is_crowd, image_size,
tolerance=2, bounding_box=None):
binary_mask_encoded = mask.encode(np.asfortranarray(binary_mask.astype(np.uint8)))
area = mask.area(binary_mask_encoded)
if area < 1:
return None
if bounding_box is None:
bounding_box = mask.toBbox(binary_mask_encoded)
if is_crowd:
segmentation = binary_mask_to_rle(binary_mask)
else :
segmentation = binary_mask_to_polygon(binary_mask, tolerance)
if not segmentation:
return None
dict_annotation_info = {
"id": annotation_id,
"image_id": image_id,
"category_id": class_id,
"iscrowd": is_crowd,
"area": area.tolist(),
"bbox": bounding_box.tolist(),
"segmentation": segmentation,
"width": image_size[1],
"height": image_size[0]
}
return dict_annotation_info
def build_coco_format(images, annotations, dataset_path, subset_dir,
info=INFO, licenses=LICENSES, categories=CATEGORIES):
""" Build dataset annotations in COCO Dataset format """
json_data = {
'info': INFO,
'licenses': LICENSES,
'categories': CATEGORIES,
'images': images,
'annotations': annotations
}
dir_annotations = os.path.join(dataset_path,'annotations')
if not os.path.exists(dir_annotations): os.makedirs(dir_annotations)
path_json = os.path.join(dir_annotations, 'instances_{}.json'.format(subset_dir))
with open(path_json, 'w') as f:
json.dump(json_data, f)
print("JSON created...OK in: %s", path_json)
return json_data