VOC数据格式与YOLO数据格式

因为早期的一些YOLO版本会考虑使用VOC数据,但是VOC数据格式同YOLO网络输入的数据格式是不一致的,但是又没有像COCO数据那样的预处理库,因此就涉及到需要将VOC格式转成YOLO格式。首先先看一下VOC数据格式,保存在Annotations文件夹下,以xml文件形式保存。下面的部分展示了某一张图像的注释,其中需要关注的内容包括filename、size、name、difficult以及bndbox中的内容。其中name表示目标所属类别,bndbox表示图像的长宽,difficult主要表示目标是否较难发现,具体可以参考下面的一段英文。

  • difficult:an object marked as difficult’ indicates that the object is considered difficult to recognize, for example an object which is clearly visible but unidentifiable without substantial use of context. Objects marked as difficult are currently ignored in the evaluation of the challenge.
<filename>2007_000027.jpg</filename>
	<source>
		<database>The VOC2007 Database</database>
		<annotation>PASCAL VOC2007</annotation>
		<image>flickr</image>
	</source>
	<size>
		<width>486</width>
		<height>500</height>
		<depth>3</depth>
	</size>
	<segmented>0</segmented>
	<object>
		<name>person</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>174</xmin>
			<ymin>101</ymin>
			<xmax>349</xmax>
			<ymax>351</ymax>
		</bndbox>

那YOLO所需要的数据是什么样的呢,就像下面这样,四个0-1之间的数值以及最后一个类别序号,其中可以发现person处在第14个(从0开始计数),类别序号转换比较容易,因此主要工作出现在了前面关于真值框位置信息的转换上。

  • names = [“aeroplane”,“bicycle”,“bird”,“boat”,“bottle”,“bus”,“car”,“cat”,“chair”,“cow”,“diningtable”,“dog”,“horse”,“motorbike” “person”,“pottedplant”,“sheep”,“sofa”,“train”,“tvmonitor”]
0.536008 0.450000 0.360082 0.500000 14

YOLO网络由于网格的原因,要求所有长度根据图像的大小归一化到0-1之间的一个数值,而要求出现的四个数字中前两个表示该真值框中心点的位置坐标,后两个分别表示框的宽度和高度。因此我们根据上面的xml中的内容可以来计算。首先是框中心点的位置可以表示为 ( x max ⁡ + x min ⁡ 2 ∗ w i d t h , y max ⁡ + y min ⁡ 2 ∗ h e i g h t ) (\frac{x_{\max}+x_{\min}}{2*width},\frac{y_{\max}+y_{\min}}{2*height}) (2widthxmax+xmin,2heightymax+ymin),特别的,因为考虑到从0计数,每个位置上的值还需要减一,因此就有(174-1+349-1)/(2*486 )= 0.536,(351-1+101-1)/(2*500)=0.45,刚好是YOLO的结果,后两个值也基本一直,可以通过(xmax-xmin)/width和(ymax-ymin)/height获得,即计算(349-174) / 486 = 0.360082和(351-101) / 500 = 0.5。

在这里插入图片描述

具体实现过程参考下述代码,当然值得注意的是,这种YOLO格式处理方式并不唯一,有些网络依然使用左上角坐标及右下角坐标的原始表示方式,但所有方法都需要将数值归一化到0-1之间。

def voc2yolo(xml_file: str) -> None:
    """Convert VOC to YOLO
    Args:
        xml_file: str
    """
    with open(f"{config.XML_DIR}/{xml_file}") as in_file:
        tree = ElementTree.parse(in_file)
        size = tree.getroot().find("size")
        height, width = map(int, [size.find("height").text, size.find("width").text])

    class_exists = False
    for obj in tree.findall("object"):
        name = obj.find("name").text
        if name in config.names:
            class_exists = True

    if class_exists:
        with open(f"{config.LABEL_DIR}/{xml_file[:-4]}.txt", "w") as out_file:
            for obj in tree.findall("object"):
                difficult = obj.find("difficult").text
                if int(difficult) == 1:
                    continue
                xml_box = obj.find("bndbox")

                x_min = float(xml_box.find("xmin").text)
                y_min = float(xml_box.find("ymin").text)

                x_max = float(xml_box.find("xmax").text)
                y_max = float(xml_box.find("ymax").text)

                # according to darknet annotation
                box_x_center = (x_min + x_max) / 2.0 - 1
                box_y_center = (y_min + y_max) / 2.0 - 1

                box_w = x_max - x_min
                box_h = y_max - y_min

                box_x = box_x_center * 1.0 / width
                box_w = box_w * 1.0 / width

                box_y = box_y_center * 1.0 / height
                box_h = box_h * 1.0 / height

                b = [box_x, box_y, box_w, box_h]

                cls_id = config.names.index(obj.find("name").text)
                out_file.write(" ".join([str(f"{i:.6f}") for i in b]) +" " + str(cls_id) + "\n")
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值