如何制作自己的TuSimple格式的车道线标注文件

以往的车道线图像检测大多是基于目标分割的,标注起来自然也是比较麻烦,基于曲线多项式拟合的车道线检测可以说是另辟蹊径,避开使用费劲低效的图像分割,而是基于打点标记车道线再使用模型基于这些点去拟合曲线,这样的话,模型推理和数据标注都非常高效而且像LSTR这样的模型加入了Transformer增强了对空间位置的学习后拟合十分精准能力强大,一定程度上能较好地解决遮挡问题,这些都是基于图像分割的车道线检测技术所不能及的。

TuSimple车道线数据集GitHub - TuSimple/tusimple-benchmark: Download Datasets and Ground Truths: https://github.com/TuSimple/tusimple-benchmark/issues/3就是基于打点标记的,参见https://github.com/TuSimple/tusimple-benchmark/tree/master/doc/lane_detection

其标记格式非常简单,标记数据json文件里有一个或多个{}包纳的json串,每个json串格式记录一张图片的标注数据,json串的格式如下:

   {
      'raw_file': str. the frame file path in a clip.
      'lanes': list. A list of lanes. For each list of one lane, the elements are width values on image.
      'h_samples': list. A list of height values corresponding to the 'lanes', which means len(h_samples) == len(lanes[i])
    }

raw_file是图片文件的路径(相对路径还是绝对路径都可以,取决于你的读取数据集的程序怎么写)

h_samples列表里的数据是所有车道线的纵坐标的集合,即图像坐标系的高度方向的坐标值,所有车道线共用这些纵坐标值,你可以想象为在图像上纵轴方向等距离画了一条条横线,每条横线和每条车道线的相交点就是该车道线的一个标记点。

lanes里有多个列表,每一个列表里的数据是一条车道线的横坐标集合。示例:

{
  "lanes": [
        [-2, -2, -2, -2, 632, 625, 617, 609, 601, 594, 586, 578, 570, 563, 555, 547, 539, 532, 524, 516, 508, 501, 493, 485, 477, 469, 462, 454, 446, 438, 431, 423, 415, 407, 400, 392, 384, 376, 369, 361, 353, 345, 338, 330, 322, 314, 307, 299],
        [-2, -2, -2, -2, 719, 734, 748, 762, 777, 791, 805, 820, 834, 848, 863, 877, 891, 906, 920, 934, 949, 963, 978, 992, 1006, 1021, 1035, 1049, 1064, 1078, 1092, 1107, 1121, 1135, 1150, 1164, 1178, 1193, 1207, 1221, 1236, 1250, 1265, -2, -2, -2, -2, -2],
        [-2, -2, -2, -2, -2, 532, 503, 474, 445, 416, 387, 358, 329, 300, 271, 241, 212, 183, 154, 125, 96, 67, 38, 9, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
        [-2, -2, -2, 781, 822, 862, 903, 944, 984, 1025, 1066, 1107, 1147, 1188, 1229, 1269, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2]
       ],
  "h_samples": [240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, 590, 600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710],
  "raw_file": "path_to_clip"
}

坐标值为-2的表示图像上该点没有车道线轨迹,那既然没有,为何还需要这个标注点呢?所有车道线上对应位置的横坐标都为-2的显然是作为负样本,对于部分车道线的横坐标不是-2其他车道线对应位置的横坐标为-2的情况,上面说了,可以想象在标记数据时在图像上画了一条条的横线,横线和车道线的交叉点为标注点,这些交叉点的位置实际上没有车道线轨迹(例如白色或黄色涂料)的,横坐标记为-2,有车道线轨迹的则记实际横坐标值。所以上面四条车道线中第一条车道线的第一个实际上存在车道线轨迹的点是(632, 280),第四条车道线的第一个实际上存在车道线轨迹的点是(781,270)。

那怎么标记图像和生成上面这样格式的json文件呢?下载官方数据集的地方https://github.com/TuSimple/tusimple-benchmark/issues/3 并没有明确提供说明,issue里面扒到的信息也比较乱,感觉都不是自己想要的那样。

个人认为,如果你想基于以前图像分割的车道线数据集转换成TuSimple格式,那需要写个脚本读取原来的分割标记数据,根据上面说的对图像高度做等距离划分取多个值,用这些值作为纵坐标值,去分割数据点集里去找每条车道线上纵坐标近似为这些值并且在同一高度的点中横向居中的点加入横坐标集合即可。 如果是从零开始标记,能打点标记的工具用labelme就行,但是怎么保证所有车道线共用相同的等分纵坐标呢?这里需要点处理技巧,可先用labelme在每条车道打少量点(每个点的label值为该车道线的编号)能反映出车道线的曲线轮廓即可,保存成labelem格式的标注数据json文件,然后写代码解析这些json文件读取其中的shapes里的点集,然后使用numpy的polyfit()和poly1d()基于已标记的点拟合出曲线,然后用对纵向取等分坐标值后在曲线上取对应的点的横坐标,然后这些点中超出首末端范围的以及有被遮挡或者根本没有车道线轨迹的做-2处理(这些区域的坐标边界如果没什么规律的话需要由标注人员手工去处理,如果有规律可以在程序里做这些处理):

with open(ann_file, 'r') as f:
        data = json.load(f)
    points = data['shapes']
    
    line1 = []
    line2 = []
    for point in points:
        if point['label'] == 'line1':
            line1.append(point['points'][0])
        else:
            line2.append(point['points'][0])
     ...
     #直线部分可能需要根据实际效果生成加密点加入集合
     ...
     paramL1 = np.polyfit(line1[:, 1], line1[:, 0], 7)
     paramL2 = np.polyfit(line2[:, 1], line2[:, 0], 7)
     poly1 = np.poly1d(paramL1)
     poly2 = np.poly1d(paramL2)
     y = np.arange(770, 1440, 10)
     x1 = poly1(y)
     x2 = poly2(y)
     ...
     #对超出标记范围的或有遮挡的段做-2处理,例如末端处理:
     min_y1 = np.min(line1[:, 1])
     min_y2 = np.min(line2[:, 1])
     x1[y < min_y1] = -2
     x2[y < min_y2] = -2
     x1 = x1.astype(np.int32)
     x2 = x2.astype(np.int32)
     ...
    
     tusimple_dict['h_samples'] = ys.tolist()
     tusimple_dict['lanes'] = [xs1.tolist(), xs2.tolist()]

然后将得到的点的纵坐标和横坐标的集合分别存入h_samples和lanes列表即可。

循环对每一个图片文件做如上处理,结果记录入一个共用的json文件或者每张图片的标注存入一个json文件,将图片和标注文件保存到你自己设计的目录结构下,即完成了TuSimple格式的数据集的生成。

你可能感兴趣的:(深度学习,TuSimple,LSTR,Lane,Detection,车道线检测,深度学习)