当前位置:   article > 正文

从VOC格式到YOLO格式:图像标注数据的转换过程_voc转yolo

voc转yolo

随着深度学习在目标检测领域的广泛应用,各类数据格式的处理和转换显得尤为重要。其中,PASCAL VOC (Visual Object Classes) 格式和YOLO (You Only Look Once) 格式是两种广泛使用的图像标注格式。本文将详细介绍如何将VOC格式的图像标注数据转换为YOLO格式。

一、VOC格式简介

PASCAL VOC格式是一种流行的目标检测数据集格式,它包含XML文件记录每张图片中目标的位置(矩形框坐标)、类别等信息。每个XML文件对应一张图片,描述了图片中的所有物体实例。

二、YOLO格式简介

YOLO格式则更为简洁直接,它通常将标注信息存储在一个文本文件中,每一行对应一张图片的数据。YOLO标注格式一般包括图片路径、每个目标的中心坐标(相对于整图宽高的比例)、目标的宽度和高度(同样以比例形式表示)以及目标的类别索引。

三、VOC转YOLO格式的具体步骤

1. **读取VOC数据**:首先需要读取VOC格式的XML标注文件,提取出每张图片的文件名、目标类别以及对应的矩形框坐标。

2. **坐标转换**:VOC格式使用的是绝对坐标(像素值),而YOLO格式使用相对坐标(比例)。因此,需要将矩形框的左上角坐标(xmin, ymin)和右下角坐标(xmax, ymax)转换为YOLO格式下的中心点坐标(x, y)和宽高(w, h),它们均是以图像宽度和高度的比例表示。

3. **格式化输出**:按照YOLO的格式要求,将每张图片的文件名、每个目标的类别索引(根据YOLO的类别字典进行映射)、以及转换后的中心坐标、宽高信息整理成一行文本,写入到YOLO格式的标注文件中。

通过以上步骤,我们就成功地将原本的VOC格式图像标注数据转换为了YOLO格式,以便于在基于YOLO的目标检测模型训练时使用。值得注意的是,在实际操作过程中可能需要编写相应的脚本或程序来自动化完成这一系列数据处理工作。

  1. import xml.etree.ElementTree as ET
  2. import sys
  3. import os.path
  4. import cv2
  5. class XmlParse:
  6. def __init__(self, file_path):
  7. # 初始化成员变量:self.tree 和 self.root 分别用于存储XML文件解析后的ElementTree对象和根节点;self.xml_file_path 存储传入的XML文件路径。
  8. self.tree = None
  9. self.root = None
  10. self.xml_file_path = file_path
  11. # 使用 try...except...finally 结构处理可能出现的异常情况。
  12. def ReadXml(self): # 该方法用于读取XML文件并解析为ElementTree对象。
  13. try:
  14. self.tree = ET.parse(self.xml_file_path) # 使用 xml.etree.ElementTree.parse() 方法解析XML文件,将结果赋值给 self.tree
  15. self.root = self.tree.getroot() # 获取XML文件的根节点并赋值给 self.root。
  16. except Exception as e: # 在 except Exception as e 块内,捕获并打印解析失败的错误信息,并通过 sys.exit() 终止程序执行。
  17. print("parse xml faild!")
  18. sys.exit()
  19. else:
  20. pass
  21. finally: # finally 块会在不论是否出现异常的情况下都会被执行,这里返回解析好的 self.tree。
  22. return self.tree
  23. def WriteXml(self, destfile):
  24. dses_xml_file = os.path.abspath(destfile)
  25. self.tree.write(dses_xml_file, encoding="utf-8", xml_declaration=True)
  26. def xml2txt(xml, labels, name_list, img_path):
  27. for i, j in zip(os.listdir(xml), os.listdir(img_path)):
  28. p = os.path.join(xml + '/' + i) # xml路径
  29. xml_file = os.path.abspath(p) # 绝对路径
  30. parse = XmlParse(xml_file)
  31. tree = parse.ReadXml() # xml树
  32. root = tree.getroot() # 根节点
  33. W = float(root.find('size').find('width').text)
  34. H = float(root.find('size').find('height').text)
  35. fil_name = root.find('filename').text[:-4]
  36. if not os.path.exists(labels): # 如果路径不存在则创建
  37. os.mkdir(labels)
  38. out = open(labels + './' + fil_name + '.txt', 'w+')
  39. for obj in root.iter('object'):
  40. x_min = float(obj.find('bndbox').find('xmin').text)
  41. x_max = float(obj.find('bndbox').find('xmax').text)
  42. y_min = float(obj.find('bndbox').find('ymin').text)
  43. y_max = float(obj.find('bndbox').find('ymax').text)
  44. print(f'------------------------{i}-----------------------')
  45. print('W:', W, 'H:', H)
  46. # 计算公式
  47. xcenter = x_min + (x_max - x_min) / 2
  48. ycenter = y_min + (y_max - y_min) / 2
  49. w = x_max - x_min
  50. h = y_max - y_min
  51. # 目标框的中心点 宽高
  52. print('center_X: ', xcenter)
  53. print('center_Y: ', ycenter)
  54. print('target box_w: ', w)
  55. print('target box_h: ', h)
  56. # 归一化
  57. xcenter = round(xcenter / W, 6)
  58. ycenter = round(ycenter / H, 6)
  59. w = round(w / W, 6)
  60. h = round(h / H, 6)
  61. print('>>>>>>>>>>')
  62. print(xcenter)
  63. print(ycenter)
  64. print(w)
  65. print(h)
  66. class_dict = dict(zip(name_list, range(0, len(name_list))))
  67. class_name = obj.find('name').text
  68. if class_name not in name_list:
  69. pass
  70. else:
  71. class_id = class_dict[class_name]
  72. print('类别: ', class_id)
  73. print("创建成功: {}".format(fil_name + '.txt'))
  74. print('----------------------------------------------------')
  75. out.write(str(class_id) + " " + str(xcenter) + " " + str(ycenter) + " " + str(w) + " " + str(h) + "\n")
  76. # show_img
  77. m = os.path.join(img_path + '/' + j)
  78. block = cv2.imread(m)
  79. cv2.rectangle(block, pt1=(int((xcenter - w / 2) * W), int((ycenter - h / 2) * H)),
  80. pt2=(int((xcenter + w / 2) * W), int((ycenter + h / 2) * H)),
  81. color=(0, 255, 0), thickness=2)
  82. cv2.imshow('block', block)
  83. cv2.waitKey(300)
  84. def folder_Path():
  85. img_path = './images_new'
  86. xml_path = './xmls_new' # xml路径
  87. labels = './labels_new' # 转txt路径
  88. name_list = ['trafficlight', 'stop', 'speedlimit', 'crosswalk'] # 类别名
  89. xml2txt(xml_path, labels, name_list, img_path)
  90. if __name__ == '__main__':
  91. folder_Path()

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/780655
推荐阅读
相关标签
  

闽ICP备14008679号