主要内容

使用HERE高清实时地图数据验证车道配置

这个例子展示了如何从HERE HD Live Map (HERE HDLM)服务读取和可视化记录的驾驶路线的车道配置。这种可视化可用于验证由车载传感器(如单目摄像机)的感知系统检测到的车道配置。

在本例中,您将了解如何从HDLM服务访问平铺层,并识别相关的道路级和车道级拓扑、几何和属性。

要读取数据,可以使用hereHDLMReader对象。使用HERE高清实时地图服务需要有效的HERE HDLM凭证。为了获得对HDLM服务的访问权,并获得使用HERE服务所需的凭证(access_key_id和access_key_secret),您需要与HERE签订单独的协议。

概述

高清地图是指专门为自动驾驶应用开发的地图服务。这些地图的精确几何形状(赤道附近分辨率高达1厘米)使它们适合自动驾驶工作流程,超越了传统地图的路线规划应用。这样的工作流包括通道级验证、本地化和路径规划。这个示例向您展示了如何使用来自HD映射数据的车道级信息来验证车道检测系统的性能。

高清地图数据的准确性使其能够作为机载传感器感知系统验证的地面真实数据来源。这种高精度可以更快、更准确地验证现有部署的算法。

HERE高清实时地图(HERE HDLM)是HERE科技公司开发的一款基于云的高清地图服务,用于支持高度自动化驾驶。金宝app数据由平铺映射层组成,提供了对道路网络的精确几何形状和鲁棒属性的访问。这些层分为以下模型:

  • 道路中心线模型:提供道路拓扑(在图中指定为节点和链接)、形状几何和其他道路级别属性。

  • 高清车道模型:提供车道拓扑(作为车道组和车道组连接器)、高度精确的几何图形和车道级属性。

  • 高清定位模型:提供支持车辆本地化策略的特性。金宝app

有关HERE HDLM层的概述,请参见这里是高清实时地图图层

在自动驾驶中,摄像头用于收集车辆周围道路拓扑结构的语义信息。车道边界检测、车道类型分类和路标检测算法构成了该摄像头处理管道的核心。您可以使用HERE HDLM服务以及安装在车辆上的高精度GPS来评估此类算法的准确性并验证其性能。

在这个例子中,你将学习如何:

  1. 从HERE HDLM服务读取记录的GPS序列的道路和车道信息。

  2. 对GPS记录数据采用启发式路径匹配方法。由于GPS数据通常是不精确的,因此有必要解决将记录的地理坐标与道路网络表示相匹配的问题。

  3. 识别与车辆相关的环境属性。一旦在地图上下文中成功定位车辆,您就可以使用与车辆相关的道路和车道属性来验证车辆车载摄像头传感器记录的数据。

加载和显示相机和GPS数据

首先从记录的驱动器加载数据。本例中记录的数据来自Udacity®自动驾驶汽车团队收集的驾驶数据集。这些数据包括由前置单目摄像头拍摄的视频,以及由GPS记录的车辆位置和速度。

加载centerCamera.avi摄像机视频数据和相应的视频时间戳。

recordedData = fullfile(toolboxdir(“开车”),“drivingdata”...“udacity”“drive_segment_09_29_16”);[videoReader, videoTime] = helperLoadCameraData(fullfile(recordedData));显示相机数据的第一帧imageFrame = readFrame(视频阅读器);imshow (imageFrame“边界”“紧”);

加载GPS数据gpsSequence.matMAT-file。

data = load(fullfile(recordedData),“gpsSequence.mat”));gpsData = data.gpsTT;绘制完整路线和GPS记录的第一个位置gpsPlayer = geoplayer(gpsData.Latitude(1), gpsData.Longitude(1), 18);plotRoute (gpsPlayer gpsData。纬度,gpsData。Longitude); plotPosition(gpsPlayer, gpsData.Latitude(1), gpsData.Longitude(1));

将记录的车辆位置与道路匹配

创建一个阅读器,用于阅读HERE高清实时地图磁贴,覆盖驱动器中所有记录的GPS位置。如果您以前没有设置HERE HDLM凭据,则会出现一个对话框提示您输入凭据。进入Access Key ID而且访问密钥秘密从HERE Technologies获得的,然后单击好吧

reader = hereHDLMReader(gpsData. reader)。纬度,gpsData.Longitude);

读取并绘制道路拓扑数据TopologyGeometry层。这一层表示道路网络的配置。网络的节点对应于交叉路口和死胡同。节点之间的链接将连接街道的形状表示为折线。控件中包含这些特性的连接性和几何形状LinksStartingInTile而且NodesInTile字段。

topologyLayer = read(读取器,“TopologyGeometry”图()“名字”“TopologyGeometry”);topologyAxes = plot(topologyLayer);持有(topologyAxes“上”);geoplot (topologyAxes gpsData。纬度,gpsData。经度,...“bo - - - - - -”“DisplayName的”“路线”);
topologyLayer = TopologyGeometry with properties: Data: HereTileId: 309106790 IntersectingLinkRefs: [44×1 struct] LinksStartingInTile: [895×1 struct] NodesInTile: [651×1 struct] TileCenterHere2dCoordinate:[37.3865 -122.1130]元数据:Catalog: 'hrn:here: Data::olp-here-had:here-hdlm-protobuf-na-2' CatalogVersion: 4601使用plot可视化TopologyGeometry数据。

控件中捕获绘图功能helperPlotLayer功能,该功能将来自HD Live Map层的可用数据与在同一地理轴上记录的驱动器可视化。这个函数在示例的最后定义,将用于绘制后续层。

给定沿着驱动器记录的GPS位置,您可以使用路由匹配算法来确定记录的位置对应于网络上的哪条道路。本例使用启发式路由匹配算法,该算法考虑空间上与记录的地理点最近的链接。该算法应用车辆的行驶方向来确定最可能的链接。这种路线匹配方法没有考虑道路连通性、车辆通道或具有高位置误差的GPS数据。因此,这种方法可能不适用于所有场景。

helperGetGeometry函数从给定的拓扑层提取几何信息,并将该信息返回到具有相应链接的表中。

topologyTable = helperGetGeometry(拓扑层。LinksStartingInTile,...“LinkId”的几何形状。Here2dCoordinateDiffs”});topologyTable.Properties.VariableNames = {“LinkId”“几何”};

HelperLinkMatcher类创建链接匹配器,其中包含所需映射块中每个链接的形状几何。这个类使用基本的空间分析来匹配记录的位置与道路链接的形状坐标。

linkMatcher = helplinkmatcher(拓扑表);将记录路由的第一个点匹配到最可能的链路[linkId, linkLat, linkLon] = match(linkMatcher, gpsData.Latitude(1),...gpsData.Longitude (1) gpsData.Velocity (1:2));绘制链接的几何形状geoplot (gpsPlayer。斧头,linkLat, linkLon,' r . - ');

沿着匹配的道路检索速度限制

给定道路上所有车道共有的特征归因于描述该道路的link元素。其中一个属性,速度限制,描述了在这条线路上行驶的车辆的最高合法速度。一旦给定的地理坐标与链接相匹配,您就可以识别该链接的速度限制。因为像速度限制这样的特性通常会随着链接的长度而变化,所以这些属性是针对链接的特定范围识别的。

SpeedAttributes层包含有关链路上的预期车辆速度的信息,包括发布的速度限制。

speedLayer = read(读取器,“SpeedAttributes”);

helperGetSpeedLimits函数提取链接的相关长度和方向的速度限制数据。与提取链接的几何信息一样,特别地捕获速度限制数据需要专门的代码。

speedTable = helperGetSpeedLimits(speedLayer);查找匹配链接的速度限制条目speed = speedTable(速度表。LinkId == LinkId,:);

将记录的位置匹配到一个Lane组

HD车道模型包含车道级的几何形状和道路属性,提供了支持自动驾驶应用程序所需的细节。金宝app与道路中心线模型非常相似,HD车道模型也遵循使用拓扑结构来描述车道级别的道路网络的模式。然后将通道组的特征归结于该拓扑结构的元素。在HD车道模型中,主要的拓扑元素是车道组。

中读取并绘制车道拓扑数据LaneTopology层。该层将车道拓扑表示为车道组和车道组连接器。车道组表示链路(路段)内的车道组。车道组连接器将各个车道组相互连接。控件中包含这些特性的连接性和几何形状LaneGroupsStartingInTile而且LaneGroupConnectorsInTile字段,分别用于车道组和车道组连接器。

laneTopologyLayer = read(读取器,“LaneTopology”) laneAxes = helperPlotLayer(laneTopologyLayer,...gpsData。纬度,gpsData.Longitude);geolimits(laneAxes, [37.3823, 37.3838], [-122.1151, -122.1128]);
laneTopologyLayer = LaneTopology with properties: Data: HereTileId: 309106790 IntersectingLaneGroupRefs: [56×1 struct] LaneGroupConnectorsInTile: [1174×1 struct] LaneGroupsStartingInTile: [1783×1 struct] TileCenterHere2dCoordinate:[37.3865 -122.1130]元数据:Catalog: 'hrn:here: Data::olp-here-had:here-hdlm-protobuf-na-2' CatalogVersion: 4601使用plot可视化LaneTopology数据。

lane组表示多个lane。因此,该元素的几何形状由该组所采用的多边形形状给出,由巷组的左右边界表示。方法从车道边界获得此车道几何形状helperGetGeometry函数。

laneGroupFields = {“LaneGroupId”...“BoundaryGeometry.LeftBoundary.Here2dCoordinateDiffs”...“BoundaryGeometry.RightBoundary.Here2dCoordinateDiffs”};laneTopologyTable = helperGetGeometry(laneTopologyLayer。LaneGroupsStartingInTile,...laneGroupFields);laneTopologyTable.Properties.VariableNames = {“LaneGroupId”...“LeftGeometry”“RightGeometry”};

与开发匹配算法来识别最可能的旅行链接一样,将给定的GPS数据与最可能的车道组匹配可以遵循多种方法。这里描述的方法使用了两层:LaneRoadReferences而且LaneTopology

  • LaneRoadReferences图层使你能够将道路中心线模型上的位置(由链接给出)转换为HD车道模型上的相应位置(由车道组给出)。由于之前已经确定了链接,因此可以将候选车道组匹配过滤到该磁贴中所有可用车道组的较小子集。

  • LaneTopologyLayer给出几何数据,可用于考虑存在于每个候选车道组边界内的空间数据。与将GPS数据与链路进行空间匹配一样,这种方法容易出错,并受记录的GPS数据的准确性的影响。除了匹配车道组外,还需要匹配车辆相对于车道组方向的方向向量。这个步骤是必要的,因为车道的属性是根据拓扑方向定义的。

使用helperGetReferences函数生成一个包含至少存在一段链路长度的所有车道组的表。

referenceLayer = read(读取器,“LaneRoadReferences”);referenceTable = helperGetReferences(referenceLayer);

创建一个车道组匹配器,其中包含所需映射瓷砖中每个车道组的边界几何图形。的HelperLaneGroupMatcher类创建一个车道组匹配器,其中包含所需映射块中每个车道组的边界形状几何。它还包含到车道组的链接的参考表。就像HelperLinkMatcher类,该类使用一个简单的空间分析方法来确定给定的记录坐标是否存在于车道组的边界内。

laneGroupMatcher = HelperLaneGroupMatcher(referenceTable, laneTopologyTable);匹配车道组和相对方向[laneGroupId, isForward, boundGeometry] = match(laneGroupMatcher, linkId,...gpsData.Latitude(1), gpsData.Longitude(1), gpsData.Velocity(1,1:2));绘制车道组的边界几何图形geoplot (gpsPlayer。坐标轴,boundGeometry(:,1), boundGeometry(:,2),“m - - - - - -”);

检索匹配的Lane组的Lane配置

与通过标识符映射到链接的速度属性一样,车道属性也通过使用车道组ID将特性分配给车道组。的LaneAttributes层包含关于车道组的信息,包括组中每个车道的类型和车道边界的特征。

使用helperGetLaneAttributes函数提取瓷砖中每个车道组的不同车道类型和车道边界标记。

laneAttributesLayer = read(读取器,“LaneAttributes”);laneattributest = helperGetLaneAttributes(laneAttributesLayer);查找匹配的车道组的车道属性条目laneAttribute = laneattribu可测试。LaneGroupId == LaneGroupId;

可视化和验证记录驱动器与这里HDLM数据

为识别道路和车道属性而生成的匹配算法和表可以扩展为记录的GPS坐标序列。对于每个时间步,车辆的位置匹配到道路上的链接和车道组。此外,速度限制和车道配置将与相应的摄像头图像一起显示。

HelperHDLMUI类创建了一个工具,用于流媒体视频和GPS数据从记录的驱动器和显示相关信息从选定的HERE高清实时地图层在每个记录的车辆位置。

hdlmUI = HelperHDLMUI(gpsData.Latitude(1), gpsData.Longitude(1));同步相机和GPS数据到一个共同的时间表synchronizedData =同步(videoTime, gpsData);videoReader。CurrentTime = 0;maxDisplayRate = videereader。FrameRate * 5;初始化一些变量以维护历史记录prevLinkId = 0;prevLaneGroupId = 0;idx = 1: height(synchronizedData) timeStamp = synchronizedData. time (idx);检查当前时间戳是否有GPS数据hasGPSFrame = ~(ismissing(synchronizedData.Latitude(idx)) || . hasGPSFrame = ~(ismissing(synchronizedData.Latitude(idx)...ismissing (synchronizedData.Longitude (idx)));如果hasGPSFrame纬度= synchronizedData.Latitude(idx);longitude = synchronizedData.Longitude(idx);velocity = synchronizedData。速度(idx 1:2);%匹配GPS位置链接[linkId, linkLat, linkLon] = match(linkMatcher, linkLat, linkLon)...纬度、经度、速度);如果linkId ~= prevLinkId%更新链接updateLink(hdlmUI, linkLat, linkLon);prevLinkId = linkId;%更新速度限制speed = speedTable(速度表。LinkId == LinkId,:);updateSpeed (hdlmUI speed.Value);结束匹配GPS位置到车道组[laneGroupId, isForward, boundGeometry] = match(laneGroupMatcher, linkId,...纬度、经度、速度);如果laneGroupId ~= prevLaneGroupId%更新车道组updateLaneGroup (hdlmUI boundGeometry);prevLaneGroupId = laneGroupId;更新车道类型和边界标记laneAttribute = laneattribu可测试。LaneGroupId == LaneGroupId;plotLanes (hdlmUI laneAttributesTable。车道{laneAttribute},...laneAttributesTable。LaneBoundaries {laneAttribute}, isForward);结束updatePosition(hdlmUI,纬度,经度);其他的%视频读取帧数imageFrame = readFrame(视频阅读器);结束updateImage (hdlmUI imageFrame);updateTime (hdlmUI、时间戳);暂停(1 / maxDisplayRate);结束

结论

在本例中,您探索了如何:

  1. 从HERE HD Live Map服务访问给定GPS序列的高清地图数据,并将该数据导入MATLAB。

  2. 将记录的GPS数据与导入的路网数据进行匹配,为每个地理坐标找到相关的链路和车道组。

  3. 查询匹配的链路和车道组的属性,例如限速和车道类型,以开发一个工具,根据记录的摄像头数据可视化地验证道路的特征。

本例中讨论的技术可以进一步扩展,以支持感知算法的自动验证。金宝app

金宝app支持功能

helperPlotLayer在地理图上绘制层数据和路线。

函数gx = helperPlotLayer(层,纬度,经度)创建带有层数据和路由的地理图% gx = helperPlotLayer(图层,纬度,经度)创建一个地理%坐标轴与可绘图的HDLM层和纬度给定的路线绘图%和经度在一个新的数字上。图;%绘图层Gx = plot(layer);%启用向图中添加数据持有(gx“上”);绘制纬度、经度数据Geoplot (gx,纬度,经度,“bo - - - - - -”“DisplayName的”“路线”);持有(gx“关闭”);结束

helperGetGeometry以表的形式从层中提取拓扑元素的几何图形。

函数几何表= helperGetGeometry(图层,字段)为拓扑元素创建一个几何表% geometryTable = helperGetGeometry(layer, fields)返回一个表使用TopologyGeometry的指定几何字段进行格式化%和LaneTopology层。预分配结构S = repmat(struct, size(layer));C = strsplit(字段{:},“。”);idx = 1:数字(层)fieldname = strjoin(C,);S (idx)。(字段名)= getfield C层,{idx}, {:});结束结束几何表= struct2table(S);结束

helperGetSpeedLimits以表格的形式从一个层中提取速度限制数据。

函数speedTable = helperGetSpeedLimits(layer)创建一个带有速度限制的数据表返回一个格式为。的表%沿指定链路的速度限制开始、结束、方向和值%,由SpeedAttributes层对象指定的layer。速度= struct(...“LinkId”{},...“开始”{},...“结束”{},...“方向”{},...“价值”, {});idx = 1: number (layer.LinkAttribution)分配链接IDlink = layer.LinkAttribution(idx);attributions = link.ParametricAttribution;检查分配给链接的每个属性attrIndex = 1:数字(attributions) linkAttr = vertcat(attributions. linkparamtricattribution);对于每个属性,检查速度限制信息是否为%上市。如果规定了速度限制,请填写。linkAttrIndex = 1:数字(linkAttr)如果~ isempty (linkAttr (linkAttrIndex) .SpeedLimit)为指定的链路分配速度限制speedLimit = struct;speedLimit。LinkId = link.LinkLocalRef;speedLimit。Start = attributes (attrIndex).AppliesToRange.RangeOffsetFromStart;speedLimit。结束= attributes (attrIndex).AppliesToRange.RangeOffsetFromEnd;speedLimit。方向= attributions(attrIndex).AppliesToDirection;speedLimit。Value = linkAttr(linkAttrIndex).SpeedLimit.Value;将时速转换为时速如果strcmpi (linkAttr .SpeedLimit.Unit (linkAttrIndex),“KILOMETERS_PER_HOUR”) speedLimit。Value = speedLimit。值/ 1.609;结束如果strcmpi (speedLimit。方向,“两个”)速度=[速度;speedLimit];% #好< AGROW >结束结束结束结束结束speedTable = struct2table(速度);结束

helperGetReferences以表的形式从层对象中提取车道道路引用。

函数laneRoadReferenceTable = helpergereferencences (layer)创建一个包含车道道路引用的数据表% laneRoadReferenceTable = helperGetReferences(layer)返回一个表使用指定链路上现有的所有通道组的列表格式化%由layer指定的LaneRoadReferences层对象给出。numLinks = nummel (layer.LinkLaneGroupReferences);引用= repmat(struct(“LinkId”{},“LaneGroupId”, {}), numLinks, 1);从链接获取到通道组的引用idx = 1: numLinks link = layer.LinkLaneGroupReferences(idx);laneGroups = vertcat(link.LaneGroupReferences.LaneGroupRef);参考(idx)。LinkId = link.LinkLocalRef;参考(idx)。LaneGroupId = [laneGroups(:).LaneGroupId]';结束laneRoadReferenceTable = struct2table(引用);结束

helperGetLaneAttributes以表的形式从层对象中提取车道属性。

函数helperGetLaneAttributes(层)创建一个包含车道和边界类型的表% laneattributest = helperGetLaneAttributes(layer)返回一个表%格式的车道类型和车道边界标记为每个由layer指定的LaneAttributes层对象中的lane组。laneGroupAttrIndex = 1: nummel (layer.LaneGroupAttribution) laneGroup = layer.LaneGroupAttribution(laneGroupAttrIndex);属性(laneGroupAttrIndex)。LaneGroupId = laneGroup.LaneGroupRef;% #好吧获取每个车道组的车道类型laneAttrIndex = 1: numel(laneGroup.LaneAttribution) lane = laneGroup.LaneAttribution(laneAttrIndex);laneAttr = vertcat(lane. paramtricattribution);laneAttr = vertcat(laneAttr. laneparameter attribution);idx = 1:数字(laneAttr)如果~ isempty (laneAttr (idx) .LaneType)属性(laneGroupAttrIndex) .Lanes{巷。LaneNumber} =...laneAttr (idx) .LaneType;结束结束结束获取每个车道组的车道边界laneBoundaryIndex = 1: number (laneGroup.LaneBoundaryAttribution) laneBoundary = laneGroup.LaneBoundaryAttribution(laneBoundaryIndex);边界= vertcat(laneboundary . parametricattribute . laneboundaryparameter attribution);属性(laneGroupAttrIndex) .LaneBoundaries {laneBoundary。LaneBoundaryNumber} =...boundaries.LaneBoundaryMarking;结束结束laneattribu可测试= struct2table(属性);结束

helperLoadCameraData从文件夹中加载视频阅读器和时间戳。

函数[videereader, videoTime] = helperLoadCameraData(dirName)从时间表的文件夹中加载相机图像% [videoReader, videoTime] = helperLoadCameraData(dirName)加载视频%从文件夹dirName。视频的时间戳从在timeStamps.mat文件夹中的% mat文件。如果~ isfolder(目录名)错误(“期望dirName是一个文件夹的路径。”结束matFileName = fullfile(dirName)“centerCameraTime.mat”);如果存在(matFileName“文件”) ~= 2错误('期望dirName有一个名为centerCameraTime的mat文件。有时间戳的垫子。”结束加载带有时间戳的mat文件ts = load(matFileName);fieldNames =字段(ts);时间= ts.(fieldNames{1});videoFileName = fullfile(dirName,“centerCamera.avi”);如果存在(matFileName“文件”) ~= 2错误(“期望dirName有一个名为centerCamera.avi的视频文件。”结束加载视频文件videoTime =时间表(时间);videereader = videereader (videoFileName);结束

另请参阅

||

相关的话题