1.xml转coco的完整代码:
import os
import json
import xml.etree.ElementTree as ET
import glob
def get_and_check(root, name, length, cast_type=int):
vars = root.findall(name)
if length > 0 and len(vars) != length:
raise ValueError(
"The size of %s is supposed to be %d, but is %d."
% (name, length, len(vars))
)
return [cast_type(var.text.strip()) for var in vars if var.text]
def get_categories(xml_files):
classes_names = set()
for xml_file in xml_files:
tree = ET.parse(xml_file)
root = tree.getroot()
for obj in root.findall("object"):
classes_names.add(get_and_check(obj, "name", 1)[0])
classes_names = list(classes_names)
classes_names.sort()
return {name: i for i, name in enumerate(classes_names)}
def generate_label_file(xml_files, json_file, categories=None):
if categories is None:
categories = get_categories(xml_files)
json_dict = {"images": [], "annotations": [], "categories": []}
bnd_id = 1
image_id = 1
for xml_file in xml_files:
tree = ET.parse(xml_file)
root = tree.getroot()
filename = get_and_check(root, "filename", 1, cast_type=str)[0]
# 直接获取尺寸信息的子元素并转换为整数
width = int(root.find("size/width").text)
height = int(root.find("size/height").text)
image = {
"file_name": filename,
"height": height,
"width": width,
"id": image_id,
}
json_dict["images"].append(image)
for obj in root.findall("object"):
category = get_and_check(obj, "name", 1, cast_type=str)[0]
if category not in categories:
print(f"Warning: {category} not in categories. Skipping object.")
continue
bndbox = obj.find("bndbox")
xmin = get_and_check(bndbox, "xmin", 1, cast_type=int)[0] - 1
ymin = get_and_check(bndbox, "ymin", 1, cast_type=int)[0] - 1
xmax = get_and_check(bndbox, "xmax", 1, cast_type=int)[0]
ymax = get_and_check(bndbox, "ymax", 1, cast_type=int)[0]
category_id = categories[category]
ann = {
"id": bnd_id,
"image_id": image_id,
"category_id": category_id,
"iscrowd": 0,
"area": (xmax - xmin) * (ymax - ymin),
"bbox": [xmin, ymin, xmax - xmin, ymax - ymin],
"segmentation": [],
"ignore": 0,
}
json_dict["annotations"].append(ann)
bnd_id += 1
image_id += 1
for cate, cid in categories.items():
cat = {"supercategory": "none", "id": cid, "name": cate}
json_dict["categories"].append(cat)
os.makedirs(os.path.dirname(json_file), exist_ok=True)
with open(json_file, "w") as json_fp:
json.dump(json_dict, json_fp, indent=4)
if __name__ == "__main__":
xml_path = "xml/test" # XML文件所在文件夹路径
xml_files = glob.glob(os.path.join(xml_path, "*.xml"))
json_file = "coco/instances_test2017.json" # 生成的JSON文件保存路径
categories = {
"cat": 1,
"dog": 2,
"people": 3,
} # 预先定义的类别字典
generate_label_file(xml_files, json_file, categories)
print(f"JSON file {json_file} has been created.")
1.1需要修改的地方
2.txt转xml完整代码,适应各种图片后缀:
# coding:utf-8
from xml.dom import minidom
import cv2,os,sys,shutil,tqdm
import numpy as np
def create_xml_test(xml_path,img_path,txt_path):
# 新建xml文档对象
xml = minidom.Document()
# 创建第一个节点,第一个节点就是根节点了
root = xml.createElement('annotation')
xml.appendChild(root)
# 那么给根节点再创建一个folder节点
folder_node = xml.createElement('folder')
root.appendChild(folder_node)
text = xml.createTextNode('JPEGImages')
folder_node.appendChild(text)
# 那么给根节点再创建一个filename节点
filename_node = xml.createElement('filename')
root.appendChild(filename_node)
text = xml.createTextNode(img_path.split('/')[-1])
filename_node.appendChild(text)
# 那么给根节点再创建一个path节点
path_node = xml.createElement('path')
root.appendChild(path_node)
text = xml.createTextNode(img_path)
path_node.appendChild(text)
# 那么给根节点再创建一个source节点
source_node = xml.createElement('source')
root.appendChild(source_node)
database_node = xml.createElement('database')
source_node.appendChild(database_node)
text = xml.createTextNode('Unknown')
database_node.appendChild(text)
# 那么给根节点再创建一个size节点
img = cv2.imread(img_path)
try:
H, W, C = img.shape
except Exception as e:
print("无法获取图像形状:", e)
print("图像内容:", img_path)
size_node = xml.createElement('size')
root.appendChild(size_node)
#width_node
width_node = xml.createElement('width')
size_node.appendChild(width_node)
text = xml.createTextNode('%d'%W)
width_node.appendChild(text)
#height_node
height_node = xml.createElement('height')
size_node.appendChild(height_node)
text = xml.createTextNode('%d'%H)
height_node.appendChild(text)
#depth_node
depth_node = xml.createElement('depth')
size_node.appendChild(depth_node)
text = xml.createTextNode('%d'%C)
depth_node.appendChild(text)
# 那么给根节点再创建一个segmented节点
segmented_node = xml.createElement('segmented')
root.appendChild(segmented_node)
text = xml.createTextNode('0')
segmented_node.appendChild(text)
## 增加 object 节点
txt_lines = open(txt_path,'r').readlines()
for line in txt_lines:
line = line.strip()
line_lst = line.split(' ')
if len(line_lst)!=5:
continue
class_id = int(line_lst[0])
class_name = CLASSES[class_id]
x_cen = float(line_lst[1]) * img.shape[1]
y_cen = float(line_lst[2]) * img.shape[0]
w = float(line_lst[3]) * img.shape[1]
h = float(line_lst[4]) * img.shape[0]
x_min = int(x_cen-w/2.0)
y_min = int(y_cen-h/2.0)
x_max = int(x_cen+w/2.0)
y_max = int(y_cen+h/2.0)
object_node = xml.createElement('object')
root.appendChild(object_node)
#name
name_node = xml.createElement('name')
object_node.appendChild(name_node)
text = xml.createTextNode(class_name)
name_node.appendChild(text)
#pose
pose_node = xml.createElement('pose')
object_node.appendChild(pose_node)
text = xml.createTextNode('Unspecified')
pose_node.appendChild(text)
#truncated
truncated_node = xml.createElement('truncated')
object_node.appendChild(truncated_node)
text = xml.createTextNode('0')
truncated_node.appendChild(text)
#difficult
difficult_node = xml.createElement('difficult')
object_node.appendChild(difficult_node)
text = xml.createTextNode('0')
difficult_node.appendChild(text)
#bndbox
bndbox_node = xml.createElement('bndbox')
object_node.appendChild(bndbox_node)
xmin_node = xml.createElement('xmin')
bndbox_node.appendChild(xmin_node)
text = xml.createTextNode('%d' % x_min)
xmin_node.appendChild(text)
ymin_node = xml.createElement('ymin')
bndbox_node.appendChild(ymin_node)
text = xml.createTextNode('%d' % y_min)
ymin_node.appendChild(text)
xmax_node = xml.createElement('xmax')
bndbox_node.appendChild(xmax_node)
text = xml.createTextNode('%d' % x_max)
xmax_node.appendChild(text)
ymax_node = xml.createElement('ymax')
bndbox_node.appendChild(ymax_node)
text = xml.createTextNode('%d'%y_max)
ymax_node.appendChild(text)
with open(xml_path, "w", encoding="utf8") as outfile:
outfile.write(xml.toprettyxml())
if __name__ == '__main__':
CLASSES = ['smoke','fire']
img_root = r"/gpfs/home/qixinggroup/newdata-07-16/data/images/train/"
img_list = os.listdir(img_root)
img_list = [img_root + v for v in img_list if (v.endswith('.jpg') or v.endswith('.png') or v.endswith('.jpeg') or v.endswith('.PNG') or v.endswith('.JPG') or v.endswith('.JPEG'))]
# img_list = [img_root + '001_img11615.jpg']
#"C:/Users/29269/Desktop/simAM/train/Annotations/"
xml_root= r"/gpfs/home/qixinggroup/newdata-07-16/data/Annotations/train/"
if os.path.exists(xml_root) is False:
os.makedirs(xml_root)
for img_path in tqdm.tqdm(img_list):
txt_path = img_path.replace('/images/','/labels/').replace('.jpg','.txt').replace('.png','.txt').replace('.PNG','.txt').replace('.JPG','.txt').replace('.jpeg','.txt').replace('.JPEG','.txt')
if os.path.exists(txt_path) is False:
continue
if os.path.exists(txt_path) is True:
print(os.path.exists(txt_path) )
xml_path = img_path.replace('/images/','/Annotations/').replace('.jpg','.xml').replace('.png','.xml').replace('.PNG','.xml').replace('.JPG','.xml').replace('.jpeg','.xml').replace('.JPEG','.xml')
create_xml_test(xml_path=xml_path,img_path=img_path,txt_path=txt_path)
2.1需要修改的地方如下:
2.2文件的路径格式需要保持如下才能正常的运行:
3.参考资料:
https://blog.csdn.net/weixin_53035684/article/details/140838377