Apollo camera 感知部分 目标检测源码阅读分析

2024-06-19 09:08

本文主要是介绍Apollo camera 感知部分 目标检测源码阅读分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

障碍物检测分为detector transformer postprocessor tracker几个部分

kitti 基于单目的3D目标检测的预备知识点:

首先是yolo3d 3d目标检测输出结果为kitti的3D格式,(其中3d信息部分是以相机坐标系为参考坐标系的)

首先介绍下kitti 3d object detection障碍物标注的的标注文件格式

KITTI数据集,label文件解析:

Car 0.00 0 -1.84 662.20 185.85 690.21 205.03 1.48 1.36 3.51 5.35 2.56 58.84 -1.75

1个字符串:代表物体类别

'Car', 'Van', 'Truck','Pedestrian', 'Person_sitting', 'Cyclist','Tram',  'Misc' or  'DontCare'

注意:’DontCare’ 标签表示该区域没有被标注,比如由于目标物体距离激光雷达太远。为了防止在评估过程中(主要是计算precision),将本来是目标物体但是因为某些原因而没有标注的区域统计为假阳性(false positives),评估脚本会自动忽略’DontCare’ 区域的预测结果。

2个数:代表物体是否被截断,从0(非截断)到1(截断)浮动,其中truncated指离开图像边界的对象

3个数:代表物体是否被遮挡,整数0123表示被遮挡的程度

0:完全可见  1:小部分遮挡  2:大部分遮挡 3:完全遮挡(unknown

4个数:alpha,物体的观察角度,范围:-pi~pi

是在相机坐标系下,以相机原点为中心,相机原点到物体中心的连线为半径,将物体绕相机y轴旋转至相机z轴,此时物体方向与相机x轴的夹角

https://img-blog.csdnimg.cn/20181204101648283.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2N1aWNodWFuY2hlbjMzMDc=,size_16,color_FFFFFF,t_70

图1

r_y + pi/2 -theta = alpha +pi/2(即图中紫色的角是相等的)

所以alpha = r_y – theta

584个数:物体的2维边界框,左上角和右下角的像素坐标

9113个数:3维物体的尺寸,高、宽、长(单位:米)

12143个数:3维物体的位置 x,y,z(在照相机坐标系下,单位:米)

15个数:3维物体的空间方向:rotation_y,在照相机坐标系下,相对于y轴的旋转角,范围:-pi~pi

物体前进方向与相机坐标系x轴的夹角,即上面的r_y

有些有第16个数:检测的置信度 仅用于结果:浮点,p / r曲线所需,越高越好

3KITTI数据集,calib解析

https://images2018.cnblogs.com/blog/1367904/201807/1367904-20180716153028727-1432159525.png

要将Velodyne坐标中的点x投影到左侧的彩色图像中y

使用公式:y = P2 * R0_rect *Tr_velo_to_cam * x

Velodyne坐标中的点投影到右侧的彩色图像中:

使用公式:y = P3 * R0_rect *Tr_velo_to_cam * x

Tr_velo_to_cam * x    :是将Velodyne坐标中的点x投影到编号为0的相机(参考相机)坐标系中

R0_rect *Tr_velo_to_cam * x    :是将Velodyne坐标中的点x投影到编号为0的相机(参考相机)坐标系中,再修正

P2 * R0_rect *Tr_velo_to_cam * x     :是将Velodyne坐标中的点x投影到编号为0的相机(参考相机)坐标系中,再修正,然后投影到编号为2的相机(左彩色相机)

注意:所有矩阵都存储在主行中,即第一个值对应于第一行。 R0_rect包含一个3x3矩阵,需要将其扩展为4x4矩阵,方法是在右下角添加1,在其他位置添加0Tr_xxx是一个3x4矩阵(R | t),需要以相同的方式扩展到4x4矩阵!

通过使用校准文件夹中的3x4投影矩阵,可以将相机坐标系中的坐标投影到图像中,对于提供图像的左侧彩色相机,必须使用P2rotation_yalpha之间的区别在于rotation_y直接在相机坐标中给出,而alpha也会考虑从相机中心到物体中心的矢量,以计算物体相对于相机的相对方向。 例如,沿着摄像机坐标系的X轴面向的汽车,无论它位于X / Z平面(鸟瞰图)中的哪个位置,它的rotation_y都为 0,而只有当此车位于相机的Z轴上时α才为零,当此车从Z轴移开时,观察角度α将会改变。

detection:

apollo 采用的yolo3d 基于caffe变种 没有开源,网上开源的方法有 deep3dbox 

查看kitti排名可以找出许多方法,例如groomed_nms kinematic3d RTM3D(该方法可以更快落地)

http://www.cvlibs.net/datasets/kitti/eval_object.php?obj_benchmark=3d

上图是我测试后RT3D的基于单目的3d目标检测效果示意图

apollo 的yolo是基于早期的deep3dbox原理做的,因此在上述label标注元素中介绍的只有alpha是通过网络直接获得的角度,关于rotation_y 和 theta_ray角度是根据坐标转换和相机外参求得的。

transformer:

主要是如下三个处理步骤:

 // set object mapper optionsfloat theta_ray = 0.0f;SetObjMapperOptions(obj, camera_k_matrix, width_image, height_image,&obj_mapper_options, &theta_ray);// processmapper_->Solve3dBbox(obj_mapper_options, object_center, dimension_hwl,&rotation_y);// fill back resultsFillResults(object_center, dimension_hwl, rotation_y, camera2world_pose,theta_ray, obj);

其中第一个是参数配置

第二个函数需要解析的一些重点操作如下:

apollo求取这些角度的方式如下代码,思路:获得图相框底边的中心点 image_point_low_center 根据内参矩阵(camera intrinsics)camera_k_matrix得到相机坐标系下的3D坐标点 point_in_camera,然后利用图1所示的原理获得 theta_ray rotation_y 两个方位角度信息。

//multicue_obstacle_transformer.ccfloat box_cent_x = (bbox2d[0] + bbox2d[2]) / 2;Eigen::Vector3f image_point_low_center(box_cent_x, bbox2d[3], 1);Eigen::Vector3f point_in_camera =static_cast<Eigen::Matrix<float, 3, 1, 0, 3, 1>>(camera_k_matrix.inverse() * image_point_low_center);*theta_ray =static_cast<float>(atan2(point_in_camera.x(), point_in_camera.z()));float rotation_y =*theta_ray + static_cast<float>(obj->camera_supplement.alpha);

求取目标物在相机坐标系下的中心点坐标:

利用小孔成像原理:

ObjMapper::SolveCenterFromNearestVerticalEdge

该函数用于获取目标中心点在相机坐标系下的坐标,以下代码做了注释。

bool ObjMapper::SolveCenterFromNearestVerticalEdge(const float *bbox,const float *hwl, float ry,float *center,float *center_2d) const {center[0] = center[1] = center[2] = 0.0f;float height_bbox = bbox[3] - bbox[1];float width_bbox = bbox[2] - bbox[0];if (width_bbox <= 0.0f || height_bbox <= 0.0f) {AERROR << "width or height of bbox is 0";return false;}if (common::IRound(bbox[3]) >= height_ - 1) {height_bbox /= params_.occ_ratio;}
//求取目标物距离相机近的一面的在相机坐标系下的深度float f = (k_mat_[0] + k_mat_[4]) / 2;float depth = f * hwl[0] * common::IRec(height_bbox);// compensate from the nearest vertical edge to centerconst float PI = common::Constant<float>::PI();float theta_bbox = static_cast<float>(atan(hwl[1] * common::IRec(hwl[2])));float radius_bbox =common::ISqrt(common::ISqr(hwl[2] / 2) + common::ISqr(hwl[1] / 2));float abs_ry = fabsf(ry);float theta_z = std::min(abs_ry, PI - abs_ry) + theta_bbox;theta_z = std::min(theta_z, PI - theta_z);
//求目标物中心点深度 需要加上目标物长度的一半并考虑角度来计算depth += static_cast<float>(fabs(radius_bbox * sin(theta_z)));// back-project to solve center 获得中心点坐标(kitti 3d label中的那几列,利用内参投影获得)center_2d[0] = (bbox[0] + bbox[2]) / 2;center_2d[1] = (bbox[1] + bbox[3]) / 2;if (hwl[1] > params_.stable_w) {GetCenter(bbox, depth, ry, hwl, center, center_2d);} else {center[2] = depth;UpdateCenterViaBackProjectZ(bbox, hwl, center_2d, center);}return center[2] > params_.depth_min;
}

bool ObjMapper::Solve3dBboxGivenOneFullBboxDimensionOrientation(const float *bbox, const float *hwl, float *ry, float *center) {const float PI = common::Constant<float>::PI();const float PI_HALF = PI / 2;const float small_angle_diff =common::IDegreeToRadians(params_.angle_resolution_degree);float center_2d[2] = {0};bool success =SolveCenterFromNearestVerticalEdge(bbox, hwl, *ry, center, center_2d);float min_x = static_cast<float>(params_.boundary_len);float min_y = static_cast<float>(params_.boundary_len);float max_x = static_cast<float>(width_ - params_.boundary_len);float max_y = static_cast<float>(height_ - params_.boundary_len);
//截断属性 判断是否截断bool truncated = bbox[0] <= min_x || bbox[2] >= max_x || bbox[1] <= min_y ||bbox[3] >= max_y;
//判断是否超过考虑的距离 目标物过远过小float dist_rough = sqrtf(common::ISqr(center[0]) + common::ISqr(center[2]));bool ry_pred_is_not_reliable = dist_rough > params_.dist_far &&bbox[3] - bbox[1] < params_.small_bbox_height;if (ry_pred_is_not_reliable || std::abs(*ry - PI_HALF) < small_angle_diff ||std::abs(*ry + PI_HALF) < small_angle_diff) {*ry = *ry > 0.0f ? PI_HALF : -PI_HALF;}if (!truncated) {PostRefineOrientation(bbox, hwl, center, ry);success =SolveCenterFromNearestVerticalEdge(bbox, hwl, *ry, center, center_2d);PostRefineZ(bbox, hwl, center_2d, *ry, center);} else {FillRyScoreSingleBin(*ry);}return success &&GetProjectionScore(*ry, bbox, hwl, center, true) > params_.iou_suc;
}

获得相机坐标系下三维框的函数是:

bool ObjMapper::Solve3dBbox(const ObjMapperOptions &options, float center[3],float hwl[3], float *ry)

第三个函数fillresults 是吧求得的所有结果 中心点 追踪id 长宽高 角度等内容存储起来:

// fill back results
FillResults(object_center, dimension_hwl, rotation_y, camera2world_pose,theta_ray, obj);

上述分析完成后 是代码移植,移植代码到windows vs2017的开发环境

模型文件所在位置:

apollo\modules\perception\production\data\perception\camera\models\yolo_obstacle_detector\3d-r4-half

这篇关于Apollo camera 感知部分 目标检测源码阅读分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1074596

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、