主要内容

单目相机的视觉感知

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

概述

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

  • 车道边界检测

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

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

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

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

定义摄像机的配置

了解相机的内部和外部标定参数对像素和车辆坐标的精确转换至关重要。

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

focalLength = [309.4362, 344.2161];% [fx, fy]以像素为单位主点=[318.9034257.5352];%[cx,cy]像素坐标中的光学中心imageSize=[480640];% (nrows, mcols)

请注意,透镜畸变系数被忽略,因为数据中几乎没有畸变。参数存储在cameraIntrinsics对象

camIntrinsics = cameraIntrinsics(focalLength, principalPoint, imageSize);

接下来,定义相对于车辆底盘的摄像机方向。您将使用这些信息来建立摄像机外部信息,定义3d摄像机坐标系相对于车辆坐标系的位置。

身高= 2.1798;%离地面的安装高度(米)距= 14;相机的角度百分比

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

传感器= moncamera (camIntrinsics, height,“节”、沥青);

请注意,monoCamera对象建立了一个非常特殊的车辆坐标系统X-轴指向车辆前方Y-轴指向车辆左侧,并且Z轴指向地面。

默认情况下,坐标系的原点位于地面上,位于由相机焦点定义的相机中心的正下方SensorLocation财产的monoCamera反对。此外,monoCamera提供了imageToVehiclevehicleToImage在图像和车辆坐标系统之间转换的方法。

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

加载一帧视频

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

首先创建一个录像机对象打开视频文件。为了节省内存,录像机一次加载一个视频帧。

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

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

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

注意:此示例忽略镜头失真。如果您担心透镜畸变引起的距离测量误差,此时您将使用undistortImage功能,以消除镜头失真。

创建鸟瞰图图像

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

考虑到摄像头的设置birdsEyeView对象将原始图像转换为鸟瞰视图。通过此对象,可以指定要使用车辆坐标变换的区域。请注意,车辆坐标单位是由monoCamera对象时,相机安装高度指定为米。例如,如果高度以毫米为单位指定,则模拟的其余部分将使用毫米。

使用车辆坐标,定义要变换的区域distaheadof传感器=30;%以米为单位,如前所述在相机高度输入中指定的spaceToOneSide = 6;所有其他距离的单位也是米bottomOffset=3;outView=[bottomOffset,距离传感器前端,-SpaceToOnSide,SpaceToOnSide];% [xmin, xmax, ymin, ymax]imageSize = [NaN, 250];输出图像宽度(像素)%;高度是自动选择的,以保持每像素的单位比例birdseeconfig = birdsEyeView(sensor, outView, imageSize);

生成鸟瞰图的形象。

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

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

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

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

有了鸟瞰图,你现在可以使用segmentLaneMarkerRidge用于将车道标记候选像素与路面分离的功能。选择该技术是因为其简单性和相对有效性。存在其他分割技术,包括语义分割(深度学习)和可控制的过滤器。你可以用下面的这些技术来获得下一阶段所需的二进制掩码。

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

%转换为灰度birdsEyeImage = im2gray (birdsEyeImage);以世界单位计算的车道标记分割ROI= outView - [- 1,2, - 3,3];向左和向右看3米,在传感器前面4米approxLaneMarkerWidthVehicle = 0.25;% 25厘米%检测车道特征laneSensitivity = 0.25;birdsEyeViewBW = segmentLaneMarkerRidge(birdsEyeImage, birdseeconfig, approxLaneMarkerWidthVehicle,...“投资回报率”vehicleROI,“敏感性”, laneSensitivity);图imshow (birdsEyeViewBW)

在固定到摄像头传感器的车辆坐标中定位各个车道标记。此示例使用抛物线车道边界模型ax^2+bx+c表示车道标记。其他表示,如三次多项式或样条曲线,也是可能的。转换为车辆坐标是必要的,否则车道标记曲率不能正确地用抛物线表示,而它会受到透视畸变的影响。

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

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

由于分割后的点中包含了很多不属于实际车道标记的异常点,因此采用基于随机样本一致性(RANSAC)的鲁棒曲线拟合算法。

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

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

请注意,findParabolicLaneBoundaries接受一个函数句柄,验证基础FCN.这个示例函数列在本示例的末尾。使用这个额外的输入可以让您根据a、b、c参数的值拒绝一些曲线。它也可以用来利用一系列帧的时间信息,通过约束未来的a, b, c值基于以前的视频帧。

确定自我通道的边界

在上一步中找到的某些曲线可能仍然无效。例如,当一条曲线适合人行横道标记时。请使用其他启发式方法拒绝许多此类曲线。

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

基于由计算的强度度量删除其他边界findParabolicLaneBoundaries功能。根据ROI和图像大小设置车道强度阈值。

%为了计算最大强度,假设ROI内的所有图像像素%是车道候选点吗birdsImageROI=车辆图像ROI(birdsEyeConfig,VehiclerRoi);[laneImageX,laneImageY]=网格(birdsImageROI(1):birdsImageROI(2),birdsImageROI(3):birdsImageROI(4));将图像点转换为车辆点vehiclePoints = imageToVehicle (birdsEyeConfig [laneImageX (:), laneImageY (:)));找到任意车道唯一x轴位置的最大数目%的边界maxPointsInOneLane =元素个数(独特(单(vehiclePoints (: 1)))));%设置车道边界的最大长度为ROI的长度maxLaneLength = diff (vehicleROI (1:2));%计算此图像大小/ROI大小的最大可能车道强度%的规范maxStrength = maxPointsInOneLane / maxLaneLength;拒绝短而弱的边界idx = 0;strongBoundaries = parabolicLaneBoundary(zeros(nnz(isOfMinLength), 3));i = 1: size(isOfMinLength,2)如果isOfMinLength(i) == 1如果(边界(i)。强度> 0.4*maxStrength) idx = idx + 1;strongBoundaries (idx) =边界(我);结束结束结束

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

当边界点不是空的时候对车道标记类型进行分类如果isempty(strongBoundaries) strongBoundaries = repmat(strongBoundaries,1,2);strongBoundaries (1) = parabolicLaneBoundary(0(1、3));strongBoundaries (2) = parabolicLaneBoundary(0(1、3));其他的strong边界=ClassifyLanetype(strong边界、边界点);结束distancestobounders=coder.nullcopy(一个(大小(strongbounders,2),1));%寻找自我通道xOffset = 0;%距离传感器0米i = 1: size(strongBoundaries, 2) distanceboundaries (i) = strongBoundaries(i).computeBoundaryModel(xOffset);结束找出应聘者的自我界限distancesToLeftBoundary = distancesToBoundaries > 0;如果minLeftDistance = min(distanceobells (distanceoleftboundary));其他的minLeftDistance = 0;结束distanceorightboundary = (distanceborders <= 0);如果minRightDistance = max(distanceborders (distanceorightboundary));其他的minRightDistance=0;结束找到左边的自我边界如果(minLeftDistance~=0)leftEgoBoundaryIndex=DistanceToBoundaryIndex==minLeftDistance;leftEgoBoundaryIndex=ParaboliclaneBundary(零(nnz(leftEgoBoundaryIndex),3));idx=0;i=1:大小(leftEgoBoundaryIndex,1)如果(leftEgoBoundaryIndex(i)=1)idx=idx+1;leftEgoBoundary(idx)=strong边界(i);结束结束其他的leftEgoBoundary=parabolicLaneBoundary.empty();结束找到正确的自我界限如果(minRightDistance ~= 0)rightgoboundary = parabolicLaneBoundary(zeros(nnz(rightgoboundary index), 3));idx = 0;i = 1: size(rightgoboundaryindex, 1)如果(rightEgoBoundaryIndex(i)=1)idx=idx+1;rightEgoBoundary(idx)=strong边界(i);结束结束其他的rightEgoBoundary = parabolicLaneBoundary.empty ();结束

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

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

在车辆坐标中定位车辆

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

加载一个聚合通道功能(ACF)检测器,该检测器经过预训练以检测车辆的前部和后部。这样的检测器可以处理发出碰撞警告很重要的情况。例如,它不足以检测在车辆前方穿过道路的车辆。

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

使用configureDetectorMonoCamera功能将通用ACF检测器专门化,以考虑典型汽车应用的几何结构。通过采用此摄像头配置,此新检测器仅搜索道路表面上的车辆,因为没有点搜索高于消失点的车辆。这节省了计算时间和r得出误报的数量。

monoDetector = configuredetectormoncamera(检测器,传感器,车辆宽度);[bboxes, scores] = detect(monoDetector, frame);

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

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

locations = computeVehicleLocations(bboxes, sensor);%在视频帧上覆盖检测imgOut = insertVehicleDetections(frame, locations, bboxes);图;imshow (imgOut);

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

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

将视频倒回开头,然后对视频进行处理。下面的代码被缩短了,因为所有关键参数都在前面的步骤中定义了。这里只使用参数,不作进一步说明。

videoReader。CurrentTime = 0;isPlayerOpen = true;快照= [];虽然hasFrame (videoReader) & & isPlayerOpen%抓取一帧视频帧= readFrame (videoReader);%计算birdsEyeView图像birdsEyeImage = transformImage(birdseeconfig, frame);birdsEyeImage = im2gray (birdsEyeImage);%检测车道边界特征birdsEyeViewBW=分段LaneMarkerRidge(birdsEyeImage,birdsEyeConfig,...approxLaneMarkerWidthVehicle,“投资回报率”vehicleROI,...“敏感性”, laneSensitivity);在车辆坐标中获得车道候选点[imageX, imageY] = find(birdsEyeViewBW);xyBoundaryPoints = imageToVehicle(birdsEyeConfig, [imageY, imageX]);%查找车道边界候选项[边界,边界点]=FindParabolicLaneBundaries(xyBoundaryPoints,boundaryWidth,...“MaxNumBoundaries”,maxLanes,“validateBoundaryFcn”,@validateBondaryFCN);%根据边界的长度和强度拒绝边界找到短的界限如果(numel(boundaries) > 0) isOfMinLength = false(1, numel(boundaries));I = 1: numel(边界)如果(diff(界限(i).XExtent)>minXLength)isOfMinLength(i)=真;结束结束其他的isOfMinLength = false;结束拒绝短而弱的边界idx = 0;strongBoundaries = parabolicLaneBoundary(zeros(nnz(isOfMinLength), 3));i = 1: size(isOfMinLength,2)如果isOfMinLength(i) == 1如果(边界(i)。强度> 0.2*maxStrength) idx = idx + 1;strongBoundaries (idx) =边界(我);结束结束结束边界=边界(isOfMinLength);强有力的=[边界。强度)> 0.2 * maxStrength;边界=边界(强有力的);当边界点不是空的时候对车道标记类型进行分类如果isempty(strongBoundaries) strongBoundaries = repmat(strongBoundaries,1,2);strongBoundaries (1) = parabolicLaneBoundary(0(1、3));strongBoundaries (2) = parabolicLaneBoundary(0(1、3));其他的strong边界=ClassifyLanetype(strong边界、边界点);结束%寻找自我通道xOffset = 0;%距离传感器0米distancestobounders=coder.nullcopy(一个(大小(strongbounders,2),1));i = 1: size(strongBoundaries, 2) distanceboundaries (i) = strongBoundaries(i).computeBoundaryModel(xOffset);结束找出应聘者的自我界限distancesToLeftBoundary = distancesToBoundaries > 0;如果minLeftDistance = min(distanceobells (distanceoleftboundary));其他的minLeftDistance = 0;结束distanceorightboundary = (distanceborders <= 0);如果minRightDistance = max(distanceborders (distanceorightboundary));其他的minRightDistance=0;结束找到左边的自我边界如果(minLeftDistance~=0)leftEgoBoundaryIndex=DistanceToBoundaryIndex==minLeftDistance;leftEgoBoundaryIndex=ParaboliclaneBundary(零(nnz(leftEgoBoundaryIndex),3));idx=0;i=1:大小(leftEgoBoundaryIndex,1)如果(leftEgoBoundaryIndex(i)=1)idx=idx+1;leftEgoBoundary(idx)=strong边界(i);结束结束其他的leftEgoBoundary=parabolicLaneBoundary.empty();结束找到正确的自我界限如果(minRightDistance ~= 0)rightgoboundary = parabolicLaneBoundary(zeros(nnz(rightgoboundary index), 3));idx = 0;i = 1: size(rightgoboundaryindex, 1)如果(rightEgoBoundaryIndex(i)=1)idx=idx+1;rightEgoBoundary(idx)=strong边界(i);结束结束其他的rightEgoBoundary = parabolicLaneBoundary.empty ();结束%检测车辆[bboxes, scores] = detect(monoDetector, frame);locations = computeVehicleLocations(bboxes, sensor);可视化传感器输出和中间结果。包的核心%传感器输出到结构中。sensorOut。leftEgoBoundary = leftEgoBoundary;sensorOut。rightEgoBoundary = rightEgoBoundary;sensorOut。vehicleLocations =位置;sensorOut。xVehiclePoints = bottomOffset: distAheadOfSensor;sensorOut。vehicleBoxes = bboxes;%打包额外的可视化数据,包括中间结果intOut。birdsEyeImage = birdsEyeImage;intOut。birdsEyeConfig = birdsEyeConfig;intOut。vehicleScores =分数;intOut。vehicleROI = vehicleROI;intOut。birdsEyeBW = birdsEyeViewBW; closePlayers = ~hasFrame(videoReader); isPlayerOpen = visualizeSensorResults(frame, sensor, sensorOut,...intOut closePlayers);时间戳= 7.5333;%获取在timeStamp秒发布的快照如果abs(videoReader.CurrentTime-时间戳)<0.01快照=拍摄快照(帧、传感器、传感器输出);结束结束

显示视频帧。快照是在时间戳秒。

如果~i空(快照)图imshow(快照)结束

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

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

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

%的传感器配置focalLength = [309.4362, 344.2161];principalPoint = [318.9034, 257.5352];imageSize = [480,640];身高= 2.1798;%离地面的安装高度(米)距= 14;相机的角度百分比camIntrinsics = cameraIntrinsics(focalLength, principalPoint, imageSize);传感器= moncamera (camIntrinsics, height,“节”、沥青);videoReader = videoReader (“caltech_washington1.avi”);

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

monoSensor = helperMonoSensor(传感器);monoSensor。LaneXExtentThreshold = 0.5;%在这个视频中,为了去除阴影中的错误检测,我们只返回%车辆检测与更高的分数。monoSensor.VehicleDetectionThreshold=20;isPlayerOpen=true;snapshot=[];虽然hasFrame(videoReader) && isPlayerOpen frame = readFrame(videoReader);得到一个帧sensorOut=processFrame(单传感器,帧);ClosePlayer=~hasFrame(视频阅读器);ISPlayerPerpen=DisplaySensorOuts(单传感器,帧,传感器输出,ClosePlayer);时间戳=11.1333;%获取在timeStamp秒发布的快照如果abs(videoReader.CurrentTime-时间戳)<0.01快照=拍摄快照(帧、传感器、传感器输出);结束结束

显示视频帧。快照是在时间戳秒。

如果~i空(快照)图imshow(快照)结束

金宝app支持功能

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

作用isPlayerOpen = visualizeSensorResults(frame, sensor, sensorOut,...输入,近距离播放)拆开主要输入leftEgoBoundary=传感器输出。leftEgoBoundary;rightEgoBoundary=传感器输出。rightEgoBoundary;位置=传感器输出。车辆位置;X车辆点=传感器输出。X车辆点;B盒=传感器输出。车辆盒;%解包额外的中间数据birdsEyeViewImage = intOut.birdsEyeImage;birdsEyeConfig = intOut.birdsEyeConfig;vehicleROI = intOut.vehicleROI;birdsEyeViewBW = intOut.birdsEyeBW;在鸟瞰视图中可视化左、右自我车道边界birdsEyeWithOverlays = insertLaneBoundary(birdsEyeViewImage, leftEgoBoundary, birdseeconfig, xVehiclePoints,“颜色”“红色”);birdseyewiththoverlay = insertLaneBoundary(birdseyewiththoverlay, rightgoboundary, birdseeconfig, xVehiclePoints,“颜色”“绿色”);%在摄像机视图中可视化自我通道边界frameWithOverlays=插入平面基础(框架、左侧边界、传感器、X车辆点、,“颜色”“红色”);framewiththoverlays = insertLaneBoundary(framewiththoverlays, rightgoboundary, sensor, xVehiclePoints,“颜色”“绿色”);framewithoverlay = insertVehicleDetections(framewithoverlay, locations, bboxes);imageROI = vehicleToImageROI(birdsEyeConfig, vehicleeroi);ROI = [imageROI(1) imageROI(3) imageROI(2)-imageROI(1) imageROI(4)-imageROI(3)];%突出显示包含异常值的候选车道点birdsEyeViewImage = insertShape (birdsEyeViewImage,“矩形”ROI);显示检测ROI= imoverlay(birdsEyeViewImage, birdsEyeViewBW,“蓝”);%显示结果frames = {framewiththoverlay, birdsEyeViewImage, birdseyewiththoverlay};持续的球员;如果isempty(players) frameames = {“行车标志及车辆侦测”“原始分割”“车道标记检测”};= helperVideoPlayerSet(帧,帧名);结束更新(球员,框架);%当第一个玩家关闭时终止循环isPlayerOpen=isOpen(玩家1);如果(~ isPlayerOpen | | closePlayers)%关闭其他玩家清晰的球员结束结束

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

作用位置=计算车辆位置(B盒,传感器)位置=零(尺寸(B盒,1),2);I = 1:size(bboxes, 1) bbox = bboxes(I,:);%获取[x,y]位置的下半部分的中心%检测边界框,单位为米。Bbox是[x, y,宽度,高度]%图像坐标,其中[x,y]表示左上角。yBottom=bbox(2)+bbox(4)-1;xCenter=bbox(1)+(bbox(3)-1)/2;%近似中心位置(i,:) = imageToVehicle(sensor, [xCenter, yBottom]);结束结束

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

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

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

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

验证基础FCN拒绝使用RANSAC算法计算的一些车道边界曲线。

作用= validateBoundaryFcn短距离(params)如果~isempty(params)a=params(1);%拒绝任何具有较小“a”系数的曲线,这会使其具有较高的稳定性%弯曲。isGood = abs(a) < 0.003;% a从ax^2+bx+c其他的好= false;结束结束

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

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

快照获取HTML发布报告的输出。

作用I=拍摄快照(帧、传感器、传感器输出)%打开输入leftEgoBoundary=sensorOut.leftEgoBoundary;rightEgoBoundary=sensorOut.rightEgoBoundary;locations=sensorOut.vehicleLocations;xVehiclePoints=sensorOut.xVehiclePoints;bboxes=sensorOut.VehicleBox;frameWithOverlays=InsertLaneBundary(框架,leftEgoBoundary,传感器,xVehiclePoints,“颜色”“红色”);framewiththoverlays = insertLaneBoundary(framewiththoverlays, rightgoboundary, sensor, xVehiclePoints,“颜色”“绿色”); frameWithOverlays=插入车辆检测(frameWithOverlays、位置、B框);I=带覆盖层的框架;结束

另请参阅

应用程序

功能

对象

相关话题