评估车道边界检测与地面真实数据
这个例子展示了如何将地面真实数据与车道边界检测算法的结果进行比较。文中还说明了如何使用这种比较来优化算法参数,以获得最佳的检测结果。
概述
地面真实数据通常在图像坐标中可用,而边界则在车辆坐标系中建模。比较两者涉及到坐标转换,因此在解释结果时需要格外小心。驾驶决策是基于车辆坐标系中的距离。因此,使用车辆坐标中的物理单位来表达和理解精度要求比使用像素坐标更有用。
的使用单目摄像机的视觉感知描述了单目摄像机传感器的内部结构和车道边界建模的过程。这个例子展示了如何根据人工验证的地面真相数据评估这些模型的准确性。在建立比较框架后,将该框架扩展到对边界检测算法的参数进行微调以获得最佳性能。
加载和准备地面真实数据
您可以使用地面真相标签应用程序在视频中标记和标签车道边界。这些注释的车道边界表示为沿着感兴趣的边界放置的点集。在评估和微调自动车道边界检测算法时,拥有一组丰富的用于各种驾驶场景的手动标注车道边界是至关重要的。为caltech_cordova1.avi
视频文件是可用的工具箱。
加载预定义的左右自我车道边界指定的图像坐标。每个边界由一组M × 2的数字表示,表示沿该边界的M个像素位置。每个视频帧最多有两个这样的集合,分别表示左车道和右车道。
装载,装载“caltech_cordova1_EgoBoundaries.mat”);传感器=负载。传感器;关联的monoCamera对象gtImageBoundaryPoints = loaded.groundTruthData.EgoLaneBoundaries;在这个帧索引处显示一个ground truth的样本frameInd = 36;加载视频帧frameTimeStamp = seconds(loaded.groundTruthData(frameInd,:).Time);videereader = videereader (loaded.videoName);videoReader。CurrentTime = frameTimeStamp;frame = videoReader.readFrame();获取这一帧的左车道点边界点= gtimage边界点{frameInd};leftLanePoints =边界点{1};图imshow(帧)保持在情节(leftLanePoints (: 1) leftLanePoints (:, 2),“+”,“MarkerSize”10“线宽”4);标题(“左车道边界的地面真实数据样本”);
将地面真值点从图像坐标转换为车辆坐标,以便与边界模型进行直接比较。要执行此转换,请使用imageToVehicle
函数与相关的monoCamera
对象执行此转换。
gtVehicleBoundaryPoints = cell(编号(gtImageBoundaryPoints),1);为frameInd = 1:numel(gtImageBoundaryPoints) boundaryPoints = gtImageBoundaryPoints{frameInd};如果~isempty(边界点)ptsInVehicle = cell(1,数字(边界点));为cInd = 1:numel(边界点)ptsInVehicle{cInd} = imageToVehicle(传感器,边界点{cInd});结束gtVehicleBoundaryPoints{frameInd} = ptsInVehicle;结束结束
使用单目传感器模拟车道边界
在样本视频上运行车道边界建模算法,获取测试数据进行比较。在这里,重用helperMonoSensor
模块中介绍的使用单目摄像机的视觉感知的例子。在处理视频时,还需要一个额外的步骤来返回检测到的边界模型。这个逻辑被包装在一个辅助函数中,detectBoundaries
,在本例的末尾定义。
monoSensor = helperMonoSensor(传感器);边界= detectBoundaries(已加载。videoName monoSensor);
评估车道边界模型
使用evaluateLaneBoundaries
函数来查找与基本真值中这些边界相匹配的边界的数量。只有当所有的实值点都在与相应的测试边界的指定距离内时,才会将实值分配给测试边界。如果有多个ground truth边界满足该条件,则选择最大横向距离最小的边界。其他的被标记为假阳性。
阈值= 0.25;车辆坐标%(米)[numMatches, numMisses, numFalsePositives, assignments] =...evaluateLaneBoundaries(边界,gtVehicleBoundaryPoints, threshold);disp (['匹配数:'num2str (numMatches)]);
匹配数:407
disp ([“失手次数:”num2str (numMisses)]);
失手次数:38次
disp ([“误报数量:”num2str (numFalsePositives)]);
误报数:28
您可以使用这些原始计数来计算其他统计数据,如精度、召回率和F1分数:
precision = numMatches/(numMatches+numFalsePositives);disp ([的精度:num2str(精密)]);
精度:0.93563
召回= numMatches/(numMatches+numMisses);disp ([的灵敏度/回忆:num2str(召回)]);
灵敏度/回忆:0.91461
f1Score = 2*(精度*召回率)/(精度+召回率);disp ([“F1分数:”num2str (f1Score)]);
F1分数:0.925
使用鸟瞰图可视化结果
evaluateLaneBoundaries
此外,对于ground truth和测试边界之间的每个成功匹配,返回赋值索引。这可以用来可视化检测到的和真实的边界,以更好地理解故障模式。
找到一个有一个匹配边界和一个假阳性的框架。每个帧的ground truth数据有两个边界。因此,一个候选框架将有两个赋值指标,其中一个为0表示假阳性。
hasMatch = cellfun(@(x)numel(x)==2,赋值);hasFalsePositive = cellfun(@(x)nnz(x)==1,赋值);frameInd = find(hasMatch&hasFalsePositive,1,“第一”);frameVehiclePoints = gtvehicleboundaries points {frameInd};frameImagePoints = gtImageBoundaryPoints{frameInd};frameModels =边界{frameInd};
使用作业
的输出evaluateLaneBoundaries
找出匹配的模型(真阳性)和不匹配的模型(假阳性)。
matchedModels = frameModels(赋值{frameInd}~=0);fpModels = frameModels(分配{frameInd}==0);
建立一个鸟瞰图,并可视化地面真相点和模型。
bep = birdsEyePlot();gtPlotter = laneBoundaryPlotter(bep,“DisplayName的”,“地面实况”,...“颜色”,“蓝”);tpPlotter = laneBoundaryPlotter(bep,“DisplayName的”,“真阳性”,...“颜色”,“绿色”);fpPlotter = laneBoundaryPlotter(bep,“DisplayName的”,“假阳性”,...“颜色”,“红色”);plotLaneBoundary (gtPlotter frameVehiclePoints);plotLaneBoundary (tpPlotter matchedModels);plotLaneBoundary (fpPlotter fpModels);标题(“比较结果鸟眼图”);
在摄像机和鸟瞰视图中可视化视频结果
为了获得更好的结果上下文,您还可以在视频上可视化地面真相点和边界模型。
得到与感兴趣的坐标系相对应的坐标系。
videereader = videereader (loaded.videoName);videoReader。CurrentTime = seconds(loaded.groundTruthData.Time(frameInd));frame = videoReader.readFrame();
将边界模型视为一条实线(不管传感器如何对其进行分类),以实现可视化。
fpModels。BoundaryType =“固体”;matchedModels。BoundaryType =“固体”;
插入匹配的模型、假阳性和地面真值点。这个图在推断人行横道的存在对边界建模算法提出了一个具有挑战性的场景时是有用的。
xVehicle = 3:20;frame = insertLaneBoundary(frame, fpModels, sensor, xVehicle,“颜色”,“红色”);frame = insertLaneBoundary(frame, matchedModels, sensor, xVehicle,“颜色”,“绿色”);图ha =坐标轴;imshow(帧,“父”,哈);组合左右边界点boundaryPoints = [frameImagePoints{1};frameImagePoints{2}];持有在plot(ha, boundaryPoints(:,1), boundaryPoints(:,2),“+”,“MarkerSize”10“线宽”4);标题(“比较结果的相机视图”);
您还可以在该框架的鸟瞰图中可视化结果。
birdsEyeImage = transformImage(monoSensor.BirdsEyeConfig,frame);xVehicle = 3:20;birdsEyeImage = insertLaneBoundary(birdsEyeImage, fpModels, monoSensor。BirdsEyeConfig xVehicle,“颜色”,“红色”);birdsEyeImage = insertLaneBoundary(birdsEyeImage, matchedModels, monoSensor。BirdsEyeConfig xVehicle,“颜色”,“绿色”);组合左右边界点ptsInVehicle = [frameVehiclePoints{1};frameVehiclePoints{2}];gtPointsInBEV = vehicleToImage(monoSensor。BirdsEyeConfig ptsInVehicle);图imshow (birdsEyeImage);持有在情节(gtPointsInBEV (: 1) gtPointsInBEV (:, 2),“+”,“MarkerSize”10“线宽”4);标题(比较结果鸟瞰图);
优化边界建模参数
您可以使用前面描述的评估框架来微调车道边界检测算法的参数。helperMonoSensor
公开控制寻道算法结果的三个参数。
LaneSegmentationSensitivity
-控制的灵敏度segmentLaneMarkerRidge
函数。该函数以二进制车道特征掩码的形式返回车道候选点。灵敏度值范围为0 ~ 1,默认值为0.25。增加这个数字会导致更多的车道候选点和潜在的更多错误检测。LaneXExtentThreshold
—车道的最小长度。它表示为检测到的车道长度与指定摄像机配置可能的最大车道长度的比率。默认值为0.4。增加该数字以拒绝较短的车道边界。LaneStrengthThreshold
-接受检测到的车道边界的最小归一化强度。
LaneXExtentThreshold
而且LaneStrengthThreshold
都是从XExtent
而且强度
的属性parabolicLaneBoundary
对象。这些属性是如何在边界建模算法上施加附加约束以获得可接受结果的示例。变化的影响LaneStrengthThreshold
有额外的细微差别值得探索。典型的车道边界用实线或虚线标记。与实线相比,虚线具有较少的内线点,从而导致较低的强度值。这使得设定一个共同的强度阈值具有挑战性。要检查此参数的影响,首先通过设置生成所有边界LaneStrengthThreshold
为0。此设置确保它不会对输出产生影响。
monoSensor。LaneStrengthThreshold = 0;边界= detectBoundaries(“caltech_cordova1.avi”, monoSensor);
的LaneStrengthThreshold
的属性helperMonoSensor
控制归一化强度
各参数parabolicLaneBoundary
模型。归一化因子,MaxLaneStrength
,是一个虚拟车道的强度,它可以在鸟瞰图像的全部范围内运行。属性决定此值birdsEyeView
的配置helperMonoSensor
.评估…的影响LaneStrengthThreshold
,首先计算样本视频中所有检测边界的归一化车道强度的分布。请注意存在两个清晰的峰值,一个在标准化强度为0.3,另一个在0.7。这两个峰值分别对应虚线和实线的车道边界。从这个图中,你可以凭经验确定,为了确保检测到虚线车道边界,LaneStrengthThreshold
应该低于0.3。
力量= cellfun(@(b)[b.]强度),边界,“UniformOutput”、假);强度=[强度{:}];normalized强项=强项/monoSensor.MaxLaneStrength;图;嘘(normalizedStrengths);标题(“标准化车道强度直方图”);
的影响可以使用比较框架进一步评估LaneStrengthThreshold
参数对建模算法检测性能的影响。注意阈值
控制模型和基本真理之间最大物理距离的值与以前相同。该值由ADAS系统的精度要求决定,通常不会改变。
阈值= .25;[~, ~, ~,赋值]=...evaluateLaneBoundaries(边界,gtVehicleBoundaryPoints, threshold);
根据每个边界的归一化强度进行Bin。的作业
信息有助于将每个边界分类为真阳性(匹配)或假阳性。LaneStrengthThreshold
是一个“最小”阈值,因此在给定值处被分类为真正值的边界对于所有较低的阈值将继续为真正值。
nMatch = 0 (1100);归一化的车道强度被分成100个桶nFP = 0 (1100);%范围从0.01到1.00。为frameInd = 1:numel(边界)frameBoundaries =边界{frameInd};frameAssignment = tasks {frameInd};为bInd = 1:numel(frameBoundaries) normalizedStrength = frameBoundaries(bInd).Strength/monoSensor.MaxLaneStrength;强度桶=地板(正常化强度*100);如果frameAssignment(绑定)%此边界与基本真理边界匹配,%记录为真阳性的所有值的强度以上%其强度值。nMatch(1:强度桶)= nMatch(1:强度桶)+1;其他的这是误报nFP(1:强度桶)= nFP(1:强度桶)+1;结束结束结束
使用这些信息来计算“错过”边界的数量,即算法在指定位置未能检测到的ground truth边界LaneStrengthThreshold
价值。有了这些信息,计算精度和召回指标。
gtTotal = sum(cellfun(@(x) nummel (x),gtVehicleBoundaryPoints));nMiss = gtTotal - nMatch;precisionPlot = nMatch。/(nMatch + nFP);recallPlot = nMatch。/(nMatch + nMiss);
根据车道强度阈值参数的不同值绘制精度和召回指标。这个图在确定车道强度参数的最佳值时很有用。对于这个视频片段,为了最大限度地提高召回率和精度指标,LaneStrengthThreshold
应该在0.20 - 0.25的范围内。
图;情节(precisionPlot);持有在;情节(recallPlot);包含(“LaneStrengthThreshold * 100”);ylabel (“精确度和召回率”);传奇(“精度”,“回忆”);标题(“LaneStrengthThreshold对精度和召回指标的影响”);
金宝app支持函数
检测视频中的边界。
detectBoundaries
使用预先配置的helperMonoSensor
对象来检测视频中的边界。
函数边界= detectBoundaries(videoName, monoSensor) videoReader = videoReader (videoName);HWB = waitbar(0,“在视频中检测和建模边界……”);closeBar = onCleanup(@()delete(hwb));frameInd = 0;边界= {};而hasFrame(videereader) frameInd = frameInd+1;frame = readFrame(视频阅读器);sensorOut = processFrame(monoSensor, frame);保存边界模型{结束+ 1}=边界...[sensorOut。leftEgoBoundary sensorOut.rightEgoBoundary);% #好< AGROW >waitbar (frameInd / (videoReader.Duration * videoReader.FrameRate), hwb);结束结束