|
4 | 4 | import cv2 |
5 | 5 | import pandas as pd |
6 | 6 | from PIL import Image |
| 7 | +from collections import defaultdict |
7 | 8 |
|
8 | 9 | from utils import * |
9 | 10 |
|
@@ -262,36 +263,49 @@ def convert_coco_json(json_dir='../coco/annotations/', use_segments=False, cls91 |
262 | 263 |
|
263 | 264 | # Create image dict |
264 | 265 | images = {'%g' % x['id']: x for x in data['images']} |
| 266 | + # Create image-annotations dict |
| 267 | + imgToAnns = defaultdict(list) |
| 268 | + for ann in data['annotations']: |
| 269 | + imgToAnns[ann['image_id']].append(ann) |
265 | 270 |
|
266 | 271 | # Write labels file |
267 | | - for x in tqdm(data['annotations'], desc=f'Annotations {json_file}'): |
268 | | - if x['iscrowd']: |
269 | | - continue |
270 | | - |
271 | | - img = images['%g' % x['image_id']] |
| 272 | + for img_id, anns in tqdm(imgToAnns.items(), desc=f'Annotations {json_file}'): |
| 273 | + img = images['%g' % img_id] |
272 | 274 | h, w, f = img['height'], img['width'], img['file_name'] |
273 | 275 |
|
274 | | - # The COCO box format is [top left x, top left y, width, height] |
275 | | - box = np.array(x['bbox'], dtype=np.float64) |
276 | | - box[:2] += box[2:] / 2 # xy top-left corner to center |
277 | | - box[[0, 2]] /= w # normalize x |
278 | | - box[[1, 3]] /= h # normalize y |
279 | | - |
280 | | - # Segments |
281 | | - if use_segments: |
282 | | - if len(x['segmentation']) > 1: |
283 | | - s = merge_multi_segment(x['segmentation']) |
284 | | - s = (np.concatenate(s, axis=0) / np.array([w, h])).reshape(-1).tolist() |
285 | | - |
286 | | - else: |
287 | | - segments = [j for i in x['segmentation'] for j in i] # all segments concatenated |
288 | | - s = (np.array(segments).reshape(-1, 2) / np.array([w, h])).reshape(-1).tolist() |
| 276 | + bboxes = [] |
| 277 | + segments = [] |
| 278 | + for ann in anns: |
| 279 | + if ann['iscrowd']: |
| 280 | + continue |
| 281 | + # The COCO box format is [top left x, top left y, width, height] |
| 282 | + box = np.array(ann['bbox'], dtype=np.float64) |
| 283 | + box[:2] += box[2:] / 2 # xy top-left corner to center |
| 284 | + box[[0, 2]] /= w # normalize x |
| 285 | + box[[1, 3]] /= h # normalize y |
| 286 | + if box[2] <= 0 or box[3] <= 0: # if w <= 0 and h <= 0 |
| 287 | + continue |
| 288 | + |
| 289 | + cls = coco80[ann['category_id'] - 1] if cls91to80 else ann['category_id'] - 1 # class |
| 290 | + box = [cls] + box.tolist() |
| 291 | + if box not in bboxes: |
| 292 | + bboxes.append(box) |
| 293 | + # Segments |
| 294 | + if use_segments: |
| 295 | + if len(ann['segmentation']) > 1: |
| 296 | + s = merge_multi_segment(ann['segmentation']) |
| 297 | + s = (np.concatenate(s, axis=0) / np.array([w, h])).reshape(-1).tolist() |
| 298 | + else: |
| 299 | + s = [j for i in ann['segmentation'] for j in i] # all segments concatenated |
| 300 | + s = (np.array(s).reshape(-1, 2) / np.array([w, h])).reshape(-1).tolist() |
| 301 | + s = [cls] + s |
| 302 | + if s not in segments: |
| 303 | + segments.append(s) |
289 | 304 |
|
290 | 305 | # Write |
291 | | - if box[2] > 0 and box[3] > 0: # if w > 0 and h > 0 |
292 | | - cls = coco80[x['category_id'] - 1] if cls91to80 else x['category_id'] - 1 # class |
293 | | - line = cls, *(s if use_segments else box) # cls, box or segments |
294 | | - with open((fn / f).with_suffix('.txt'), 'a') as file: |
| 306 | + with open((fn / f).with_suffix('.txt'), 'a') as file: |
| 307 | + for i in range(len(bboxes)): |
| 308 | + line = *(segments[i] if use_segments else bboxes[i]), # cls, box or segments |
295 | 309 | file.write(('%g ' * len(line)).rstrip() % line + '\n') |
296 | 310 |
|
297 | 311 |
|
|
0 commit comments