主要内容

根据地面真实情况评估和可视化车道边界检测

这个例子展示了如何评估车道边界检测的性能与已知的地面真值。在本例中,您将通过计算拟合度度量来描述每帧车道边界检测算法的性能。此度量可用于查明、可视化和理解底层算法中的故障模式。

概述

随着人们对基于视觉的自动驾驶问题解决方案越来越感兴趣,能够评估和验证检测算法的准确万博 尤文图斯性变得非常重要。在具有多个参数的检测算法中,验证精度尤其重要,这些参数可以调整以获得满足预定义质量要求的结果。本例将介绍一个这样的工作流,其中可以测量车道边界的精度级别。该工作流程有助于在每帧的基础上确定这些算法中的故障模式,并描述其总体性能。此工作流还可以帮助您直观和定量地了解算法的性能。然后,您可以使用这种理解来调整底层算法,以提高其性能。

加载地面真实数据

本例中使用的数据集是一辆行驶在街道上的车辆上的前置摄像头的视频文件。车道边界的地面真相已经用地面真相标签应用程序在视频上手动标记,使用线ROI标记为“lane boundary”。这个视频是8秒,或250帧长。它有三个十字路口,几辆车(停着和移动着),和车道边界(双线,单线和虚线)。为您自己的视频创建一个地面真线边界数据集,您可以使用地面实况贴标签机应用程序。

%加载MAT文件与地面真实数据。加载=加载(“加州理工学院科尔多瓦1号”和“汽车地面真相.mat”);

加载Structure包含三个字段:

  1. 地面数据,有两栏的时间表:LaneBoundaries车辆LaneBoundaries包含自我通道边界的地面真值点(左和右),表示为XY点的单元阵列,形成一条多边形线。车辆包含摄影机视图中车辆的地面真实边界框,表示为[x,y,宽度,高度]的M×4阵列。

  2. 传感器A.monoCamera对象,该对象具有安装在车辆上的已校准摄像头的属性。此对象可用于估计车辆与其前方对象之间的真实距离。

  3. videoName,一个字符数组,包含存储帧的视频文件名。

从该结构中的数据中,使用录像机在帧之间循环。帧录像机对象使用一个helperMonoSensor对象使用存储在中的摄影机设置检测视频帧中的车道和对象传感器.一个时间表变量存储在gtdata保存地面真实数据。此变量包含用于以后分析的每帧数据。

%创建VideoReader对象以读取视频帧。videoName = loaded.videoName;fileReader = VideoReader (videoName);%地面实况数据按时间表组织。gtdata=加载的地面数据;%显示地面真实数据的前几行。总目(gtdata)
车辆LaneBoundaries ans = 8 x2时间表时间  ____________ ____________ ______________ 0秒{6 x4双}}{2 x1细胞0.033333秒{6 x4双}}{2 x1细胞0.066667秒{6 x4双}}{2 x1细胞0.1秒{6 x4双}}{2 x1细胞0.13333秒{6 x4双}}{2 x1细胞0.16667秒{6 x4双}}{2 x1细胞0.2秒{6 x4双}}{2 x1细胞0.23333秒{5 x4双}{2 x1细胞}

gtdata时间表有以下几列车辆LaneBoundaries.在每个时间戳中车辆列包含车辆边界框和LaneBoundaries列包含左右车道边界点的两元素单元数组。

首先,为图像帧可视化加载的地面真实数据。

阅读视频的第一帧。帧= readFrame (fileReader);%提取第一帧中的所有车道点。lanePoints = gtdata.LaneBoundaries {1};%提取第一帧中的车辆边界框。VehicleBox=gtdata.Vehicles{1};%叠加右车道点和车辆包围框。frame=insertMarker(frame,lanePoints{2},“X”);= insertObjectAnnotation帧(帧,“矩形”,车辆箱,“车辆”);%在第一帧显示地面真实数据。图imshow(框架)

车道边界检测算法

使用视频帧和monoCamera参数,可以自动估计车道边界的位置。插图,过程框架的方法helperMonoSensor类用于检测车道边界(如parabolicLaneBoundary物体)和车辆(如[x, y,宽度,高度]包围盒矩阵)。就本例而言,这是车道边界检测“待测算法”。您可以使用相同的模式来评估自定义车道边界检测算法,其中过程框架替换为自定义检测功能。车辆坐标中的地面真值点也存储在兰尼森维切科德酒店gtdata时间表。这样,它们就可以在稍后的鸟瞰图中显示出来。首先,配置helperMonoSensor对象的传感器.的helperMonoSensor类集合运行车道边界检测算法所需的所有必要步骤。

%设置monoSensorHelper处理视频。monoCameraSensor = loaded.sensor;monoSensorHelper = helperMonoSensor (monoCameraSensor);%为测量创建具有相同时间向量的新时间表。测量=时间表(gtdata.Time);为保持车道边界和车辆数据设置时间表列。numFrames=floor(fileReader.FrameRate*fileReader.Duration);measurements.LaneBoundaries=cell(numFrames,2);measurements.VehicleDetections=cell(numFrames,1);gtdata.LanesInVehicleCoord=cell(numFrames,2);%将视频回放到t=0,并创建一个帧索引以保持当前状态%框架。fileReader.CurrentTime=0;frameIndex=0;%循环播放视频文件,直到没有新的帧。虽然hasFrame(文件阅读器)frameIndex=frameIndex+1;frame=readFrame(文件阅读器);%使用processFrame方法计算检测。%这个方法可以被一个自定义的车道检测方法代替。detections = processFrame(monoSensorHelper,帧);%存储估计的车道边界和车辆检测。measures.LaneBoundaries{frameIndex}=[detections.leftegobundary]...detections.rightEgoBoundary];Measures.VehicleDetections{frameIndex}=detections.vehicleBoxes;%为便于比较,请将地面真实车道点转换为%车辆坐标系。gtPointsThisFrame = gtdata.LaneBoundaries {frameIndex};车辆点数= cell(1, numel(gtpointthisframe));ii=1:numel(gtPointsThisFrame)车辆点{ii}=imageToVehicle(单摄像机传感器,gtPointsThisFrame{ii});结束%存储以车辆坐标表示的地面真值点。gtdata.LanesInVehicleCoord{frameIndex}=车辆点;结束

现在,您已经使用车道检测算法处理了视频,请验证地面真实点是否正确转换为车辆坐标系兰尼森维切科德酒店gtdata时刻表包含第一帧的车辆坐标。在鸟瞰视图的第一帧上绘制这些地面真实点。

%倒带视频到t = 0。fileReader。CurrentTime = 0;阅读视频的第一帧。帧= readFrame (fileReader);birdsEyeImage = transformImage (monoSensorHelper。BirdsEyeConfig,框架);%在鸟瞰图中提取第一帧右车道点。firstFrameVehiclePoints = gtdata.LanesInVehicleCoord {1};pointsInBEV = vehicleToImage (monoSensorHelper。BirdsEyeConfig, firstFrameVehiclePoints {2});%在框架上叠加点。birdsEyeImage=插入标记(birdsEyeImage,pointsInBEV,“X”“大小”6);在鸟瞰视图中显示变换后的点。图imshow (birdsEyeImage)

测量检测误差

计算车道边界检测中的误差是验证几个下游子系统性能的关键步骤。这些子系统包括车道偏离警告系统,其取决于车道检测子系统的精度。

您可以通过测量拟合优度来估计精度。通过计算地面真值点和估计值,您现在可以对它们进行比较和可视化,以了解检测算法的性能。

拟合优度可以在每帧级别或整个视频中测量。每帧统计信息提供了有关特定场景的详细信息,例如检测算法性能可能不同的弯道行为。全局统计信息提供了漏检车道数的总体估计在…上

使用evaluateLaneBoundaries函数返回全局检测统计信息和作业数组中。该阵列将估计的车道边界目标与相应的地面真值点进行匹配。

中的阈值参数evaluateLaneBoundaries函数表示车辆坐标中的最大横向距离,以与估计的抛物线车道边界匹配。

阈值=0.25;%以米为单位[numMatches, numMisses, numFalsePositives, assignments] =...评估车道边界(测量值、车道基础、,...gtdata。LanesInVehicleCoord,...阈值)(['匹配数:'num2str (numMatches)]);disp (['未命中次数:',num2str(nummiss)];disp(['误报数:',num2str(numFalsePositives)];
匹配次数:409失败次数:36误报次数:27

使用作业数组,您可以计算有用的每车道度量,如估计值和地面真值点之间的平均横向距离。这些指标表明算法的执行情况如何。要计算平均距离度量值,请使用helper函数助手计算机统计,它在本例的最后定义。

averageDistance=helperComputeLaneStatistics(测量值。LaneBoundaries,...gtdata。LanesInVehicleCoord,...作业,平均分);%绘制估计值与地面真实值之间的平均距离。图阻止(gtdata。时间,averageDistance) title(“估计值与地面真实值之间的平均距离”网格)在…上伊拉贝尔(“米距离”)传奇(的左边界“右边界”

可视化和回顾地面真相和你的算法之间的差异

现在,您已经对车道检测算法的准确性有了定量的了解。但是,仅根据上一节中的绘图不可能完全理解故障。因此,查看视频并在每帧的基础上可视化错误对于识别特定故障模式至关重要,而这些故障模式可以改善通过改进算法得到验证。

您可以使用Ground Truth Labeler应用程序作为可视化工具来查看包含地面真实数据和估计车道边界的视频。的驱动连接器类提供了将自定义可视化工具附加到Ground Truth label的接口。

使用parabolicLaneBoundary阵列和地面真实数据,计算估计点的车辆坐标位置。的parabolicLaneBoundary数组定义一条线,地面真值数据在道路上标出离散点。的helperGetCorrespondingPoints函数估计与车辆相同Y轴距离对应的估计线上的点。此帮助器函数在示例末尾定义。

地面真实点和估计点现在包含在新的时间表在地面真理标签应用程序中可视化。创造groundTruth对象然后存储为MAT文件。

%使用单相机计算估计的点位置。[estVehiclePoints, estImagePoints] = helpergetcordingpoints (monocamerassensor,...测量方法。LaneBoundaries,...gtdata。LanesInVehicleCoord,...任务);%将估计车道添加到测量时间表中。测量。EstimatedLanes = estImagePoints;测量。LanesInVehicleCoord = estVehiclePoints;%创建一个新的时间表,包含可视化所需的所有变量。名称= {“LanePoints”“DetectedLanePoints”};类型= labelType ({“行”“行”});= table(名称,类型,“变化无常”, {“名字”“类型”});(gtdata visualizeInFrame =时间表。时间,...gtdata.LaneBoundaries,...测量。估算平面,...“变化无常”、名称);%创建groundTruth对象。数据源=groundTruthDataSource(videoName);dataToVisualize=groundTruth(数据源、labelDefs、VisualizationInframe);%将上一节的所有结果保存在distanceData.mat中的%临时文件夹。dataToLoad=[tempdir“distanceData.mat”];保存(数据加载),“单传感器辅助器”“视频名称”“测量”“gtdata”“averageDistance”);

helperCustomUI类使用从MAT文件加载的数据创建绘图和鸟瞰视图,就像刚才创建的一样helperCustomUI类通过助手连接器类将视频与平均距离图和鸟瞰图同步。此同步使您能够以分析方式和视觉方式分析每帧结果。

按照以下步骤将结果可视化,如下图所示:

  • 转到临时目录,其中distanceData.mat保存并打开地面真理贴标机应用程序。然后启动地面真理贴标机应用程序,连接器手柄指定为助手连接器使用以下命令:

>> origdir = pwd;>> cd(tempdir) >> groundTruthLabeler(dataSource,“连接器argethandle”,@helperUIConnector);
  • 导入标签:在图像坐标中可视化地面真实车道标记和估计车道。从应用程序toolstrip中,单击导入标签。然后选择从工作空间选项并加载数据可视化将真相导入应用程序。应用程序主窗口现在包含车道标记的注释。

现在您可以浏览视频并检查错误。要返回到原始目录,可以输入:

> > cd (origdir)

从这个可视化中,您可以对算法和地面真实数据的质量做出几个推论。

  • 左车道精度始终低于右车道精度。在鸟瞰视图显示中仔细观察后,地面真实数据被标记为双线的外边界,而估计的车道边界通常位于双线标记的中心。这表明左车道估计与事实上,这比数字描述的更准确,而且一个明确定义的地面真相数据集对于此类观测至关重要。

  • 2.3秒和4秒左右的检测间隔对应于道路上有人行横道的十字路口。这表明该算法在存在人行横道的情况下性能不佳。

  • 大约6.8秒,当车辆接近第三个十字路口时,ego车道分流为左车道和直车道。在这里,算法也无法准确捕获左车道,地面真实数据也不包含五帧的任何信息。

结论

这个例子展示了如何测量精度的车道边界检测算法和可视化它使用地面实况贴标签机你可以将这个概念扩展到其他自定义算法,以简化这些工作流程,并扩展应用程序的功能,用于自定义测量。

万博1manbetx辅助功能

助手计算机统计

此辅助函数计算车道边界检测与地面真值点相比的统计数据。它包含一个函数句柄,可用于概括需要计算的统计数据,包括@mean和@median。

作用stat = helperComputeLaneStatistics(estModels, gtPoints, assignments, fcnHandle) numFrames = length(estModels);%默认情况下,进行左右估计NaN以表示缺少%的数据。stat=NaN*one(numFrames,2);frameInd=1:numFrames%默认情况下进行左估计和右估计。stat(frameInd,:)=NaN*one(2,1);idx = 1:长度(estModels {frameInd})%忽略假阳性分配。如果赋值{frameInd}(idx)==0持续结束%estModelInFrame中的第k个边界与第k个匹配%通过gtPointsInFrame中的赋值索引的元素。thisModel=estModels{frameInd}(idx);thisGT=gtPoints{frameInd}{assignments{frameInd}(idx)};thisGTModel=driving.internal.piecewiseLinearBoundary(thisGT);如果平均值(thisGTModel.Points(:,2))>0%左车道xPoints = thisGTModel.Points (: 1);yDist = 0(大小(xPoints));索引=1:numel(xPoints)gtYPoints=thisGTModel.computeBoundaryModel(xPoints(index));testYPoints=thisModel.computeBoundaryModel(xPoints(index));yDist(index)=abs(testYPoints gtYPoints);结束stat(frameInd, 1) = fcnHandle(yDist); / /删除帧其他的%右车道xPoints = thisGTModel.Points (: 1);yDist = 0(大小(xPoints));索引=1:numel(xPoints)gtYPoints=thisGTModel.computeBoundaryModel(xPoints(index));testYPoints=thisModel.computeBoundaryModel(xPoints(index));yDist(index)=abs(testYPoints gtYPoints);结束stat(frameInd, 2) = fcnHandle(yDist); / /删除帧结束结束结束结束

helperGetCorrespondingPoints

这个辅助函数在x轴位置创建与地面真实点匹配的车辆和图像坐标点。

作用[vehiclePoints, imagePoints] = helpergetcordingpoints (monocamerassensor, estModels, gtPoints, assignments) numFrames = length(estModels);imagePoints = cell(numFrames, 1);车辆点数= cell(numFrames, 1);frameInd=1:numFrames如果isempty(赋值{frameInd})imagePointsInFrame=[];vehiclePointsInFrame=[];其他的estModelInFrame=estModels{frameInd};gtPointsInFrame=gtPoints{frameInd};imagePointsInFrame=单元格(长度(estModelInFrame),1);vehiclePointsInFrame=单元格(长度(estModelInFrame),1);idx=1:长度(estModelInFrame)%忽略假阳性分配。如果赋值{frameInd}(idx)==0图像点帧{idx}=[NaN-NaN];持续结束%estModelInFrame中的第k个边界与第k个匹配%通过gtPointsInFrame中的赋值索引的元素。这种模式下= estModelInFrame (idx);thisGT = gtPointsInFrame{作业{frameInd} (idx)};xPoints = thisGT(:, 1); / /点击这里yPoints = thisModel.computeBoundaryModel (xPoints);vehiclePointsInFrame{idx} = [xPoints, yPoints];imagePointsInFrame{idx} = vehicleToImage(monocamerassensor, [xPoints yPoints]);结束结束vehiclePoints{frameInd}=vehiclePointsInFrame;imagePoints{frameInd}=imagePointsInFrame;%使imagePoints[]而不是{}符合groundTruth对象。如果isempty(imagePoints{frameInd})imagePoints{frameInd}=[];结束如果isempty(车辆点{frameInd})车辆点{frameInd}=[];结束结束结束

另请参阅

应用程序

功能

对象

相关话题