---
# System prepended metadata

title: YOLO convert COCO format to YOLO format
tags: [YOLO]

---

# YOLO convert COCO format to YOLO format
###### tags: `YOLO`


## Step 1: Download dataset
如果檔案太大，可以不要下載test2017.zip 以及 unlabeled2017.zip (我也僅用 train(64K images) 以及 val (26K images)做，大概就有40GB左右了)

```bash=
mkdir coco
cd coco
mkdir images
cd images

wget -c http://images.cocodataset.org/zips/train2017.zip
wget -c http://images.cocodataset.org/zips/val2017.zip
wget -c http://images.cocodataset.org/zips/test2017.zip
wget -c http://images.cocodataset.org/zips/unlabeled2017.zip

unzip train2017.zip
unzip val2017.zip
unzip test2017.zip
unzip unlabeled2017.zip

rm train2017.zip
rm val2017.zip
rm test2017.zip
rm unlabeled2017.zip 

cd ../
wget -c http://images.cocodataset.org/annotations/annotations_trainval2017.zip
wget -c http://images.cocodataset.org/annotations/stuff_annotations_trainval2017.zip
wget -c http://images.cocodataset.org/annotations/image_info_test2017.zip
wget -c http://images.cocodataset.org/annotations/image_info_unlabeled2017.zip

unzip annotations_trainval2017.zip
unzip stuff_annotations_trainval2017.zip
unzip image_info_test2017.zip
unzip image_info_unlabeled2017.zip

rm annotations_trainval2017.zip
rm stuff_annotations_trainval2017.zip
rm image_info_test2017.zip
rm image_info_unlabeled2017.zip
```

## Step 2: Convert to xml

```bash=
cd coco
vim convert2xml.py
```

加入內容如下:
```python=
import os

from shutil import copyfile
from pycocotools.coco import COCO
from xml.dom.minidom import parseString
from lxml.etree import Element, SubElement, tostring
from IPython.display import clear_output

def update_progress(progress):
    bar_length = 20
    if isinstance(progress, int):
        progress = float(progress)
    if not isinstance(progress, float):
        progress = 0
    if progress < 0:
        progress = 0
    if progress >= 1:
        progress = 1
    block = int(round(bar_length * progress))
    clear_output(wait = True)
    text = "Progress: [{0}] {1:.1f}%".format( "#" * block + "-" * (bar_length - block), progress * 100)
    print(text)
    
current_path = os.path.abspath(os.getcwd())

COCO_ANNOTATIONS_PATH = current_path + "/annotations/instances_val2017.json"
COCO_IMAGES_DIRECTORY = current_path + "/images/val2017/"
EXTRACTED_SAVING_PATH = current_path + "/test_coco_format/"
SAVE_FOLDER = EXTRACTED_SAVING_PATH.split('/')[len(EXTRACTED_SAVING_PATH.split('/'))-2]

if not os.path.exists(EXTRACTED_SAVING_PATH):
    os.mkdir(EXTRACTED_SAVING_PATH)

coco = COCO(COCO_ANNOTATIONS_PATH)

cats = coco.loadCats(coco.getCatIds())

nms=[cat['name'] for cat in cats]

target_classes = []
with open(current_path + '/classes.txt', 'r') as f:
    for line in f.readlines():
        target_classes.append(line.strip())

img_dict = {}
for classes in target_classes:
    catIds = coco.getCatIds(catNms=[classes])
    imgIds = coco.getImgIds(catIds=catIds)
    for imgID in imgIds:
        try:
            content = ''
            content = img_dict[imgID] + ','
        except:
            pass
        img_dict[imgID] = content + classes

total_progress = len(img_dict)
progress = 0

for img_id in img_dict:
    progress +=1
    annotation_ids = coco.getAnnIds(img_id)
    annotations = coco.loadAnns(annotation_ids)
    
    image_meta = coco.loadImgs(annotations[0]["image_id"])[0]
    node_root = Element('annotation')
    node_folder = SubElement(node_root, 'folder')
    node_folder.text = SAVE_FOLDER
    node_filename = SubElement(node_root, 'filename')
    node_filename.text = image_meta['file_name']
    node_size = SubElement(node_root, 'size')
    node_width = SubElement(node_size, 'width')
    node_width.text = str(image_meta['width'])
    node_height = SubElement(node_size, 'height')
    node_height.text = str(image_meta['height'])
    node_depth = SubElement(node_size, 'depth')
    node_depth.text = '3'

    for i in range(len(annotations)):
        entity_id = annotations[i]["category_id"]
        entity = coco.loadCats(entity_id)[0]["name"]
        if entity in target_classes:
            node_object = SubElement(node_root, 'object')
            node_name = SubElement(node_object, 'name')
            node_name.text = entity
            node_difficult = SubElement(node_object, 'difficult')
            node_difficult.text = '0'
            node_bndbox = SubElement(node_object, 'bndbox')
            node_xmin = SubElement(node_bndbox, 'xmin')
            node_xmin.text = str(round(annotations[i]['bbox'][0]))
            node_ymin = SubElement(node_bndbox, 'ymin')
            node_ymin.text = str(round(annotations[i]['bbox'][1]))
            node_xmax = SubElement(node_bndbox, 'xmax')
            node_xmax.text = str(round(annotations[i]['bbox'][0]+annotations[i]['bbox'][2]))
            node_ymax = SubElement(node_bndbox, 'ymax')
            node_ymax.text = str(round(annotations[i]['bbox'][1]+annotations[i]['bbox'][3]))
    
    xml = tostring(node_root, pretty_print=True)
    dom = parseString(xml)
    with open( EXTRACTED_SAVING_PATH + image_meta['file_name'].split('.')[0] + '.xml','w') as xml_file:
        xml_file.write(dom.toxml())
        
    copyfile(COCO_IMAGES_DIRECTORY + image_meta['file_name'],
             EXTRACTED_SAVING_PATH + image_meta['file_name'])
    
    update_progress(progress/total_progress)
```

### 修改 convert.py 內的三個變數
COCO_ANNOTATIONS_PATH // COCO ANNOTATIONS
COCO_IMAGES_DIRECTORY // COCO IMAGES
EXTRACTED_SAVING_PAT // 轉換後的路徑

### 建立classes.txt，放入你想抓出來的class名稱，並以Enter換行作為區隔
```bash=
vim classes.txt
```

## convert xml to yolo format


```python=
from bs4 import BeautifulSoup
import os
import shutil
from IPython.display import clear_output

status_dic = {'person':0}             #用dictionary 記錄label的名稱

def getYoloFormat(filename, label_path, img_path, yolo_path, newname):    
    with open(label_path+filename, 'r') as f:        
        soup = BeautifulSoup(f.read(), 'xml')
        imgname = soup.select_one('filename').text         #讀取xml
        image_w = soup.select_one('width').text
        image_h = soup.select_one('height').text
        ary = []
        for obj in soup.select('object'):                  #取出xmin, xmax, ymin, ymax及name
            xmin = int(obj.select_one('xmin').text)          #並且用status_dictionary 來轉換name，good =>2
            xmax = int(obj.select_one('xmax').text)
            ymin = int(obj.select_one('ymin').text)
            ymax = int(obj.select_one('ymax').text)            
            objclass = status_dic.get(obj.select_one('name').text)

            x = (xmin + (xmax-xmin)/2) * 1.0 / float(image_w)    #YOLO吃的參數檔有固定的格式
            y = (ymin + (ymax-ymin)/2) * 1.0 / float(image_h)    #先照YOLO的格式訂好x,y,w,h
            w = (xmax-xmin) * 1.0 / float(image_w)
            h = (ymax-ymin) * 1.0 / float(image_h)
            ary.append(' '.join([str(objclass), str(x), str(y), str(w), str(h)]))
      
        if os.path.exists(img_path+imgname+'.jpg'):                              # 圖片本來在image裡面，把圖片移到yolo資料夾下    
            shutil.copyfile(img_path+imgname+'.jpg', yolo_path+newname+'.jpg')     #同時把yolo參數檔寫到yolo之下
            with open(yolo_path+newname+'.txt', 'w') as f:
                f.write('\n'.join(ary))            
        elif os.path.exists(img_path+imgname):  #有的labelImg名稱有自動加上.jpg                           
            shutil.copyfile(img_path+imgname, yolo_path+newname+'.jpg')
            with open(yolo_path+newname+'.txt', 'w') as f:
                f.write('\n'.join(ary))
                
def update_progress(progress):
    bar_length = 20
    if isinstance(progress, int):
        progress = float(progress)
    if not isinstance(progress, float):
        progress = 0
    if progress < 0:
        progress = 0
    if progress >= 1:
        progress = 1
    block = int(round(bar_length * progress))
    clear_output(wait = True)
    text = "Progress: [{0}] {1:.1f}%".format( "#" * block + "-" * (bar_length - block), progress * 100)
    print(text)
    
    

labelpath = '/home/jim93073/coco/test_coco_format/'           #設定路徑
imgpath = '/home/jim93073/coco/test_coco_format/'
yolopath = '/home/jim93073/coco/test_yolo_person/'
ary = []
total_progress = len(os.listdir(labelpath))
progress = 0
for idx, f in enumerate(os.listdir(labelpath)):   #透過getYoloFormat將圖像和參數檔全部寫到YOLO下
    progress += 1
    try:
        if f.split('.')[1] == 'xml':
            getYoloFormat(f, labelpath, imgpath, yolopath, str(idx))
    except Exception as e:
        print(e)
    update_progress(progress/total_progress)
```


### 修改 labelpath 、imgpath 、yolopath 
labelpath // 放置 xml 檔案的地方
imgpath // 放置 image 的地方
yolopath // 輸出成 yolo 格式的地方


## 建立訓練的 txt 檔案

```python=
import os
import random

save_path = '/home/jim93073/coco/test_yolo_person/'
create_txt_path = '/home/jim93073/coco/cfg/test_person.txt'
datasets = [save_path + f for f in os.listdir(save_path) if  f.endswith('.jpg')]
random.shuffle(datasets)


len_dataset = int(len(datasets) * 1.0)
random.shuffle(datasets)
print('All data length',len(datasets))
print(len_dataset) 
# print(len(datasets)-len_dataset)     

with open(create_txt_path, 'w') as f:
    f.write('\n'.join(datasets[:len_dataset]))
```

### 修改 save_path 及 create_txt_path 

save_path // 要訓練的 image 路徑
create_txt_path //轉乘 txt 的檔案名稱