获取xml_使用DOM进行XML文件的解析

本文介绍了XML和DOM的概念,DOM将XML文件抽象为树形结构,通过getElementsByTagName、getAttributeNode等方法解析XML。以车道线标注为例,展示了如何解析CVAT系统生成的XML标注文件,从中提取图像名称、车道线等信息。
摘要由CSDN通过智能技术生成

60ca336e6e5439d2520a4cb62f560651.png

1. 什么是XML?

xml是格式化的纯文本,用于存储数据和格式。

2. DOM是什么?

DOM是xml的一种解析方法(此外还包括SAX等,此处不提),它将xml文件抽象成为一个树型结构,这棵树个各个树叶就是节点。也就是说,DOM 定义了所有文档元素的对象和属性,以及访问它们的方法(接口)。

DOM的主要性质:

  • 文档是一个文档节点,即根节点,对象树型是domTree.documentElement
  • 每个 XML 标签是一个元素节点,元素节点接口方法见链接, 主要包括的方法和属性有:
    • getElementsByTagName():根据tag获取elements
    • getAttributeNode():获取特定属性值
    • childNodes:子节点的nodelist
    • ...
  • 包含在 XML 元素中的文本是文本节点
  • 每一个 XML 属性是一个属性节点
  • 注释属于注释节点

3. 使用dom解析xml例程

  1. 例程说明

“博主用了一个图像标注系统CVAT进行车道线的标注,如下图,系统输出的标注结果就是一个xml文件。我们的label有6类,'left_3', 'left_2', 'left_1', 'right_1', 'right_2', 'right_3'。我们的工作就是解析xml文件。”

af2b09d20780d68697658f9ab952fc23.png

我的xml文件如下所示, 可以复制下来进行代码测试。

<?xml version="1.0" encoding="utf-8"?>
<annotations>
  <version>1.1</version>
  <meta>
    <task>
      <id>71</id>
      <name>front_lane_normal_bright_20200826_1</name>
      <size>1455</size>
      <mode>annotation</mode>
      <overlap>0</overlap>
      <bugtracker></bugtracker>
      <created>2020-08-26 02:13:44.099919+00:00</created>
      <updated>2020-08-28 08:57:13.943460+00:00</updated>
      <start_frame>0</start_frame>
      <stop_frame>1454</stop_frame>
      <frame_filter></frame_filter>
      <z_order>False</z_order>
      <labels>
        <label>
          <name>left_3</name>
          <attributes>
          </attributes>
        </label>
        <label>
          <name>left_2</name>
          <attributes>
          </attributes>
        </label>
        <label>
          <name>left_1</name>
          <attributes>
          </attributes>
        </label>
        <label>
          <name>right_1</name>
          <attributes>
          </attributes>
        </label>
        <label>
          <name>right_2</name>
          <attributes>
          </attributes>
        </label>
        <label>
          <name>right_3</name>
          <attributes>
          </attributes>
        </label>
      </labels>
      <segments>
        <segment>
          <id>221</id>
          <start>0</start>
          <stop>19</stop>
          <url>http://xxx.xxx.xxx.xxx:8080/?id=221</url>
        </segment>
      </segments>
      <owner>
        <username>test</username>
        <email>test@test.tech</email>
      </owner>
      <assignee>
        <username>test</username>
        <email>test@test.tech</email>
      </assignee>
    </task>
    <dumped>2020-08-30 09:49:39.875576+00:00</dumped>
  </meta>
  <image id="0" name="00.jpg" width="1280" height="1080">
    <polyline label="right_2" occluded="0" points="660.79,372.67;874.57,473.35;1280.00,681.03">
    </polyline>
    <polyline label="right_1" occluded="0" points="604.04,364.96;723.04,545.20;1064.02,1074.54">
    </polyline>
    <polyline label="left_3" occluded="0" points="513.18,378.36;271.53,515.26;0.00,681.53">
    </polyline>
    <polyline label="left_2" occluded="0" points="563.04,366.94;360.00,644.00;64.83,1080.00">
    </polyline>
    <polyline label="left_1" occluded="0" points="568.56,365.28;437.94,580.75;145.64,1080.00">
    </polyline>
  </image>
</annotations>

对应的原始图像在下面

1b19a727f1448888d8b2fe03cab9607d.png

2. xml文件说明

为了方便可以使用浏览器打开,是下面这样的格式。可以看到,根节点就是annotations, 其子节点包括version、meta、image等等,其中meta->task->labels是我们规定的标注规范中的label类别,包括"left_3"...."right_3"等。另外各个image节点就是我们对应的每一张图像的标注结果,子元素节点包括多个polyline,每个polyline就是一条车道线,采用str类型的点对表示。另外,image节点中包含了"id","name","width","height"等等属性节点,我们可以通过"name"属性节点找到对应的图像名称。

e42e2d4067292e6c3646c90de59be6b8.png

3. 上代码

#-*-coding:utf-8-*-
from xml.dom.minidom import parse  # 导入dom相应的模块
import cv2  # 用于图像的显示
import os
import numpy as np


def parsingLabel(xml_path):
    """
    parsing the cvat xml file
    :return:
    """
    # 一些参数的设置
    annotation_labels = []
    annotation_label_dicts = {
            "left_1":0,
            "left_2":1,
            "left_3":2,
            "right_1":3,
            "right_2":4,
            "right_3":5
        }
    annotation_label_colors = {
            "left_1":(255, 0, 0),
            "left_2":(0, 255, 0),
            "left_3":(0, 0, 255),
            "right_1":(125, 125, 125),
            "right_2":(125, 200, 200),
            "right_3":(200, 100, 200)
        }
    img_dir = "/home/cjs/Downloads/data"  # 设置加载的图像路径

    # 获取dom树
    domTree = parse(xml_path)  
    rootNode = domTree.documentElement  # 获取文档根元素
    # print(rootNode.nodeName)
    # 根据名称获取version节点
    version = rootNode.getElementsByTagName('version')[0]  # 注意返回值是nodelist
    # 需要注意的是,xml中每一个元素都要看成一个节点,因此想得到节点的值,需要通过childNodes属性得到
    # 子节点,然后通过nodeValue得到其节点值。
    print("the version of the cvat is {}".format(version.childNodes[0].nodeValue))
    
    # 获取meta节点(我们这里只有一个meta节点,因此取nodelist的第0个值)
    meta = rootNode.getElementsByTagName("meta")[0]
    task = meta.getElementsByTagName("task")[0]  # 获取task子节点
    # 获取所有的label
    task_labels = task.getElementsByTagName("labels")[0].getElementsByTagName("label")
    for task_label in task_labels:
        task_label_one = task_label.getElementsByTagName("name")[0]
        task_label_one_value = task_label_one.childNodes[0].nodeValue
        # print(task_label_one_value)
        annotation_labels.append(task_label_one_value)

    # 解析所有的image标注结果
    img_labels = rootNode.getElementsByTagName("image")
    for img_label in img_labels:
        # 获取并加载原始图像,读者可以自己照一张1280*1080大小的图片进行测试
        img_label_name = img_label.getAttribute("name").split("/")[-1]
        img_path = os.path.join(img_dir, img_label_name)
        img = cv2.imread(img_path, -1)
        img_width = int(float(img_label.getAttribute("width").strip()))
        img_height = int(float(img_label.getAttribute("height").strip()))
        # 获取所有image标注的车道线结果elements的值
        img_label_totals = img_label.getElementsByTagName("polyline")
        # 对所有标注结果进行转换
        for img_label_one in img_label_totals:
            label_type_name = img_label_one.getAttribute("label")
            label_type_index = annotation_label_dicts[label_type_name]
            label_points = img_label_one.getAttribute("points")
            label_points = label_points.strip().split(';')
            tmp_line_pts = [label_type_name]
            for ii in range(len(label_points)):
                label_point = label_points[ii]
                label_point = label_point.split(",")
                pt_x = int(float(label_point[0]))
                pt_x = np.clip(pt_x, 0, img_width-1)
                pt_y = int(float(label_point[1]))
                pt_y = np.clip(pt_y, 0, img_height-1)
                cv2.circle(img, (pt_x, pt_y), 20, annotation_label_colors[label_type_name], -1)
                tmp_line_pts.append([pt_x, pt_y])
            
        print("finished one label converting named {}".format(img_path))
        cv2.imshow("img", img)
        cv2.waitKey(0)

if __name__ == "__main__":
    parsingLabel("./annotations.xml")

运行脚本结果如下图所示,各个车道线分别由不同的点集组成。

c178759f278fac16cc6483124db801a8.png

总结

DOM将XML看成一个节点,节点类型包括元素节点,文本节点等,解析过程就是利用element类的各种属性和方法来得到想要的值的过程。

码字不易,觉得不错的看官就点个赞再走吧~

参考文献:

  1. xml dom课程,w3school
  2. xml中element的属性和方法
  3. cvat图像标注系统
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值