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。

你可能感兴趣的:(kinect for windows - DepthBasics-D2D详解之二)