Skip to content
This repository has been archived by the owner on Aug 12, 2023. It is now read-only.

rihib/p2y-converter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 

Repository files navigation

P2Y Converter

P2Y

This script converts a Pascal voc file to a text file in YOLO format. For Japanese → https://qiita.com/Rihib/items/e163d90c009f4fe12782

Instructions

  1. Rewrite the following part at the top of the main.py file according to the instructions written in the comment out. You don't need to worry about the location of each directory at all. It's okay to mix xml files and image files in the same directory. Of course, you can also put them in separate directories.
  2. Run the script.

If it doesn't work, check the contents of your xml files against the GetDataFromXMLfile class in main.py to make sure that your xml files are being parsed properly.

main.py

############    Please edit this section only.#######################################################################################################

#  The paths must end with '/'.      
absolutepath_of_directory_with_xmlfiles = 'Enter the absolute path of directory here.'  # It is okay to have a mix of xml files and images in the same directory.
absolutepath_of_directory_with_imgfiles = 'Enter the absolute path of directory here.'
absolutepath_of_directory_with_yolofiles = 'Enter the absolute path of directory here.'  # Yolo files will be created under this directory.
absolutepath_of_directory_with_classes_txt = 'Enter the absolute path of directory here.'  # You do not need to create classes.txt. classes.txt will be generated automatically.
absolutepath_of_directory_with_error_txt = 'Enter the absolute path of directory here.'  # The file names of files that do not have a paired xml or image file will be written to a text file under this directory.

#####################################################################################################################################################

import os
import cv2
from lxml import etree
from xml.etree import ElementTree
from glob import glob


class GetDataFromXMLfile:
    def __init__(self, xmlfile_path):
        self.xmlfile_path = xmlfile_path
        self.xmlfile_datalists_list = []

    def get_datalists_list(self):
        self.parse_xmlfile()
        return self.xmlfile_datalists_list

    def parse_xmlfile(self):
        lxml_parser = etree.XMLParser(encoding='utf-8')
        xmltree = ElementTree.parse(self.xmlfile_path, parser=lxml_parser).getroot()

        for object in xmltree.findall('object'):
            xmlfile_datalist = []
            class_name = object.find('name').text
            xmlfile_datalist.append(class_name)
            bndbox = object.find("bndbox")
            xmlfile_datalist.append(bndbox)
            self.xmlfile_datalists_list.append(xmlfile_datalist)

        img_filename = xmltree.find('filename').text
        
        self.add_data_to_datalist(img_filename)
    
    def add_data_to_datalist(self, img_filename):
        for xmlfile_datalist in self.xmlfile_datalists_list:
            xmin = float(xmlfile_datalist[1].find('xmin').text)
            ymin = float(xmlfile_datalist[1].find('ymin').text)
            xmax = float(xmlfile_datalist[1].find('xmax').text)
            ymax = float(xmlfile_datalist[1].find('ymax').text)
            bndbox_coordinates_list = [(xmin, ymin), (xmax, ymin), (xmax, ymax), (xmin, ymax)]
            xmlfile_datalist[1] = bndbox_coordinates_list
        self.xmlfile_datalists_list.append(img_filename)
        self.xmlfile_datalists_list.append(self.xmlfile_path)


class CreateYOLOfile:
    def __init__(self, xmlfile_datalists_list, classes_list):
        self.xmlfile_datalists_list = xmlfile_datalists_list
        self.xmlfile_path = self.xmlfile_datalists_list.pop()
        self.img_filename = self.xmlfile_datalists_list.pop()
        self.yolofile_path = absolutepath_of_directory_with_yolofiles + os.path.basename(self.xmlfile_path).split('.', 1)[0] + '.txt'
        self.classes_list = classes_list
        try:
            (self.img_height, self.img_width, _) = cv2.imread(absolutepath_of_directory_with_imgfiles + self.img_filename).shape
            self.create_yolofile()
        except:
            with open(absolutepath_of_directory_with_error_txt+'xmlfiles_with_no_paired.txt', 'a') as f:
                f.write(os.path.basename(self.xmlfile_path)+'\n')

    def create_yolofile(self):
        for xmlfile_datalist in self.xmlfile_datalists_list:
            yolo_datalist = self.convert_xml_to_yolo_format(xmlfile_datalist)

            with open(self.yolofile_path, 'a') as f:
                f.write("%d %.06f %.06f %.06f %.06f\n" % (yolo_datalist[0], yolo_datalist[1], yolo_datalist[2], yolo_datalist[3], yolo_datalist[4]))

    def convert_xml_to_yolo_format(self, xmlfile_datalist):
        class_name = xmlfile_datalist[0]
        self.add_class_to_classeslist(class_name)
        bndbox_coordinates_list = xmlfile_datalist[1]
        coordinates_min = bndbox_coordinates_list[0]
        coordinates_max = bndbox_coordinates_list[2]

        class_id = self.classes_list.index(class_name)
        yolo_xcen = float((coordinates_min[0] + coordinates_max[0])) / 2 / self.img_width
        yolo_ycen = float((coordinates_min[1] + coordinates_max[1])) / 2 / self.img_height
        yolo_width = float((coordinates_max[0] - coordinates_min[0])) / self.img_width
        yolo_height = float((coordinates_max[1] - coordinates_min[1])) / self.img_height
        yolo_datalist = [class_id, yolo_xcen, yolo_ycen, yolo_width, yolo_height]

        return yolo_datalist
    
    def add_class_to_classeslist(self, class_name):
        if class_name not in self.classes_list:
            self.classes_list.append(class_name)


class CreateClasssesfile:
    def __init__(self, classes_list):
        self.classes_list = classes_list

    def create_classestxt(self):
        with open(absolutepath_of_directory_with_classes_txt + 'classes.txt', 'w') as f:
            for class_name in self.classes_list:
                f.write(class_name+'\n')


xmlfiles_pathlist = glob(absolutepath_of_directory_with_xmlfiles + "/*.xml")
classes_list = []

for xmlfile_path in xmlfiles_pathlist:
    process_xmlfile = GetDataFromXMLfile(xmlfile_path)
    xmlfile_datalists_list = process_xmlfile.get_datalists_list()
    CreateYOLOfile(xmlfile_datalists_list, classes_list)

process_classesfile = CreateClasssesfile(classes_list)
process_classesfile.create_classestxt()

Releases

No releases published

Packages

No packages published

Languages