1

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

Kinect 图像

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

4

2 回答 2

3

不久前我做过类似的事情:

最大深度

视频在这里

我所做的很简单:

  1. 使用 OpenCV 的 haar 级联检测 RGB 图像中的人脸
  2. 使用检测到的人脸矩形从深度图像中仅裁剪人脸区域
  3. 将深度图像转换为深度值(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,所以目前不能更具体。

简而言之:

  1. 检测人脸
  2. 在深度图中隔离人脸区域
  3. 将深度图面区域转换为点云/网格/等。
于 2013-05-24T16:26:03.823 回答
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。但我不知道该怎么做。

于 2013-05-27T09:49:56.507 回答