评估和可视化Lane边界检测与地面真相
这个例子展示了如何根据已知的地面真值来评估车道边界检测的性能。在本例中,您将通过计算拟合优度度量来描述车道边界检测算法在每帧基础上的性能。该度量可用于查明、可视化和理解底层算法中的故障模式。
概述
随着人们对基于视觉的自动驾驶问题解决方案越来越感兴趣,能够评估和验证检测算法的准确金宝搏官方网站性变得非常重要。验证准确性在检测算法中尤其重要,因为检测算法有几个参数,这些参数可以调整以达到满足预定义质量要求的结果。本示例演示了一个这样的工作流,其中可以测量车道边界的精确度。该工作流有助于在每帧的基础上查明这些算法中的故障模式,并描述其整体性能。此工作流还可以帮助您直观地和定量地了解算法的性能。然后,您可以使用这种理解来调优底层算法以提高其性能。
负载接地真实数据
本例中使用的数据集是来自行驶在街道上的车辆的前置摄像头的视频文件。车道边界的地面真相已经用Ground truth Labeler应用程序手动标记在视频上,使用标记为“LaneBoundary”的线ROI。这个视频是8秒,或250帧长。它有三个十字路口,几辆车(停放和移动),车道边界(双线,单线和虚线)。要为您自己的视频创建地面真实车道边界数据集,您可以使用地面真理标签机应用程序。
加载具有地面真实数据的MAT文件。加载=加载“caltech_cordova1_laneAndVehicleGroundTruth.mat”);
的加载
结构包含三个字段:
groundTruthData
,有两栏的时间表;LaneBoundaries
和车辆
.LaneBoundaries
包含自我车道边界(左和右)的地面真值点,以XY点的单元数组表示,形成一条多线段。车辆
包含相机视图中车辆的地面真实边界框,表示为m × 4数组[x,y,宽度,高度]。传感器
,一个monoCamera
对象,其属性与安装在车辆上的校准相机有关。这个对象可以让你估计现实世界中车辆与前方物体之间的距离。videoName
,包含存储帧的视频文件名的字符数组。
利用该结构中的数据,打开视频文件VideoReader
循环遍历帧。的VideoReader
对象使用helperMonoSensor
物体检测车道和物体在视频帧中,使用相机设置存储在传感器
.一个时间表
存储在gtdata
持有地面真实数据。该变量包含以后用于分析的每帧数据。
创建一个VideoReader对象来读取视频的帧。videoName = loaded.videoName;fileReader = VideoReader(videoName);地面真实数据按时间表组织。gtdata = loaded.groundTruthData;%显示地面真值数据的前几行。头(gtdata)
Time Vehicles LaneBoundaries ____________ ____________ ______________ 0秒{6x4 double} {2x1 cell} 0.033333秒{6x4 double} {2x1 cell} 0.066667秒{6x4 double} {2x1 cell} 0.1秒{6x4 double} {2x1 cell} 0.16667秒{6x4 double} {2x1 cell} 0.2秒{6x4 double} {2x1 cell} 0.23333秒{5x4 double} {2x1 cell}
的gtdata
时间表有列车辆
和LaneBoundaries
.在每个时间戳中,车辆
列包含一个m × 4的车辆边界框数组和LaneBoundaries
Column保存左、右车道边界点的双元素单元格数组。
首先,可视化图像帧加载的地面真值数据。
阅读视频的第一帧。frame = readFrame(fileReader);提取第一帧中的所有车道点。lanePoints = gtdata.LaneBoundaries{1};在第一帧中提取车辆边界框。vehicleBBox = gtdata.Vehicles{1};叠加右侧车道点和车辆边界框。frame = insertMarker(frame, lanePoints{2},“X”);frame = insertobjectnotation(帧,“矩形”vehicleBBox,“汽车”);在第一帧显示地面真实数据。图imshow(框架)
运行车道边界检测算法
使用视频帧和monoCamera
参数,可以自动估计车道边界的位置。举例来说,processFrame
方法helperMonoSensor
类在这里用于检测车道边界(如parabolicLaneBoundary
对象)和车辆(作为[x, y,宽度,高度]边界框矩阵)。在本例中,这是车道边界检测“正在测试的算法”。您可以使用相同的模式来评估自定义车道边界检测算法,其中processFrame
替换为自定义检测功能。车辆坐标中的地面真实点也存储在LanesInVehicleCoord
列gtdata
时间表。这样,它们就可以在稍后的鸟瞰图中显示出来。首先,配置helperMonoSensor
对象。传感器
.的helperMonoSensor
类组装运行车道边界检测算法所需的所有必要步骤。
设置monoSensorHelper来处理视频。monocamerassensor =加载的传感器;monoSensorHelper = helperMonoSensor(monocamerassensor);%创建新的时间表,使用相同的时间向量进行测量。测量=时间表(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;循环播放视频文件,直到没有新的帧。而hasFrame(fileReader) frameIndex = frameIndex+1;frame = readFrame(fileReader);使用processFrame方法来计算检测。此方法可替换为自定义车道检测方法。detection = processFrame(monoSensorHelper, frame);存储估计的车道边界和车辆检测。测量。LaneBoundaries{frameIndex} = [detection . leftegoboundary .…detections.rightEgoBoundary];测量。VehicleDetections{frameIndex} = detection . vehicleboxes;为便于比较,将地面真理巷点转换为%车辆坐标系统。gtPointsThisFrame = gtdata.LaneBoundaries{frameIndex};vehiclePoints = cell(1, numel(gtPointsThisFrame));为ii = 1: nummel (gtPointsThisFrame) vehiclePoints{ii} = imageToVehicle(monocamerassensor, gtPointsThisFrame{ii});结束%存储以车辆坐标表示的地面真实点。gtdata。LanesInVehicleCoord{frameIndex} = vehiclePoints;结束
现在您已经使用车道检测算法处理了视频,请验证地面真实点是否正确地转换为车辆坐标系。的第一个条目LanesInVehicleCoord
列gtdata
时间表包含第一帧的车辆坐标。在鸟瞰图的第一帧上绘制这些地面真实点。
%将视频倒带到t = 0。fileReader。CurrentTime = 0;阅读视频的第一帧。frame = readFrame(fileReader);birdsEyeImage = transformImage(monoSensorHelper)。BirdsEyeConfig,框架);在鸟瞰图中提取第一帧的右巷点。firstFrameVehiclePoints = gtdata.LanesInVehicleCoord{1};pointsInBEV = vehicleToImage(monoSensorHelper)。BirdsEyeConfig, firstFrameVehiclePoints {2});在框架上叠加点。birdsEyeImage = insertMarker(birdsEyeImage, pointsInBEV,“X”,“大小”6);在鸟瞰中显示变换后的点。图imshow (birdsEyeImage)
测量检测误差
车道边界检测误差的计算是验证下游子系统性能的重要步骤。这样的子系统包括车道偏离警告系统,它依赖于车道检测子系统的准确性。
您可以通过测量拟合优度来估计这种准确性。有了地面真值点和估算值,您现在可以对它们进行比较和可视化,以了解检测算法的执行情况。
适合度可以在每帧或整个视频级别进行测量。每帧统计数据提供了有关特定场景的详细信息,例如在检测算法性能可能发生变化的弯道处的行为。全球统计数据提供了错过检测的车道数量的总体估计。
使用evaluateLaneBoundaries
函数返回全局检测统计信息作业
数组中。该阵列将估计的车道边界对象与相应的地面真值点相匹配。
中的阈值参数evaluateLaneBoundaries
函数表示车辆坐标中符合估计抛物线车道边界的最大横向距离。
阈值= 0.25;米百分比[numMatches, numMisses, numfalse positive, assignments] =…evaluateLaneBoundaries(测量。LaneBoundaries,…gtdata。LanesInVehicleCoord,…阈值);disp ([“火柴数:”num2str (numMatches)]);disp ([“失手次数:”num2str (numMisses)]);disp ([“误报次数:”num2str (numFalsePositives)]);
匹配次数:402未匹配次数:43误报次数:30
使用作业
数组中,您可以计算有用的每车道度量,例如估计值和地面真值点之间的平均横向距离。这些指标表明了算法的执行情况。要计算平均距离度量,请使用辅助函数helperComputeLaneStatistics
,它在本示例的末尾定义。
averageDistance = helpercomputelanstatistics(测量)。LaneBoundaries,…gtdata。LanesInVehicleCoord,…作业,@mean);%估算值与地面真实值之间的平均距离。图阻止(gtdata。时间,averageDistance) title(“估算值与实际情况之间的平均距离”网格)在ylabel (“米距离”)传说(的左边界,“右边界”)
可视化并回顾实际情况和算法之间的差异
您现在对车道检测算法的准确性有了定量的了解。然而,我们不可能仅仅根据前一节的情节就完全理解失败。因此,在每帧的基础上查看视频和可视化错误对于识别特定的故障模式至关重要,这可以通过改进算法来改进。
您可以使用Ground Truth Labeler应用程序作为可视化工具来查看包含Ground Truth数据和估计车道边界的视频。的
类提供了一个接口,将自定义可视化工具附加到Ground Truth label。driving.connector.Connector
使用parabolicLaneBoundary
阵列和地面真值数据,计算车辆坐标位置的估计点。的parabolicLaneBoundary
数组定义一条线,地面真值数据在道路上有离散点标记。的helperGetCorrespondingPoints
函数估计估计线上的点,这些点对应于与车辆相同的y轴距离。这个辅助函数在示例的末尾定义。
地面真值点和估计点现在包含在一个新的时间表
在地面真相标签应用程序中可视化groundTruth
对象然后存储为MAT文件。
使用单相机计算估计的点位置。[estVehiclePoints, estImagePoints] = helperGetCorrespondingPoints(monocamerassensor),…测量。LaneBoundaries,…gtdata。LanesInVehicleCoord,…作业);在测量时间表中添加估计车道。测量。EstimatedLanes = estImagePoints;测量。LanesInVehicleCoord = estVehiclePoints;创建一个包含可视化所需的所有变量的新时间表。名称= {“LanePoints”;“DetectedLanePoints”};type = labelType({“行”;“行”});labelDefs = table(名称,类型,“VariableNames”, {“名字”,“类型”});visualizeInFrame =时间表时间,…gtdata。LaneBoundaries,…测量。EstimatedLanes,…“VariableNames”、名称);%创建groundTruth对象。dataSource = groundTruthDataSource(videoName);dataToVisualize = groundTruth(dataSource, labeldef, visualizeInFrame);%将前一节的所有结果保存在distanceData中。在一个%临时文件夹。dataToLoad = [tempdir . dataToLoad“distanceData.mat”];保存(dataToLoad,“monoSensorHelper”,“videoName”,“测量”,“gtdata”,“averageDistance”);
的helperCustomUI
类使用从MAT文件(如刚才创建的文件)加载的数据创建绘图和鸟瞰图。Ground Truth label应用程序的连接器接口与helperCustomUI
类通过helperUIConnector
类将视频与平均距离图和鸟瞰图同步。这种同步使您能够分析和可视化地分析每帧结果。
按照以下步骤将结果可视化,如下图所示:
进入临时目录
distanceData.mat
保存并打开Ground Truth Labeler应用程序。然后启动Ground Truth Labeler应用程序,连接器句柄指定为helperUIConnector
使用如下命令:
>> origdir = pwd;>> cd(tempdir) >> groundtruthlabel (dataSource,“ConnectorTargetHandle”, @helperUIConnector);
导入标签:在图像坐标中可视化地面真实车道标记和估计车道。在应用程序工具栏中单击进口标签.然后选择从工作空间选项并加载
dataToVisualize
在应用程序的主窗口现在包含车道标记的注释。
现在您可以浏览视频并检查错误。要返回到原来的目录,你可以输入:
> > cd (origdir)
从这个可视化中,您可以对算法和地面真值数据的质量做出一些推断。
左球道的准确性一直比右球道的准确性差。在鸟瞰图中仔细观察,地面真实数据被标记为双线的外边界,而估计的车道边界通常位于双线标记的中心。这表明左车道估计可能比数字描绘的更准确,并且明确定义的地面真实数据集对于此类观察至关重要。
2.3秒和4秒左右的检测间隔对应的是道路上有人行横道的十字路口。这表明该算法在存在人行横道的情况下表现不佳。
大约6.8秒时,当车辆驶近第三个十字路口时,自我车道分成左车道和直车道。在这里,算法也不能准确地捕获左侧车道,并且地面真实数据在5帧内也不包含任何信息。
结论
此示例演示了如何测量车道边界检测算法的准确性,并使用地面真理标签机您可以将此概念扩展到其他自定义算法,以简化这些工作流程并扩展应用程序的自定义测量功能。
金宝app支持功能
helperComputeLaneStatistics
与地面真值点相比,这个辅助函数计算车道边界检测的统计数据。它接受一个函数句柄,该句柄可用于概括需要计算的统计信息,包括@mean和@median。
函数stat = helperComputeLaneStatistics(estModels, gtPoints, assignments, fcnHandle);默认情况下,左估计和右估计NaN表示缺乏%的数据。stat = NaN*ones(numFrames, 2);为frameInd = 1:numFrames%默认情况下进行左右估计NaN。stat(frameInd,:) = NaN*ones(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);如果mean(thisGTModel.Points(:,2)) > 0%左车道xPoints = thisGTModel.Points(,1);yDist = 0 (size(xPoints));为索引= 1:nummel (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 (size(xPoints));为索引= 1:nummel (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] = helperGetCorrespondingPoints(monocamerassensor, estModels, gtPoints, assignments) numFrames = length(estModels);imagePoints = cell(numFrames, 1);vehiclePoints = cell(numFrames, 1);为frameInd = 1:numFrames如果isempty(assignments{frameInd}) imagePointsInFrame = [];vehiclePointsInFrame = [];其他的estModelInFrame = estModels{frameInd};gtPointsInFrame = gtPoints{frame};imagePointsInFrame = cell(length(estModelInFrame), 1);vehiclePointsInFrame = cell(length(estModelInFrame), 1);为idx = 1:length(estModelInFrame)忽略假阳性赋值。如果赋值{frameInd}(idx) == 0 imagePointsInFrame{idx} = [NaN NaN];继续;结束estModelInFrame中的第k个边界匹配到第k个%的元素被gtPointsInFrame中的赋值索引。thisModel = estModelInFrame(idx);thisGT = gtPointsInFrame{assignments{frameInd}(idx)};xPoints = thisGT(:, 1);yPoints = thisModel.computeBoundaryModel(xPoints);vehiclePointsInFrame{idx} = [xPoints, yPoints];imagePointsInFrame{idx} = vehicleToImage(monocamerassensor, [xPoints yPoints]);结束结束车辆点{frameInd} =车辆点sinframe;imagePoints{frameInd} = imagePointsInFrame;%使imagePoints[]而不是{}符合groundTruth对象。如果isempty(imagePoints{frameInd}) imagePoints{frameInd} = []结束如果isempty(车辆点{frameInd})车辆点{frameInd} = [];结束结束结束