C++ 从三维kinect模型中提取人脸

C++ 从三维kinect模型中提取人脸,c++,3d,kinect,C++,3d,Kinect,我正在使用Kinect创建一个人的3D模型。我得到的是这样的东西: 我将其导出到Wavefront.obj文件。但我只对脸本身感兴趣,我想去掉它周围的一切。由于Kinect有一个RGB摄像头,我可以在RGB中进行人脸检测,没有问题。但这给了我一个包含人脸的640x480图像内的矩形,我如何将其转换为3D网格 不久前我也做过类似的事情: 录像带 我所做的很简单: 使用OpenCV的haar级联检测RGB图像中的人脸 使用检测到的面矩形仅从深度图像裁剪面区域 将深度图像转换为深度值(3d点云/网

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


我将其导出到Wavefront.obj文件。但我只对脸本身感兴趣,我想去掉它周围的一切。由于Kinect有一个RGB摄像头,我可以在RGB中进行人脸检测,没有问题。但这给了我一个包含人脸的640x480图像内的矩形,我如何将其转换为3D网格

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

录像带

我所做的很简单:

  • 使用OpenCV的haar级联检测RGB图像中的人脸
  • 使用检测到的面矩形仅从深度图像裁剪面区域
  • 将深度图像转换为深度值(3d点云/网格/等)
  • 理想情况下,您需要校准两个(rgb,深度)流

    我使用的是libreenet,但这种技术应该与OpenNI、KinectSDK一起使用

    我注意到你的应用程序的标题是Kinect Fusion,所以我猜你是从Microsoft Kinect SDK 1.7中的Kinect Fusion示例开始的。应该有一个内置功能来对齐rgb和深度流。关于CV零件,您可以在线找到Kinect到OpenCV Mat的转换,例如。还有人脸检测。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);
        }
    };
    
    void processDepth()
    {
    NUI_图像_帧深度FRAME={0};
    错误检查(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::无法获取当前世界到现金转移(&世界到现金转移);
    hr=m_pVolume->ProcessFrame(m_pDepthFloatImage,NUI_FUSION_DEFAULT_ALIGN_ITERATION_COUNT,
    NUI_FUSION_DEFAULT_INTEGRATION_WEIGHT和worldToCameraTransform);
    世界货币转换;
    如果(失败(小时)){
    ++跟踪错误计数;
    如果(trackingErrorCount>=100){
    trackingErrorCount=0;
    m_pVolume->reset重构(&IdentityMatrix(),nullptr);
    }
    返回;
    }
    //点云
    hr=m_pVolume->CalculatePointCloud(m_pPointCloud和worldToCameraTransform);
    如果(失败(小时)){
    抛出std::runtime_错误(“CalculatePointCloud失败”);
    }
    //点云
    hr=::NuiFusionShadePointCloud(m_PointCloud和worldToCameraTransform,
    &worldToBGRTransform,m_pshaddedsface,nullptr);
    如果(失败(小时)){
    抛出std::runtime_错误(“::NuiFusionShadePointCloud失败”);
    }
    INuiFrameTexture*pShadedImageTexture=m_pShadedSurface->pFrameTexture;
    NUI_LOCKED_RECT ShadedLockedRect;
    hr=pShadedImageTexture->LockRect(0,&ShadedLockedRect,nullptr,0);
    如果(失败(小时)){
    抛出std::runtime_错误(“LockRect失败”);
    }
    pshadeImageTexture->UnlockRect(0);
    }
    };
    

    现在我认为最好的方法是编辑/裁剪depthData.pBits。但我不知道如何做到这一点。

    您使用点云库吗?这就是您想要的:非常感谢,编辑输入以计算点云可能确实比尝试编辑输出更有意义。但我还不知道怎么做。我对这个很陌生。我在下面添加了更多信息。