├── README.md ├── fire.yaml ├── fire_classes.txt └── xml2yolo.py /README.md: -------------------------------------------------------------------------------- 1 | # xml_to_textYolo 2 | Fire Dataset:https://github.com/OlafenwaMoses/FireNET/releases/download/v1.0/fire-dataset.zip 3 | YouTube:https://youtu.be/S0GwVgwjEd0 4 | -------------------------------------------------------------------------------- /fire.yaml: -------------------------------------------------------------------------------- 1 | train: ./data/fire/train/images 2 | val: ./data/fire/valid/images 3 | 4 | nc: 1 5 | names: ['fire'] 6 | -------------------------------------------------------------------------------- /fire_classes.txt: -------------------------------------------------------------------------------- 1 | fire 2 | -------------------------------------------------------------------------------- /xml2yolo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf8 -*- 3 | import os 4 | import sys 5 | from xml.etree import ElementTree 6 | from xml.etree.ElementTree import Element, SubElement 7 | from lxml import etree 8 | import codecs 9 | import cv2 10 | from glob import glob 11 | 12 | XML_EXT = '.xml' 13 | ENCODE_METHOD = 'utf-8' 14 | 15 | class PascalVocReader: 16 | def __init__(self, filepath): 17 | # shapes type: 18 | # [labbel, [(x1,y1), (x2,y2), (x3,y3), (x4,y4)], color, color, difficult] 19 | self.shapes = [] 20 | self.filepath = filepath 21 | self.verified = False 22 | try: 23 | self.parseXML() 24 | except: 25 | pass 26 | 27 | def getShapes(self): 28 | return self.shapes 29 | 30 | def addShape(self, label, bndbox, filename, difficult): 31 | xmin = int(bndbox.find('xmin').text) 32 | ymin = int(bndbox.find('ymin').text) 33 | xmax = int(bndbox.find('xmax').text) 34 | ymax = int(bndbox.find('ymax').text) 35 | points = [(xmin, ymin), (xmax, ymin), (xmax, ymax), (xmin, ymax)] 36 | self.shapes.append((label, points, filename, difficult)) 37 | 38 | def parseXML(self): 39 | assert self.filepath.endswith(XML_EXT), "Unsupport file format" 40 | parser = etree.XMLParser(encoding=ENCODE_METHOD) 41 | xmltree = ElementTree.parse(self.filepath, parser=parser).getroot() 42 | filename = xmltree.find('filename').text 43 | path = xmltree.find('path').text 44 | try: 45 | verified = xmltree.attrib['verified'] 46 | if verified == 'yes': 47 | self.verified = True 48 | except KeyError: 49 | self.verified = False 50 | 51 | for object_iter in xmltree.findall('object'): 52 | bndbox = object_iter.find("bndbox") 53 | label = object_iter.find('name').text 54 | # Add chris 55 | 56 | difficult = False 57 | if object_iter.find('difficult') is not None: 58 | difficult = bool(int(object_iter.find('difficult').text)) 59 | self.addShape(label, bndbox, path, difficult) 60 | return True 61 | 62 | 63 | classes = dict() 64 | num_classes = 0 65 | 66 | try: 67 | input = raw_input 68 | except NameError: 69 | pass 70 | 71 | 72 | parentpath = './' #"Directory path with parent dir before xml_dir or img_dir" 73 | addxmlpath = parentpath + 'fire-dataset/validation/annotations' #"Directory path with XML files" 74 | addimgpath = parentpath + 'fire-dataset/validation/images' #"Directory path with IMG files" 75 | outputpath = parentpath + 'labels' #"output folder for yolo format" 76 | classes_txt = './fire_classes.txt' #"File containing classes" 77 | ext = '.jpg' #"Image file extension [.jpg or .png]" 78 | 79 | 80 | if os.path.isfile(classes_txt): 81 | with open(classes_txt, "r") as f: 82 | class_list = f.read().strip().split() 83 | classes = {k : v for (v, k) in enumerate(class_list)} 84 | 85 | xmlPaths = glob(addxmlpath + "/*.xml") 86 | #imgPaths = glob(addimgpath + "/*"+ext) 87 | 88 | for xmlPath in xmlPaths: 89 | tVocParseReader = PascalVocReader(xmlPath) 90 | shapes = tVocParseReader.getShapes() 91 | 92 | with open(outputpath + "/" + os.path.basename(xmlPath)[:-4] + ".txt", "w") as f: 93 | for shape in shapes: 94 | class_name = shape[0] 95 | box = shape[1] 96 | #filename = os.path.splittext(xmlPath)[0] + ext 97 | filename = os.path.splitext(addimgpath + "/" + os.path.basename(xmlPath)[:-4])[0] + ext 98 | 99 | if class_name not in classes.keys(): 100 | classes[class_name] = num_classes 101 | num_classes += 1 102 | class_idx = classes[class_name] 103 | 104 | (height, width, _) = cv2.imread(filename).shape 105 | 106 | coord_min = box[0] 107 | coord_max = box[2] 108 | 109 | xcen = float((coord_min[0] + coord_max[0])) / 2 / width 110 | ycen = float((coord_min[1] + coord_max[1])) / 2 / height 111 | w = float((coord_max[0] - coord_min[0])) / width 112 | h = float((coord_max[1] - coord_min[1])) / height 113 | 114 | f.write("%d %.06f %.06f %.06f %.06f\n" % (class_idx, xcen, ycen, w, h)) 115 | print(class_idx, xcen, ycen, w, h) 116 | 117 | with open(parentpath + "classes.txt", "w") as f: 118 | for key in classes.keys(): 119 | f.write("%s\n" % key) 120 | print(key) 121 | --------------------------------------------------------------------------------