主要内容

评估和可视化地面真理的车道边界检测

此示例显示如何评估Lane边界检测对已知地面真理的性能。在此示例中,您将通过计算拟合良好度量来表征基路边界检测算法的性能。该措施可用于针对底层算法的故障模式来定位,可视化和理解故障模式。

概述

随着人们对基于视觉的自动驾驶问题解决方案越来越感兴趣,能够评估和验证检测算法的准确金宝搏官方网站性变得非常重要。在具有多个参数的检测算法中,验证准确性尤其重要,这些参数可以通过调整来达到满足预定义质量要求的结果。本例通过一个这样的工作流程,其中车道边界可以根据其准确性水平进行测量。这个工作流有助于在每帧的基础上确定这些算法的故障模式,以及表征其整体性能。此工作流还可以帮助您直观和定量地理解算法的性能。然后,您可以使用这一理解来调优底层算法,以提高其性能。

地面真实数据

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

%加载与地面真实数据的垫文件加载=负载(“caltech_cordova1_laneAndVehicleGroundTruth.mat”);

加载结构包含三个字段:

  1. 地下田间,两个列的时间表:巷道车辆巷道包含自我巷边界(左右)的地面真相,表示为形成多线的XY点的单元阵列。车辆包含摄像机视图中车辆的地面真实边界框,用[x,y,宽度,高度]的m × 4数组表示。

  2. 传感器, 一种monoCamera具有关于安装在车辆上的校准相机的属性的对象。此目的让您估计车辆与它前面的物体之间的真实距离。

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

从该结构中的数据中,使用VideoReader通过帧循环。的VideoReader物体使用A.helperMonoSensor对象来检测视频帧中的通道和对象,使用存储在中的摄像机设置传感器.一个时间表变量存储在gtdata持有地面真相数据。这个变量包含以后用于分析的逐帧数据。

%创建一个录像机对象以读取视频的帧。VideoName =加载.VideOname;filereader = Videoreader(VideoName);地面事实数据被组织成一个时间表。gtdata = loaded.groundtruthdata;%显示地面真理数据的前几行。头(gtdata)
ans = 8x2时间表时间车道____________________________ 0秒{6x4 double} {2x1 cell} {2x1 cell} 0.066667秒{6x4 double} {2x1 cell} 0.1秒{6x4 double} {2x1 cell}0.13333秒{6x4 double} {2x1 cell} 0.16667 sec {6x4 double} {2x1 cell} 0.2 sec {6x4 double} {2x1 cell} 0.2333秒{5x4 double} {2x1 cell}

gtdata时间表有列车辆巷道.在每个时间戳上车辆列持有一个M-by-4阵列的车辆边界盒和巷道列包含左车道和右车道边界点的二元单元数组。

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

%读取视频的第一帧。帧= readFrame (fileReader);%提取第一帧中的所有车道点。lanepoints = gtdata.laneboundaries {1};%在第一帧中提取车辆边界框。车辆箱= gtdata.vehlicle {1};%叠加右车道点和车辆边界框。Frame = InsertMarker(帧,LanePoints {2},'X');Frame = InsertObjectAnnotation(帧,'长方形',车辆箱,'车辆');%在第一帧显示地面真实数据。图imshow(框架)

运行车道边界检测算法

使用视频帧和monoCamera参数,可以自动估计车道边界的位置。插图,ProcessFrame.方法的方法helperMonoSensor这里使用类来检测车道边界(如parabolicLaneBoundary对象)和车辆(如[x, y,宽度,高度]包围盒矩阵)。在本例中,这是车道边界检测的“测试算法”。您可以使用相同的模式来评估自定义车道边界检测算法,其中ProcessFrame.替换为自定义检测功能。车辆坐标中的地面真实点也存储在LanesInVehicleCoord列的gtdata时间表。这样,它们就可以在稍后的鸟瞰显示中可视化。首先,配置helperMonoSensor对象与之传感器.的helperMonoSensor类组装运行车道边界检测算法所需的所有必要步骤。

%设置monoSensorHelper处理视频。monocameraSensor =加载。Sensor;monosensorhelper = helpermonosensor(单声道血管传感器);%创建新的时间表,使用相同的时间向量进行度量。测量=时间表(gtdata.time);%设置用于保持车道边界和车辆数据的时间表列。numframes = floor(filereader.framerate * filereader.duration);测量.LaneBoundaries = cell(numframes,2);测量。vehicledetections = cell(numframes,1);gtdata.lanesinvehiclecoord = cell(numframes,2);%回放视频到t = 0,并创建一个帧索引保持当前%框架。filereader.currenttime = 0;FrameIndex = 0;%循环通过videfile直到没有新的帧。尽管hasFrame(fileReader) frameIndex = frameIndex+1;帧= readFrame (fileReader);%使用ProcessFrame方法计算检测。%可以用自定义车道检测方法替换此方法。检测= ProcessFrame(MonosensorHelper,Frame);%存储估计的车道边界和车辆检测。测量。(detections.leftEgoBoundary LaneBoundaries {frameIndex} =...detections.rightEgoBoundary];测量。VehicleDetections {frameIndex} = detections.vehicleBoxes;为便于比较,将地面真实巷点转换为%车辆坐标系。gtPointsThisFrame = gtdata.LaneBoundaries {frameIndex};vehicle = cell(1, numel(gtPointsThisFrame));ii = 1:numel(gtpointtsthisframe) vehiclePoints{ii} = imageToVehicle(monocamersensor, gtpointtsthisframe {ii});结束%储存在车辆坐标中表达的地面真相。gtdata。LanesInVehicleCoord {frameIndex} = vehiclePoints;结束

既然您已经使用车道检测算法处理了视频,请验证接地真理点是否正确转换为车辆坐标系。第一次进入LanesInVehicleCoord列的gtdata时间表包含第一帧的车辆坐标。在鸟瞰图中的第一帧上绘制这些地面真理点。

%把视频倒回t = 0。filereader.currenttime = 0;%读取视频的第一帧。帧= readFrame (fileReader);BirdseyeImage = Transportimage(Monosensorhelper.birdseyeconfig,框架);在鸟瞰视图中提取第一帧的右车道点。firstFrameVehiclePoints = gtdata.LanesInVehicleCoord {1};pointsInBEV = vehicleToImage (monoSensorHelper。BirdsEyeConfig, firstFrameVehiclePoints {2});%在框架上叠加点。birdsEyeImage = insertMarker(birdsEyeImage, pointsInBEV,'X''尺寸'6);%在鸟瞰图中显示变换的点。图imshow(birdseyeimage)

测量检测错误

车道边界检测误差的计算是验证多个下游子系统性能的关键步骤。这些子系统包括依赖于车道检测子系统的准确性的车道偏离预警系统。

你可以通过测量拟合优度来估计这个精度。有了地面真实点和计算出的估计值,您现在可以比较和可视化它们,以了解检测算法的性能如何。

可以在每个帧级或整个视频中测量拟合的良好。每个帧统计数据提供有关具体场景的详细信息,例如道路弯曲的行为,其中检测算法性能可能变化。全球统计数据提供了错过检测的车道数量的大图片估计。

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

阈值参数中的阈值参数评估索兰ou道恩函数表示车辆坐标中的最大横向距离,以符合估计的抛物线车道边界。

阈值= 0.25;%在米[nummatches,nummisses,numfalsepositive,作业] =...evaluateLaneBoundaries(测量。LaneBoundaries,...gtdata。LanesInVehicleCoord,...临界点);DISP(['比赛数量:',num2str(nummatches)]);DISP(['错过的人数:',num2str(nummisses)]);DISP([误报次数:num2str (numFalsePositives)]);
匹配数量:321未命中次数:124误报数:25

使用分配数组,您可以计算有用的每道路指标,例如估计和地面真理点之间的平均横向距离。此类指标表示算法的表现如何。要计算平均距离度量,请使用辅助功能辅助录像机,在此示例结束时定义。

averageDistance = helperComputeLaneStatistics(测量。LaneBoundaries,...gtdata。LanesInVehicleCoord,...作业,@mean);%绘制估计与地面真相之间的平均距离。图阻止(gtdata。时间,averageDistance) title(“估算值与地面真实值之间的平均距离”) 网格ylabel (“米距离”)传说(的左边界“右边界”

可视化和审查地面真理与算法之间的差异

现在您对车道检测算法的准确性有了定量的理解。但是,仅根据前一节中的图是不可能完全理解故障的。观看视频并在每帧的基础上可视化错误是至关重要的识别特定的故障模式,可以通过改进算法来改进。

您可以使用地面真理贴标程序应用程序作为可视化工具,以查看包含地面真实数据和估计的车道边界的视频。的驾驶.Connector.Connector.Connector.类提供了一个接口来将自定义可视化工具附加到Ground Truth Labeler。

使用parabolicLaneBoundary阵列和地面真实数据来计算车辆坐标位置的估计点。的parabolicLaneBoundary阵列定义了一条线,地面真理数据具有标记在路上的离散点。的helperGetCorrespondingPoints函数估计与车辆相同y轴距离的估计直线上的点。这个助手函数在示例的最后定义。

现实的真实性点和估计点现在包括在一个新的时间表在Ground Truth Labeler应用程序中被可视化地面对象然后存储为MAT文件。

%使用单纸片计算估计的点位置。[estVehiclePoints, estImagePoints] = helpergetrespondingpoints (monocamersensor,...测量.LaneBoundaries,...gtdata。LanesInVehicleCoord,...作业);%在测量时间表中添加估计的车道。测量。EstimatedLanes = estImagePoints;测量。LanesInVehicleCoord = estVehiclePoints;%创建一个新的时间表,包含可视化所需的所有变量。名称= {'lanepoints''检测到Lanepoints'};类型= labeltype({“行”“行”});labeldefs = table(名称,类型,“VariableNames”,{“名字”'类型'});(gtdata visualizeInFrame =时间表。时间,...gtdata.laneboundaries,...测量。最期待,...“VariableNames”、名称);%创建groundTruth对象。数据源= groundTruthDataSource (videoName);dataToVisualize = groundTruth(dataSource, labelDefs, visualizeInFrame);%在distanceData中保存上一节的所有结果。垫在%的临时文件夹。dataToLoad = [tempdir'distanceata.mat'];保存(数据罗拉,“monoSensorHelper”“videoName”'测量''gtdata'“averageDistance”);

Helpercustomui.类使用从垫文件加载的数据创建绘图和鸟瞰图,就像刚刚创建的数据一样。地面真实贴标程序应用程序的连接器接口与之交互Helpercustomui.班级通过helperUIConnector类同步视频与平均距离图和鸟瞰。这种同步使您能够分析和可视化地分析每帧的结果。

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

  • 转到临时目录distanceData.mat已保存并打开地面真相贴标程序应用程序。然后启动地面真相贴标程序应用程序,指定的连接器句柄helperUIConnector使用如下命令:

>> Origdir = PWD;>> CD(Tempdir)>>地面标签(DataSource,“ConnectorTargetHandle”, @helperUIConnector);
  • 导入标签:可视化地面真相车道标记和图像坐标中的估计车道。从App ToolStrip,单击导入标签.然后选择从工作空间选项,并加载Datatovisualize.将真相进入应用程序。主应用程序窗口现在包含Lane标记的注释。

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

> > cd (origdir)

从这种可视化,您可以对算法和地面真理数据的质量进行多次推断。

  • 左车道精度始终如一比右车道精度更差。在俯视鸟瞰显示的观察时,地面真理数据被标记为双线的外边界,而估计的车道边界通常在双线标记的中心处铺设。这表明左车道估计可能比数字描绘更准确,并且一个明确定义的地面真理数据集对于这些观察结果至关重要。

  • 大约2.3秒和4秒的检测间隔对应于前面有人行横道的道路十字路口。这表明该算法在有人行横道的情况下表现不佳。

  • 大约6.8秒,当车辆接近第三个十字路口时,自我车道分叉为只靠左的车道和直线车道。这里算法也不能准确的捕捉到左车道,ground truth data也不包含任何5帧的信息。

结论

此示例显示了如何测量车道边界检测算法的准确性并使用该算法可视化它地面真理贴标机您可以将这个概念扩展到其他定制算法,以简化这些工作流,并扩展应用程序的功能,以定制测量。

金宝app支持功能

辅助录像机

与地面真理点相比,此辅助功能计算车道边界检测的统计数据。它采用函数句柄,可用于概括需要计算的统计信息,包括@mean和@Median。

功能stat = helpercomputelanstatistics (estModels, gtPoints, assignments, fcnHandle) numFrames = length(estModels);默认情况下,%使左右估计南部缺乏% 数据。stat = NaN*ones(numFrames, 2);Frameind = 1:NumFrames默认情况下,%使左右估计。stat(frameInd,:) = NaN*ones(2,1);idx = 1:长度(estModels {frameInd})忽略假阳性赋值。如果作业{frameInd} (idx) = = 0继续结束% estModelInFrame中的第k个边界匹配到第k个%元素索引的分配在gtPointsInFrame。这种模式下= estModels {frameInd} (idx);thisGT = gtPoints {frameInd}{作业{frameInd} (idx)};thisGTModel = driving.internal.piecewiseLinearBoundary (thisGT);如果意味着(thisGTModel.Points (:, 2)) > 0% 左车道xpoints = thinggtmodel.points(:1);Ydist =零(尺寸(xpoints));gtYPoints = thisgtmodel . computeborderymodel (xPoints(index));testYPoints = thisModel.computeBoundaryModel (xPoints(指数));yDist(指数)= abs (testYPoints-gtYPoints);结束stat(frameind,1)= fcnhandle(ydist);别的% 右侧车道xpoints = thinggtmodel.points(:1);Ydist =零(尺寸(xpoints));gtYPoints = thisgtmodel . computeborderymodel (xPoints(index));testYPoints = thisModel.computeBoundaryModel (xPoints(指数));yDist(指数)= abs (testYPoints-gtYPoints);结束stat(frameind,2)= fcnhandle(ydist);结束结束结束结束

helperGetCorrespondingPoints

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

功能[vehiclePoints, imagePoints] = helpergetrespondingpoints (monocamersensor, estModels, gtPoints, assignments) numFrames = length(estModels);imagePoints = cell(numFrames, 1);vehicle = cell(numFrames, 1);Frameind = 1:NumFrames如果isempty(assignments{frameInd}) imagePointsInFrame = [];vehiclePointsInFrame = [];别的estmodelinframe = estmodels {frameind};gtpointsinframe = gtpoints {frameind};imagePointsinframe = cell(长度(estmodelinframe),1);vertinpointsinframe = cell(长度(estmodelinframe),1);IDX = 1:长度(Estmodelinframe)忽略假阳性赋值。如果分配{frameind}(idx)== 0 imagepointsinframe {idx} = [nan nan];继续结束% estModelInFrame中的第k个边界匹配到第k个%元素索引的分配在gtPointsInFrame。thismodel = estmodelinframe(Idx);thisgt = gtpointsinframe {dispordments {frameind}(idx)};xpoints = thinggt(:,1);ypoints = thismodel.computeboundarymodel(xpoints);verthpointsinframe {idx} = [xpoints,ypoints];imagePointsinframe {idx} = vevicletoimage(monocamerasensor,[xpoints ypoints]);结束结束车辆点{frameind} = verthingspointsinframe;imagePoints {frameind} = imagepointsinframe;%makeportpoints []而不是{}符合Toundtruth对象。如果isempty(imagePoints{frameInd}) imagePoints{frameInd} = [];结束如果isempty(verthpoints {frameind})resplopitts {frameind} = [];结束结束结束

另请参阅

应用程序

功能

对象

相关的话题