目标检测中统计xml文件中目标的属性并绘制直方图

在目标检测中,我们通常需要分析数据的属性,例如各类目标的个数、大小分布等。本文以统计斜框检测中的角度分布、目标数量为例。详细讲解怎么读取xml文件并绘制直方图。
首先是导入各种库,添加几个变量,如文件夹、存储角度和目标数量的列表:

import os
import xml.etree.ElementTree as ET
import math
import matplotlib.pyplot as plt
import numpy as np

xmls_dir = 'E:/Projects/xmls_origin'
angle_list = []   # 存储角度的列表
object_list = []  # 存储目标(正框、斜框)的列表

接下来是读取xml的函数:

# 读取xml文件,存储其中的angle值
def read_xml(xml_file):
    """
    读取xml文件,找到角度并存储进列表
    :param xml_file:xml文件的路径
    :return:
    """
    tree = ET.parse(xml_file)
    objs = tree.findall('object')
    for ix, obj in enumerate(objs):
        robndbox = obj.find('robndbox')
        if robndbox is not None:
            object_list.append('robndbox')  # 斜框的数量+1
            angle = float(robndbox.find('angle').text)
            angle = angle * 180 / math.pi   # 弧度转化为角度
            angle_list.append(angle)        # 添加进列表
        bndbox =obj.find('bndbox')
        if bndbox is not None:
            object_list.append('bndbox')    # 正框的数量+1

同时,我们来看一下我的xml文件长啥样,可以看到,里面包含两种目标,一种是robndbox,一种是bndbox,其中robndbox里头包含有angle值。我要做的就是统计每种目标的个数和angle的分布。如果要统计别的也是类似的。

<annotation verified="no">
  <folder>ship_data</folder>
  <filename>1</filename>
  <path>D:\data\1.jpg</path>
  <source>
    <database>Unknown</database>
  </source>
  <size>
    <width>600</width>
    <height>600</height>
    <depth>3</depth>
  </size>
  <segmented>0</segmented>
  <object>
    <type>robndbox</type>
    <name>ship</name>
    <pose>Unspecified</pose>
    <truncated>0</truncated>
    <difficult>0</difficult>
    <robndbox>
      <cx>148.3626</cx>
      <cy>534.0</cy>
      <w>41.0</w>
      <h>12.0</h>
      <angle>2.301593</angle>
    </robndbox>
  </object>
  <object>
    <type>bndbox</type>
    <name>ship</name>
    <pose>Unspecified</pose>
    <truncated>1</truncated>
    <difficult>0</difficult>
    <bndbox>
      <xmin>259</xmin>
      <ymin>568</ymin>
      <xmax>298</xmax>
      <ymax>600</ymax>
    </bndbox>
  </object>
</annotation>

然后是绘制直方图的函数,在直方图的绘制中,添加了x/y轴的标签及刻度。

def plt_hist(angle_list,robndbox_num,bndbox_num):
    # 绘制直方图
    plt.hist(x=angle_list,  # 指定绘图数据
    bins = 30,  # 指定直方图中条块的个数
    color = 'steelblue',  # 指定直方图的填充色
    edgecolor = 'black')  # 指定直方图的边框色
    # 添加x轴和y轴标签
    plt.xlabel('Angle ( ro: %d,bnd: %d )'%(robndbox_num,bndbox_num))
    plt.ylabel('Object_num ( all:%d )'%(robndbox_num + bndbox_num))
    # 添加标题
    plt.title('xml-angle')
    # 设置横坐标刻度和起始
    my_xticks = np.arange(-90,95,15)
    plt.xticks(my_xticks)
    # 显示图形
    plt.show()

最后是主函数:

if __name__ == '__main__':
    xmls = os.listdir(xmls_dir)
    for xml in xmls:
        read_xml(os.path.join(xmls_dir,xml)) # 读取一遍xml文件,存储角度值
    # 正框和斜框的数量
    robndbox_num = object_list.count('robndbox')
    bndbox_num = object_list.count('bndbox')
    plt_hist(angle_list,robndbox_num,bndbox_num)

下面就是绘制出来的直方图,显示了角度的分布,横轴是角度值,纵轴是各个角度对应的目标个数。并且在横轴和纵轴上显示了目标的总个数和正框、斜框目标分别的数量。
绘制出来的直方图
完整脚本如下,运行环境为 python3.6+:

# *_* coding : UTF-8 *_*
# 开发人员   :csu·pan-_-||
# 开发时间   :2020/11/4 9:16
# 文件名称   :hist_angle.py
# 开发工具   :PyCharm
# 功能描述   :计算roLableImg标注的xml文件中angle的直方图

import os
import xml.etree.ElementTree as ET
import math
import matplotlib.pyplot as plt
import numpy as np

xmls_dir = 'E:/Projects/xmls_origin'
angle_list = []   # 存储角度的列表
object_list = []  # 存储目标(正框、斜框)的列表

# 读取xml文件,存储其中的angle值
def read_xml(xml_file):
    """
    读取xml文件,找到角度并存储进列表
    :param xml_file:xml文件的路径
    :return:
    """
    tree = ET.parse(xml_file)
    objs = tree.findall('object')
    for ix, obj in enumerate(objs):
        robndbox = obj.find('robndbox')
        if robndbox is not None:
            object_list.append('robndbox')  # 斜框的数量+1
            angle = float(robndbox.find('angle').text)
            angle = angle * 180 / math.pi   # 弧度转化为角度
            angle_list.append(angle)        # 添加进列表
        bndbox =obj.find('bndbox')
        if bndbox is not None:
            object_list.append('bndbox')    # 正框的数量+1

def plt_hist(angle_list,robndbox_num,bndbox_num):
    # 绘制直方图
    plt.hist(x=angle_list,  # 指定绘图数据
    bins = 30,  # 指定直方图中条块的个数
    color = 'steelblue',  # 指定直方图的填充色
    edgecolor = 'black')  # 指定直方图的边框色
    # 添加x轴和y轴标签
    plt.xlabel('Angle ( ro: %d,bnd: %d )'%(robndbox_num,bndbox_num))
    plt.ylabel('Object_num ( all:%d )'%(robndbox_num + bndbox_num))
    # 添加标题
    plt.title('xml-angle')
    # 设置横坐标刻度和起始
    my_xticks = np.arange(-90,95,15)
    plt.xticks(my_xticks)
    # 显示图形
    plt.show()

if __name__ == '__main__':
    xmls = os.listdir(xmls_dir)
    for xml in xmls:
        read_xml(os.path.join(xmls_dir,xml)) # 读取一遍xml文件,存储角度值
    # 正框和斜框的数量
    robndbox_num = object_list.count('robndbox')
    bndbox_num = object_list.count('bndbox')
    plt_hist(angle_list,robndbox_num,bndbox_num)

总结:之前觉得操作xml文件是一件比较痛苦的事,做了几次之后,反倒xml文件的组织形式很清晰(难道这就是所谓的"悟"?)。这个脚本没花多少时间就写出来了,希望给后面有需要的朋友一点帮助。毕竟互联网精神是开放、平等、协作、快速、分享(大家都是面向百度、谷歌、CSDN、Github编程的,O(∩_∩)O哈哈~)

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值