双目视觉测距,目标点三维信息求其深度值

来源:互联网 发布:精点数据公司怎么样 编辑:程序博客网 时间:2024/06/10 03:29


我的两个相机是竖直交叉放置的,以下相机光心作为世界坐标系原点,以下相机光轴作为世界坐标系Z轴。通过坐标系转换,建立超定方程,求解得到目标点的三维信息(X,Y,Z),但是这个Z不是深度值,他只是世界坐标系Z轴方向上的Z值。我要求得目标点深度(或几个目标点的相对深度),该如何办?

我要求的是目标点到镜头的距离在水平面方向的深度 画个图:  红色的坐标系 是以下面相机的光心为原点,以水平面OA方向为Z轴,以竖直方向OC位Y轴,OB为X轴建立的坐标系。我现在求出的三维坐标是世界坐标系与下相机坐标系重合的情况下的。所以  求出的Z并不是目标点下相机光心的距离,而只是Z方向的一个分量而已。

图中下面那个相机的方位并不一定和O-ABC坐标系一致是吧? 但是你需要的是OP1在OA方向的投影长度?

把两个坐标系的关系建立起来,很简单的计算

OABC选好基准,注意OA的方向是很多选择的,选定一个  OC是确定的,竖直向下,OB=OAXOC

O保持为相机的光心,那么相机本身的位姿调整有两个转角:1 绕竖直方向的转角 2 相对水平面的俯仰角

从你的工作图来看无法获取两个转角,参考以下方案:

在你的工作空间内建立几个参照点(3个以上),保证每次都会被拍进去

这3个点可以方便获取OABC坐标系中的三维坐标

你的相机在某个位置

拍出来这三个点在相机坐标系中的三维坐标

理论上这两组数据可构建变换关系(一个旋转矩阵!),可以把实际被测点转换到OABC中  得到深度

其实我想求得是目标点p1  p2谁离镜头近,如何衡量呢,我的想法是求p1、  p2到穿过下相机光心的竖直线的距离。。我的思路对吗?如何求这个距离呢?我的想法是建立坐标系时,世界坐标系的Y轴就取穿过下相机光心的竖直线。但是Z轴和X轴不知该如何描述,它们的选择有多种,Z轴肯定在水平面内,并且指向目标点所在的视野。您说,我建立这样一个坐标系可行吗?以下相机光心为原点,经过下相机光心的竖直线为Y轴,以经过光心的水平面并且指向目标点所在的场景的直线为Z轴,以垂直于ZY面的直线为X轴建立世界坐标系,那么最终按照坐标系变换方法算出的目标点的三维坐标中的Z值就是目标点到镜头的距离了。其实更准确的说法是目标点到穿过光心所在竖直线的距离。


需求: 根据当前像素的Depth计算出其View空间的Position

先说一种惯性思维的方法: 既然知道depth是怎么算出来的, 那么进行逆运算回去不就得到position了?

先说说depth是怎么出来的:

Vertex shader:

output.position = mul(input.postion, matWorldViewProject);

output.depth.xy = output.position.zw;

Pixel shader(输出z/w):

return input.depth.x / input.depth.y;

那么, 逆运算回去就很直接了(input.uv是全屏矩形的纹理坐标):

float z = tex2D(DepthSampler, input.uv);

// transform to projection space

float x = input.uv.x * 2 - 1;

float y = (1 - input.uv.y) * 2 - 1;

float4 vProjectedPos = float4(x, y, z, 1);

// transform to view space 

float4 vPosition = mul(vProjectedPos , matInvProject);

return (vPosition.xyz / vPosition.w);

那么这样做有什么缺点呢?

z/w是非线性分布的, 经过RTT后再变换回去会有精度上的损失

计算量有点大, 要知道PS里的每个指令都是很宝贵的.

下面说说另一种非常快的算法, 而且也可以解决精度问题. 先看看摄像机视锥体的抽象形式:

从摄像机位置到远裁剪面发射一条射线, 那么, 对于可见的任意一点, 有这么个关系:

vPositionView = vViewRayDir * fLinearDepth;

其中, fLinearDepth代表规格化的Z, 它是线性分布的, 即:

fLinearDepth = vPositionView.z / fFarClipDist;

剩下的, 就是这个屏幕射线vViewRayDir从哪来的问题了.

我们知道, 在View空间, 摄像机位置是(0, 0, 0). 那么, 对于每条射线的方向, 等价于射线与远裁剪面的交点坐标. 即:

vViewRayDir = float3(fFarClipX, fFarClipY, fFarClipDist);

远裁剪面上的4个顶点坐标我们是可以算出来的, 就是Frustum中的四个顶点. 如果我们把这四个顶点坐标写入全屏矩形的顶点坐标中, 然后在VS中输出, 那么在PS中得到的就是已经插值好的射线方向了!

整理一下整个思路:

1. 把vPositionView.z / fFarClipDist输出到RTT, 这里因为是线性分布的, 在精度允许的前提下可以进行压缩

2. 从RTT里得到fLinearDepth, 从VS_OUTPUT出的寄存器里得到已经插值好的vViewRayDir.xy, vViewRayDir.z就是fFarClipDist, Position的重建只需要一句计算就可以得到:

vPositionView = vViewRayDir * fLinearDepth;

Reference(要翻墙): http://mynameismjp.wordpress.com/2009/03/10/reconstructing-position-from-depth


0 0