Pascal VOC XML 2 YoLo txt format

less than 1 minute read

Published:

0.结论

在将Pascal VOC的Xml格式转为YoLo的txt格式时,计算中心点坐标需要减去1。 具体解释见2.2 追根溯源

1. 问题

在对Pascal VOC xml格式的数据转为yolo的txt格式数据时,可能会看到以下两种代码:

# https://christianbernecker.medium.com/convert-bounding-boxes-from-coco-to-pascal-voc-to-yolo-and-back-660dc6178742

def pascal_voc_to_yolo(x1, y1, x2, y2, image_w, image_h):
    return [((x2 + x1)/(2*image_w)), ((y2 + y1)/(2*image_h)), (x2 - x1)/image_w, (y2 - y1)/image_h]


# https://cvmart.net/document 这里的数据预处理
def convert(size, box):
    dw = 1./(size[0])
    dh = 1./(size[1])
    x = (box[0] + box[1])/2.0 - 1  # 有的减去1,有的不减
    y = (box[2] + box[3])/2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x*dw
    w = w*dw
    y = y*dh
    h = h*dh
    return (x, y, w, h)

不难发现,二者的主要区别在于计算中心点时,是否要减去1

2. 探索问题

2.1 自然的想法

假设有一个$28\times 28$的图像,其中存在一个bounding box的信息为: \(x_1=1,x_2=7,y_1=2,y_2=7\)

  • 人工计算的话,可知:对于x方向,中心点坐标为4,而对于y方向,中心点坐标为4.5。
  • 使用程序计算(未除以图像的高和宽时的中心点):
    • 不减1的中心点:x:(1+7)/2.0=4.0; y:(2+7)/2.0=4.5;
    • 减去1的中心点:x:(1+7)/2.0-1=3.0; y:(2+7)/2.0-1=3.5;
  • 则除以图像的高宽后真正的中心点坐标是:
    • 不减1的中心点:(x,y)=(0.14285,0.16071)
    • 减去1的中心点:(x,y)=(0.10714,0.125)
  • 这样看起来似乎没有什么问题。

2.2 追根溯源

中心点坐标减去1的来源是这里:darknet/scripts/voc_label.py

根据ultralytics-yolo-format可知:

转换后的yolo的bounding box的xyhw值的范围是[0,1]

issue中也有一些讨论:What is the reason for changing code in the scripts/voc_label.py? #341,大意如下:

图像的像素值可以是1~width,也可以是0~width-1,

  1. 举例来说:假设width=5,
    • 若坐标是从1开始,则(1+5)/2-1=2;
    • 若坐标是从0开始,则(0+4)/2=2;
    • 很明显,基于1的坐标系统,如果不减去1的话会不一致
  2. 从转换后yolo的bounding box的xyhw的值的范围是[0,1]考虑:
    • 对于从1开始的像素,转换后的最小值是(1+1)/2/width,永远不会为0
    • 对于从0开始的像素,转换后的最小值是(0+0)/2/width,可以满足[0,1]的范围。
  3. 以上,减去1是一个正确的选择