公众号|沐洒(ID:musama2018) 关注我,带你学点有用的
老粉应该都知道,我是一个不幸闯入自动驾驶领域的前端仔,去年开始陆续在这个领域做了一些事儿,不过后来因为一些变动,调整去支持另外的项目。直到最近,才又回来接手自动驾驶相关的事情。
所以你会发现前阵子我都没怎么写这个领域的东西,主要还是因为暂时离开了这个项目。
Anyway,现在我又回来了!
这次回归自动驾驶话题,自然不会让各位失望,我给大家带来了一篇对技术人而言极其实用的干货,关于「一次小小的技术方案预研」。
对方案细节不感兴趣,只想学如何做技术方案预研的同学,可以直接跳到结尾总结部分。
话不多说,进入正题。
1. 背景概述
Q平台(化名)上的有一个模块,用户可以在这里训练自己的自动驾驶标注能力。而训练必然要有考核,也就是对训练结果进行准确性校验,说白了就是一个自动阅卷能力。
毕竟自动驾驶点云数据长这样:
数据量庞大不说,这事儿本身用人眼分辨准确性也不是那么容易的事。所以咱需要一个「3D点云数据准确性自动化校验」的能力。
2. 需求文档
这部分涉及内部敏感信息,就不展示了。
需要自动校验的数据类型有:
3D框
2D框
车道线
关键点
点云多边形
And more......
3. 技术预研
初步分析,上述N种数据类型,根据实现原理分为2D和3D两种,可以通过一个统一的diff文件向外统一输出校验接口,然后根据入参表达的数据类型分发到不同的diff算法,如下:
arduino
diff
|---index.ts // diff出口文件
|---box.ts // 3D框
|---rect.ts // 2D框
|---line.ts // 车道线
|---point.ts // 关键点
// 省略更多类型
// index.ts
const diffFunctions = {
[SomeEnum.box]: xxx,
[SomeEnum.rect]: xxx,
// ...略
}
export const diff = (data: SomeType, type: SomeEnum) => {
return diffFunctions[type](data);
}
入口分发不难,难点在不同类型的数据校验算法逻辑(本文只讲3D校验的部份)。
3.1 初步思考
要校验「用户3D框」和「系统标准框」是否一致,不可以直接粗暴的做框体坐标的比对,于是我换了一个思路:
想办法判断出两个框体的叠加区域(或非叠加区域),然后看这个区域的尺寸是否小于某个系统设定的阈值。
就这么干!
3.2 竞品分析
目前开源的3D框体交叉检测代码非常少,而且很多都已经很陈旧了。千辛万苦找到两个看起来可能行的库进行了尝试(box-intersect 和 glaabb3)。
3.2.1 box-intersect
NPM包地址:<www.npmjs.com/package/box...
GITHUB:github.com/mikolalysen...
这个包可以比对多个立体框,每个框都按照扁平化的坐标数组传入([minX, minY, minZ, maxX, maxY, maxZ]),然后输入一个新数组,类似这样:
原以为这个crossings可以返回立方体叠加的区域坐标,然而经过实验后发现并不是,这个仅仅是一个立方体在输入数组里的序号(index)!
也就是说,这个库仅仅只能判断哪些立方体有叠加区域。这个效果显然不符合我的预期,放弃。
3.2.2 glb-aabb3
NPM包地址:www.npmjs.com/package/gl-...
这个库太老旧了,连文档都没有,不知道有哪些API,我只能看源码:
尝试一下其中的「intersection」 方法:
ini
import gl from 'gl-aabb3';
const red = [0, 0, 0, 4, 4, 4]; //Format: [minX, minY, minZ, maxX, maxY, maxZ]
const blue = [1, 0, 0, 6, 4, 4];
const vec3 = [];
gl.intersection(vec3, red, blue);
console.log(vec3);
输出:
用THREEJS把这三个立体框画出来,就是这样:(为了直观的看到效果,我把叠加部分vec3往Z轴方向挪了4个单位,与原数据错开)
可以看到效果是不错的,确实拿到了叠加区域。但是我们对蓝色立方体进行45度旋转再看看:
哦嚯!不行,交叉区域并未带入旋转分量。
尝试下使用BoundingBox:
害!这就更加不对了。
至此,两个开源库宣告退赛。
3.3 方案设计(自研)
在大量的尝试和搜索过程中,我接触到一个新的概念,AABB (axis-aligned bounding box),中文直译的话就是"轴对齐包围盒"。
这个AABB在处理3D碰撞检测领域被广泛使用,仔细研究了相关方案,大概心里有点思路了。(AABB相关知识可以参考我之前的文章《这个知识点99%的前端都没有听过,不信你进来看?》)
其中包围盒之间的冲突检测方式如下图:
简单讲就是,「使用AABB,把一个旋转物体包裹在内,不管物体如何旋转,AABB始终能包裹住物体,那么物体之间的碰撞就可以用AABB碰撞来做检测」。
回到我们这个场景,其实就是判断两个AABB的差异 是否小于某个阈值。
看到这里别着急喷,友情提示,后面有彩蛋
4. 最终方案
最终暂定使用AABB来做检测,先分别计算出两个box的AABB:(这里直接用THREEJS的API)
ini
cube.geometry.computeBoundingBox();
设定一个误差阈值:
ini
const POS_GAP_LIMIT = 0.1; // 这个值可以配置
然后分别对这两个AABB的[minX, minY, minZ, maxX, maxY, maxZ]进行误差判断,若小于阈值,则我们认为两个盒子基本一致。
javascript
function positionEquals(a, b) {
const [axmin,aymin,azmin,axmax,aymax,azmax] = a;
const [bxmin,bymin,bzmin,bxmax,bymax,bzmax] = b;
return (Math.abs(axmin - bxmin) <= POS_GAP_LIMIT &&
Math.abs(aymin - bymin) <= POS_GAP_LIMIT &&
Math.abs(azmin - bzmin) <= POS_GAP_LIMIT &&
Math.abs(axmax - bxmax) <= POS_GAP_LIMIT &&
Math.abs(aymax - bymax) <= POS_GAP_LIMIT &&
Math.abs(azmax - bzmax) <= POS_GAP_LIMIT;
}
这里还存在一个需要在开发调试中进行探索确认的点,就是是否还需要进一步比对两个box的旋转分量,因为旋转分量会直接影响盒子的方位,而且对称的旋转分量很可能产生相同的AABB。
比如这个情况,红蓝两个盒子分别旋转45度和-45度,二者明显不一致,但是二者的AABB是完全一致的。那么这种情况下如果单纯的依赖AABB检测,就会失效,所以我倾向于引入rotation协同检测。
也同样设置一个旋转误差阈值:
ini
const ANGLE_GAP_LIMIT = 1; // 角度误差可配置
然后比对二者的旋转角度即可:
javascript
function rotationEquals(a, b) {
const [axr, ayr, azr] = a;
const [bxr, byr, bzr] = b;
return (Math.abs(axr - bxr) <= ANGLE_GAP_LIMIT &&
Math.abs(ayr - byr) <= ANGLE_GAP_LIMIT &&
Math.abs(azr - bzr) <= ANGLE_GAP_LIMIT);
}
通过positionEquals + rotationEquals 协同比对,可以更有效的检测出两个框的方位一致性。
以上是针对3D立方体比对的最终方案。
当然了,实际落地方案比这个要复杂一些。
5. 总结
面对纷繁复杂的业务需求,很多时候方案是不明朗的,甚至是完全未知的,这种时候,就需要一个技术人员勇敢站出来(通常是高职级),先去前边儿探探路,写一份技术预研文档,帮助团队指明方向。
而一份最简版的技术方案预研,可以参考这个框架:
-
背景
-
需求
-
挑战/思路
-
竞品分析
-
方案设计
沿着这个脉络写文档,就算是新手,也能写得大差不差了。
6. 彩蛋
作为一个3D开发领域的新人,在无人指导的情况下摸索到了AABB解法,别提多开心了,于是我吭哧吭哧把上面的方案落地了,效果也还不错。
然而,有一天,一个偶然的机会加了一个资深的图形化开发大佬,他一句话,给我整破防了:
怀着将信将疑的心情,于是我去搜了一下,然后惊讶的发现,窝草,这不就是我想要的东西么!!!
AABB和OBB的区别如下图:
用OBB矩阵来解决这个问题,简直完美!天然带入了旋转分量,根本不需要我自己进行拙劣的逻辑判断,直接用线性代数就搞定!
所以说,在未知领域,找到一个引路人是多么重要。
技术交流群
我建了个前端技术交流群,整体氛围非常好,每天大家都会在群里真诚的交流技术问题,从前端到全栈,从尚未毕业的小年轻,到不惑之年的老大哥,大家都在拼命的汲取知识!
最近群里正在组织前端项目实战练习,很快就要开始大干一场了!有想要交流&学习前端知识的老少朋友,欢迎加入我们!
进群方式【重要】:
关注公众号 "沐洒 ",回复"技术群",获取最新群聊二维码。
全文完。
码字不易,如果你还想继续看我写的东西,就关注我吧(记得加星标🌟哦),顺便给个赞👍或点一下在看,你的支持是我继续写下去的动力。
公众号|沐洒(ID:musama2018) 关注我,带你学点有用的