Skip to content

Commit b3f8db9

Browse files
committed
Add COCO to labelImg format.
1 parent 9d59957 commit b3f8db9

File tree

16 files changed

+272
-194
lines changed

16 files changed

+272
-194
lines changed

README.md

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,55 @@
6868
```
6969
- 可以进一步直接对`dataset/labelImg_dataset_output`目录作转COCO的转换
7070
```shell
71-
python yolov5_2_coco.py --dir_path dataset/lablelImg_dataset_output
71+
python yolov5_2_coco.py --data_dir dataset/lablelImg_dataset_output
7272
```
7373
7474
</details>
7575
76+
#### COCO格式数据 → labelImg
77+
<details>
78+
79+
- 将COCO格式数据一键转换为labelImg标注的yolo格式数据
80+
- COCO格式数据目录结构如下(详情参见:`dataset/YOLOV5_COCO_format`):
81+
```text
82+
YOLOV5_COCO_format
83+
├── annotations
84+
│ ├── instances_train2017.json
85+
│ └── instances_val2017.json
86+
├── train2017
87+
│ ├── 000000000001.jpg
88+
│ └── 000000000002.jpg # 这个是背景图像
89+
└── val2017
90+
└── 000000000001.jpg
91+
```
92+
- 转换
93+
```bash
94+
python coco_2_labelImg.py --data_dir dataset/YOLOV5_COCO_format
95+
```
96+
- `--data_dir`: COCO格式数据集所在目录
97+
- 转换后目录结构(详情参见:`dataset/COCO_labelImg_format`):
98+
```text
99+
COCO_labelImg_format
100+
├── train
101+
│ ├── 000000000001.jpg
102+
│ ├── 000000000001.txt
103+
│ |-- 000000000002.jpg
104+
│ └── classes.txt
105+
└── val
106+
├── 000000000001.jpg
107+
├── 000000000001.txt
108+
└── classes.txt
109+
```
110+
- 对转换之后的目录,可以直接用`labelImg`库直接打开,更改标注,具体命令如下:
111+
```shell
112+
$ cd dataset/COCO_labelImg_format
113+
$ labelImg train train/classes.txt
114+
115+
# or
116+
$ labelImg val val/classes.txt
117+
```
118+
</details>
119+
76120
#### YOLOV5格式数据 → COCO
77121
<details>
78122

@@ -104,9 +148,9 @@
104148
```
105149
- 转换
106150
```shell
107-
python yolov5_2_coco.py --dir_path dataset/YOLOV5 --mode_list train,val
151+
python yolov5_2_coco.py --data_dir dataset/YOLOV5 --mode_list train,val
108152
```
109-
- `--dir_path`:整理好的数据集所在目录
153+
- `--data_dir`:整理好的数据集所在目录
110154
- `--mode_list`:指定生成的json,前提是要有对应的txt文件,可单独指定。(e.g. `train,val,test`)
111155
112156
- 转换后目录结构(详情参见`dataset/YOLOV5_COCO_format`):
@@ -169,7 +213,7 @@
169213
170214
- 转换
171215
```shell
172-
python darknet2coco.py --data_path dataset/darknet/gen_config.data
216+
python darknet_2_coco.py --data_path dataset/darknet/gen_config.data
173217
```
174218
</details>
175219

coco_2_labelImg.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# -*- encoding: utf-8 -*-
2+
# @Author: SWHL
3+
# @Contact: [email protected]
4+
import argparse
5+
import json
6+
import shutil
7+
from pathlib import Path
8+
9+
import numpy as np
10+
from tqdm import tqdm
11+
12+
13+
class COCO2labelImg():
14+
def __init__(self, data_dir: str = None):
15+
# coco dir
16+
self.data_dir = Path(data_dir)
17+
self.verify_exists(self.data_dir)
18+
19+
anno_dir = self.data_dir / 'annotations'
20+
self.verify_exists(anno_dir)
21+
22+
self.train_json = anno_dir / 'instances_train2017.json'
23+
self.val_json = anno_dir / 'instances_val2017.json'
24+
self.verify_exists(self.train_json)
25+
self.verify_exists(self.val_json)
26+
27+
self.train2017_dir = self.data_dir / 'train2017'
28+
self.val2017_dir = self.data_dir / 'val2017'
29+
self.verify_exists(self.train2017_dir)
30+
self.verify_exists(self.val2017_dir)
31+
32+
# save dir
33+
self.save_dir = self.data_dir.parent / 'COCO_labelImg_format'
34+
self.mkdir(self.save_dir)
35+
36+
self.save_train_dir = self.save_dir / 'train'
37+
self.mkdir(self.save_train_dir)
38+
39+
self.save_val_dir = self.save_dir / 'val'
40+
self.mkdir(self.save_val_dir)
41+
42+
def __call__(self, ):
43+
train_list = [self.train_json, self.save_train_dir, self.train2017_dir]
44+
self.convert(train_list)
45+
46+
val_list = [self.val_json, self.save_val_dir, self.val2017_dir]
47+
self.convert(val_list)
48+
49+
print(f'Successfully convert, detail in {self.save_dir}')
50+
51+
def convert(self, info_list: list):
52+
json_path, save_dir, img_dir = info_list
53+
54+
data = self.read_json(str(json_path))
55+
self.gen_classes_txt(save_dir, data.get('categories'))
56+
57+
id_img_dict = {v['id']: v for v in data.get('images')}
58+
all_annotaions = data.get('annotations')
59+
for one_anno in tqdm(all_annotaions):
60+
image_info = id_img_dict.get(one_anno['image_id'])
61+
img_name = image_info.get('file_name')
62+
img_height = image_info.get('height')
63+
img_width = image_info.get('width')
64+
65+
seg_info = one_anno.get('segmentation')
66+
if seg_info:
67+
bbox = self.get_bbox(seg_info)
68+
xywh = self.xyxy_to_xywh(bbox, img_width, img_height)
69+
category_id = int(one_anno.get('category_id')) - 1
70+
xywh_str = ' '.join([str(v) for v in xywh])
71+
label_str = f'{category_id} {xywh_str}'
72+
73+
# 写入标注的txt文件
74+
txt_full_path = save_dir / f'{Path(img_name).stem}.txt'
75+
self.write_txt(txt_full_path, label_str, mode='a')
76+
77+
# 复制图像到转换后目录
78+
img_full_path = img_dir / img_name
79+
shutil.copy2(img_full_path, save_dir)
80+
81+
@staticmethod
82+
def read_json(json_path):
83+
with open(json_path, 'r', encoding='utf-8') as f:
84+
data = json.load(f)
85+
return data
86+
87+
def gen_classes_txt(self, save_dir, categories_dict):
88+
class_info = [value['name'] for value in categories_dict]
89+
self.write_txt(save_dir / 'classes.txt', class_info)
90+
91+
def get_bbox(self, seg_info):
92+
seg_info = np.array(seg_info[0]).reshape(4, 2)
93+
x0, y0 = np.min(seg_info, axis=0)
94+
x1, y1 = np.max(seg_info, axis=0)
95+
bbox = [x0, y0, x1, y1]
96+
return bbox
97+
98+
@staticmethod
99+
def write_txt(save_path: str, content: list, mode='w'):
100+
if not isinstance(save_path, str):
101+
save_path = str(save_path)
102+
103+
if isinstance(content, str):
104+
content = [content]
105+
with open(save_path, mode, encoding='utf-8') as f:
106+
for value in content:
107+
f.write(f'{value}\n')
108+
109+
@staticmethod
110+
def xyxy_to_xywh(xyxy: list,
111+
img_width: int,
112+
img_height: int) -> tuple([float, float, float, float]):
113+
"""
114+
xyxy: (list), [x1, y1, x2, y2]
115+
"""
116+
x_center = (xyxy[0] + xyxy[2]) / (2 * img_width)
117+
y_center = (xyxy[1] + xyxy[3]) / (2 * img_height)
118+
119+
box_w = abs(xyxy[2] - xyxy[0])
120+
box_h = abs(xyxy[3] - xyxy[1])
121+
122+
w = box_w / img_width
123+
h = box_h / img_height
124+
return x_center, y_center, w, h
125+
126+
@staticmethod
127+
def verify_exists(file_path):
128+
file_path = Path(file_path)
129+
if not file_path.exists():
130+
raise FileNotFoundError(f'The {file_path} is not exists!!!')
131+
132+
@staticmethod
133+
def mkdir(dir_path):
134+
Path(dir_path).mkdir(parents=True, exist_ok=True)
135+
136+
137+
if __name__ == '__main__':
138+
parser = argparse.ArgumentParser('Datasets convert from COCO to labelImg')
139+
parser.add_argument('--data_dir', type=str,
140+
default='dataset/YOLOV5_COCO_format',
141+
help='Dataset root path')
142+
args = parser.parse_args()
143+
144+
converter = COCO2labelImg(args.data_dir)
145+
converter()

coco_visual.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,10 @@
1010

1111

1212
def visualization_bbox(num_image, json_path, img_path):
13-
with open(json_path) as annos:
13+
with open(json_path, 'r', encoding='utf-8') as annos:
1414
annotation_json = json.load(annos)
15-
1615
print('The annotation_json num_key is:', len(annotation_json))
17-
1816
print('The annotation_json key is:', annotation_json.keys())
19-
2017
print('The annotation_json num_images is:', len(annotation_json['images']))
2118

2219
categories = annotation_json['categories']

darknet2coco.py renamed to darknet_2_coco.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# !/usr/bin/env python
22
# -*- encoding: utf-8 -*-
3-
# @File: darknet2coco.py
3+
# @File: darknet_2_coco.py
44
import argparse
55
import configparser as cfg
66
import json
15.9 KB
Loading
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
0 0.274554 0.205357 0.38839300000000004 0.383929
2+
0 0.7544639999999999 0.207589 0.375 0.379464
3+
0 0.5044640000000001 0.5111610000000001 0.33928600000000003 0.34375000000000006
4+
0 0.243304 0.7924110000000001 0.3794640000000001 0.3794640000000001
5+
0 0.774554 0.796875 0.3705359999999999 0.3705359999999999
6+
0 0.274554 0.205357 0.38839300000000004 0.383929
7+
0 0.7544639999999999 0.207589 0.375 0.379464
8+
0 0.5044640000000001 0.5111610000000001 0.33928600000000003 0.34375000000000006
9+
0 0.243304 0.7924110000000001 0.3794640000000001 0.3794640000000001
10+
0 0.774554 0.796875 0.3705359999999999 0.3705359999999999
11+
0 0.274554 0.205357 0.38839300000000004 0.383929
12+
0 0.7544639999999999 0.207589 0.375 0.379464
13+
0 0.5044640000000001 0.5111610000000001 0.33928600000000003 0.34375000000000006
14+
0 0.243304 0.7924110000000001 0.3794640000000001 0.3794640000000001
15+
0 0.774554 0.796875 0.3705359999999999 0.3705359999999999
47.1 KB
Loading
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
stamp
7.68 KB
Loading
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
0 0.497537 0.39516100000000004 0.807882 0.653226
2+
0 0.497537 0.39516100000000004 0.807882 0.653226
3+
0 0.497537 0.39516100000000004 0.807882 0.653226

0 commit comments

Comments
 (0)