深度生成器(Depth Generator)也是图生成器的一种,其产生的一张张像素图中每一个像素所存储的数据是这个像素点距离摄像头的距离,也就是深度。
6.3.1 获取深度元数据对象
1.实例
因为深度图本质是每一个像素点存储的都是像素点位置到摄像头的距离,所以空间中不同的物件其对应像素反应出来的深度会有其特有的规律,因此在OpenNI应用中会经常涉及深度图分析。
2.解决方法
在分析整张深度图时,首先就是获取整张深度图,以及深度图的相关信息,OpenNI中提供了GetMetaData()函数,通过调用该函数,就可以获得深度生成器的元数据对象。其实现方法如下代码所示。
// GetDepthMetaData xn::DepthMetaData depthMD; xn::DepthGenerator mDepthGenerator; mDepthGenerator.GetMetaData(depthMD);
例中通过深度生成器mDepthGener调用其下的GetMetaData函数,并把结果传递给depthMD深度元数据对象。通过这样的步骤之后,depthMD就是所需要的深度元数据对象。
6.3.2 获取深度图
1.实例
深度图是一张记录了深度数据的图,它也可以看成是一张由深度像素组成的一维矩阵,其大小为nXRes*nYRes,在某些应用中,比如计算机视觉领域中,应用深度图进行分析是经常和必要的。
2.实现方法
获取一张深度图,首先需要有能存储这张图的像素矩阵,OpenNI中有XnDepthPiexl这样类型的变量,通过这种类型的变量组成的一维矩阵,并且通过GetDepthMap()函数,即可获得当前深度生成器更新数据后产生的最新的深度图,其具体使用方法如下面的代码所示。
// GetDepthMap xn::DepthGenerator mDepthGenerator; eResult = mDepthGenerator.Create(mContext); CheckError(eResult); eResult = mContext.StartGeneratingAll(); // 开始产生数据 eResult = mContext.WaitAndUpdateAll(); // 更新数据 if (eResult == XN_STATUS_OK) // 获取深度图 { const XnDepthPixel* pDepthMap = mDepthGenerator.GetDepthMap(); }
上面代码中,首先声明了一个XnDepthPixel类型的常量指针pDepthMap,这实质是一个用于指向存放深度图的一维矩阵,而后是通过深度生成器mDepthGenerator调用其下的GetDepthMap()函数,并将返回的一维深度矩阵传递给pDepthMap,这样获取到的pDepthMap就是所需要的深度图。
6.3.3 获取设备最大深度
1.实例
每一个3D sensor所支持的工作范围是不同的,也就是它们最大的深度是不同的,超出这个限度的物件就不能正确地被设备抓取到。所以,知道设备的最大深度是至关重要的。
2.实现方法
最大深度对于深度生成器所产生的数据来说是关键性的数据,所以在深度生成器中提供了GetDeviceMaxDepth()函数来获取最大深度,调用该函数会返回一个XnDepthPixel类型的常量深度数据,也就是所需获知的最大深度,具体使用方法如下代码所示:
// GetDeviceMaxDepth XnDepthPixel mDeviceMaxDepth; xn::DepthGenerator mDepthGenerator; mDeviceMaxDepth = mDepthGenerator.GetDeviceMaxDepth();
例中定义的XnDepthPixel类型的变量mDeviceMaxDepth,就是用来存储返回的设备最大深度值。
6.3.4 获取设备视野范围
1.实例
对于深度生成器来说,除了通过深度属性来得知设备的工作范围之外,设备的视野范围也同样是得知设备工作范围的属性,也就是设备工作视野的水平弧度和垂直弧度,这些数据对于设备视野的判断也是至关重要的。
2.实现方法
深度生成器中提供了GetFiledOfView()函数,调用该函数之后,系统会返回一个XnFieldOfView类型的数据,该数据类型里记录了深度获取设备的垂直视野弧度和水平视野弧度,具体代码如下。
// GetFiledOfView XnFieldOfView mFOV; xn::DepthGenerator mDepthGenerator; mDepthGenerator.GetFieldOfView(mFOV);
首先定义一个XnFieldOfView类型的变量mFOV,而后调用深度生成器mDepthGenerator下的GetFieldOfView()函数,并传入变量mFOV。这样,函数返回的值就会存入mFOV变量,实际上XnFieldOfView类型的结构体包含两个变量,具体结构体代码如下。
// Struct of XnFieldOfView XnDouble fHFOV XnDouble fVFOV
其中fHFOV代表水平弧度值,fVFOV代表垂直弧度值。
6.3.5 绝对坐标和相对坐标转换
1.实例
在OpenNI中,存在两种坐标体系,一种是绝对坐标,一种是相对坐标,通常开发者可以根据不同的情况选择使用不同的坐标,不过这两种坐标本身也是可以相互转换的。
2.实现方法
坐标的相互转化主要是应用在深度生成器上的,在OpenNI深度生成器类下提供了ConvertProjectiveToRealWorld()函数实现从相对坐标(二维坐标)到绝对坐标(实际空间坐标)的转化;还提供了ConvertRealWorldToProjective()函数以实现从绝对坐标到相对坐标的转化。这两个函数的具体使用方法如下代码所示。
// ConvertProjectiveToRealWorld()&ConvertRealWorldToProjective xn::DepthMetaData depthMD; mDepthGenerator.GetMetaData(depthMD); XnPoint3D *ProjectivePoint = new XnPoint3D[5]; XnPoint3D *ProjectivePoint2 = new XnPoint3D[5]; XnPoint3D *RealPoint = new XnPoint3D[5]; ProjectivePoint[0] = xnCreatePoint3D(mapMode.nXRes/2, mapMode.nYRes/2, depthMD(mapMode.nXRes/2,mapMode.nYRes/2)); mDepthGenerator.ConvertProjectiveToRealWorld(5,ProjectivePoint,RealPoint); printf("RealPoint.X=%f,RealPoint.Y=%f,RealPoint.Z=%f", RealPoint[0].X,RealPoint[0].Y,RealPoint[0].Z); mDepthGenerator.ConvertRealWorldToProjective(5,RealPoint,ProjectivePoint2); printf("ProjectivePoint2.X=%f,ProjectivePoint2.Y=%f,ProjectivePoint2.Z=%f", ProjectivePoint2[0].X,ProjectivePoint2[0].Y,ProjectivePoint2[0].Z); delete [] ProjectivePoint; delete [] RealPoint;
这是一个相对坐标和绝对坐标互相转化的例子,不过需要知道的一点是,例中首先是从深度元数据对象中获取的数据来创建的一个XnPoint3D类型的点,这个点的数据源就是一个相对坐标的点,因此例中先将这个相对坐标的深度点转化为绝对坐标的深度点。具体步骤如下,首先定义深度元数据对象,并调用深度生成器mDepthGenerator获得深度元数据对象数据,而后创建一个相对坐标点ProjectivePoint,调用深度生成器下的ConvertProjectiveToRealWorld()函数将该相对坐标点转化为绝对坐标点。
而绝对坐标转化为相对坐标的用法也和相对坐标转化为绝对坐标类似,只要调用ConvertRealWorldToProjective()将绝对坐标转化为相对坐标即可,例中将绝对坐标RealPoint转化为相对坐标ProjectivePoint2。
6.3.6 获取用户位置功能
1.实例
因为通过深度图的数据可以分析出一些特定的数据,OpenNI在深度生成器下就挂载了用户位置功能。开发者可以调用出用户位置功能,从而使用功能内的应用。
2.实现方法
考虑到获取的是用户位置功能,其拿到的是一个功能,所以首先要创建一个UserPositionCapability,而后调用GetUserPositionCapability()将获取到的Capability传递过去,这样就可以使用这个Capability了。
// Get UserPositionCapability xn::DepthGenerator mDepthGenerator; xn::UserPositionCapability UserPositionCAP; UserPositionCAP = mDepthGenerator.GetUserPositionCap();
例中首先创建一个UserPositionCapability类型的变量UserPositionCAP;而后调用深度生成器mDepthGenerator下的GetUserPositionCap()函数,将获取到的Capability传递给UserPositionCAP,这样开发者就可以通过UserPositionCAP来进一步调用用户位置功能下的应用了。