kinect for windows - DepthBasics-D2D详解之二
通过上篇文章,我们了解了在视频图像从kinect开发包传输到应用程序之前的一系列初始化工作,那么这篇文章主要来叙述,如何将一帧图像数据获取到,并显示出来的。
更新窗口是在Run函数消息处理中,当KinectSDK触发了m_hNextDepthFrameEvent之后,上层收到这个Event就调用Update函数去更新窗口了。关键代码如下图,Run函数的全部代码也可以从上一篇博文中找到:
Update函数:
void CDepthBasics::Update()
{
if (NULL == m_pNuiSensor) // 如果pNuiSensor为空,那说明设备还没有初始化
{
return;
}
// 继续判断m_hNextDepthFrameEvent是否有消息,其实这个判断这里可以去掉,但是考虑鲁棒性,还是留着吧
if ( WAIT_OBJECT_0 == WaitForSingleObject(m_hNextDepthFrameEvent, 0) )
{
ProcessDepth(); // 处理
}
}update函数做了一些错误处理,真正的更新窗口的代码在ProcessDepth中,接下来看ProcessDepth函数
void CDepthBasics::ProcessDepth()
{
HRESULT hr;
NUI_IMAGE_FRAME imageFrame;
// 通过kinect对象,从m_pDepthStreamHandle中获取图像数据,还记得m_pDepthStreamHandle么,是在初始化kinect设备时创建的深度图流
// 在这里调用这个代码的意义是:将一帧深度图,保存在imageFrame中
hr = m_pNuiSensor->NuiImageStreamGetNextFrame(m_pDepthStreamHandle, 0, &imageFrame);
if (FAILED(hr))
{
return;
}
BOOL nearMode;
INuiFrameTexture* pTexture;
// Get the depth image pixel texture,通过imageFrame把数据转化成纹理
hr = m_pNuiSensor->NuiImageFrameGetDepthImagePixelFrameTexture(
m_pDepthStreamHandle, &imageFrame, &nearMode, &pTexture);
if (FAILED(hr))
{
goto ReleaseFrame;
}
NUI_LOCKED_RECT LockedRect;
// Lock the frame data so the Kinect knows not to modify it while we're reading it,锁定数据
pTexture->LockRect(0, &LockedRect, NULL, 0);
// Make sure we've received valid data
if (LockedRect.Pitch != 0)
{
// Get the min and max reliable depth for the current frame
int minDepth = (nearMode ? NUI_IMAGE_DEPTH_MINIMUM_NEAR_MODE : NUI_IMAGE_DEPTH_MINIMUM) >> NUI_IMAGE_PLAYER_INDEX_SHIFT;
int maxDepth = (nearMode ? NUI_IMAGE_DEPTH_MAXIMUM_NEAR_MODE : NUI_IMAGE_DEPTH_MAXIMUM) >> NUI_IMAGE_PLAYER_INDEX_SHIFT;
// 将m_depthRGBX的首地址保存在rgbrun,方便赋值
BYTE * rgbrun = m_depthRGBX;
const NUI_DEPTH_IMAGE_PIXEL * pBufferRun = reinterpret_cast<const NUI_DEPTH_IMAGE_PIXEL *>(LockedRect.pBits);
// end pixel is start + width*height - 1
const NUI_DEPTH_IMAGE_PIXEL * pBufferEnd = pBufferRun + (cDepthWidth * cDepthHeight);
// 对m_depthRGBX也就是rgbrun赋值
while ( pBufferRun < pBufferEnd )
{
// discard the portion of the depth that contains only the player index
USHORT depth = pBufferRun->depth;
// To convert to a byte, we're discarding the most-significant
// rather than least-significant bits.
// We're preserving detail, although the intensity will "wrap."
// Values outside the reliable depth range are mapped to 0 (black).
// Note: Using conditionals in this loop could degrade performance.
// Consider using a lookup table instead when writing production code.
BYTE intensity = static_cast<BYTE>(depth >= minDepth && depth <= maxDepth ? depth % 256 : 0);
// Write out blue byte
*(rgbrun++) = intensity;
// Write out green byte
*(rgbrun++) = intensity;
// Write out red byte
*(rgbrun++) = intensity;
// We're outputting BGR, the last byte in the 32 bits is unused so skip it
// If we were outputting BGRA, we would write alpha here.
++rgbrun;
// Increment our index into the Kinect's depth buffer
++pBufferRun;
}
// Draw the data with Direct2D 最后将m_depthRGBX保存的图片,显示在窗口上
m_pDrawDepth->Draw(m_depthRGBX, cDepthWidth * cDepthHeight * cBytesPerPixel);
}
// We're done with the texture so unlock it,解锁和释放纹理
pTexture->UnlockRect(0);
pTexture->Release();
ReleaseFrame:
// Release the frame 释放帧
m_pNuiSensor->NuiImageStreamReleaseFrame(m_pDepthStreamHandle, &imageFrame);
}从以上代码可以看到处理Depth数据的流程,获取一个深度图帧,然后经过转换成RGB格式,最后通过ImageRenderer::Draw函数将其画出来。但是ImageRenderer的功能和Kinect关系不大,不是我们学习的重点,因此我们可以先忽略它。那么深度图的获取详细过程就到这里,在下一篇文章中,我们来总结一下这两篇文章所提到的一些Kinect SDK中的函数,并详细了解熟悉这些函数的参数,更进一步的学习Kinect SDK。
浙公网安备 33010602011771号