博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
kinnect face tracking大概流程
阅读量:4041 次
发布时间:2019-05-24

本文共 17567 字,大约阅读时间需要 58 分钟。

先看SingleFace.cpp

初始化InitInstance函数, 返回

return SUCCEEDED(m_FTHelper.Init(m_hWnd,        FTHelperCallingBack,        this,        m_depthType,        m_depthRes,        m_bNearMode,        TRUE, // if near mode doesn't work, fall back to default mode        m_colorType,        m_colorRes,        m_bSeatedSkeletonMode));

回调函数长这样, 其会在后面的SubmitFraceTrackingResult函数里面执行, 主要设置鸡蛋脸的一些参数

/** The "Face Tracker" helper class is generic. It will call back this function* after a face has been successfully tracked. The code in the call back passes the parameters* to the Egg Avatar, so it can be animated.*/void SingleFace::FTHelperCallingBack(PVOID pVoid){    SingleFace* pApp = reinterpret_cast
(pVoid); if (pApp) { IFTResult* pResult = pApp->m_FTHelper.GetResult(); if (pResult && SUCCEEDED(pResult->GetStatus())) { FLOAT* pAU = NULL; UINT numAU; pResult->GetAUCoefficients(&pAU, &numAU); pApp->m_eggavatar.SetCandideAU(pAU, numAU); FLOAT scale; FLOAT rotationXYZ[3]; FLOAT translationXYZ[3]; pResult->Get3DPose(&scale, rotationXYZ, translationXYZ); pApp->m_eggavatar.SetTranslations(translationXYZ[0], translationXYZ[1], translationXYZ[2]); pApp->m_eggavatar.SetRotations(rotationXYZ[0], rotationXYZ[1], rotationXYZ[2]); } }}

在Helper的init函数里面创建了一个线程

HRESULT FTHelper::Init(HWND hWnd, FTHelperCallBack callBack, PVOID callBackParam,                        NUI_IMAGE_TYPE depthType, NUI_IMAGE_RESOLUTION depthRes, BOOL bNearMode, BOOL bFallbackToDefault, NUI_IMAGE_TYPE colorType, NUI_IMAGE_RESOLUTION colorRes, BOOL bSeatedSkeletonMode){    if (!hWnd || !callBack)    {        return E_INVALIDARG;    }    m_hWnd = hWnd;    m_CallBack = callBack;    m_CallBackParam = callBackParam;    m_ApplicationIsRunning = true;    m_depthType = depthType;    m_depthRes = depthRes;    m_bNearMode = bNearMode;    m_bFallbackToDefault = bFallbackToDefault;    m_bSeatedSkeletonMode = bSeatedSkeletonMode;    m_colorType = colorType;    m_colorRes = colorRes;    m_hFaceTrackingThread = CreateThread(NULL, 0, FaceTrackingStaticThread, (PVOID)this, 0, 0);    return S_OK;}
DWORD WINAPI FTHelper::FaceTrackingStaticThread(PVOID lpParam){    FTHelper* context = static_cast
(lpParam); if (context) { return context->FaceTrackingThread(); } return 0;}

这个线程里面

DWORD WINAPI FTHelper::FaceTrackingThread(){    FT_CAMERA_CONFIG videoConfig;    FT_CAMERA_CONFIG depthConfig;    FT_CAMERA_CONFIG* pDepthConfig = NULL;    // Try to get the Kinect camera to work    HRESULT hr = m_KinectSensor.Init(m_depthType, m_depthRes, m_bNearMode, m_bFallbackToDefault, m_colorType, m_colorRes, m_bSeatedSkeletonMode);    if (SUCCEEDED(hr))    {        m_KinectSensorPresent = TRUE;        m_KinectSensor.GetVideoConfiguration(&videoConfig);        m_KinectSensor.GetDepthConfiguration(&depthConfig);        pDepthConfig = &depthConfig;        m_hint3D[0] = m_hint3D[1] = FT_VECTOR3D(0, 0, 0);    }    else    {        m_KinectSensorPresent = FALSE;        WCHAR errorText[MAX_PATH];        ZeroMemory(errorText, sizeof(WCHAR) * MAX_PATH);        wsprintf(errorText, L"Could not initialize the Kinect sensor. hr=0x%x\n", hr);        MessageBoxW(m_hWnd, errorText, L"Face Tracker Initialization Error\n", MB_OK);        return 1;    }    // Try to start the face tracker.    m_pFaceTracker = FTCreateFaceTracker(_opt);    if (!m_pFaceTracker)    {        MessageBoxW(m_hWnd, L"Could not create the face tracker.\n", L"Face Tracker Initialization Error\n", MB_OK);        return 2;    }    hr = m_pFaceTracker->Initialize(&videoConfig, pDepthConfig, NULL, NULL);     if (FAILED(hr))    {        WCHAR path[512], buffer[1024];        GetCurrentDirectoryW(ARRAYSIZE(path), path);        wsprintf(buffer, L"Could not initialize face tracker (%s). hr=0x%x", path, hr);        MessageBoxW(m_hWnd, /*L"Could not initialize the face tracker.\n"*/ buffer, L"Face Tracker Initialization Error\n", MB_OK);        return 3;    }    hr = m_pFaceTracker->CreateFTResult(&m_pFTResult);    if (FAILED(hr) || !m_pFTResult)    {        MessageBoxW(m_hWnd, L"Could not initialize the face tracker result.\n", L"Face Tracker Initialization Error\n", MB_OK);        return 4;    }    // Initialize the RGB image.    m_colorImage = FTCreateImage();    if (!m_colorImage || FAILED(hr = m_colorImage->Allocate(videoConfig.Width, videoConfig.Height, FTIMAGEFORMAT_UINT8_B8G8R8X8)))    {        return 5;    }    if (pDepthConfig)    {        m_depthImage = FTCreateImage();        if (!m_depthImage || FAILED(hr = m_depthImage->Allocate(depthConfig.Width, depthConfig.Height, FTIMAGEFORMAT_UINT16_D13P3)))        {            return 6;        }    }    SetCenterOfImage(NULL);    m_LastTrackSucceeded = false;    while (m_ApplicationIsRunning)    {        CheckCameraInput();        InvalidateRect(m_hWnd, NULL, FALSE);        UpdateWindow(m_hWnd);        Sleep(16);    }    m_pFaceTracker->Release();    m_pFaceTracker = NULL;    if(m_colorImage)    {        m_colorImage->Release();        m_colorImage = NULL;    }    if(m_depthImage)     {        m_depthImage->Release();        m_depthImage = NULL;    }    if(m_pFTResult)    {        m_pFTResult->Release();        m_pFTResult = NULL;    }    m_KinectSensor.Release();    return 0;}

这个线程会在一个循环里面执行

while (m_ApplicationIsRunning)    {        CheckCameraInput();        InvalidateRect(m_hWnd, NULL, FALSE);        UpdateWindow(m_hWnd);        Sleep(16);    }

然后CheckCameraInput处理每帧

// Get a video image and process it.void FTHelper::CheckCameraInput(){    HRESULT hrFT = E_FAIL;    if (m_KinectSensorPresent && m_KinectSensor.GetVideoBuffer())    {        HRESULT hrCopy = m_KinectSensor.GetVideoBuffer()->CopyTo(m_colorImage, NULL, 0, 0);        if (SUCCEEDED(hrCopy) && m_KinectSensor.GetDepthBuffer())        {            hrCopy = m_KinectSensor.GetDepthBuffer()->CopyTo(m_depthImage, NULL, 0, 0);        }        // Do face tracking        if (SUCCEEDED(hrCopy))        {            FT_SENSOR_DATA sensorData(m_colorImage, m_depthImage, m_KinectSensor.GetZoomFactor(), m_KinectSensor.GetViewOffSet());            FT_VECTOR3D* hint = NULL;            if (SUCCEEDED(m_KinectSensor.GetClosestHint(m_hint3D)))            {                hint = m_hint3D;            }            if (m_LastTrackSucceeded)            {                hrFT = m_pFaceTracker->ContinueTracking(&sensorData, hint, m_pFTResult);            }            else            {                hrFT = m_pFaceTracker->StartTracking(&sensorData, NULL, hint, m_pFTResult);            }        }    }    m_LastTrackSucceeded = SUCCEEDED(hrFT) && SUCCEEDED(m_pFTResult->GetStatus());    if (m_LastTrackSucceeded)    {        SubmitFraceTrackingResult(m_pFTResult);    }    else    {        m_pFTResult->Reset();    }    SetCenterOfImage(m_pFTResult);}

在SubmitFraceTrackingResult函数里面获取结果参数,并将网格边框显示出来。

BOOL FTHelper::SubmitFraceTrackingResult(IFTResult* pResult){    if (pResult != NULL && SUCCEEDED(pResult->GetStatus()))    {        if (m_CallBack)        {            (*m_CallBack)(m_CallBackParam);//回调函数会在这里执行        }        if (m_DrawMask)        {            FLOAT* pSU = NULL;            UINT numSU;            BOOL suConverged;            m_pFaceTracker->GetShapeUnits(NULL, &pSU, &numSU, &suConverged);            POINT viewOffset = {
0, 0}; FT_CAMERA_CONFIG cameraConfig; if (m_KinectSensorPresent) { m_KinectSensor.GetVideoConfiguration(&cameraConfig); } else { cameraConfig.Width = 640; cameraConfig.Height = 480; cameraConfig.FocalLength = 500.0f; } IFTModel* ftModel; HRESULT hr = m_pFaceTracker->GetFaceModel(&ftModel); if (SUCCEEDED(hr)) { hr = VisualizeFaceModel(m_colorImage, ftModel, &cameraConfig, pSU, 1.0, viewOffset, pResult, 0x00FFFF00); ftModel->Release(); } } } return TRUE;}
HRESULT VisualizeFaceModel(IFTImage* pColorImg, IFTModel* pModel, FT_CAMERA_CONFIG const* pCameraConfig, FLOAT const* pSUCoef,     FLOAT zoomFactor, POINT viewOffset, IFTResult* pAAMRlt, UINT32 color){    if (!pColorImg || !pModel || !pCameraConfig || !pSUCoef || !pAAMRlt)    {        return E_POINTER;    }    HRESULT hr = S_OK;    UINT vertexCount = pModel->GetVertexCount();    FT_VECTOR2D* pPts2D = reinterpret_cast
(_malloca(sizeof(FT_VECTOR2D) * vertexCount)); if (pPts2D) { FLOAT *pAUs; UINT auCount; hr = pAAMRlt->GetAUCoefficients(&pAUs, &auCount); if (SUCCEEDED(hr)) { FLOAT scale, rotationXYZ[3], translationXYZ[3]; hr = pAAMRlt->Get3DPose(&scale, rotationXYZ, translationXYZ); if (SUCCEEDED(hr)) { hr = pModel->GetProjectedShape(pCameraConfig, zoomFactor, viewOffset, pSUCoef, pModel->GetSUCount(), pAUs, auCount, scale, rotationXYZ, translationXYZ, pPts2D, vertexCount); if (SUCCEEDED(hr)) { POINT* p3DMdl = reinterpret_cast
(_malloca(sizeof(POINT) * vertexCount)); if (p3DMdl) { for (UINT i = 0; i < vertexCount; ++i) { p3DMdl[i].x = LONG(pPts2D[i].x + 0.5f); p3DMdl[i].y = LONG(pPts2D[i].y + 0.5f); } FT_TRIANGLE* pTriangles; UINT triangleCount; hr = pModel->GetTriangles(&pTriangles, &triangleCount); if (SUCCEEDED(hr)) { struct EdgeHashTable { UINT32* pEdges; UINT edgesAlloc; void Insert(int a, int b) { UINT32 v = (min(a, b) << 16) | max(a, b); UINT32 index = (v + (v << 8)) * 49157, i; for (i = 0; i < edgesAlloc - 1 && pEdges[(index + i) & (edgesAlloc - 1)] && v != pEdges[(index + i) & (edgesAlloc - 1)]; ++i) { } pEdges[(index + i) & (edgesAlloc - 1)] = v; } } eht; eht.edgesAlloc = 1 << UINT(log(2.f * (1 + vertexCount + triangleCount)) / log(2.f)); eht.pEdges = reinterpret_cast
(_malloca(sizeof(UINT32) * eht.edgesAlloc)); if (eht.pEdges) { ZeroMemory(eht.pEdges, sizeof(UINT32) * eht.edgesAlloc); for (UINT i = 0; i < triangleCount; ++i) { eht.Insert(pTriangles[i].i, pTriangles[i].j); eht.Insert(pTriangles[i].j, pTriangles[i].k); eht.Insert(pTriangles[i].k, pTriangles[i].i); } for (UINT i = 0; i < eht.edgesAlloc; ++i) { if(eht.pEdges[i] != 0) { pColorImg->DrawLine(p3DMdl[eht.pEdges[i] >> 16], p3DMdl[eht.pEdges[i] & 0xFFFF], color, 1); } } _freea(eht.pEdges); } // Render the face rect in magenta RECT rectFace; hr = pAAMRlt->GetFaceRect(&rectFace); if (SUCCEEDED(hr)) { POINT leftTop = {rectFace.left, rectFace.top}; POINT rightTop = {rectFace.right - 1, rectFace.top}; POINT leftBottom = {rectFace.left, rectFace.bottom - 1}; POINT rightBottom = {rectFace.right - 1, rectFace.bottom - 1}; UINT32 nColor = 0xff00ff; SUCCEEDED(hr = pColorImg->DrawLine(leftTop, rightTop, nColor, 1)) && SUCCEEDED(hr = pColorImg->DrawLine(rightTop, rightBottom, nColor, 1)) && SUCCEEDED(hr = pColorImg->DrawLine(rightBottom, leftBottom, nColor, 1)) && SUCCEEDED(hr = pColorImg->DrawLine(leftBottom, leftTop, nColor, 1)); } } _freea(p3DMdl); } else { hr = E_OUTOFMEMORY; } } } } _freea(pPts2D); } else { hr = E_OUTOFMEMORY; } return hr;}

然后在主窗口的消息循环中

case WM_PAINT:        hdc = BeginPaint(hWnd, &ps);        // Draw the avatar window and the video window        PaintWindow(hdc, hWnd);        EndPaint(hWnd, &ps);        break;

画图函数长这样

// Draw the egg head and the camera video with the mask superimposed.BOOL SingleFace::PaintWindow(HDC hdc, HWND hWnd){    static int errCount = 0;    BOOL ret = FALSE;    RECT rect;    GetClientRect(hWnd, &rect);    int width = rect.right - rect.left;    int height = rect.bottom - rect.top;    int halfWidth = width/2;    // Show the video on the right of the window    errCount += !ShowVideo(hdc, width - halfWidth, height, halfWidth, 0);    // Draw the egg avatar on the left of the window    errCount += !ShowEggAvatar(hdc, halfWidth, height, 0, 0);    return ret;}

其中ShowVideo会调用 m_FTHelper.GetColorImage(),获取helper画好的网格和边框。

// Drawing the video windowBOOL SingleFace::ShowVideo(HDC hdc, int width, int height, int originX, int originY){    BOOL ret = TRUE;    // Now, copy a fraction of the camera image into the screen.    IFTImage* colorImage = m_FTHelper.GetColorImage();    if (colorImage)    {        int iWidth = colorImage->GetWidth();        int iHeight = colorImage->GetHeight();        if (iWidth > 0 && iHeight > 0)        {            int iTop = 0;            int iBottom = iHeight;            int iLeft = 0;            int iRight = iWidth;            // Keep a separate buffer.            if (m_pVideoBuffer && SUCCEEDED(m_pVideoBuffer->Allocate(iWidth, iHeight, FTIMAGEFORMAT_UINT8_B8G8R8A8)))            {                // Copy do the video buffer while converting bytes                colorImage->CopyTo(m_pVideoBuffer, NULL, 0, 0);                // Compute the best approximate copy ratio.                float w1 = (float)iHeight * (float)width;                float w2 = (float)iWidth * (float)height;                if (w2 > w1 && height > 0)                {                    // video image too wide                    float wx = w1/height;                    iLeft = (int)max(0, m_FTHelper.GetXCenterFace() - wx / 2);                    iRight = iLeft + (int)wx;                    if (iRight > iWidth)                    {                        iRight = iWidth;                        iLeft = iRight - (int)wx;                    }                }                else if (w1 > w2 && width > 0)                {                    // video image too narrow                    float hy = w2/width;                    iTop = (int)max(0, m_FTHelper.GetYCenterFace() - hy / 2);                    iBottom = iTop + (int)hy;                    if (iBottom > iHeight)                    {                        iBottom = iHeight;                        iTop = iBottom - (int)hy;                    }                }                int const bmpPixSize = m_pVideoBuffer->GetBytesPerPixel();                SetStretchBltMode(hdc, HALFTONE);                BITMAPINFO bmi = {
sizeof(BITMAPINFO), iWidth, iHeight, 1, static_cast
(bmpPixSize * CHAR_BIT), BI_RGB, m_pVideoBuffer->GetStride() * iHeight, 5000, 5000, 0, 0}; if (0 == StretchDIBits(hdc, originX, originY, width, height, iLeft, iBottom, iRight-iLeft, iTop-iBottom, m_pVideoBuffer->GetBuffer(), &bmi, DIB_RGB_COLORS, SRCCOPY)) { ret = FALSE; } } } } return ret;}

ShowEggAvatar会调用m_eggavatar.DrawImage(m_pImageBuffer);画鸡蛋脸, 注意鸡蛋脸的参数在回调函数里面设置好了

// Drawing codeBOOL SingleFace::ShowEggAvatar(HDC hdc, int width, int height, int originX, int originY){    static int errCount = 0;    BOOL ret = FALSE;    if (m_pImageBuffer && SUCCEEDED(m_pImageBuffer->Allocate(width, height, FTIMAGEFORMAT_UINT8_B8G8R8A8)))    {        memset(m_pImageBuffer->GetBuffer(), 0, m_pImageBuffer->GetStride() * height); // clear to black        m_eggavatar.SetScaleAndTranslationToWindow(height, width);        m_eggavatar.DrawImage(m_pImageBuffer);        BITMAPINFO bmi = {
sizeof(BITMAPINFO), width, height, 1, static_cast
(m_pImageBuffer->GetBytesPerPixel() * CHAR_BIT), BI_RGB, m_pImageBuffer->GetStride() * height, 5000, 5000, 0, 0}; errCount += (0 == StretchDIBits(hdc, 0, 0, width, height, 0, 0, width, height, m_pImageBuffer->GetBuffer(), &bmi, DIB_RGB_COLORS, SRCCOPY)); ret = TRUE; } return ret;}

转载地址:http://uaxdi.baihongyu.com/

你可能感兴趣的文章
coursesa课程 Python 3 programming course_2_assessment_8 sorted练习题
查看>>
在unity中建立最小的shader(Minimal Shader)
查看>>
1.3 Debugging of Shaders (调试着色器)
查看>>
关于phpcms中模块_tag.class.php中的pc_tag()方法的含义
查看>>
vsftp 配置具有匿名登录也有系统用户登录,系统用户有管理权限,匿名只有下载权限。
查看>>
linux安装usb wifi接收器
查看>>
补充自动屏蔽攻击ip
查看>>
多线程使用随机函数需要注意的一点
查看>>
getpeername,getsockname
查看>>
让我做你的下一行Code
查看>>
浅析:setsockopt()改善程序的健壮性
查看>>
关于对象赋值及返回临时对象过程中的构造与析构
查看>>
VS 2005 CRT函数的安全性增强版本
查看>>
SQL 多表联合查询
查看>>
Visual Studio 2010:C++0x新特性
查看>>
drwtsn32.exe和adplus.vbs进行dump文件抓取
查看>>
cppcheck c++静态代码检查
查看>>
在C++中使用Lua
查看>>
一些socket的编程经验
查看>>
socket编程中select的使用
查看>>