导航:首页 > 源码编译 > dlt算法建立点云

dlt算法建立点云

发布时间:2023-09-03 02:41:09

⑴ 3. 用任意一种编程语言(C/C++/Java/C#/VB.NET)写出任意一种你所知的排序算法(比如:冒泡排序, 归并排

#include<stdio.h>
#include<stdlib.h>
void BubbleSort(int a[], const int first, const int last);//冒泡排序
void InsertSort(int a[], const int first, const int last);//插入排序
void SelectSort(int a[], const int first, const int last);//选择排序
void MergeSort(int a[], const int p, const int r);//合并排序
void QuickSort(int a[],const int p,const int r);//快速排序
void ShellSort(int a[],const int p,const int r,const int dlta[],const int t);//希尔排序
void HeapSort(int a[],const int p, int r); //堆排序
void StoogeSort(int a[],const int p,const int r);//Stooge排序(不用)算法复杂度没算清楚

void main()
{
//插入排序算法
int a[11] = {6,4,5,3,2,1};
int dlta[]={9,5,3,2,1};
//BubbleSort(a,0,5);
//InsertSort(a,0,5);
//SelectSort(a,0,5);
//MergeSort(a,0,5);
//QuickSort(a,0,5);
//ShellSort(a,0,5,dlta,5);
HeapSort(a,0,5);
//StoogeSort(a,0,5);

for(int i=0; i<=5;i++)
{
printf("%d ",a[i]);
}

}

/************************冒泡排序***********************/
void BubbleSort(int a[], int first, int last)
{
//实现对数组a[]中a[first]到a[last]升序的“冒泡”排序
int i,j,temp;
for(i=first; i<=last; i++)
{
for(j=first; j< last-i; j++)
{
if(a[j] > a[j+1])
{
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}

/************************插入排序***********************/
void InsertSort(int a[], int first, int last)
{
//实现对数组a[]中a[first]到a[last]升序的“插入”排序
//最坏情况为n的平方,,多用于小数组
int i,j,temp;
for(i=first+1; i<=last; i++)
{
temp = a[i];
j = i - 1;
while((j >= 0) && (a[j] > temp))
{
a[j+1] = a[j];
j--;
}
a[j+1] = temp;
}
}

/************************选择排序***********************/
void SelectSort(int a[], int first, int last)
{
//实现对数组a[]中a[first]到a[last]升序的“选择”排序
int i, j, temp, num;
for(i=first; i<last; i++)
{
num = i;
for(j=i+1; j<=last; j++)
{
if(a[j] < a[num])
{
num = j;
}
}
if(i != num)
{
temp = a[num];
a[num] = a[i];
a[i] = temp;
}
}
}

/************************合并排序***********************/
void Merge(int a[],const int p,const int q,const int r)
{
//合并排序算法中的实现合并的子程序
int iLLength,iRLength;
int *L, *R, i, j, k;
iLLength = q - p + 1;
iRLength = r - q;
L = (int *)malloc(iLLength*sizeof(int)); //或者 C++中 new int[iLLength];
R = (int *)malloc(iRLength*sizeof(int)); //或者 C++中 new int[iRLength];
if(L == 0 || R== 0)
{
printf("内存分配失败!!!");
return;
}
for(i=0; i<iLLength; i++)
{
L[i] = a[p+i];
}
for(j=0; j<iRLength; j++)
{
R[j] = a[q+j+1];
}
i = 0;
j = 0;
for(k=p; k<=r; k++)
{
if((i<iLLength) && (j<iRLength) && (L[i]<=R[j]) || (j == iRLength))
{
a[k] = L[i];
i++;
}
else if(j<iRLength)
{
a[k] = R[j];
j++;
}
}

free(R);free(L);
}
void MergeSort(int a[],const int p,const int r)
{
//合并排序算法-主程序
//n*lg(n),系数较小
int q;
if(p<r)
{
q = (p+r)/2;
MergeSort(a,p,q);
MergeSort(a,q+1,r);
Merge(a,p,q,r);
}
}

/************************Stooge排序***********************/
void StoogeSort(int a[],const int p,const int r)
{
//Stooge算法
int temp, k;
if(a[p]>a[r])
{
temp = a[p];
a[p] = a[r];
a[r] = temp;
}
if((p+1) >= r)
{
return;
}
k = (r-p+1)/3;
StoogeSort(a,p,r-k);
StoogeSort(a,p+k,r);
StoogeSort(a,p,r-k);
}

/************************快速排序*********************/
int QuickPartition(int a[],const int p,const int r)
{
//快速排序的(关键)分治过程
int temp, x, i, j;
x = a[r];
i = p - 1;
for(j=p; j<r; j++)
{
if(a[j] <= x)
{
i = i + 1;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
temp = a[i+1];
a[i+1] = a[r];
a[r] = temp;
return (i+1);
}
/*
void QuickSort(int a[],const int p,const int r)
{
//快速排序算法-主程序
//与下面的“尾递归实现方法”比较,缺点:右边数组的递归不是必须的,增加了运行堆栈深度和调用开销
int q;
if(p < r)
{
q = QuickPartition(a, p, r);
QuickSort(a, p, q-1);
QuickSort(a, q+1, r);
}
}
*/
void QuickSort(int a[],int p,const int r)
{
//快速排序算法-主程序
//“尾递归实现方法”是对上面的快速排序主程序实现的一种优化
//系数较小,常用大数组
int q;
while(p < r)
{
q = QuickPartition(a, p, r);
QuickSort(a, p, q-1);
p = q + 1;
}
}

/************************希尔排序**********************/
void ShellInsert(int a[],const int p,const int r, int dk)
{
//希尔排序算法的关键子程序-插入排序子程序
int i, j, temp;
for(i=p+dk; i<=r; i++)
{
if(a[i] < a[i-dk])
{
temp = a[i];
for(j=i-dk; ((j>=0) && (temp < a[j])); j -= dk)
{
a[j+dk] = a[j];
}
a[j+dk] = temp;
}
}
}

void ShellSort(int a[],const int p,const int r,const int dlta[],const int t)
{
//希尔排序算法-主程序
//按增量序列dlta[]中的前t个增量,实现对数组a[]中a[p]到a[r]的排序
//dlta[]可能取值如:1,2,3,5,9 dala[k]=2^(t-k+1)-1 其中0<=k<=t<=ld(b-1)
//增量序列的最后一个值必须是1
//增量序列中的值没有除1以外的因子, 其精确时间复杂度:数学上尚未解决的难题
int k;
for(k=0; k<t; k++)
{
ShellInsert(a,p,r,dlta[k]);
}
}

/************************堆排序***********************/
//堆排序,不如快速排序
//但是可用其来实现“优先级队列”
int Parent(int i)
{
return ((i+1)/2-1);
}

int Right(int i)
{
return (2*(i+1)-1);
}

int Left(int i)
{
return (2*(i+1));
}

void Max_Heapify(int a[],const int hplast,const int i)
{
int l, r,largest,temp;
l = Left(i);
r = Right(i);
largest = ((l<=hplast) && (a[l]>a[i])) ? l:i;
if((r<=hplast) && (a[r]>a[largest]))
{
largest = r;
}
if(largest != i)
{
temp = a[i];
a[i] = a[largest];
a[largest] = temp;
Max_Heapify(a,hplast,largest);
}

}

void Build_Max_Heap(int a[],const int p, const int r)
{
int i;
for(i = (p+r)/2; i>=p; i--)
{
Max_Heapify(a,r,i);
}
}

void HeapSort(int a[],const int p, int r)
{
int i,temp;
Build_Max_Heap(a,p,r);
for(i = r; i > p; i--)
{
temp = a[p];
a[p] = a[i];
a[i] = temp;
r -= 1;
Max_Heapify(a,r,0);
}
}

⑵ 无人驾驶(三)行人跟踪算法

姓名:王梦妮

学号:20021210873

学院:电子工程学院

【嵌牛导读】本文主要介绍了无人驾驶中所需的拿肢行人跟踪算法

【嵌牛鼻子】无人驾驶 环境感知 计算机视觉 卡尔曼滤波 粒子滤波 均值漂移

【嵌牛提问】无人驾驶中所用到的行人跟踪算法有哪些

【嵌牛正文】

行人跟踪一直是视觉领域的一个难点,实际应用环境复杂、遮挡以及行人姿态变化等外界因素都影响着行人跟踪算法的研究。行人跟踪算法模型主要分为生成模型和判别模型。

(一)生成式模型

生成式模型是一种通过在线学习行人目标特征,建立行人跟踪模型,然后使用模型来搜索误差最小的目标区域,从而完成对行人的跟踪。这种算法在构建模型只考虑了行人本身的特征,忽略了背景信息,没有做到有效利用图像中的全部信息。其中比较经典的算法主要有卡尔曼滤波,粒子滤波,mean-shift等。

(1)卡尔曼滤波算法

卡尔曼滤波算法是一种通过对行人构建状态方程和观测方程为基础,计算最小均方误差来实现跟踪的最优线性递归滤波算法,通过递归行人的运动状态来预测行人轨迹的变化。

首先设定初始参数,读取视频序列。然后进行背景估计,产生初始化背景图像。然后依次读取视频序列,利用Kahnan滤波算法,根据上一帧估计的背景和当前帧数据得到当前帧的前景目标。然后对前景目标进行连通计算,检测出运动目标的轨迹。经典的卡尔曼滤波算法.只能对线性运动的行人实现跟踪,之后学者改进了卡尔曼滤波算法,能够实现对非线性运动的行人进行跟踪,计算量小,能实现实时跟踪,但是跟踪效果不理想。

(2)粒子滤波

    粒子滤波的核心就是贝叶斯推理和重要性采样。粒子滤波可用于非线性非高斯模型,这是由于贝叶斯推理采用蒙特卡洛法,以某个时间点事件出现的频率表示其概率。通过一组粒子消宴世对整个模型的后验概率分布进行近似的表示,通过这个表示来估计整个非线性非高斯系统的状态。重要性采用就是通过粒子的置信度来赋予不同的权重,置信度高的粒子,赋予较大的权重,通过权重的分布形式表示相似程度。

(3)均值漂移(mean-shift)

    Mean-shift算法属于核密度估计法。不必知道先验概率,密度函数值由采样点的特征空间计算。通过计算当前帧目标区域的像素特征值概率来描述目标模型,并对候选区域进行统一描述,使用相似的函数表示目标模型与候选模板之间的相似度,然后选择在具有相似函数值最大的候选模型中,您将获得关于目标模型的均值漂移向量,该向量表示目标从当前位置移动到下一个位置的向量。通过连续迭代地计算均值偏移矢量,行人跟踪算法将最终收敛到行人的实际位置,从而实现行人跟踪。

(二) 判别式模型

判别模型与生成模型不同,行人跟踪被视为二分类问题。提取图像中的行人和背景信息,并用于训练分类器。通过分类将行人从图像背景中分离出来,以获取行人的当前位置。以行人区域为正样本,背景区域为负样本,通过机器学习算法对正样本和负样本进行训练,训练后的分类器用于在下一帧中找到相似度最高的区域,以完成行人轨迹更新。判别式模型不像生成式模型仅仅利用了行人的信息,还利用了背景信息,因此判别式模型的跟踪效果普遍优于生成式模型。

(1)基于相关滤波的跟踪算法

      核相关滤波(KCF)算法是基于相关滤波的经典跟踪算法,具有优良的跟踪效果和跟踪速度。这是由于其采用了循环移位的方式来进行样本生产,用生成的样本来训练分类器,通过高斯核函数来计算当前帧行人与下一帧中所有候选目标之间的相似概率图,找到相似概率图最大的那个候选目标,就得到了行人的新位置。KCF算法为了提高跟踪精度,使用HOG特征对行人进行描述,同时结合了离散傅里叶变换来降低计算量。

(2)基于深度学习的跟踪算法

    近年来,深度学习在图像和语音方面取得了较大的成果,因此有许多科研人员将深度学习与行人跟踪相结合,取得了比传统跟踪算法更好的性能。DLT就是一个基于深度学习的行人跟踪算法,利用深度模型自动编码器通过离线训练的方式,在大规模行人数据集上得到一个行人模型,然后在线对行人进行跟踪来微调模型。首先通过粒子滤波获取候选行人目标,然后利用自动编码器进行预测,最终得到行人的预测位置即最大输出值的候选行人目标位置。2015年提出的MDNet算法采用了分域训练的方式祥森。对于每个类别,一个单独的全连接层用于分类,并且全连接层前面的所有层都是共享,用于特征提取。2017年提出的HCFT算法使用深度学习对大量标定数据进行训练,得到强有力的特征表达模型,结合基于相关滤波的跟踪算法,用于解决在线进行跟踪过程中行人样本少、网络训练不充分的问题。此外,通过深度学习提取特征,利用数据关联的方法来实现跟踪的算法,其中最为着名的就JPDAF与MHT这两种方法。

⑶ 区块链行业应用有哪些

区块链技术有广泛的应用领域,以下是一些主要的行业应用:1. 加密货币:比特币、以太币等数字货币的发行与交易。2. 金融:用于交易结算、证券交易、银行贷款、交易融资等业务。3. 物流和供租并启应链管理: 用于优化物流过程和减少物流成本。4. 物联网:与物联网相关的数据、应用和通信,保证数据的安全和一致性。5. 版权管理: 用于版权信息的打包、存储、管理和交易。6. 选举: 用于公开、透明、安全的虚拟选举。7. 公共服弊如务:政府的文件和数据集的管理,例如出生证明、死蔽扰亡证明等。8. 医疗:用于管理医疗档案和提供更好的医疗服务。9. 慈善事业:用于捐赠和筹款。10. 游戏:游戏虚拟货币的发行管理。

⑷ 编写程序用直接插入排序的算法进行排序。

#include<stdio.h>
#include<time.h>
#include<math.h>
#include<malloc.h>

void BubbleSort(int *L,int N)
{ //冒泡
int i,j;
int t;

for(i=1;i<=N;i++)
{
for(j=N;j>i;j--)
if(L[j]<L[j-1])
{
t=L[j];
L[j]=L[j-1];
L[j-1]=t;
}
}
}

int SelectMinKey(int *L,int N,int n)
{
int i,min=n;

for(i=n+1;i<=N;i++)
if(L[i]<L[min])
min=i;

return min;
}

void SelectSort(int *L,int N)
{ //选择
int i,j;
int t;

for(i=1;i<N;i++)
{
j=SelectMinKey(L,N,i);
if(i!=j)
{
t=L[i];
L[i]=L[j];
L[j]=t;
}
}
}

void InsertSort(int *L,int N)
{ //插入
int i,j;

for(i=2;i<=N;i++)
{
if(L[i]<L[i-1])
{
L[0]=L[i];
L[i]=L[i-1];
for(j=i-2;L[0]<L[j];j--)
L[j+1]=L[j];
L[j+1]=L[0];
}
}
}

void ShellInsert(int *L,int N, int dk)
{ // 对顺序表L作一趟希尔插入排序。本算法对算法10.1作了以下修改:
// 1. 前后记录位置的增量是dk,而不是1;
// 2. r[0]只是暂存单元,不是哨兵。当j<=0时,插入位置已找到。
int i,j;
for(i=dk+1;i<=N;++i)
if(L[i]<L[i-dk])
{ // 需将L.r[i]插入有序增量子表
L[0]=L[i]; // 暂存在L.r[0]
for(j=i-dk;(j>0&&L[0]<L[j]);j-=dk)
L[j+dk]=L[j]; // 记录后移,查找插入位置
L[j+dk]=L[0]; // 插入
}
} // ShellInsert

void ShellSt(int *L,int N, int dlta[], int t)
{ // 算法10.5
// 按增量序列dlta[0..t-1]对顺序表L作希尔排序。
for(int k=0;k<t;++k)
ShellInsert(L,N, dlta[k]); // 一趟增量为dlta[k]的插入排序
} // ShellSort

void ShellSort(int *L,int N)
{ //希尔
int t=(int)log(N);
int k,*dlta;

dlta=(int*)malloc(t*4); //产生增量序列
for(k=0;k<t;k++)
dlta[k]=(int)pow(2,t-k)-1;

ShellSt(L,N,dlta,t);
}

int main()
{
int N=250;
int i,j,k;
int t;
int ti[16];
int *L;

srand(time(NULL));

printf("长度\t|冒泡\t|选择\t|插入\t|希尔\n");
printf("--------+-------------------------------------------------------------");
for(j=0;N<100000;j++)
{
L=(int *)malloc((N+1)*4);

t=0;

for(i=1;i<=N;i++)
L[i]=rand();
ti[t++]=clock();
BubbleSort(L,N);
ti[t++]=clock();

for(i=1;i<=N;i++)
L[i]=rand();
ti[t++]=clock();
SelectSort(L,N);
ti[t++]=clock();

for(i=1;i<=N;i++)
L[i]=rand();
ti[t++]=clock();
InsertSort(L,N);
ti[t++]=clock();

for(i=1;i<=N;i++)
L[i]=rand();
ti[t++]=clock();
ShellSort(L,N);
ti[t++]=clock();

printf("\n%d\t",N);
for(k=0;k<4;k++)
printf("| %d\t",(ti[2*k+1]-ti[2*k]));

N*=5;
}
printf("\n\n");
}

//这是我们当年学数据结构时我自己写的,给你改了一下,输出是对随机产生一些数,对四种算法进行比较,有问题可以hi我啊

⑸ 全局视觉定位系统研究的意义

全局视觉定位

1. 引言
自主机器人是机器人研究的重点方向,定位和导航是自主机器人研究的核心问题。机器人在执行任务过程中需要确定自身当前位置,根据目标位置和当前位置之间的关系计算如何到达目的地完成任务,其中前者要解决的是自定位问题,后者是导航问题,本文主要研究前者。基于视觉的定位技术还能帮助盲人、视弱以至普通人确定自身位置。 环境模型是定位的基础。基于模型的定位方法包括基于环境三维模型和基于拓扑地图的定位方法。环境三维模型的建模过程非常复杂,特别是在室外的场景中建模可能遇到极大的困难。拓扑定位用图的形式来表示环境模型,其中图中的节点表示环境中的地点,连接节点的边表示地点之间的联系,拓扑定位目的是确定机器人当前的位置与地图中的哪个节点最近,也就是机器人处于哪个地点。

在无人驾驶中,感知、定位、规划决策、控制是四个基本的系统模块。由于当前算法还无法实现绝对的智能,因此依然需要大量的先验知识来提高模块性能、鲁棒性,以实现安全的自动驾驶。其中,高精地图是对道路及周边环境先验知识的集成。而建立在地图之上的准确定位,是判断行车状况的重要依据,为后续的感知、规划决策提供有力支撑。
用于定位的主要数据源目前主要有 GPS、激光雷达、视觉、毫米波雷达。对于视觉而言,虽然目前还没有一套产业内公认的足够可靠的定位方案,但是在这方面探索从未停止过,主要原因如下:
安全性是无人驾驶系统最重要的指标,因此大部分功能的实现,都是多源数据、不同算法结果的耦合。没有哪种传感器方案是完美的,比如 GPS RTK 作为广泛使用的方案,容易受卫星状况、天气状况、 数据链传输状况影响,在隧道内、室内和高楼密集区无法使用。再者,激光雷达虽然具有运算量小,提供深度信息,不受光照影响等优点,但信息稀疏,造价目前还十分昂贵,还不具备大批量车辆装配能力。相比较而言,摄像头提供的视觉信息,虽然会受到光照、天气影响,但是成本低,内容丰富,是目前辅助驾驶方案主要数据源,在地图定位方面也具有很大潜力。

由于主流基于视觉定位算法的核心思想一脉相承,所以本文仅从一系列重要算法框架组件角度,介绍了目前实践中最常用的、基于特征点的全局定位算法,即在地图坐标系下进行定位。本文省略了其中涉及到的优化、几何约束公式推导,旨在给同学们一个定位算法的宏观介绍,具体细节可以参考相关文献和书籍。

2. 基于特征点的全局定位算法视觉全局定位,指的是根据当前图像,求出相机在地图坐标系中的 6 个自由度 (Degree of freedom, DoF) 位姿 (Pose) , 即 (x, y, z) 坐标,以及环绕三个坐标轴的角度偏转 (yaw, pitch, roll) 。目前主要可以分类为基于 3D 结构的方法、基于 2D 图像的方法、基于序列图像的方法、基于深度学习的方法。其中,基于深度学习的方法属于端到端 (End-to-end) 的方法,而其它多阶段 (Multi-stage) 非端到端方法虽然流程有所差别,但算法思路大都如 Fig. 1 所示:
Figure 1: 根据查询图像,计算 2D-3D 转换矩阵,求解相机位姿
基于已建的地图,匹配历史中最相似的地图子集(图像/点云/特征点),根据匹配到的地图子集所提供的历史位姿真值、特征点坐标真值,计算点对间的变换矩阵,求解当前相机位姿。

所以,其核心包含图像描述、建图查询、特征匹配,位姿计算四个方面。这里仅仅是技术层面的宏观分类,实际算法框架不一定按照此顺序执行,而学者在研究中主要针对这些技术进行改进。整体而言,基于特征点的图像描述基本成熟,发展较少。而位姿计算由于是基于几何约束的优化问题,所以方法也较为固定。相对地,建图查询和特征匹配中改进技术较多。根据数据源不同,建图查询、匹配可以是2D-2D,2D-3D,3D-3D。2D 图像由相机得到,3D 点云可以由提供深度的双目相机、RGB-D 相机产生。

2.1 特征点提取
2D 图像本身是一个由亮度、色彩组成的矩阵,对视角、光照、色调变化等很敏感,直接使用十分困难。所以,一般会使用具有代表性的点进行相关计算。人们希望这样的点具有旋转、平移、尺度、光照不变性等优点。这些点称为图像的特征 (Feature) 点,包含关键点(Key-points) 和描述子 (Descriptor) 两部分。关键点表达了特征点的位置,而描述子则是对于特征点视觉特性的描述,大多为向量形式。一般而言,描述子主要是以某种模式,统计关键点周围的灰度/色彩梯度变化。一种鲁棒的描述子,在不同图像 的不同情况下,同一特征点的描述子的距离 (Distance) 应当较小。

描述子一般是人为手工设计的 (Hand-crafted features) 。经典的描述如 HOG(Histogram of oriented gradients)[1],SIFT(Scale-invariant feature transform)[2],SURF(Speeded up robust features)[3],AKAZE(Accelerated KAZE)[4] 等。

为了实时性的要求,一些计算速度更快的二值模式描述子被设计出来,如 LBP(Local binary patterns)[5],BRIEF(Binary robust independent elementary features),ORB(Oriented FAST and rotated BRIEF)[6],BRISK(Binary robust invariant scalable key-point)[7],FREAK(Fast retina key-point)[8] 等。

在深度学习流行之前,这些手工特征一直引领着整个计算视觉产业,直到今天,这些特征在那些缺少标注数据、约束较多的场景下,依然被广泛应用。下面简单介绍两类常用的描述子。

2.1.1 SIFTSIFT 描述子可以算是 CV 界最具影响力的技术之一。从关键点检测层面,主要使用高斯差分 (Difference of Gaussian, DoG) 方法检测多尺度空间上的极值点,作为关键点。而 Babaud 等人 [9] 证明了高斯平滑是唯一的能用多尺度空间平滑滤波核,为相关方法提供了充足的理论支持。
那么为什么这样的方法可以找到特征关键点呢?
由于高斯核可以通过模糊的方式把图像缩放到不同尺度空间,而梯度变化较小的平滑区域在不同尺度空间的值差距较小。相反,边缘、点、角、纹理等区域则差距较大。这样通过对相邻尺度的图像做差分,最终可以算得多尺度空间的极值点。但是,不同的图像细节本身就处于不同的尺度中。比如一副人物画像中,人脸可能经过较小的模糊就会被平滑为一片,而画框的角则可能需要更大尺度的平滑才会体现出局部“极值”。
因此,如 Fig. 2 所示,首先利用图像金字塔将图像先分组 (Octave) ,每组中再使用不同尺度的高斯核,形成一系列的层。这种方式比单纯地使用更多尺度的高斯核效果更好,可以检测到更多的特征点。需要注意的是,虽然 SIFT 使用了 DoG 进行关键点检测,但是其它检测方法也是可行的,并不影响 SIFT 描述子的建立。
Figure 2: 高斯差分方法

SIFT 特征点的描述子,可以理解为一种简单统计版的 HOG。如 Fig. 3所示,以检测到的关键点为中心,选取周围 16 × 16 的区域,将区域再组织为 4 个 4 × 4 的块(Patch)。对每一个块,使用 8-bins 的直方图对梯度进行统计,梯度方向决定落入哪个 bin,而梯度的模决定值的大小。为了保证尺度一致性,梯度大小需要进行归一化。为了保证旋转不变性,会根据 16 × 16 的区域内的所有梯度计算出一个主方向, 所有梯度按照主方向进行旋转。最终形成 4 × 4 × 8 的 128 维向量。
Figure 3: 基于梯度分块统计的 SIFT 描述子
2.1.2 二值描述子虽然在 SIFT 提出后,又产生了一些改进算法如 SURF、AKAZE 等,但是即使放在 2019 年的今天, 依然难以保证一些场景对算法实时性的要求。例如,手持设备一般算力有限。而无人驾驶中,CPU、GPU资源需要被多个计算密集型模块同时调度。因此,效率是考察算法实用性的重要指标。

为了提高效率,一些二值描述子被学者们提出。一般地,这些方法都是在特征关键点周围进行点采 样。然后比较一对点的灰度大小,结果以 0/1 表示,形成 N 维的二进制描述向量,构成特征点的二值模式。而不同二值描述子最大的差别,主要在于特征采样模式不同、点对选取方法不同。
Figure 4: LBP 描述子采样模式

如 Fig. 4所示,LBP 描述子采用对关键点周围,进行环形采样,并与中心关键点的灰度进行比较的方案。圆环上展示了灰度比较结果,黑色的点是 0,白色的点是 1。LBP 是二值描述子最简单的形式,而 ORB 改进了 BRIEF 特征,是目前比较常用的二值描述子。如 Fig. 5所示,在点对选取上,与单纯使用中心点不同,ORB 采用了随机的方式,更全面地描述局部细节。但点对的相关性会比较大,从而降低描述子的判别性(Discriminative)。ORB 直接采用了贪婪法、穷举法解决这一问题,寻找相关性低的随机点对。
Figure 5: ORB 描述子点对选取模式

以上二值描述子的采样方式和点对选取方式符合人们一般直觉,而 BRISK、FREAK 等描述子则提供了更加规则化、自带尺度信息的二值模式构建方法。例如,FREAK 描述子模仿了人眼的视觉采样模式。如 Fig. 6所示,每个采样点的值是红色圆圈范围内的灰度均值,蓝线则表示点对选取方案。
Figure 6: FREAK 描述子采样、点对选取摸式

二值描述子的高效率,主要体现在三个方面。

(1)二值描述子使用二进制向量作为特征描述,只需要 比较点对大小而不需要计算具体梯度。(2)两个描述子之间比较可以使用计算更快,更容易优化的汉明距离 (Hamming distance)。(3)由于每个二进制向量都对应一个十进制数,所以其本身也代了表一种模 式,而不需要像 SIFT 一样使用直方图进行表示。

二值描述子一般判别性不如 SIFT 家族描述子,但在特定场景下,配合并行化编程,可以在保证相似判别能力的同时,效率高出几十甚至百倍。
2.2 数据库建立与查询数据库可以理解为于地图 + 索引的集成。地图可以是由单纯的 2D 图像组成,也可以是由 3D 点云地图组成,也可以是 2D 图像和 3D 点云的结合。3D 点云地图生成主要使用三维重建的方法 SfM(Structure from motion),从时间序列的 2D 图像中推算 3D 信息。如果有双目、RGB-D 相机提供深度,可以获得 更准确的 3D 点信息。其中也包含了一些诸如关键帧(Key-frame)的选取策略,具体方法超出了本文的讨论范围,有兴趣的同学可以自行查阅相关资料。数据库的作用在于:

对于一张输入的观测图像,通过数据库,查询建图历史(图像/点云/特征点),得到当前图像最可能观测到的地图子集(图像/点云/特征点),将地图与观测信息进行匹配,计算变换矩阵,得到观测相机的位姿。

索引则是加速这一过程的关键。数据库本身往往是巨大的。以美团的小袋机器人在北京朝阳大悦城二层试运营为例,安装有 3 个深度相机,即使经过筛选,也使用了将近 8 万张 900 × 600 的图片。考虑到定位所需要的实时性,查询时不可能每次都和 8 万张图片一一对比,所以要使用索引技术加速整个算法。这方面技术与 SLAM 中的回环测试,视觉中的图像检索、位置识别等高度重合,以下仅介绍一般方法。

一张图像内有若干特征点,需要先对特征点进行编码,如 VLAD(Vector of locally aggregated descriptors) 编码,用局部描述子形成图像的全局描述。再使用索引,如 kd-tree,进行图像级查询。当然,编码和索引也可以同时进行,如层次化词袋模型(Bag-of-words,BoW)+ 正向索引 + 逆向索引的方法。
2.2.1 VLAD 编码VLAD(Vector of locally aggregated descriptors)[10],如 Fig. 7所示,是一种通过聚合局部描述子形成码本 (Codebook) ,通过累加计算描述子与码词 (Word) 的距离,进行全局编码的简单方法。一个 d 维描述子 x 通过 k 个码词的码本进行编码,可以形成一个 d*k 维的描述向量,向量中的值是描述子与第

k个码词在第 d 维的差。之后进行 L2 归一化,形成最后的 VLAD 向量。
Figure 7: VLAD 通过描述子与码词的距离进行编码
这里要特别提介绍一下 DenseVLAD[11] 和 NetVLAD[12] 。Torii 等人证明,DenseSIFT 在查询、匹配上都优于标准 SIFT。DenseVLAD 在四个尺度,以 2 个像素间隔的网格状采样模式,提取 SIFT 点。在全局随机采样 25M 个描述子,用 k-means 算法生成 128 个码词的码本。VLAD 向量在归一化后使用 PCA(Principal component analysis) 降维,形成最后 4096 维的 DenseVLAD 向量。如 Fig. 8所示,使用DenseSIFT 匹配后的内点(绿)数量更多。
Figure 8: DenseSIFT 和标准 SIFT 特征点,匹配后内点(绿)对比

而 NetVLAD,将 VLAD 中加入了监督信息,加强 VLAD 编码的判别性。如 Fig. 9所示,假设红、绿两个描述子来源于不应匹配到一起的两张图片。由于它们都离 VLAD 中心(×)半径较大且距离相似,经过 L2 归一化,它们编码后值也会很相似。而加入了红、绿描述子所对应图片不匹配的监督信息后,NetVLAD 生成的中心点(★)则可以更好地区分两个描述子,增加他们编码后的距离(半径)差。
Figure 9: NetVLAD 聚类中心(×)与 VLAD 聚类中心(★)对比。
2.2.2 BoW 编码 + 索引基于词袋模型 BoW[13, 14] 的特征编码及其设计思想在计算机视觉发展中具有举足轻重的地位,这里不再展开介绍。本文以 2D 查询图像匹配 2D 图像数据库为例,介绍一种常见的 BoW 编码、索引一体化的模型。如 Fig. 10所示,词典 (Vocabulary) 生成采用层次化方法,对于数据集中的所有描述子,按树状结构进行空间划分,每一层都是由 k-means 聚类计算。最终叶子节点就相当于码词(Fig. 10中有 9个码词)。
Figure 10: 带正向索引、逆向索引的层次化 BoW 模型
树的构造过程,实际上就是将原始图像编码的过程。但是编码本身并不能加快搜索过程,与 VLAD 相似,还是需要与数据库中的图像逐一比较。因此,这里设计了一种逆向索引(Inverse index) ,不需要比较编码后的向量。其原理如 Fig. 11所示,对于一张查询图像 (Query image) ,将提取的描述子输入到 BoW 中,最终会落入码词叶子结点 (Visual word) k 中。而每个码词对应一个索引,记录码词 k
对于数据库中第 i
张图的权重
(Fig.10)。这里权重使用 TF-IDF(Term frequency–inverse document frequency) 计算。即如果一个词 k
在某个图像 i
中出现频率高,在其它图像出现频率低,则这个词对于图像判别性较好,权重值
较高。最终通过投票 (Voting) 机制,选出匹配图像。同样需要注意的是,逆向索引不一定建立在树形结构的 BoW 上,它仅仅是提供一种快速查询的方法。
Figure 11: 通过逆向索引 + 投票机制,直接查询图像
而正向索引 (Direct Index) 的作用主要是记录构造 BoW 时,数据库图片的特征点都落入了哪些结点中,这样当查询到图像后,不需要计算特征点,可以直接通过索引提取特征点。

2.2.3 3D 点云查询2D 图像查询中,是先从语意层面查询图像,因此可以通过图像对特征点的空间范围进行约束。3D 点云查询没有这样的约束,所以具诸多难点。如需要考虑空间连续性,查询到的点是否都在可观测范围内等。这里仅介绍 Sattler 在 TPAMI 2016 上发表的方法 [15],经过多年的打磨,这套方法框架相对简洁、完善。由于其中的词典编码搜索步骤与上节内容有所重叠,这里仅介绍 Active Search 和 Visbility Filtering 两种机制。

Active Search 主要是为了使得匹配到的 3D 点尽可能空间中临近、有几何意义。如 Fig. 12所示,红 色的点通过一系列编码、精化过程(红线),匹配到了点云中一个点。根据所提出优先排序(Prioritization) 框架,从点云中找到一个概率最大的 3D 点,并反向(蓝线)匹配查询图像中的一个对应的 2D 点。
Figure 12: Active Search
Figure 13: Visbility Filtering
Visbility Filtering 主要是为了让匹配到的点尽可能可以被相机观测到(定位是无监督的,并不能知道所匹配到的点是否正确)。这里采用的方法是在使用 SfM 建立 3D 点云地图时,同时建立一个双向可见图 (Bipartite visibility graph) 。如 Fig. 13(左)所示,当一个点可以同时被两个相机观测时,则建立拓扑关系。Fig. 13(中)里,蓝色的点为匹配到的点,它们从观测视角上存在冲突。通过在已有拓扑上进 行图聚类,将相机两两分组,如 Fig. 13(右)。这样就可以生成新的图拓扑关系。之后通过判断每个子图(Sub-graph)间的重合情况,过滤掉那些那大概率不可见的点。

需要说明的是,虽然双目相机和 RGB-D 相机可以获取深度,查询 2D 图像也可以获得限定范围内的 3D 特征点坐标,但是由于目前技术限制,在室内材质复杂,室外大尺度场景下,深度并不可靠。所以 2D图像点和 3D 点云地图的匹配依然是一种重要的方法。

2.3 特征点匹配特征点匹配过程可以是在数据库查询中自适应完成的,这多见于基于 3D 结构的查询。匹配也可以是在查询后单独进行,多见于基于 2D 图像查询。特征匹配的目的是,为后续的变换矩阵计算提供匹配的点对集,实现位姿的解算。

2.3.1 经典 RANSAC随机抽样一致算法 (Random sample consensus,RANSAC)[16] 是一种经典的数据过滤、参数拟合算法。它假设数据(内点,Inliers)分布符合一定的数学模型,通过迭代计算,去除外点 (Outliers) 、噪声点, 同时获取概率上最佳的模型参数。在全局定位中,内点指正确的匹配,外点指错误的匹配,参数模型指匹配点对的空间变换矩阵。如 Fig. 14所示,经过 RANSAC 算法优化后,匹配更加合理。RANSAC 所期望找到的匹配子集需要满足两个指标:内点重投影误差尽可能小;内点数量尽可能多。所以基本流程如下:

· ①采样初始子集。

· ②计算变换矩阵。

· ③ 根据变换矩阵计算匹配点的重投影误差。

· ④ 去除误差较大的点

· ⑤ 循环①-④,保留最满足指标的匹配方案。
Figure 14: (上)原始特征匹配;(下)经过 RANSAC 算法优化后的匹配

其中,初始候选匹配是根据描述子之间的距离产生的,但重投影误差则只和关键点的空间位置有关, 与描述子本身无关。具体投影矩阵方法请参考“2.4 位姿计算”。需要指出的是,RANSAC 算法受到原始匹 配误差和参数选择的影响,只能保证算法有足够高的概率合理,不一定得到最优的结果。算法参数主要包括阈值和迭代次数。RANSAC 得到可信模型的概率与迭代次数成正比,所得到的匹配数量和阈值成反比。因此实际使用时,可能需要反复尝试不同的参数设置才能得到较优的结果。

学者们对经典 RANSAC 算法进行了很多改进,如 Fig. 15所示,提出了全局 RANSAC(Universal- RANSAC)[17] 的结构图,形成了具有普适性的 RANSAC 架构,涵盖了几乎所有的 RANSAC 的改进方 面,如预滤波、最小子集采样、由最小子集生成可靠模型、参数校验、模型精化。
Figure 15: Universal-RANSAC 通用算法框架

2.3.3 可微分 RANSAC由于手工描述子在定位领域依然表现出较高的性能,所以一些学者开始探索使用深度学习代替算法框架中的某些部分,而不是直接使用端到端的位姿估计模型完全代替传统方法。可微分 RANSAC(Differentiable RANSAC,DSAC)[18] 旨在用概率假说选择代替确定性假说选择,使得 RANSAC 过程可以被求导,流程如 Fig. 16所示,其中“Scoring”步骤依然采用重投影误差作为指标,所不同的是,误差是基于整张图像而不是特征点,而原先筛选特征点匹配的过程被换为了直接以概率筛选相机位姿假设 h 的过程。虽然目 前方法局限性比较大,但 DSAC 为如何在当前无监督为主的定位算法框架中加入先验知识,提供了一种可行的思路。
Figure 16: 差分 RANSAC 算法框架

P3P 法可以看作是 PnP 法的特殊解法,如 Fig. 17所示,利用三角形相似性质增加更多约束,只需要 3 对点就可以求解。其它解法还有直接线性变换法 (Direct linear transformation,DLT),EPnP(Efficient PnP) 法,和 UPnP(Uncalibrated PnP)等。相对于以上线性优化方法,非线性优化方法如Bundle Adjustment(BA) 也有着广泛的应用。BA 方法在视觉 SLAM 中是一种“万金油”的存在,可以同时优化多个变量,这样可以一定程度缓解局部误差带来的系统不鲁棒,感兴趣的同学可以翻阅相关资料更深入地进行了解。
Figure 17: 2D-3D 变换矩阵计算中的 P3P 方法

3. 总结与展望

本文从图像描述、建图查询、特征匹配,位姿计算四个方面介绍了基于特征点的位姿估计算法。虽然传统视觉全局定位方法目前依然是实际应用中的首选,但是,传统方法是建立在特征点被正确定义、正确提取、正确匹配、正确观测的前提下进行的,这一前提对于视觉本身而言就是巨大的挑战。其次,由于传统方法是 multi-stage 框架,而非 end-to-end,所以中间每个环节,环节之间的交互,都需要众多参数调整,每个环节的技术都可以作为一个单独的研究方向。实际应用时,也需要加入对应具体场景的大量tricks,工程上比较复杂。

而人们对 end-to-end 方法的期望催生出了如 PoseNet,VLocNet,HourglassNet 等网络,在 benchmark上取得了不错的成绩。笔者认为目前 end-to-end 的方法还存在很多问题,主要有 loss function 缺少几何 约束,建图时位姿的 6 自由度空间并不连续,与输入空间难以形成良好映射,而且缺少相应的位姿回归、 精化机制等。不能否认,作为非线性空间最有力的建模工具,深度学习在未来会更多地出现在定位领域中。

回归到视觉定位本身,由于视觉最重要的优势就是成本低、语意丰富、使用场景限制少。因此,以视觉为主,其它低成本传感器为辅的定位融合方案在未来也将会是一个重要的课题。

参考资料

[1] Dalal, N., and B. Triggs. ”Histograms of oriented gradients for human detection.” CVPR, 2005.

[2] Lowe, David G. ”Distinctive Image Features from Scale-Invariant Keypoints.” IJCV, 2004.

[3] Bay, Herbert, T. Tuytelaars, and L. V. Gool. ”SURF: Speeded Up Robust Features.” ECCV, 2006.[4] P.F.Alcantarilla,J.Nuevo,andA.Bartoli.Fast explicit diffusion for accelerated features in nonlinear scale spaces. BMVC, 2013.

[5] Ojala, Timo. ”Gray Scale and Rotation Invariant Texture Classification with Local Binary Patterns.” ECCV, 2000.

[6] Rublee, Ethan , et al. ”ORB: An efficient alternative to SIFT or SURF.” ICCV, 2011.

[7] Leutenegger, Stefan , M. Chli , and R. Y. Siegwart . ”BRISK: Binary Robust invariant scalable keypoints.” ICCV, 2011

[8] Alahi, Alexandre , R. Ortiz , and P. Vandergheynst . ”FREAK: Fast retina keypoint.” CVPR, 2012.

[9] Witkin, A P, M. Baudin, and R. O. Duda. ”Uniqueness of the Gaussian Kernel for Scale-Space Filtering.” TPAMI, 1986.

[10] Jegou, Herve , et al. ”Aggregating local descriptors into a compact image representation.” CVPR, 2010.

[11] Torii, Akihiko , et al. ”24/7 place recognition by view synthesis.” CVPR, 2015.

[12] Arandjelovic, Relja, et al. ”NetVLAD: CNN architecture for weakly supervised place recognition.” TPAMI, 2017.

[13] Li, Fei Fei . ”A Bayesian Hierarchical Model for Learning Natural Scene Categories. CVPR, 2005.
[14] Galvez-Lopez, D. , and J. D. Tardos . ”Bags of Binary Words for Fast Place Recognition in Image Sequences.” TRO, 2012.

[15] Sattler, Torsten , B. Leibe , and L. Kobbelt . ”Efficient & Effective Prioritized Matching for Large- Scale Image-Based Localization.” TPAMI, 2016.

[16] Fischler, Martin A., and R. C. Bolles. ”Random sample consensus: a paradigm for model fitting with applications to image analysis and automated cartography.” Communications of the ACM, 1981.

[17] Raguram, Rahul , et al. ”USAC: A Universal Framework for Random Sample Consensus.” TPAMI, 2013.

[18] Brachmann, Eric, et al. ”DSAC —Differentiable RANSAC for Camera Localization.” CVPR, 2017.

阅读全文

与dlt算法建立点云相关的资料

热点内容
ipv4内部服务器地址怎么分配 浏览:461
java线程安全的方法 浏览:950
重复命令画梯形 浏览:162
在疫情就是命令 浏览:326
自己搭建一个什么服务器好玩 浏览:251
java基础马士兵 浏览:821
完美世界手游如何查看服务器 浏览:857
光遇安卓与ios什么时候互通 浏览:598
js如何运行时编译 浏览:916
引力app在哪里下载 浏览:609
编写app如何得到钱 浏览:800
吉利汽车软件放哪个文件夹安装 浏览:223
多文件编译c 浏览:542
头顶加密后为什么反而更稀疏 浏览:794
离心机压缩机扬程高 浏览:659
xshell连接linux命令 浏览:5
把多个文件夹的内容合并在一起 浏览:484
基于单片机的浇花系统设计ppt 浏览:685
卷积码编译码及纠错性能验证实验 浏览:355
请在删除驱动器之前暂停加密什么意思 浏览:788