1数据格式
点云数据一般是pcd,ply等等,下载的rgbd数据集是ply类型的,另外还有label和pose格式的数据文件。ply用matlab或者pcl打开。
通常深度数据使用整形数进行表示,范围在0-65535之间,类型为UINT16,即unsigned short,无符号2字节
单位为毫米(mm),但是某些SDK也支持使用100微米(um)来进行表示,如OpenNI支持的深度数据格式有PIXEL_FORMAT_DEPTH_1_MM,PIXEL_FORMAT_DEPTH_100_UM等。至于分辨率则通常是万年的640x480,有些甚至是320x240插值上去的。由于Depth有一定的有效工作范围,以PrimeSense Carmine 1.09为例,其工作范围只有0.35-1.4m,即数据范围是350-1400,通常会使用一个数值来表示无效的数据,如0或65535。
2存储读取
深度图的表示,如下:
char RGBData[640][480][3];
typedef unsigned short UINT16,PUINT16;
UINT16 DepthData[640][480];
我们可以自己实现保存与读取的方法,也可以借助一些第三方SDK,如OpenCV进行读写,
在操作深度图时,OpenCV使用的格式是 CV_16U
inline cv::Mat getMat(const VideoFrameRef &frame,int dataStride,int openCVFormat){
//深度图PNG16类型(short),Little-Endian(低位在低字节)
//RGB图BGR24类型
int h=frame.getHeight();
int w=frame.getWidth();
getMat(frame,2,CV_16U); //For Depth
getMat(frame,3,CV_8UC3); //For RGB
深度图的Mat可以保存为PNG16格式,直接保存即可,读取时记得加上cv::IMREAD_UNCHANGED的FLAG
3可视化
深度图的可视化有多种方法,如三维点云,Mesh等,但是通常获取的深度数据是一张二维的图像,需要转换成三维数据才可以显示,二维图像则采用colormap来进行显示。
获取三维坐标
在OpenNI中,有这样一个接口,如下:
UINT16 deep=depthImage.at(row,col);
float fx, fy, fz;
openni::CoordinateConverter::convertDepthToWorld(depth, col, row, deep, &fx, &fy, &fz);
这个是什么意思呢,我们来看一下具体实现:
OniStatus VideoStream::convertDepthToWorldCoordinates(float depthX, float depthY, float depthZ, float pWorldX, float* pWorldY, float* pWorldZ)
一般来说我们直接将深度表示为Z坐标,而X与Y则与Z坐标有一个对应关系,未必是正比,可能是一个系数,m_worldConvertCache的数据结构如下,同时标注出了一个可能的参数列表,不同的相机可能不同:
struct WorldConversionCache
有时相机厂家提供的SDK可能封装了三维坐标的计算,我们可以根据获取到XYZ值进行反推coeffX与coeffY,从而得到相机相关的参数,具体的计算方式则如下:
m_worldConvertCache.xzFactor = tan(horizontalFov / 2) * 2;
m_worldConvertCache.yzFactor = tan(verticalFov / 2) * 2;
要计算出这些参数,我们需要知道相机在两个方向的视场角,并且知道图像的分辨率,一种可能的计算视场角的方式如下:
有了三维坐标我们就可以绘制点云或者Mesh,同时进行2D纹理贴图了,在此不赘述。
色彩图
colormap有很多种,主要思想是使用平滑过渡的不同颜色来表示不同范围的数值。
以常见的 MATLAB Jet 为例,我们可以指定越远的深度越蓝,越近的越红。