yolo转voc:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time :2021/8/31 下午3:06
# @Author :
# @ProjectName :mmdetection-master
# @File :yolo2voc.py
# @Description :
import os
import codecs
import cv2
import random
import xml.etree.ElementTree as ET
from xml.dom.minidom import parse
def vocXMLFormat(filePath, imgName, imgW, imgH, objNames, locs, depth=3, truncated=0, difficult=0):
"""
Generate xml annotation file,eg:
vocXMLFormat("0000.xml", "0001.png", 608, 608, ["person", "TV"], [[24, 32, 156, 145], [124, 76, 472, 384]])
Args:
filePath:The path of the file saved in the generated xml
imgName:xml file annotates the name of the picture
imgW:
imgH:
objNames:The object contained in the picture, format: ["object label 1", "object label 2"...]
locs:The picture contains the coordinates of the object, format: [[x,y,w,h],[x,y,w,h]...]
depth:
truncated:
difficult:
Returns:
"""
if (objNames == None) or (locs == None):
print("The objNames or locs is None!!!")
return
with codecs.open(filePath, 'w', 'utf-8') as xml:
xml.write('<?xml version="1.0" encoding="UTF-8"?>\n')
xml.write('<annotation>\n')
xml.write('\t<folder>' + 'voc format' + '</folder>\n')
xml.write('\t<filename>' + imgName + '</filename>\n')
xml.write('\t<path>' + imgName + '</path>\n')
xml.write('\t<source>\n')
xml.write('\t\t<database>weiz</database>\n')
xml.write('\t</source>\n')
xml.write('\t<size>\n')
xml.write('\t\t<width>' + str(imgW) + '</width>\n')
xml.write('\t\t<height>' + str(imgH) + '</height>\n')
xml.write('\t\t<depth>' + str(depth) + '</depth>\n')
xml.write('\t</size>\n')
xml.write('\t<segmented>0</segmented>\n')
for ind, name in enumerate(objNames):
xml.write('\t<object>\n')
xml.write('\t\t<name>' + name + '</name>\n')
xml.write('\t\t<pose>Unspecified</pose>\n')
xml.write('\t\t<truncated>' + str(truncated) + '</truncated>\n')
xml.write('\t\t<difficult>' + str(difficult) + '</difficult>\n')
xml.write('\t\t<bndbox>\n')
xml.write('\t\t\t<xmin>' + str(locs[ind][0]) + '</xmin>\n')
xml.write('\t\t\t<ymin>' + str(locs[ind][1]) + '</ymin>\n')
xml.write('\t\t\t<xmax>' + str(locs[ind][0] + locs[ind][2]) + '</xmax>\n')
xml.write('\t\t\t<ymax>' + str(locs[ind][1] + locs[ind][3]) + '</ymax>\n')
xml.write('\t\t</bndbox>\n')
xml.write('\t</object>\n')
xml.write('</annotation>')
xml.close()
print("The {} accomplish!".format(filePath))
def read_line(file_name):
"""
read file by line
:param file_name:
:return:
"""
lines = []
file = open(file_name)
for line in file:
line = line.strip('\n')
lines.append(line)
file.close()
return lines
def showAnnotions(image, locs, labels):
"""
show annotions
:param locs:
:param labels:
:return:
"""
for ind, (x, y, w, h) in enumerate(locs):
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv2.putText(image, labels[ind], (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1)
cv2.imshow("iamge", image)
cv2.waitKey(30)
def yolo2voc(txt_path, image_path, save_xml_path, label_path):
"""
Args:
txt_path:
image_path:
save_xml_path:
label_path:
Returns:
"""
txt_list = os.listdir(txt_path)
label_list = read_line(label_path)
for txt_name in txt_list:
image_name, _ = os.path.splitext(txt_name)
for extension in ["png", "jpg"]: # read image
image_name_path = image_name + '.' + extension
image_name_path = os.path.join(image_path, image_name_path)
if os.path.exists(image_name_path):
image = cv2.imread(image_name_path)
image_h, image_w, image_channel = image.shape
break
else:
continue
txt_name_path = os.path.join(txt_path, txt_name)
lines = read_line(txt_name_path)
object_locs = []
object_labels = []
for line in lines:
ind, center_x, center_y, w, h = line.split(' ')
x = (float(center_x) - float(w) / 2) * image_w
y = (float(center_y) - float(h) / 2) * image_h
w = float(w) * image_w
h = float(h) * image_h
object_locs.append([int(x), int(y), int(w), int(h)])
object_labels.append(label_list[int(ind)])
# showAnnotions(image, object_locs, object_labels)
xml_name_path = os.path.join(save_xml_path, image_name + ".xml")
vocXMLFormat(xml_name_path, os.path.split(image_name_path)[-1], image_w, image_h, object_labels, object_locs,
image_channel)
def fractionalSet(imagePath, txtSavePath):
"""
Args:
imagePath:
txtSavePath:
Returns:
"""
testPercent = 0.1
valPercent = 0.1
trainPercent = 0.8
imageNames = os.listdir(imagePath)
testNum = int(len(imageNames) * testPercent)
print("testNum:", testNum)
valNum = int(len(imageNames) * valPercent)
print("valNum:", valNum)
trainNum = len(imageNames) - testNum - valNum
print("trainNum", trainNum)
trainValNum = trainNum + valNum
print("trainValNum:", trainValNum)
test = random.sample(imageNames, testNum)
imageNamesTrainVal = list(set(imageNames) - set(test))
val = random.sample(imageNamesTrainVal, valNum)
train = list(set(imageNamesTrainVal) - set(val))
ftrainval_path = os.path.join(txtSavePath, "trainval.txt")
ftest_path = os.path.join(txtSavePath, "test.txt")
ftrain_path = os.path.join(txtSavePath, "train.txt")
fval_path = os.path.join(txtSavePath, "val.txt")
ftrainval = open(ftrainval_path, 'w')
ftest = open(ftest_path, 'w')
ftrain = open(ftrain_path, 'w')
fval = open(fval_path, 'w')
for imageName in imageNames:
if imageName in test:
imageName = imageName.split('.')[0] + "\n"
ftest.write(imageName)
else:
if imageName in val:
imageName = imageName.split('.')[0] + "\n"
fval.write(imageName)
else:
imageName = imageName.split('.')[0] + "\n"
ftrain.write(imageName)
ftrainval.write(imageName)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
def convert(size, box):
"""
·µ»Ø¹éÒ»»¯ºóµÄÖÐÐĵ㣬¿í¸ßÖµ
:param size:
:param box:
:return:
"""
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 count_label_num(xml_path):
"""
Args:
xml_path:
Returns:
"""
classes = []
num = []
xml_list = os.listdir(xml_path)
for xml_name in xml_list:
xml_name_path = os.path.join(xml_path, xml_name)
et = ET.parse(xml_name_path)
root = et.getroot()
for obj in root.iter('object'):
cls = obj.find("name").text
try:
cls_id = classes.index(cls)
except ValueError:
classes.append(cls)
num.append(0)
print("add new label:{}".format(cls))
cls_id = classes.index(cls)
num[cls_id] += 1
return classes, num
def checkLabel(imagePath, labelPath):
"""
Ëæ»ú³é²é¼ì²é±ê×¢Êý¾ÝÊÇ·ñÕýÈ·
:param imagePath:
:param labelPath:
:return:
"""
labelNames = os.listdir(labelPath)
while True:
index = random.randint(0, len(labelNames) - 1)
labelPath_tmp = os.path.join(labelPath, labelNames[index])
tree = ET.parse(labelPath_tmp)
root = tree.getroot()
imageName = root.find('filename').text
labels = [] # ±êÇ©ÐÅÏ¢[[x,y,w,h,label]]
for obj in root.iter('object'):
x1 = int(obj.find("bndbox").find("xmin").text)
y1 = int(obj.find("bndbox").find("ymin").text)
x2 = int(obj.find("bndbox").find("xmax").text)
y2 = int(obj.find("bndbox").find("ymax").text)
name = obj.find("name").text
labels.append([x1, y1, x2, y2, name])
imagePath_tmp = os.path.join(imagePath, imageName)
img = cv2.imread(imagePath_tmp)
for label in labels:
cv2.rectangle(img, (label[0], label[1]), (label[2], label[3]), (0, 0, 255))
cv2.putText(img, label[-1], (label[0], label[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2)
cv2.imshow(imageName, img)
k = cv2.waitKey(0)
# °´Esc¼üÍ˳ö
if k == 27:
break
# °´ÓÒ¼ýÍ·ºÍϼýÍ·¼ÌÐø¼ì²â
if k != 1 and k != 2:
if k == 27:
break
k = cv2.waitKey(0)
if k == 27:
break
cv2.destroyAllWindows()
txt_path = "/home/zyy/桌面/label"
image_path = "./defect4/JPEGImages"
save_xml_path = "./defect4/Annotations"
image_sets = "./defect4/ImageSets/Main"
label_path = "./defect4/label.txt"
setNames = ["test.txt", "val.txt", "train.txt", "trainval.txt"]
def main():
# yolo2voc(txt_path, image_path, save_xml_path, label_path)
# fractionalSet(image_path, image_sets)
# classes, num = count_label_num(save_xml_path)
# print(classes)
# print(num)
checkLabel(image_path, save_xml_path)
if __name__ == "__main__":
main()
voc转yolo
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time :2025/1/16 16:46
# @Author :weiz
# @ProjectName :weizTools
# @File :voc2yolo.py
# @Description :
import os
import xml.etree.ElementTree as ET
from glob import glob
import shutil
def main():
# 创建输出目录
if not os.path.exists(g_output_dir):
os.makedirs(g_output_dir)
# 读取类别列表并创建索引映射
with open(g_classes_file, 'r') as f:
classes = [line.strip() for line in f.readlines()]
class_to_idx = {cls_name: idx for idx, cls_name in enumerate(classes)}
# 遍历所有的XML文件
for xml_file in glob(os.path.join(g_voc_annotations_dir, '*.xml')):
tree = ET.parse(xml_file)
root = tree.getroot()
image_filename = root.find('filename').text
image_width = int(root.find('size/width').text)
image_height = int(root.find('size/height').text)
yolo_annotations = []
for obj in root.findall('object'):
class_name = obj.find('name').text
if class_name not in class_to_idx:
print(f"Warning: Skipping unknown class '{class_name}'")
continue
class_idx = class_to_idx[class_name]
bndbox = obj.find('bndbox')
xmin = float(bndbox.find('xmin').text)
ymin = float(bndbox.find('ymin').text)
xmax = float(bndbox.find('xmax').text)
ymax = float(bndbox.find('ymax').text)
x_center = (xmin + xmax) / 2 / image_width
y_center = (ymin + ymax) / 2 / image_height
width = (xmax - xmin) / image_width
height = (ymax - ymin) / image_height
yolo_annotations.append(f"{class_idx} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
# 写入YOLO格式的标注文件
txt_file_path = os.path.join(g_output_dir, os.path.splitext(image_filename)[0] + '.txt')
with open(txt_file_path, 'w') as f:
f.write('\n'.join(yolo_annotations))
# 复制图片到输出目录
src_image_path = os.path.join(g_images_dir, image_filename)
dst_image_path = os.path.join(g_output_dir, image_filename)
shutil.copy(src_image_path, dst_image_path)
print("Conversion completed.")
# 设置路径
g_voc_annotations_dir = r'C:\Users\weiz\Desktop\data2\Annotations'
g_images_dir = r'C:\Users\weiz\Desktop\data2\JPEGImages'
g_output_dir = r'C:\Users\weiz\Desktop\data2\yolo_format'
g_classes_file = r'C:\Users\weiz\Desktop\data2\classes.txt' # 包含所有类别的文本文件,一行一个类别名
if __name__ == "__main__":
main()
voc转coco
import xml.etree.ElementTree as ET
import os
import json
coco = dict()
coco['images'] = []
coco['type'] = 'instances'
coco['annotations'] = []
coco['categories'] = []
category_set = dict()
image_set = set()
category_item_id = -1
image_id = 20180000000
annotation_id = 0
def addCatItem(name):
global category_item_id
category_item = dict()
category_item['supercategory'] = 'none'
category_item_id += 1
category_item['id'] = category_item_id
category_item['name'] = name
coco['categories'].append(category_item)
category_set[name] = category_item_id
return category_item_id
def addImgItem(file_name, size):
global image_id
if file_name is None:
raise Exception('Could not find filename tag in xml file.')
if size['width'] is None:
raise Exception('Could not find width tag in xml file.')
if size['height'] is None:
raise Exception('Could not find height tag in xml file.')
image_id += 1
image_item = dict()
image_item['id'] = image_id
image_item['file_name'] = file_name
image_item['width'] = size['width']
image_item['height'] = size['height']
coco['images'].append(image_item)
image_set.add(file_name)
return image_id
def addAnnoItem(object_name, image_id, category_id, bbox):
global annotation_id
annotation_item = dict()
annotation_item['segmentation'] = []
seg = []
# bbox[] is x,y,w,h
# left_top
seg.append(bbox[0])
seg.append(bbox[1])
# left_bottom
seg.append(bbox[0])
seg.append(bbox[1] + bbox[3])
# right_bottom
seg.append(bbox[0] + bbox[2])
seg.append(bbox[1] + bbox[3])
# right_top
seg.append(bbox[0] + bbox[2])
seg.append(bbox[1])
annotation_item['segmentation'].append(seg)
annotation_item['area'] = bbox[2] * bbox[3]
annotation_item['iscrowd'] = 0
annotation_item['ignore'] = 0
annotation_item['image_id'] = image_id
annotation_item['bbox'] = bbox
annotation_item['category_id'] = category_id
annotation_id += 1
annotation_item['id'] = annotation_id
coco['annotations'].append(annotation_item)
def _read_image_ids(image_sets_file):
ids = []
with open(image_sets_file) as f:
for line in f:
ids.append(line.rstrip())
return ids
def parseXmlFiles_by_txt(data_dir, json_save_path, split='train'):
"""
Args:
data_dir:
json_save_path:
split: 'train' 'trainval' 'test'
Returns:
"""
labelfile = split + ".txt"
image_sets_file = data_dir + "/ImageSets/Main/" + labelfile
ids = _read_image_ids(image_sets_file)
for _id in ids:
xml_file = data_dir + f"/Annotations/{_id}.xml"
bndbox = dict()
size = dict()
current_image_id = None
current_category_id = None
file_name = None
size['width'] = None
size['height'] = None
size['depth'] = None
tree = ET.parse(xml_file)
root = tree.getroot()
if root.tag != 'annotation':
raise Exception('pascal voc xml root element should be annotation, rather than {}'.format(root.tag))
# elem is <folder>, <filename>, <size>, <object>
for elem in root:
current_parent = elem.tag
current_sub = None
object_name = None
if elem.tag == 'folder':
continue
if elem.tag == 'filename':
file_name = elem.text
if file_name in category_set:
raise Exception('file_name duplicated')
# add img item only after parse <size> tag
elif current_image_id is None and file_name is not None and size['width'] is not None:
if file_name not in image_set:
current_image_id = addImgItem(file_name, size)
print('add image with {} and {}'.format(file_name, size))
else:
raise Exception('duplicated image: {}'.format(file_name))
# subelem is <width>, <height>, <depth>, <name>, <bndbox>
for subelem in elem:
bndbox['xmin'] = None
bndbox['xmax'] = None
bndbox['ymin'] = None
bndbox['ymax'] = None
current_sub = subelem.tag
if current_parent == 'object' and subelem.tag == 'name':
object_name = subelem.text
if object_name not in category_set:
current_category_id = addCatItem(object_name)
else:
current_category_id = category_set[object_name]
elif current_parent == 'size':
if size[subelem.tag] is not None:
raise Exception('xml structure broken at size tag.')
size[subelem.tag] = int(subelem.text)
# option is <xmin>, <ymin>, <xmax>, <ymax>, when subelem is <bndbox>
for option in subelem:
if current_sub == 'bndbox':
if bndbox[option.tag] is not None:
raise Exception('xml structure corrupted at bndbox tag.')
bndbox[option.tag] = int(option.text)
# only after parse the <object> tag
if bndbox['xmin'] is not None:
if object_name is None:
raise Exception('xml structure broken at bndbox tag')
if current_image_id is None:
raise Exception('xml structure broken at bndbox tag')
if current_category_id is None:
raise Exception('xml structure broken at bndbox tag')
bbox = []
# x
bbox.append(bndbox['xmin'])
# y
bbox.append(bndbox['ymin'])
# w
bbox.append(bndbox['xmax'] - bndbox['xmin'])
# h
bbox.append(bndbox['ymax'] - bndbox['ymin'])
print('add annotation with {},{},{},{}'.format(object_name, current_image_id, current_category_id,
bbox))
addAnnoItem(object_name, current_image_id, current_category_id, bbox)
json.dump(coco, open(json_save_path, 'w'))
"""Ö±½Ó´ÓxmlÎļþ¼ÐÖÐÉú³É"""
def parseXmlFiles(xml_path, json_save_path):
for f in os.listdir(xml_path):
if not f.endswith('.xml'):
continue
bndbox = dict()
size = dict()
current_image_id = None
current_category_id = None
file_name = None
size['width'] = None
size['height'] = None
size['depth'] = None
xml_file = os.path.join(xml_path, f)
print(xml_file)
tree = ET.parse(xml_file)
root = tree.getroot()
if root.tag != 'annotation':
raise Exception('pascal voc xml root element should be annotation, rather than {}'.format(root.tag))
# elem is <folder>, <filename>, <size>, <object>
for elem in root:
current_parent = elem.tag
current_sub = None
object_name = None
if elem.tag == 'folder':
continue
if elem.tag == 'filename':
file_name = elem.text
if file_name in category_set:
raise Exception('file_name duplicated')
# add img item only after parse <size> tag
elif current_image_id is None and file_name is not None and size['width'] is not None:
if file_name not in image_set:
current_image_id = addImgItem(file_name, size)
print('add image with {} and {}'.format(file_name, size))
else:
raise Exception('duplicated image: {}'.format(file_name))
# subelem is <width>, <height>, <depth>, <name>, <bndbox>
for subelem in elem:
bndbox['xmin'] = None
bndbox['xmax'] = None
bndbox['ymin'] = None
bndbox['ymax'] = None
current_sub = subelem.tag
if current_parent == 'object' and subelem.tag == 'name':
object_name = subelem.text
if object_name not in category_set:
current_category_id = addCatItem(object_name)
else:
current_category_id = category_set[object_name]
elif current_parent == 'size':
if size[subelem.tag] is not None:
raise Exception('xml structure broken at size tag.')
size[subelem.tag] = int(subelem.text)
# option is <xmin>, <ymin>, <xmax>, <ymax>, when subelem is <bndbox>
for option in subelem:
if current_sub == 'bndbox':
if bndbox[option.tag] is not None:
raise Exception('xml structure corrupted at bndbox tag.')
bndbox[option.tag] = int(option.text)
# only after parse the <object> tag
if bndbox['xmin'] is not None:
if object_name is None:
raise Exception('xml structure broken at bndbox tag')
if current_image_id is None:
raise Exception('xml structure broken at bndbox tag')
if current_category_id is None:
raise Exception('xml structure broken at bndbox tag')
bbox = []
# x
bbox.append(bndbox['xmin'])
# y
bbox.append(bndbox['ymin'])
# w
bbox.append(bndbox['xmax'] - bndbox['xmin'])
# h
bbox.append(bndbox['ymax'] - bndbox['ymin'])
print('add annotation with {},{},{},{}'.format(object_name, current_image_id, current_category_id,
bbox))
addAnnoItem(object_name, current_image_id, current_category_id, bbox)
json.dump(coco, open(json_save_path, 'w'))
if __name__ == '__main__':
# 下面三个test.json、train.json、val.json只能一个一个运行
voc_data_dir = "./defect4"
json_save_path = "./defect4/test.json"
parseXmlFiles_by_txt(voc_data_dir, json_save_path, "test")
# json_save_path = "./defect4/train.json"
# parseXmlFiles_by_txt(voc_data_dir, json_save_path, "train")
# json_save_path = "./defect4/val.json"
# parseXmlFiles_by_txt(voc_data_dir, json_save_path, "val")
# ann_path = "E:/VOCdevkit/VOC2007/Annotations"
# json_save_path = "E:/VOCdevkit/test.json"
# parseXmlFiles(ann_path, json_save_path)
voc数据删除指定类别或更改类别名称
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time :2023/8/8 9:08
# @Author :weiz
# @ProjectName :jiangling_new
# @File :xml_process.py
# @Description :
# Copyright (C) 2021-2025 Jiangxi Institute Of Intelligent Industry Technology Innovation
import os
import xml.dom.minidom
import xml.etree.cElementTree as ET
def delete_specified_cls(xmlFolderPath, xmlSavePath, delete_cls):
xml_list = os.listdir(xmlFolderPath)
for xml_name in xml_list:
xml_tree = ET.parse(os.path.join(xmlFolderPath, xml_name))
xml_root = xml_tree.getroot()
total_class_num = 0
class_del_num = 0
for xml_child in xml_root.findall("object"):
total_class_num = total_class_num + 1
old_cls = xml_child.find("name").text
if old_cls in delete_cls:
class_del_num = class_del_num + 1
xml_root.remove(xml_child)
if total_class_num == class_del_num:
print("类别全部被删除了,请删除该文件及对应的图片:", xml_name)
xml_tree.write(os.path.join(xmlSavePath, xml_name))
else:
xml_tree.write(os.path.join(xmlSavePath, xml_name))
print(xml_name, "删除指定类别成功")
def change_class_name(xmlFolderPath, xmlSavePath, old_class, new_class):
"""
voc 数据类别替换
:param xmlFolderPath:
:param xmlSavePath:
:param old_class:
:param new_class:
:return:
"""
xml_list = os.listdir(xmlFolderPath)
for xml_name in xml_list:
xml_dom = xml.dom.minidom.parse(os.path.join(xmlFolderPath, xml_name))
root = xml_dom.documentElement
newfilename = root.getElementsByTagName('name')
for i, node in enumerate(newfilename):
for j, cls in enumerate(old_class):
if node.firstChild.data == cls:
newfilename[i].firstChild.data = new_class[j]
with open(os.path.join(xmlSavePath, xml_name), 'w') as fh:
xml_dom.writexml(fh)
print(xml_name, "文件类别替换成功")
g_delete_cls = ["spare_tire"]
# g_old_class = ["EKS_18_19", "EKS_20寸", "743出口", "743国内", "743BEV", "756"]
# g_new_class = ["NS1-1532-EA", "NS1-1352-DB", "MS1-1532-BA", "FS1-1532-AC", "KS2-1352-AA", "KS1-1532-AA"]
# g_old_class = ["fuel_92", "fuel_91", "fuel_87", "gasolina", "fuel_91_ron"]
# g_new_class = ["FS1-9A095-AB", "LK29-9A095-BA", "NS1-9A095-CA", "MS1-9A095-AA", "NS1-9A095-AA"]
g_old_class = ["strchromium", "nonchromium"]
g_new_class = ["KS1-D13210-BFD1", "KS1-D13210-ADD1"]
g_xmlFolderPath = r"E:\江铃工业相机及手机采集数据\FL09\燃油标签\Annotations"
g_xmlSavePath = r"E:\江铃工业相机及手机采集数据\FL09\燃油标签\Annotations"
if __name__ == "__main__":
change_class_name(g_xmlFolderPath, g_xmlSavePath, g_old_class, g_new_class)
#delete_specified_cls(g_xmlFolderPath, g_xmlSavePath, g_delete_cls)