格式转换
1. xml转yolo txt
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
def convert(size, box):
# size=(width, height) b=(xmin, xmax, ymin, ymax)
# x_center = (xmax+xmin)/2 y_center = (ymax+ymin)/2
# x = x_center / width y = y_center / height
# w = (xmax-xmin) / width h = (ymax-ymin) / height
x_center = (box[0]+box[1])/2.0
y_center = (box[2]+box[3])/2.0
x = x_center / size[0]
y = y_center / size[1]
w = (box[1] - box[0]) / size[0]
h = (box[3] - box[2]) / size[1]
# print(x, y, w, h)
return (x,y,w,h)
def convert_annotation(xml_files_path, save_txt_files_path, classes):
xml_files = os.listdir(xml_files_path)
# print(xml_files)
for xml_name in xml_files:
# print(xml_name)
xml_file = os.path.join(xml_files_path, xml_name)
out_txt_path = os.path.join(save_txt_files_path, xml_name.split('.')[0] + '.txt')
out_txt_f = open(out_txt_path, 'w')
tree=ET.parse(xml_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))
# b=(xmin, xmax, ymin, ymax)
# print(w, h, b)
bb = convert((w,h), b)
out_txt_f.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
if __name__ == "__main__":
# 把forklift_pallet的voc的xml标签文件转化为yolo的txt标签文件
# 1、需要转化的类别
classes = ['forklift_pallet']#注意:这里根据自己的类别名称及种类自行更改
# 2、voc格式的xml标签文件路径
xml_files1 = r'/home/wangmj/pallet_data/Annotations'
# 3、转化为yolo格式的txt标签文件存储路径
save_txt_files1 = r'/home/wangmj/pallet_data/test'
convert_annotation(xml_files1, save_txt_files1, classes)
2. yolo .txt转xml
import os
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import Element, SubElement
from PIL import Image
class Xml_make(object):
def __init__(self):
super().__init__()
def __indent(self, elem, level=0):
i = "\n" + level * "\t"
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + "\t"
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
self.__indent(elem, level + 1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
def _imageinfo(self, list_top):
annotation_root = ET.Element('annotation')
# annotation_root.set('verified', 'no')
tree = ET.ElementTree(annotation_root)
# '''
# 0:xml_savepath 1:folder,2:filename,3:path
# 4:checked,5:width,6:height,7:depth
# '''
folder_element = ET.Element('folder')
folder_element.text = list_top[1]
annotation_root.append(folder_element)
filename_element = ET.Element('filename')
filename_element.text = list_top[2]
annotation_root.append(filename_element)
source_element = ET.Element('source')
database_element = SubElement(source_element, 'database')
database_element.text = 'KAIST'
annotation_root.append(source_element)
size_element = ET.Element('size')
width_element = SubElement(size_element, 'width')
width_element.text = str(list_top[3])
height_element = SubElement(size_element, 'height')
height_element.text = str(list_top[4])
depth_element = SubElement(size_element, 'depth')
depth_element.text = str(list_top[5])
annotation_root.append(size_element)
segmented_person_element = ET.Element('segmented')
segmented_person_element.text = '0'
annotation_root.append(segmented_person_element)
return tree, annotation_root
def _bndbox(self, annotation_root, list_bndbox):
for i in range(0, len(list_bndbox), 9):
object_element = ET.Element('object')
name_element = SubElement(object_element, 'name')
name_element.text = list_bndbox[i]
bndbox_element = SubElement(object_element, 'bndbox')
xmin_element = SubElement(bndbox_element, 'xmin')
xmin_element.text = str(list_bndbox[i + 1])
ymin_element = SubElement(bndbox_element, 'ymin')
ymin_element.text = str(list_bndbox[i + 2])
xmax_element = SubElement(bndbox_element, 'xmax')
xmax_element.text = str(list_bndbox[i + 3])
ymax_element = SubElement(bndbox_element, 'ymax')
ymax_element.text = str(list_bndbox[i + 4])
pose_element = SubElement(object_element, 'pose')
pose_element.text = list_bndbox[i + 5]
truncated_element = SubElement(object_element, 'truncated')
truncated_element.text = list_bndbox[i + 6]
difficult_element = SubElement(object_element, 'difficult')
difficult_element.text = list_bndbox[i + 7]
flag_element = SubElement(object_element, 'occlusion')
flag_element.text = list_bndbox[i + 8]
annotation_root.append(object_element)
return annotation_root
def txt_to_xml(self, list_top, list_bndbox):
tree, annotation_root = self._imageinfo(list_top)
annotation_root = self._bndbox(annotation_root, list_bndbox)
self.__indent(annotation_root)
tree.write(list_top[0], encoding='utf-8', xml_declaration=True)
def txt_2_xml(source_path, xml_save_dir, txt_dir):
COUNT = 0
for folder_path_tuple, folder_name_list, file_name_list in os.walk(source_path):
for file_name in file_name_list:
file_suffix = os.path.splitext(file_name)[-1]
if file_suffix != '.jpg':
continue
list_top = []
list_bndbox = []
path = os.path.join(folder_path_tuple, file_name)
xml_save_path = os.path.join(xml_save_dir, file_name.replace(file_suffix, '.xml'))
txt_path = os.path.join(txt_dir, file_name.replace(file_suffix, '.txt'))
filename = os.path.splitext(file_name)[0]
im = Image.open(path)
im_w = im.size[0]
im_h = im.size[1]
width = str(im_w)
height = str(im_h)
depth = '3'
occlusion = '0'
pose = 'unknown'
truncated = '0'
difficult = '0'
list_top.extend([xml_save_path, folder_path_tuple, filename,
width, height, depth])
for line in open(txt_path, 'r'):
line = line.strip()
if line == "% bbGt version=3":
continue
info = line.split(' ')
name = info[0]
xmin = float(info[1])
ymin = float(info[2])
xmax = float(info[3])
ymax = float(info[4])
# xmax = xmin + w
# ymax = ymin + h
# x_cen = float(info[1]) * im_w
# y_cen = float(info[2]) * im_h
# w = float(info[3]) * im_w
# h = float(info[4]) * im_h
# xmin = int(x_cen - w / 2)
# ymin = int(y_cen - h / 2)
# xmax = int(x_cen + w / 2)
# ymax = int(y_cen + h / 2)
list_bndbox.extend([name, str(xmin), str(ymin), str(xmax), str(ymax), pose, truncated, difficult,
occlusion])
Xml_make().txt_to_xml(list_top, list_bndbox)
COUNT += 1
print(COUNT, xml_save_path)
if __name__ == '__main__':
source_path = r' your img path' # txt标注文件所对应的的图片
xml_save_dir = r' your xml path' # 转换为xml标注文件的保存路径
txt_dir = r' your txt path' # 需要转换的txt标注文件
txt_2_xml(source_path, xml_save_dir, txt_dir)
YOLO数据集划分
"""
将数据集划分为训练集,验证集,测试集
"""
import os
import random
import shutil
# 创建保存数据的文件夹
def makedir(new_dir):
if not os.path.exists(new_dir):
os.makedirs(new_dir)
def split_data(img_dir, label_dir, split_dir, TEST=True):
'''
args:
img_dir:原图片数据集路径
label_dir:原yolog格式txt文件数据集路径
split_dir:划分后数据集保存路径
TEST:是否划分测试集
用于将数据集划分为YOLO数据集格式的训练集,验证集,测试集
'''
random.seed(42) # 随机种子
# 1.确定原图片数据集路径
datasetimg_dir = img_dir
# 确定原label数据集路径
datasetlabel_dir = label_dir
images_dir = os.path.join(split_dir, 'images')
labels_dir = os.path.join(split_dir, 'labels')
dir_list = [images_dir, labels_dir]
if TEST:
type_label = ['train', 'valid', 'test']
else:
type_label = ['train', 'valid']
for i in range(len(dir_list)):
for j in range(len(type_label)):
makedir(os.path.join(dir_list[i], type_label[j]))
# 3.确定将数据集划分为训练集,验证集,测试集的比例
train_pct = 0.8
valid_pct = 0.1
test_pct = 0.1
# 4.划分
labels = os.listdir(datasetlabel_dir) # 展示目标文件夹下所有的文件名
labels = list(filter(lambda x: x.endswith('.txt'), labels)) # 取到所有以.txt结尾的yolo格式文件
random.shuffle(labels) # 乱序路径
label_count = len(labels) # 计算图片数量
train_point = int(label_count * train_pct) # 0:train_pct
valid_point = int(label_count * (train_pct + valid_pct)) # train_pct:valid_pct
for i in range(label_count):
if i < train_point: # 保存0-train_point的图片和标签到训练集
out_dir = os.path.join(images_dir, 'train')
label_out_dir = os.path.join(labels_dir, 'train')
elif train_point <= i < valid_point: # 保存train_point-valid_point的图片和标签到验证集
out_dir = os.path.join(images_dir, 'valid')
label_out_dir = os.path.join(labels_dir, 'valid')
else: # 保存test_point-结束的图片和标签到测试集
out_dir = os.path.join(images_dir, 'test')
label_out_dir = os.path.join(labels_dir, 'test')
label_target_path = os.path.join(label_out_dir, labels[i]) # 指定目标保存路径
label_src_path = os.path.join(datasetlabel_dir, labels[i]) # 指定目标原文件路径
img_target_path = os.path.join(out_dir, labels[i].split('.')[0] + '.JPG') # 指定目标保存路径
img_src_path = os.path.join(datasetimg_dir, labels[i].split('.')[0] + '.JPG') # 指定目标原图像路径
shutil.copy(label_src_path, label_target_path) # 复制txt
shutil.copy(img_src_path, img_target_path) # 复制图片
print('train:{}, valid:{}, test:{}'.format(train_point, valid_point - train_point,
label_count - valid_point))
if __name__ == "__main__":
img_dir = r'totrain\segmentdata_withlabel\jpg'
label_dir = r'totrain\segmentdata_withlabel\txt'
split_dir = r'totrain\segmentdata_withlabel\split'
split_data(img_dir, label_dir, split_dir, TEST=True)
# for dir in os.listdir(root):
# if not dir.endswith('.py') and not dir.endswith('txt'):
# split_data(dir, label_dir, root, split_dir)
数据整合
将一个包含多个子文件夹的目录中的所有图片复制到一个单独的目标文件夹中。
import os
import shutil
def copy_images(source_dir, target_dir, image_extensions):
"""
复制指定目录及其子目录中的所有图片到目标文件夹。
:param source_dir: 源目录路径,包含子目录和图片。
:param target_dir: 目标目录路径,用于存放复制的图片。
:param image_extensions: 图片文件扩展名的元组。
"""
# 确保目标文件夹存在
if not os.path.exists(target_dir):
os.makedirs(target_dir)
# 遍历源目录及其子目录
for root, dirs, files in os.walk(source_dir):
for file in files:
# 检查文件扩展名是否为图片格式
if file.lower().endswith(image_extensions):
source_file = os.path.join(root, file)
# 构造目标文件路径
target_file = os.path.join(target_dir, file)
# 复制图片文件
shutil.copy(source_file, target_file)
print(f"Copied: {source_file} to {target_file}")
# 源文件夹路径,包含多个子文件夹
source_folder = '/path/to/source/folder'
# 目标文件夹路径
target_folder = '/path/to/target/folder'
# 支持的图片文件扩展名
image_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.gif')
# 调用函数执行复制操作
copy_images(source_folder, target_folder, image_extensions)
print("Image copying completed.")