从3D kinect模型中提取面部

时间:2013-05-24 13:15:11

标签: c++ 3d kinect

我正在使用Kinect创建一个人的3D模型。我得到的是这样的:

Kinect image

我将它导出到Wavefront .obj文件。但我只对脸本身感兴趣,并希望删除它周围的一切。由于Kinect有RGB相机,我可以毫无问题地进行RGB人脸检测。但是这给了我一个包含面部的640x480图像内的矩形,我该如何将其转换为3D网格?

2 个答案:

答案 0 :(得分:3)

我前段时间做过类似的事情:

Max in depth

视频here

我所做的很简单:

  1. 使用OpenCV的haar级联来检测RGB图像中的面部
  2. 使用检测到的面部矩形仅从深度图像中裁剪面部区域
  3. 将深度图像转换为深度值(3d点云/网格/等)
  4. 理想情况下,您可以校准两个(rgb,深度)流。

    我使用的是libreenect,但这种技术应该适用于OpenNI,KinectSDK。

    我注意到你的应用程序的标题是KinectFusion所以我猜你是从Microsoft Kinect SDK 1.7中的Kinect Fusion示例开始的。应该有一个内置函数来对齐rgb和深度流。关于CV部分,您可以在线找到Kinect to OpenCV Mat转换,例如Dennis Ippel functionsEgmuCV也有面部检测。并且KinectSDK本身允许您以3D形式跟踪面部,因此我必须在SDK中进行面部检测(甚至不是跟踪)。我自己没有充分使用Kinect SDK,所以目前还不能更具体。

    简而言之:

    1. 检测面部
    2. 隔离深度图中的面部区域
    3. 将深度贴图区域区域转换为点云/网格/等。

答案 1 :(得分:0)

这是我用来获取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。但我不知道该怎么做。