,,,,,,,<_python ner 标注 格式 转换">
当前位置:   article > 正文

自学python(3):python处理各种标注文件的格式转换(json,txt,xml相互转化)_python ner 标注 格式 转换

python ner 标注 格式 转换

目录

#txt转xml

#xml转txt 

#json转xml

#xml转json


#txt转xml

  1. # coding: utf-8
  2. # author: HXY
  3. # 2020-4-17
  4. """
  5. 该脚本用于visdrone数据处理;
  6. 将annatations文件夹中的txt标签文件转换为XML文件;
  7. txt标签内容为:
  8. <bbox_left>,<bbox_top>,<bbox_width>,<bbox_height>,<score>,<object_category>,<truncation>,<occlusion>
  9. 类别:
  10. ignored regions(0), pedestrian(1),
  11. people(2), bicycle(3), car(4), van(5),
  12. truck(6), tricycle(7), awning-tricycle(8),
  13. bus(9), motor(10), others(11)
  14. """
  15. import os
  16. import cv2
  17. import time
  18. from xml.dom import minidom
  19. name_dict = {'0': 'ignored regions', '1': 'pedestrian', '2': 'people',
  20. '3': 'bicycle', '4': 'car', '5': 'van', '6': 'truck',
  21. '7': 'tricycle', '8': 'awning-tricycle', '9': 'bus',
  22. '10': 'motor', '11': 'others'}
  23. def transfer_to_xml(pic, txt, file_name):
  24. xml_save_path = 'F:/bling/data/VisDrone2019-DET-train/Annotations_XML' # 生成的xml文件存储的文件夹
  25. if not os.path.exists(xml_save_path):
  26. os.mkdir(xml_save_path)
  27. img = cv2.imread(pic)
  28. img_w = img.shape[1]
  29. img_h = img.shape[0]
  30. img_d = img.shape[2]
  31. doc = minidom.Document()
  32. annotation = doc.createElement("annotation")
  33. doc.appendChild(annotation)
  34. folder = doc.createElement('folder')
  35. folder.appendChild(doc.createTextNode('visdrone'))
  36. annotation.appendChild(folder)
  37. filename = doc.createElement('filename')
  38. filename.appendChild(doc.createTextNode(file_name))
  39. annotation.appendChild(filename)
  40. source = doc.createElement('source')
  41. database = doc.createElement('database')
  42. database.appendChild(doc.createTextNode("Unknown"))
  43. source.appendChild(database)
  44. annotation.appendChild(source)
  45. size = doc.createElement('size')
  46. width = doc.createElement('width')
  47. width.appendChild(doc.createTextNode(str(img_w)))
  48. size.appendChild(width)
  49. height = doc.createElement('height')
  50. height.appendChild(doc.createTextNode(str(img_h)))
  51. size.appendChild(height)
  52. depth = doc.createElement('depth')
  53. depth.appendChild(doc.createTextNode(str(img_d)))
  54. size.appendChild(depth)
  55. annotation.appendChild(size)
  56. segmented = doc.createElement('segmented')
  57. segmented.appendChild(doc.createTextNode("0"))
  58. annotation.appendChild(segmented)
  59. with open(txt, 'r') as f:
  60. lines = [f.readlines()]
  61. for line in lines:
  62. for boxes in line:
  63. box = boxes.strip('/n')
  64. box = box.split(',')
  65. x_min = box[0]
  66. y_min = box[1]
  67. x_max = int(box[0]) + int(box[2])
  68. y_max = int(box[1]) + int(box[3])
  69. object_name = name_dict[box[5]]
  70. # if object_name is 'ignored regions' or 'others':
  71. # continue
  72. object = doc.createElement('object')
  73. nm = doc.createElement('name')
  74. nm.appendChild(doc.createTextNode(object_name))
  75. object.appendChild(nm)
  76. pose = doc.createElement('pose')
  77. pose.appendChild(doc.createTextNode("Unspecified"))
  78. object.appendChild(pose)
  79. truncated = doc.createElement('truncated')
  80. truncated.appendChild(doc.createTextNode("1"))
  81. object.appendChild(truncated)
  82. difficult = doc.createElement('difficult')
  83. difficult.appendChild(doc.createTextNode("0"))
  84. object.appendChild(difficult)
  85. bndbox = doc.createElement('bndbox')
  86. xmin = doc.createElement('xmin')
  87. xmin.appendChild(doc.createTextNode(x_min))
  88. bndbox.appendChild(xmin)
  89. ymin = doc.createElement('ymin')
  90. ymin.appendChild(doc.createTextNode(y_min))
  91. bndbox.appendChild(ymin)
  92. xmax = doc.createElement('xmax')
  93. xmax.appendChild(doc.createTextNode(str(x_max)))
  94. bndbox.appendChild(xmax)
  95. ymax = doc.createElement('ymax')
  96. ymax.appendChild(doc.createTextNode(str(y_max)))
  97. bndbox.appendChild(ymax)
  98. object.appendChild(bndbox)
  99. annotation.appendChild(object)
  100. with open(os.path.join(xml_save_path, file_name + '.xml'), 'w') as x:
  101. x.write(doc.toprettyxml())
  102. x.close()
  103. f.close()
  104. if __name__ == '__main__':
  105. t = time.time()
  106. print('Transfer .txt to .xml...ing....')
  107. txt_folder = 'F:/bling/data/VisDrone2019-DET-train/annotations' # visdrone txt标签文件夹
  108. txt_file = os.listdir(txt_folder)
  109. img_folder = 'F:/bling/data/VisDrone2019-DET-train/images' # visdrone 照片所在文件夹
  110. for txt in txt_file:
  111. txt_full_path = os.path.join(txt_folder, txt)
  112. img_full_path = os.path.join(img_folder, txt.split('.')[0] + '.jpg')
  113. try:
  114. transfer_to_xml(img_full_path, txt_full_path, txt.split('.')[0])
  115. except Exception as e:
  116. print(e)
  117. print("Transfer .txt to .XML sucessed. costed: {:.3f}s...".format(time.time() - t))

#xml转txt 

  1. import os
  2. import xml.etree.ElementTree as ET
  3. dirpath = 'F:/bling/data/xml/' #原来存放xml文件的目录
  4. newdir = 'F:/bling/data/txt/' #修改label后形成的txt目录
  5. if not os.path.exists(newdir):
  6. os.makedirs(newdir)
  7. for fp in os.listdir(dirpath):
  8. root = ET.parse(os.path.join(dirpath,fp)).getroot()
  9. xmin, ymin, xmax, ymax = 0,0,0,0
  10. sz = root.find('size')
  11. width = float(sz[0].text)
  12. height = float(sz[1].text)
  13. filename = root.find('filename').text
  14. for child in root.findall('object'): #找到图片中的所有框
  15. #print(child.find('name').text)
  16. sub = child.find('bndbox') #找到框的标注值并进行读取
  17. label = child.find('name').text
  18. xmin = float(sub[0].text)
  19. ymin = float(sub[1].text)
  20. xmax = float(sub[2].text)
  21. ymax = float(sub[3].text)
  22. try: #转换成yolov3的标签格式,需要归一化到(0-1)的范围内
  23. x_center = (xmin + xmax) / (2 * width)
  24. y_center = (ymin + ymax) / (2 * height)
  25. w = (xmax - xmin) / width
  26. h = (ymax - ymin) / height
  27. except ZeroDivisionError:
  28. print(filename,'的 width有问题')
  29. with open(os.path.join(newdir, fp.split('.')[0]+'.txt'), 'a+') as f:
  30. f.write(' '.join([str(label), str(x_center), str(y_center), str(w), str(h) + '\n']))
  31. print('ok')

#json转xml

  1. import xmltodict
  2. import json
  3. import os
  4. # json to xml
  5. def jsonToXml(json_str):
  6. try:
  7. xml_str=""
  8. xml_str = xmltodict.unparse(json_str, encoding='utf-8')
  9. except:
  10. xml_str = xmltodict.unparse({'request': json_str}, encoding='utf-8')
  11. finally:
  12. return xml_str
  13. def json_to_xml(json_path,xml_path):
  14. if(os.path.exists(xml_path)==False):
  15. os.makedirs(xml_path)
  16. dir = os.listdir(json_path)
  17. for file in dir:
  18. file_list=file.split(".")
  19. with open(os.path.join(json_path,file), 'r') as load_f:
  20. load_dict = json.load(load_f)
  21. json_result = jsonToXml(load_dict)
  22. f = open(os.path.join(xml_path,file_list[0]+".xml"), 'w', encoding="UTF-8")
  23. f.write(json_result)
  24. f.close()
  25. if __name__ == '__main__':
  26. json_path=r"F:/bling/data/json" #该目录为存放json文件的路径 ps:目录中只能存放json文件
  27. xml_path=r"F:/bling/data/train" #该目录为放xml文件的路径
  28. json_to_xml(json_path,xml_path)

#xml转json

  1. import cv2
  2. import xml.etree.ElementTree as ET
  3. import numpy as np
  4. import os
  5. import json
  6. import shutil
  7. import base64
  8. '''
  9. 该脚本实现将xml类型标签(或者yolo格式标签)转为json格式标签
  10. 需要的数据:原始图像 原始xml标签(原始txt标签)
  11. '''
  12. # 解析数据集,输入单张图片路径,图片路径不能出现中文,因为是cv2读取的。和对应xml文件的路径
  13. # 返回图片 该图所有的目标框[[x1,y1,x2,y2],....] 每个框的类别[label1, label2, label3,.....] 注意是label而不是索引
  14. def parse_img_label(img_path, xml_path): # 绝对路径
  15. img = cv2.imread(img_path)
  16. tree = ET.parse(xml_path)
  17. root = tree.getroot()
  18. objs = root.findall('object')
  19. bboxes = [] # 坐标框
  20. h ,w = img.shape[0], img.shape[1]
  21. #gt_labels = [] # 标签名
  22. for obj in objs: # 遍历所有的目标
  23. label = obj[0].text # <name>这个tag的值,即标签
  24. label = label.strip(' ')
  25. box = [int(obj[4][i].text) for i in range(4)]
  26. box.append(label) # box的元素 x1 y1 x2 y2 类别
  27. bboxes.append(box)
  28. return img, bboxes
  29. # 该函数用于将yolo的标签转回xml需要的标签。。即将归一化后的坐标转为原始的像素坐标
  30. def convert_yolo_xml(box,img): #
  31. x,y,w,h = box[0], box[1], box[2], box[3]
  32. # 求出原始的x1 x2 y1 y2
  33. x2 = (2*x + w)*img.shape[1] /2
  34. x1 = x2 - w*img.shape[1]
  35. y2 = (2*y+h)*img.shape[0] /2
  36. y1 = y2 - h* img.shape[0]
  37. new_box = [x1,y1, x2, y2]
  38. new_box = list(map(int,new_box))
  39. return new_box
  40. # 该函数用于解析yolo格式的数据集,即txt格式的标注 返回图像 边框坐标 真实标签名(不是索引,因此需要预先定义标签)
  41. def parse_img_txt(img_path, txt_path):
  42. name_label = ['class0','class1','class2'] # 需要自己预先定义,它的顺序要和实际yolo格式的标签中0 1 2 3的标签对应 yolo标签的类别是索引 而不是名字
  43. img = cv2.imread(img_path)
  44. f = open(txt_path)
  45. bboxes = []
  46. for line in f.readlines():
  47. line = line.split(" ")
  48. if len(line) == 5:
  49. obj_label = name_label[int(line[0])] # 将类别索引转成其名字
  50. x = float(line[1])
  51. y = float(line[2])
  52. w = float(line[3])
  53. h = float(line[4])
  54. box = convert_yolo_xml([x,y,w,h], img)
  55. box.append(obj_label)
  56. bboxes.append(box)
  57. return img, bboxes
  58. # 制作labelme格式的标签
  59. # 参数说明 img_name: 图像文件名称
  60. # txt_name: 标签文件的绝对路径,注意是绝对路径
  61. # prefix: 图像文件的上级目录名。即形如/home/xjzh/data/ 而img_name是其下的文件名,如00001.jpg
  62. # prefix+img_name即为图像的绝对路径。不该路径能出现中文,否则cv2读取会有问题
  63. #
  64. def get_json(img_name, txt_name, prefix, yolo=False):
  65. # 图片名 标签名 前缀
  66. label_dict = {} # json字典,依次填充它的value
  67. label_dict["imagePath"] = prefix + img_name # 图片路径
  68. label_dict["fillColor"] = [255,0,0,128] # 目标区域的填充颜色 RGBA
  69. label_dict["lineColor"] = [0,255,0,128] # 线条颜色
  70. label_dict["flag"] = {}
  71. label_dict["version"] = "3.16.7" # 版本号,随便
  72. with open(prefix + img_name,"rb") as f:
  73. img_data = f.read()
  74. base64_data = base64.b64encode(img_data)
  75. base64_str = str(base64_data, 'utf-8')
  76. label_dict["imageData"] = base64_str # labelme的json文件存放了图像的base64编码。这样如果图像路径有问题仍然能够打开文件
  77. img, gt_box = parse_img_label(prefix + img_name, txt_name) if not yolo else parse_img_txt(prefix + img_name, txt_name) # 读取真实数据
  78. label_dict["imageHeight"] = img.shape[0] # 高度
  79. label_dict["imageWidth"] = img.shape[1]
  80. shape_list = [] # 存放标注信息的列表,它是 shapes这个键的值。里面是一个列表,每个元素又是一个字典,字典内容是该标注的类型 颜色 坐标点等等
  81. #label_dict["shapes"] = [] # 列表,每个元素是字典。
  82. # box的元素 x1 y1 x2 y2 类别
  83. for box in gt_box:
  84. shape_dict = {} # 表示一个目标的字典
  85. shape_dict["shape_type"] = "rectangle" # 因为xml或yolo格式标签是矩形框标注,因此是rectangle
  86. shape_dict["fill_color"] = None #该类型的填充颜色
  87. shape_dict["line_color"] = None # 线条颜色 可以设置,或者根据标签名自己预先设定labe_color_dict
  88. shape_dict["flags"] = {}
  89. shape_dict["label"] = box[-1] # 标签名
  90. shape_dict["points"] = [[box[0],box[1]], [box[2], box[3]]]
  91. # 通常contours是长度为1的列表,如果有分块,可能就有多个 # [[x1,y1], [x2,y2]...]的列表
  92. shape_list.append(shape_dict)
  93. label_dict["shapes"] = shape_list #
  94. return label_dict
  95. imgs_path = "F:/bling/data/images/" # 图像路径
  96. xmls_path ="F:/bling/data/xml/" # xml文件路径
  97. img_path = os.listdir(imgs_path)
  98. out_json = 'F:/bling/data/json/' # 保存的json文件路径
  99. for nums, path in enumerate(img_path):
  100. if nums %200==0:
  101. print(f"processed {nums} images")
  102. xml_path = xmls_path + path.replace('jpg','xml') # xml文件的绝对路径
  103. label_dict = get_json(path, xml_path,prefix=imgs_path) #
  104. with open(out_json + path.replace("jpg","json"),'w') as f: # 写入一个json文件
  105. f.write(json.dumps(label_dict, ensure_ascii=False, indent=4, separators=(',', ':')))

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签