主要内容

使用单目摄像机的视觉感知

本例展示了如何构建一个能够进行车道边界和车辆检测的单目摄像机传感器仿真。传感器将在车辆坐标系中报告这些检测结果。在本例中,您将了解自动驾驶工具箱™使用的坐标系,以及单目相机传感器样本设计中涉及的计算机视觉技术。

概述

包含ADAS功能或设计为完全自动驾驶的车辆依赖于多个传感器。这些传感器包括声纳、雷达、激光雷达和摄像头。本例说明了单目摄像系统设计中涉及的一些概念。这样的传感器可以完成许多任务,包括:

  • 车道边界检测

  • 车辆、人员和其他物体的探测

  • 自我车辆到障碍物的距离估计

随后,由单眼摄像头传感器返回的读数可用于发出车道偏离警告,碰撞警告,或设计车道保持辅助控制系统。与其他传感器配合使用,它还可用于实现紧急制动系统和其他安全关键功能。

该示例实现了在完全开发的单目摄像机系统上发现的功能子集。它可以检测车道边界和车辆的后面,并报告它们在车辆坐标系统中的位置。

定义摄像头配置

了解相机的内、外标定参数是实现像素坐标与车辆坐标准确转换的关键。

首先定义相机的内在参数。下面的参数是在之前使用使用棋盘式校准模式的摄像机校准程序确定的。您可以使用相机校准器应用程序获取他们为您的相机。

focalLength = [309.4362, 344.2161];% [fx, fy](像素单位)principalPoint = [318.9034, 257.5352];% [cx, cy]像素坐标的光学中心imageSize = [480,640];% [nrows, McOls]

注意,镜头失真系数被忽略了,因为数据中几乎没有失真。参数存储在cameraIntrinsics对象。

camintrinsic = cameraIntrinsics(focalLength, principalPoint, imageSize);

接下来,定义相对于车辆底盘的摄像头方向。您将使用此信息来建立摄像机外部参数,该参数定义3-D摄像机坐标系统相对于车辆坐标系统的位置。

高度= 2.1798;%安装高度,以米为单位Pitch = 14;相机的% pitch(以度为单位)

函数返回的旋转和平移矩阵可导出上述量estimateExtrinsics函数。俯仰指定相机从水平位置的倾斜。对于本例中使用的相机,传感器的滚转和偏航都为零。定义内部函数和外部函数的整个配置存储在monoCamera对象。

传感器= monoCamera(camintrinsic,高度,“节”、沥青);

注意monoCamera对象设置了一个非常特定的车辆坐标系,其中X-轴指向车辆前方,则Y-轴指向车辆左侧,而Z-轴指向地面。

默认情况下,坐标系统的原点是在地面上,直接低于相机焦点所定义的相机中心。类的SensorLocation属性monoCamera对象可以用来给出相机的X和Y相对于它的位置。此外,monoCamera提供了imageToVehicle而且vehicleToImage图像和车辆坐标系之间转换的方法。

注:坐标系之间的转换假设道路平坦。它基于建立一个单应矩阵,将成像平面上的位置映射到路面上的位置。非平坦的道路会在距离计算中引入错误,特别是在远离车辆的位置。

加载一帧视频

在处理整个视频之前,先处理一个视频帧,以说明设计单目摄像机传感器所涉及的概念。

首先创建一个VideoReader对象,用于打开视频文件。为了提高内存利用率,VideoReader每次加载一个视频帧。

videoName =“caltech_cordova1.avi”;videereader = videereader (videoName);

阅读一个包含车道标记和车辆的有趣框架。

timeStamp = 0.06667;%时间从视频开始videoReader。CurrentTime = timeStamp;%指向所选框架frame = readFrame(视频阅读器);%在时间戳秒读取帧imshow(框架)%显示框

图中包含一个轴对象。axis对象包含一个image类型的对象。

注意:这个例子忽略了镜头失真。如果你担心由镜头畸变引起的距离测量误差,此时你可以使用undistortImage功能消除镜头畸变。

创建鸟瞰图

有许多方法来分割和检测车道标志。一种方法是使用鸟瞰图像变换。尽管会产生计算成本,但这种转换提供了一个主要优势。鸟瞰图中的车道标记物厚度均匀,简化了分割过程。属于同一车道的车道标记也变得平行,从而使进一步的分析更容易。

给定相机设置,birdsEyeView对象将原始图像转换为鸟瞰图。该对象允许您使用车辆坐标指定要转换的区域。注意,车辆坐标单元是由monoCamera对象,当摄像机安装高度以米为单位指定时。例如,如果高度以毫米为单位指定,那么模拟的其余部分将使用毫米。

使用车辆坐标,定义要转换的区域distAheadOfSensor = 30;%,单位为米,如先前在monoCamera高度输入中指定的那样spaceToOneSide = 6;所有其他距离量也都以米为单位bottomOffset = 3;outView = [bottomOffset, distAheadOfSensor, -spaceToOneSide, spaceToOneSide];% [xmin, xmax, ymin, ymax]imageSize = [NaN, 250];%输出图像宽度(像素);高度是自动选择,以保留单位每像素的比率birdsEyeConfig = birdsEyeView(sensor, outView, imageSize);

生成鸟瞰图。

birdsEyeImage = transformImage(birdsEyeConfig, frame);图imshow (birdsEyeImage)

图中包含一个轴对象。axis对象包含一个image类型的对象。

距离传感器较远的区域更模糊,因为像素较少,因此需要更多的插值。

请注意,您可以在不使用鸟瞰图的情况下完成后一个处理步骤,只要您可以在车辆坐标中定位车道边界候选像素。

在车辆坐标中找到车道标记

有了鸟瞰图后,现在可以使用segmentLaneMarkerRidge函数将车道标记候选像素从路面分离。选择这种技术是因为它简单和相对有效。可供选择的分割技术包括语义分割(深度学习)和可操纵过滤器。您可以替换下面的这些技术,以获得下一阶段所需的二进制掩码。

下面函数的大多数输入参数以世界单位指定,例如,输入的车道标记宽度segmentLaneMarkerRidge.世界单位的使用允许您轻松地尝试新的传感器,即使输入图像大小发生变化。这是非常重要的,使设计更加健壮和灵活,以改变相机硬件和处理不同的标准在许多国家。

%转换为灰度birdsEyeImage = im2gray(birdsEyeImage);%车道标记分割ROI(世界单位)vehicleROI = outView - [- 1,2, - 3,3];左右各3米,传感器前方4米approxLaneMarkerWidthVehicle = 0.25;% 25厘米检测车道特征lanessensitivity = 0.25;birdsEyeViewBW = segmentLaneMarkerRidge(birdsEyeImage, birdsEyeConfig, approxLaneMarkerWidthVehicle,...“投资回报”vehicleROI,“敏感”, laneSensitivity);图imshow (birdsEyeViewBW)

图中包含一个轴对象。axis对象包含一个image类型的对象。

定位单个车道标记发生在车辆坐标,锚定到相机传感器。本例使用抛物线车道边界模型ax^2 + bx + c来表示车道标记。其他表示形式,如三次多项式或样条,也是可能的。转换到车辆坐标是必要的,否则车道标志曲率不能正确地表示为抛物线,而它受到一个视角扭曲的影响。

车道模型适用于车辆路径上的车道标记。横过道路的车道标志或涂在柏油路上的路标被拒绝使用。

在车辆坐标中获取车道候选点[imageX, imageY] = find(birdsEyeViewBW);xyBoundaryPoints = imageToVehicle(birdsEyeConfig, [imageY, imageX]);

由于分割点包含许多不是实际车道标记的异常值,因此使用基于随机样本共识(RANSAC)的鲁棒曲线拟合算法。

的数组中返回边界及其抛物线参数(a, b, c)parabolicLaneBoundary对象,边界

maxLanes = 2;寻找最多两个车道标志boundaryWidth = 3*approxLaneMarkerWidthVehicle;%扩展边界宽度[边界,边界点]= find抛物线laneboundaries (xyBoundaryPoints,边界宽度,...“MaxNumBoundaries”maxLanes,“validateBoundaryFcn”, @validateBoundaryFcn);

注意findParabolicLaneBoundaries取一个函数句柄,validateBoundaryFcn.这个示例函数在本示例的末尾列出。使用这个额外的输入可以让您根据a、b、c参数的值拒绝一些曲线。它还可以用于利用一系列帧上的时间信息,基于之前的视频帧约束未来的a, b, c值。

确定自我通道的边界

在前一步中找到的一些曲线可能仍然无效。例如,当一个曲线适合人行横道标志。使用额外的启发式来拒绝许多这样的曲线。

根据边界的长度建立拒绝边界的标准。maxPossibleXLength = diff(vehicleROI(1:2));minXLength = maxpossible length * 0.60;%建立阈值%找到短的界限如果(数字(边界)> 0)isOfMinLength = false(1,数字(边界));I = 1:数值(边界)如果(diff(boundaries(i).XExtent) > minXLength) isOfMinLength(i) = true;结束结束其他的isOfMinLength = false;结束

方法计算的强度度量基础上删除附加边界findParabolicLaneBoundaries函数。根据ROI和图像大小设置车道强度阈值。

要计算最大强度,假设所有图像像素都在ROI内%为车道候选点birdsImageROI = vehicleToImageROI(birdsEyeConfig, vehicleROI);[laneImageX,laneImageY] = meshgrid(birdsImageROI(1):birdsImageROI(2),birdsImageROI(3):birdsImageROI(4));将图像点数转换为车辆点数vehiclePoints = imageToVehicle(birdsEyeConfig,[laneImageX(:),laneImageY(:)]);找出任意车道可能的唯一x轴位置的最大数目%的边界maxPointsInOneLane = numel(unique(single((vehiclePoints(:,1)))));%设置车道边界的最大长度为ROI长度maxLaneLength = diff(vehicleROI(1:2));计算此图像大小/ROI大小的最大可能通道强度%的规范maxPointsInOneLane/maxLaneLength;拒绝短而弱的边界Idx = 0;strongBoundaries =抛物线界线(零(nnz(isOfMinLength), 3));i = 1: size(isOfMinLength,2)如果(isOfMinLength(i) == 1)如果(边界(i)。强度> 0.4*maxStrength) idx = idx + 1;strongBoundaries(idx) = boundaries(i);结束结束结束

将车道标记类型分类为实线/虚线的启发式方法包含在本示例底部列出的辅助函数中。了解车道标志类型对于自动驾驶车辆至关重要。例如,禁止越过实心标记。

当边界点不为空时,分类车道标记类型如果isempty(boundaryPoints) strongBoundaries = repmat(strongBoundaries,1,2);strongBoundaries(1) =抛物线界线(零(1,3));strongBoundaries(2) =抛物线界线(零(1,3));其他的strongBoundaries = classifyLaneTypes(strongBoundaries, boundaryPoints);结束distancebounds = code .nullcopy(ones(size(strongBoundaries,2),1));%找到自我路线xOffset = 0;距离传感器% 0米i = 1: size(strongBoundaries, 2) distancebounds (i) = strongBoundaries(i).computeBoundaryModel(xOffset);结束找到候选人自我的界限distanceoleftboundary = distanceboundaries >0;如果(numel(distancebounds (distanceoleftboundary))) minLeftDistance = min(distanceboundaries (distanceoleftboundary));其他的minLeftDistance = 0;结束distanceorightboundary = (distanceorightboundary <= 0);如果(nummel (distancebounds (distanceorightboundary))) minRightDistance = max(distanceboundaries (distanceorightboundary));其他的minRightDistance = 0;结束找到左自我边界如果(minLeftDistance ~= 0) leftEgoBoundaryIndex = distanceboundaries == minLeftDistance;leftEgoBoundary =抛物线界线(零(nnz(leftEgoBoundaryIndex), 3));Idx = 0;i = 1: size(leftEgoBoundaryIndex, 1)如果(leftEgoBoundaryIndex(i) == 1) idx = idx + 1;leftEgoBoundary(idx) = strongBoundaries(i);结束结束其他的leftEgoBoundary =抛物lane boundary .empty();结束找到正确的自我边界如果(minRightDistance ~= 0) rdgoboundaryindex = distanceboundaries == minRightDistance;理义边界=抛物线界线(零(nnz(理义边界指数),3));Idx = 0;i = 1: size(理亏边界索引,1)如果(rightgoboundaryindex (i) == 1) idx = idx + 1;rightgoboundary (idx) = strongBoundaries(i);结束结束其他的理义边界=抛物线边界.empty();结束

在鸟瞰图和常规视图中显示检测到的车道标记。

xVehiclePoints = bottomOffset:distAheadOfSensor;birdsEyeWithEgoLane = insertLaneBoundary(birdsEyeImage, leftEgoBoundary, birdsEyeConfig, xVehiclePoints,“颜色”“红色”);birdsEyeWithEgoLane = insertLaneBoundary(birdsEyeWithEgoLane, goboundary, birdsEyeConfig, xVehiclePoints,“颜色”“绿色”);frameWithEgoLane = insertLaneBoundary(frame, leftEgoBoundary, sensor, xVehiclePoints,“颜色”“红色”);frameWithEgoLane = insertLaneBoundary(frameWithEgoLane, righgoboundary, sensor, xVehiclePoints,“颜色”“绿色”);图次要情节(“位置”, [0, 0, 0.5, 1.0])%[左,底,宽,高]为标准化单位imshow (birdsEyeWithEgoLane)次要情节(“位置”, [0.5, 0, 0.5, 1.0]) imshow(frameWithEgoLane)

图中包含2个轴对象。坐标轴对象1包含一个image类型的对象。坐标轴对象2包含一个image类型的对象。

在车辆坐标中定位车辆

车辆的检测和跟踪是车辆前方碰撞预警(FCW)和自动紧急制动(AEB)系统的关键。

加载一个聚合通道特征(ACF)检测器,该检测器被预先训练以检测车辆的前后。像这样的检测器可以处理发出碰撞警告非常重要的场景。例如,对于检测在自我车辆前面穿过道路的车辆是不够的。

探测器= vehicleDetectorACF();普通车辆的宽度在1.5 - 2.5米之间vehicleWidth = [1.5, 2.5];

使用configureDetectorMonoCamera功能专门化通用ACF检测器,以考虑典型的汽车应用的几何形状。通过这种摄像头配置,这种新型探测器只搜索路面上的车辆,因为搜索消失点以上的车辆是没有意义的。这节省了计算时间,并减少了误报的数量。

monoDetector = configureDetectorMonoCamera(检测器,传感器,vehicleWidth);[bboxes, scores] = detect(monoDetector, frame);

由于本例仅演示如何处理单个帧,因此不能在原始检测之上应用跟踪。跟踪的加入使得返回车辆位置的结果更加可靠,因为即使车辆被部分遮挡,跟踪器也会继续返回车辆的位置。有关更多信息,请参见使用摄像头跟踪多辆车的例子。

接下来,将车辆检测转换为车辆坐标。的computeVehicleLocations函数,包含在这个示例的末尾,计算车辆在车辆坐标中的位置,给定由检测算法返回的图像坐标中的边界框。它返回车辆坐标中边界框底部的中心位置。因为我们使用的是单目摄像传感器和简单的单应相仪,所以只能精确地计算出沿路面的距离。计算三维空间中的任意位置需要使用立体摄像机或其他能够进行三角测量的传感器。

locations = computevehicllocations(箱子,传感器);在视频帧上覆盖检测imgOut = insertVehicleDetections(帧,位置,盒子);图;imshow (imgOut);

图中包含一个轴对象。axis对象包含一个image类型的对象。

用视频输入模拟一个完整的传感器

现在您已经了解了各个步骤的内部工作原理,让我们将它们组合在一起,并将它们应用到一个视频序列中,在这个视频序列中我们还可以利用时间信息。

倒回到视频的开头,然后处理视频。下面的代码被缩短了,因为所有关键参数都是在前面的步骤中定义的。这里使用的参数没有进一步解释。

videoReader。CurrentTime = 0;isPlayerOpen = true;快照= [];hasFrame(videereader) && isPlayerOpen抓取一帧视频frame = readFrame(视频阅读器);计算birdsEyeView图像birdsEyeImage = transformImage(birdsEyeConfig, frame);birdsEyeImage = im2gray(birdsEyeImage);检测车道边界特征birdsEyeViewBW = segmentLaneMarkerRidge(birdsEyeImage, birdsEyeConfig,...approxLaneMarkerWidthVehicle,“投资回报”vehicleROI,...“敏感”, laneSensitivity);在车辆坐标中获取车道候选点[imageX, imageY] = find(birdsEyeViewBW);xyBoundaryPoints = imageToVehicle(birdsEyeConfig, [imageY, imageX]);查找车道边界候选[边界,边界点]= find抛物线laneboundaries (xyBoundaryPoints,边界宽度,...“MaxNumBoundaries”maxLanes,“validateBoundaryFcn”, @validateBoundaryFcn);根据界限的长度和强度拒绝界限%找到短的界限如果(数字(边界)> 0)isOfMinLength = false(1,数字(边界));I = 1:数值(边界)如果(diff(boundaries(i).XExtent) > minXLength) isOfMinLength(i) = true;结束结束其他的isOfMinLength = false;结束拒绝短而弱的边界Idx = 0;strongBoundaries =抛物线界线(零(nnz(isOfMinLength), 3));i = 1: size(isOfMinLength,2)如果(isOfMinLength(i) == 1)如果(边界(i)。强度> 0.2*maxStrength) idx = idx + 1;strongBoundaries(idx) = boundaries(i);结束结束结束边界=边界(isOfMinLength);isStrong =[边界。强度]> 0.2*maxStrength;边界=边界(isStrong);当边界点不为空时,分类车道标记类型如果isempty(boundaryPoints) strongBoundaries = repmat(strongBoundaries,1,2);strongBoundaries(1) =抛物线界线(零(1,3));strongBoundaries(2) =抛物线界线(零(1,3));其他的strongBoundaries = classifyLaneTypes(strongBoundaries, boundaryPoints);结束%找到自我路线xOffset = 0;距离传感器% 0米distancebounds = code .nullcopy(ones(size(strongBoundaries,2),1));i = 1: size(strongBoundaries, 2) distancebounds (i) = strongBoundaries(i).computeBoundaryModel(xOffset);结束找到候选人自我的界限distanceoleftboundary = distanceboundaries >0;如果(numel(distancebounds (distanceoleftboundary))) minLeftDistance = min(distanceboundaries (distanceoleftboundary));其他的minLeftDistance = 0;结束distanceorightboundary = (distanceorightboundary <= 0);如果(nummel (distancebounds (distanceorightboundary))) minRightDistance = max(distanceboundaries (distanceorightboundary));其他的minRightDistance = 0;结束找到左自我边界如果(minLeftDistance ~= 0) leftEgoBoundaryIndex = distanceboundaries == minLeftDistance;leftEgoBoundary =抛物线界线(零(nnz(leftEgoBoundaryIndex), 3));Idx = 0;i = 1: size(leftEgoBoundaryIndex, 1)如果(leftEgoBoundaryIndex(i) == 1) idx = idx + 1;leftEgoBoundary(idx) = strongBoundaries(i);结束结束其他的leftEgoBoundary =抛物lane boundary .empty();结束找到正确的自我边界如果(minRightDistance ~= 0) rdgoboundaryindex = distanceboundaries == minRightDistance;理义边界=抛物线界线(零(nnz(理义边界指数),3));Idx = 0;i = 1: size(理亏边界索引,1)如果(rightgoboundaryindex (i) == 1) idx = idx + 1;rightgoboundary (idx) = strongBoundaries(i);结束结束其他的理义边界=抛物线边界.empty();结束%检测车辆[bboxes, scores] = detect(monoDetector, frame);locations = computevehicllocations(箱子,传感器);可视化传感器输出和中间结果。包装核心%传感器输出到一个结构。sensorOut。leftEgoBoundary = leftEgoBoundary;sensorOut。理顺边界=理顺边界;sensorOut。vehicllocations =位置;sensorOut。xVehiclePoints = bottomOffset:distAheadOfSensor;sensorOut。vehicleBoxes =箱子;打包额外的可视化数据,包括中间结果。intOut。birdsEyeImage = birdsEyeImage;intOut。birdsEyeConfig = birdsEyeConfig;intOut。vehicleScores =分数;intOut。vehicleROI = vehicleROI;intOut。birdsEyeBW = birdsEyeViewBW; closePlayers = ~hasFrame(videoReader); isPlayerOpen = visualizeSensorResults(frame, sensor, sensorOut,...intOut closePlayers);timeStamp = 7.5333;用于在时间戳秒发布快照如果abs (videoReader。CurrentTime - timeStamp) < 0.01 snapshot = takeSnapshot(帧,传感器,传感器);结束结束

显示视频帧。快照摄于时间戳秒。

如果~isempty(快照)图imshow(快照)结束

图中包含一个轴对象。axis对象包含一个image类型的对象。

在不同的视频上尝试传感器设计

helperMonoSensor类将设置和模拟单目摄像机传感器的所有必要步骤组装成一个完整的包,可以应用于任何视频。由于传感器设计中使用的大多数参数都是基于世界单位,因此该设计对包括图像大小在内的相机参数的变化具有鲁棒性。方法中的代码helperMonoSensor类与前一节中用于说明基本概念的循环不同。

除了提供一个新的视频,您还必须提供一个与该视频相对应的摄像头配置。这个过程如下所示。在你自己的视频中试试。

传感器配置focalLength = [309.4362, 344.2161];principalPoint = [318.9034, 257.5352];imageSize = [480,640];高度= 2.1798;%安装高度,以米为单位Pitch = 14;相机的% pitch(以度为单位)camintrinsic = cameraIntrinsics(focalLength, principalPoint, imageSize);传感器= monoCamera(camintrinsic,高度,“节”、沥青);视频阅读器=视频阅读器(“caltech_washington1.avi”);

创建helperMonoSensor对象,并将其应用于视频。

monoSensor = helperMonoSensor(传感器);monoSensor。LaneXExtentThreshold = 0.5;为了在这个视频中去除阴影中的错误检测,我们只返回%得分较高的车辆侦测率。monoSensor。VehicleDetectionThreshold = 20;isPlayerOpen = true;快照= [];hasFrame(视频阅读器)&& isPlayerOpen frame = readFrame(视频阅读器);%获得一个帧sensorOut = processFrame(monoSensor, frame);closePlayers = ~hasFrame(视频阅读器);isPlayerOpen = displaySensorOutputs(monoSensor, frame, sensorOut, closePlayers);timeStamp = 11.1333;用于在时间戳秒发布快照如果abs (videoReader。CurrentTime - timeStamp) < 0.01 snapshot = takeSnapshot(帧,传感器,传感器);结束结束

显示视频帧。快照摄于时间戳秒。

如果~isempty(快照)图imshow(快照)结束

图中包含一个轴对象。axis对象包含一个image类型的对象。

金宝app支持功能

visualizeSensorResults显示来自单目相机传感器模拟的核心信息和中间结果。

函数isPlayerOpen = visualizeSensorResults(帧,传感器,sensorOut,...intOut closePlayers)打开主要输入包leftEgoBoundary = sensorOut.leftEgoBoundary;理义边界= sensorout .理义边界;locations = sensorout . vehicllocations;xVehiclePoints = sensorOut.xVehiclePoints;bboxes = sensorOut.vehicleBoxes;解包额外的中间数据birdsEyeViewImage = intOut.birdsEyeImage;birdsEyeConfig = intOut.birdsEyeConfig;vehicleROI = intOut.vehicleROI;birdsEyeViewBW = intOut.birdsEyeBW;以鸟瞰的视角来想象左右自我道的界限。birdseyewithoverlay = insertLaneBoundary(birdsEyeViewImage, leftEgoBoundary, birdsEyeConfig, xVehiclePoints,“颜色”“红色”);birdseyewithoverlay = insertLaneBoundary(birdseyewithoverlay, rightgoboundary, birdsEyeConfig, xVehiclePoints,“颜色”“绿色”);在相机视图中可视化自我通道边界。framewithoverlay = insertLaneBoundary(frame, leftEgoBoundary, sensor, xVehiclePoints,“颜色”“红色”);framewithoverlay = insertLaneBoundary(framewithoverlay, righgoboundary, sensor, xVehiclePoints,“颜色”“绿色”);framewithoverlay = insertVehicleDetections(framewithoverlay, locations, bboxes);imageROI = vehicleToImageROI(birdsEyeConfig, vehicleROI);ROI = [imageROI(1) imageROI(3) imageROI(2)-imageROI(1) imageROI(4)-imageROI(3)];突出显示包含异常值的候选车道点birdsEyeViewImage = insertShape(birdsEyeViewImage,“矩形”ROI);显示检测ROIbirdsEyeViewImage = imoverlay(birdsEyeViewImage, birdsEyeViewBW,“蓝”);显示结果frames = {framewithoverlay, birdsEyeViewImage, birdseyewithoverlay};持续的球员;如果isempty(玩家)“车道标志和车辆探测”“原始分割”“车道标志探测”};玩家= helperVideoPlayerSet(帧,帧);结束更新(球员,框架);当第一个播放器关闭时终止循环isPlayerOpen = isOpen(玩家,1);如果(~isPlayerOpen || closePlayers)压制其他球员清晰的球员结束结束

computeVehicleLocations给定检测算法在图像坐标中返回的边界框,计算车辆在车辆坐标中的位置。它返回车辆坐标中边界框底部的中心位置。由于使用了单目相机传感器和简单的单应相图,因此只能计算沿道路表面的距离。计算三维空间中的任意位置需要使用立体摄像机或其他能够进行三角测量的传感器。

函数locations = computevehicllocations (bboxes, sensor) locations = 0 (size(bboxes,1),2);I = 1:size(bboxes, 1) bbox = bboxes(I,:);的下部分的中心[x,y]位置%检测包围框,单位为米。盒子是[x, y,宽度,高度]在%图像坐标,其中[x,y]表示左上角。yBottom = bbox(2) + bbox(4) - 1;xCenter = bbox(1) + (bbox(3)-1)/2;近似中心%locations(i,:) = imageToVehicle(sensor, [xCenter, yBottom]);结束结束

insertVehicleDetections插入边界框并显示与返回的车辆检测对应的[x,y]位置。

函数imgOut = insertVehicleDetections(imgIn, locations, bboxes);I = 1:size(locations, 1) location = locations(I,:);Bbox = bboxes(i,:);标签= sprintf(“X = % 0.2 f, Y = % 0.2 f ',位置(1),位置(2));imgOut = insertObjectAnnotation(imgOut,...“矩形”, bbox, label,“颜色”‘g’);结束结束

vehicleToImageROI将车辆坐标中的ROI转换为鸟瞰图像中的图像坐标。

函数imageROI = vehicleToImageROI(birdsEyeConfig, vehicleROI) vehicleROI = double(vehicleROI);loc2 = abs(vehicleToImage(birdsEyeConfig, [vehicleROI(2) vehicleROI(4)]));loc1 = abs(vehicleToImage(birdsEyeConfig, [vehicleROI(1) vehicleROI(4)]));loc4 = vehicleToImage(birdsEyeConfig, [vehicleROI(1) vehicleROI(4)]);loc3 = vehicleToImage(birdsEyeConfig, [vehicleROI(1) vehicleROI(3)]);[minRoiX, maxRoiX, minRoiY, maxRoiY] = deal(loc4(1), loc3(1), loc2(2), loc1(2)));imageROI = round([minRoiX, maxRoiX, minRoiY, maxRoiY]);结束

validateBoundaryFcn拒绝使用RANSAC算法计算的部分车道边界曲线。

函数isGood = validateBoundaryFcn(params)如果~isempty(params) a = params(1);拒绝任何具有小“a”系数的曲线,这使得它很高%弯曲。isGood = abs(a) < 0.003;% a从ax^2+bx+c其他的isGood = false;结束结束

classifyLaneTypes确定车道标记类型为固体等。

函数边界= classifyLaneTypes(边界,边界点)bInd = 1: size(边界,2)vehiclePoints =边界点{bInd};%按x排序车辆积分= sortrows(车辆积分,1);xVehicle =车辆点数(:,1);xVehicleUnique = unique(xVehicle);虚线vs实线xdiff = diff(xVehicleUnique);设置一个阈值,以删除实线中的空白,但不删除空格%虚线。xdiffThreshold = mean(xdiff) + 3*std(xdiff);largeGaps = xdiff(xdiff > xdiffThreshold);%安全默认值边界=边界(绑定);%根据set/get方法更改边界。BoundaryType = LaneBoundaryType.Solid;如果largeGaps > 1理想情况下,这些差距应该是一致的,但你不能依赖。%,除非你知道ROI范围至少包括3个破折号。边界。BoundaryType = LaneBoundaryType.Dashed;结束边界(bInd) =边界;结束结束

takeSnapshot捕获HTML发布报告的输出。

函数I = takeSnapshot(frame, sensor, sensorOut)解压缩输入leftEgoBoundary = sensorOut.leftEgoBoundary;理义边界= sensorout .理义边界;locations = sensorout . vehicllocations;xVehiclePoints = sensorOut.xVehiclePoints;bboxes = sensorOut.vehicleBoxes;framewithoverlay = insertLaneBoundary(frame, leftEgoBoundary, sensor, xVehiclePoints,“颜色”“红色”);framewithoverlay = insertLaneBoundary(framewithoverlay, righgoboundary, sensor, xVehiclePoints,“颜色”“绿色”);framewithoverlay = insertVehicleDetections(framewithoverlay, locations, bboxes);I = framewithoverlay;结束

另请参阅

应用程序

功能

对象

相关的话题