Skip to content

Instantly share code, notes, and snippets.

@Amir22010
Forked from vdalv/convert_voc_to_yolo.md
Created February 22, 2020 22:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Amir22010/780698cf1f1513fd79d83e5d75f31583 to your computer and use it in GitHub Desktop.
Save Amir22010/780698cf1f1513fd79d83e5d75f31583 to your computer and use it in GitHub Desktop.

Convert PascalVOC Annotations to YOLO

This script reads PascalVOC xml files, and converts them to YOLO txt files.

Note: This script was written and tested on Ubuntu. YMMV on other OS's.

Disclaimer: This code is a modified version of Joseph Redmon's voc_label.py

Instructions:

  1. Place the convert_voc_to_yolo.py file into your data folder.
  2. Edit the dirs array (line 8) to contain the folders where your images and xmls are located. Note: this script assumes all of your images are .jpg's (line 13).
  3. Edit the classes array (line 9) to contain all of your classes.
  4. Run the script. Upon running the script, each of the given directories will contain a 'yolo' folder that contains all of the YOLO txt files. A text file containing all of the image paths will be created in the cwd, for each given directory.

convert_voc_to_yolo.py:

import glob
import os
import pickle
import xml.etree.ElementTree as ET
from os import listdir, getcwd
from os.path import join

dirs = ['train', 'val']
classes = ['person', 'car']

def getImagesInDir(dir_path):
    image_list = []
    for filename in glob.glob(dir_path + '/*.jpg'):
        image_list.append(filename)

    return image_list

def convert(size, box):
    dw = 1./(size[0])
    dh = 1./(size[1])
    x = (box[0] + box[1])/2.0 - 1
    y = (box[2] + box[3])/2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x*dw
    w = w*dw
    y = y*dh
    h = h*dh
    return (x,y,w,h)

def convert_annotation(dir_path, output_path, image_path):
    basename = os.path.basename(image_path)
    basename_no_ext = os.path.splitext(basename)[0]

    in_file = open(dir_path + '/' + basename_no_ext + '.xml')
    out_file = open(output_path + basename_no_ext + '.txt', 'w')
    tree = ET.parse(in_file)
    root = tree.getroot()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    for obj in root.iter('object'):
        difficult = obj.find('difficult').text
        cls = obj.find('name').text
        if cls not in classes or int(difficult)==1:
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
        bb = convert((w,h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')

cwd = getcwd()

for dir_path in dirs:
    full_dir_path = cwd + '/' + dir_path
    output_path = full_dir_path +'/yolo/'

    if not os.path.exists(output_path):
        os.makedirs(output_path)

    image_paths = getImagesInDir(full_dir_path)
    list_file = open(full_dir_path + '.txt', 'w')

    for image_path in image_paths:
        list_file.write(image_path + '\n')
        convert_annotation(full_dir_path, output_path, image_path)
    list_file.close()

    print("Finished processing: " + dir_path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment