我正在使用 Kinect 创建一个人的 3D 模型。我得到的是这样的:
我将它导出到 Wavefront .obj 文件。但我只对脸本身感兴趣,并想删除它周围的所有东西。由于 Kinect 有一个 RGB 相机,我可以毫无问题地在 RGB 中进行人脸检测。但这给了我一个包含面部的 640x480 图像内的矩形,我如何将其转换为 3D 网格?
不久前我做过类似的事情:
视频在这里
我所做的很简单:
理想情况下,您将校准两个 (rgb,depth) 流。
我使用的是 libreenect,但这种技术应该适用于 OpenNI、KinectSDK。
我注意到您的应用程序的标题是 KinectFusion,所以我猜您是从 Microsoft Kinect SDK 1.7 中的 Kinect Fusion 示例开始的。应该有一个内置函数来对齐 rgb 和深度流。关于 CV 部分,您可以在线找到 Kinect 到 OpenCV Mat 的转换,例如Dennis Ippel 函数。EgmuCV也具有人脸检测功能。KinectSDK 本身允许您在 3D 中跟踪人脸,因此我怀疑 SDK 中一定有一些东西用于人脸检测(甚至没有跟踪)。我自己还没有使用足够多的 Kinect SDK,所以目前不能更具体。
简而言之:
这是我用来获取 Depthstream 并使用 Fusion 处理它的代码:
void processDepth()
{
NUI_IMAGE_FRAME depthFrame = { 0 };
ERROR_CHECK( kinect->NuiImageStreamGetNextFrame( depthStreamHandle, 0, &depthFrame ) );
BOOL nearMode = FALSE;
INuiFrameTexture *frameTexture = 0;
kinect->NuiImageFrameGetDepthImagePixelFrameTexture( depthStreamHandle, &depthFrame, &nearMode, &frameTexture );
NUI_LOCKED_RECT depthData = { 0 };
frameTexture->LockRect( 0, &depthData, 0, 0 );
if ( depthData.Pitch == 0 ) {
std::cout << "zero" << std::endl;
}
processKinectFusion( (NUI_DEPTH_IMAGE_PIXEL*)depthData.pBits, depthData.size);
ERROR_CHECK( kinect->NuiImageStreamReleaseFrame( depthStreamHandle, &depthFrame ) );
}
void processKinectFusion( const NUI_DEPTH_IMAGE_PIXEL* depthPixel, int depthPixelSize)
{
// DepthImagePixel
HRESULT hr = ::NuiFusionDepthToDepthFloatFrame( depthPixel, width, height, m_pDepthFloatImage,
NUI_FUSION_DEFAULT_MINIMUM_DEPTH, NUI_FUSION_DEFAULT_MAXIMUM_DEPTH, TRUE );
if (FAILED(hr)) {
throw std::runtime_error( "::NuiFusionDepthToDepthFloatFrame failed." );
}
Matrix4 worldToBGRTransform = { 0.0f };
worldToBGRTransform.M11 = 256 / 512;
worldToBGRTransform.M22 = 256 / 384;
worldToBGRTransform.M33 = 256 / 512;
worldToBGRTransform.M41 = 0.5f;
worldToBGRTransform.M42 = 0.5f;
worldToBGRTransform.M44 = 1.0f;
Matrix4 worldToCameraTransform;
m_pVolume->GetCurrentWorldToCameraTransform( &worldToCameraTransform );
hr = m_pVolume->ProcessFrame( m_pDepthFloatImage, NUI_FUSION_DEFAULT_ALIGN_ITERATION_COUNT,
NUI_FUSION_DEFAULT_INTEGRATION_WEIGHT, &worldToCameraTransform );
worldToCameraTransform;
if (FAILED(hr)) {
++trackingErrorCount;
if ( trackingErrorCount >= 100 ) {
trackingErrorCount = 0;
m_pVolume->ResetReconstruction( &IdentityMatrix(), nullptr );
}
return;
}
// PointCloud
hr = m_pVolume->CalculatePointCloud( m_pPointCloud, &worldToCameraTransform );
if (FAILED(hr)) {
throw std::runtime_error( "CalculatePointCloud failed." );
}
// PointCloud
hr = ::NuiFusionShadePointCloud( m_pPointCloud, &worldToCameraTransform,
&worldToBGRTransform, m_pShadedSurface, nullptr );
if (FAILED(hr)) {
throw std::runtime_error( "::NuiFusionShadePointCloud failed." );
}
INuiFrameTexture * pShadedImageTexture = m_pShadedSurface->pFrameTexture;
NUI_LOCKED_RECT ShadedLockedRect;
hr = pShadedImageTexture->LockRect(0, &ShadedLockedRect, nullptr, 0);
if (FAILED(hr)) {
throw std::runtime_error( "LockRect failed." );
}
pShadedImageTexture->UnlockRect(0);
}
};
现在我认为最好的方法是编辑/裁剪 depthData.pBits。但我不知道该怎么做。