diff options
author | Stéphane Lenclud <github@lenclud.com> | 2019-01-31 10:32:17 +0100 |
---|---|---|
committer | Stéphane Lenclud <github@lenclud.com> | 2019-02-07 13:24:13 +0100 |
commit | a774441fde00f0ce6c8387339c786e9e2f42f088 (patch) | |
tree | 0877ab55801aee6b4de748dcbd1190a4922da41b /tracker-kinect-face | |
parent | b9d34a26d35d05f793161e54001329edb5122a81 (diff) |
Kinect: First draft.
Diffstat (limited to 'tracker-kinect-face')
-rw-r--r-- | tracker-kinect-face/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tracker-kinect-face/lang/nl_NL.ts | 22 | ||||
-rw-r--r-- | tracker-kinect-face/lang/ru_RU.ts | 22 | ||||
-rw-r--r-- | tracker-kinect-face/lang/stub.ts | 22 | ||||
-rw-r--r-- | tracker-kinect-face/lang/zh_CN.ts | 22 | ||||
-rw-r--r-- | tracker-kinect-face/test.cpp | 45 | ||||
-rw-r--r-- | tracker-kinect-face/test.h | 28 | ||||
-rw-r--r-- | tracker-kinect-face/test.ui | 65 | ||||
-rw-r--r-- | tracker-kinect-face/test_dialog.cpp | 3 | ||||
-rw-r--r-- | tracker-kinect-face/tracker.cpp | 451 | ||||
-rw-r--r-- | tracker-kinect-face/tracker.h | 90 |
11 files changed, 776 insertions, 0 deletions
diff --git a/tracker-kinect-face/CMakeLists.txt b/tracker-kinect-face/CMakeLists.txt new file mode 100644 index 00000000..d139b445 --- /dev/null +++ b/tracker-kinect-face/CMakeLists.txt @@ -0,0 +1,6 @@ + +if(DEFINED ENV{KINECTSDK20_DIR}) + otr_module(tracker-kinect-face) + target_include_directories(opentrack-tracker-kinect-face SYSTEM PUBLIC $ENV{KINECTSDK20_DIR}inc) + target_link_libraries(opentrack-tracker-kinect-face $ENV{KINECTSDK20_DIR}lib/x86/kinect20.lib $ENV{KINECTSDK20_DIR}lib/x86/kinect20.face.lib) +endif() diff --git a/tracker-kinect-face/lang/nl_NL.ts b/tracker-kinect-face/lang/nl_NL.ts new file mode 100644 index 00000000..b6139882 --- /dev/null +++ b/tracker-kinect-face/lang/nl_NL.ts @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="nl_NL"> +<context> + <name>test_metadata</name> + <message> + <source>Kinect Face</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>test_ui</name> + <message> + <source>Sine wave</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Pressing "Abort" will immediately crash the application.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/tracker-kinect-face/lang/ru_RU.ts b/tracker-kinect-face/lang/ru_RU.ts new file mode 100644 index 00000000..52aab9f3 --- /dev/null +++ b/tracker-kinect-face/lang/ru_RU.ts @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="ru_RU"> +<context> + <name>test_metadata</name> + <message> + <source>Kinect Face</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>test_ui</name> + <message> + <source>Sine wave</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Pressing "Abort" will immediately crash the application.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/tracker-kinect-face/lang/stub.ts b/tracker-kinect-face/lang/stub.ts new file mode 100644 index 00000000..84a3c6af --- /dev/null +++ b/tracker-kinect-face/lang/stub.ts @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +<context> + <name>test_metadata</name> + <message> + <source>Kinect Face</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>test_ui</name> + <message> + <source>Sine wave</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Pressing "Abort" will immediately crash the application.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/tracker-kinect-face/lang/zh_CN.ts b/tracker-kinect-face/lang/zh_CN.ts new file mode 100644 index 00000000..84a3c6af --- /dev/null +++ b/tracker-kinect-face/lang/zh_CN.ts @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +<context> + <name>test_metadata</name> + <message> + <source>Kinect Face</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>test_ui</name> + <message> + <source>Sine wave</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Pressing "Abort" will immediately crash the application.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/tracker-kinect-face/test.cpp b/tracker-kinect-face/test.cpp new file mode 100644 index 00000000..c1ada177 --- /dev/null +++ b/tracker-kinect-face/test.cpp @@ -0,0 +1,45 @@ +/* Copyright (c) 2014, Stanislaw Halik <sthalik@misaki.pl> + + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted, + * provided that the above copyright notice and this permission + * notice appear in all copies. + */ + +#include "test.h" +#include "tracker.h" +#include "api/plugin-api.hpp" +#include "compat/math-imports.hpp" + +#include <QPushButton> + +#include <cmath> +#include <QDebug> + + +test_dialog::test_dialog() +{ + ui.setupUi(this); + + connect(ui.buttonBox, &QDialogButtonBox::clicked, [this](QAbstractButton* btn) { + if (btn == ui.buttonBox->button(QDialogButtonBox::Abort)) + // NOLINTNEXTLINE + *(volatile int*)nullptr = 0; + }); + + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK())); + connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel())); +} + +void test_dialog::doOK() +{ + //s.b->save(); + close(); +} + +void test_dialog::doCancel() +{ + close(); +} + +OPENTRACK_DECLARE_TRACKER(KinectFaceTracker, test_dialog, test_metadata) diff --git a/tracker-kinect-face/test.h b/tracker-kinect-face/test.h new file mode 100644 index 00000000..2e105ae3 --- /dev/null +++ b/tracker-kinect-face/test.h @@ -0,0 +1,28 @@ +#pragma once +#include "ui_test.h" +#include "compat/macros.hpp" +#include "api/plugin-api.hpp" + + +class test_dialog : public ITrackerDialog +{ + Q_OBJECT + + Ui::test_ui ui; +public: + test_dialog(); + void register_tracker(ITracker *) override {} + void unregister_tracker() override {} +private slots: + void doOK(); + void doCancel(); +}; + +class test_metadata : public Metadata +{ + Q_OBJECT + + QString name() { return tr("Kinect Face"); } + QIcon icon() { return QIcon(":/images/opentrack.png"); } +}; + diff --git a/tracker-kinect-face/test.ui b/tracker-kinect-face/test.ui new file mode 100644 index 00000000..509eb819 --- /dev/null +++ b/tracker-kinect-face/test.ui @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>test_ui</class> + <widget class="QWidget" name="test_ui"> + <property name="windowModality"> + <enum>Qt::NonModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>278</width> + <height>58</height> + </rect> + </property> + <property name="windowTitle"> + <string>Sine wave</string> + </property> + <property name="windowIcon"> + <iconset> + <normaloff>../gui/images/opentrack.png</normaloff>../gui/images/opentrack.png</iconset> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Pressing "Abort" will immediately crash the application.</string> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Abort|QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> + <slots> + <slot>startEngineClicked()</slot> + <slot>stopEngineClicked()</slot> + <slot>cameraSettingsClicked()</slot> + </slots> +</ui> diff --git a/tracker-kinect-face/test_dialog.cpp b/tracker-kinect-face/test_dialog.cpp new file mode 100644 index 00000000..5d33555b --- /dev/null +++ b/tracker-kinect-face/test_dialog.cpp @@ -0,0 +1,3 @@ +#include "test.h" +#include "api/plugin-api.hpp" + diff --git a/tracker-kinect-face/tracker.cpp b/tracker-kinect-face/tracker.cpp new file mode 100644 index 00000000..3fe3b8cc --- /dev/null +++ b/tracker-kinect-face/tracker.cpp @@ -0,0 +1,451 @@ + + +#include "tracker.h" + + +const double KinectFaceTracker::incr[6] = +{ + 50, 40, 80, + 70, 5, 3 +}; + +KinectFaceTracker::KinectFaceTracker(): + m_pKinectSensor(nullptr), + m_pCoordinateMapper(nullptr), + m_pColorFrameReader(nullptr), + m_pColorRGBX(nullptr), + m_pBodyFrameReader(nullptr) + +{ + for (int i = 0; i < BODY_COUNT; i++) + { + m_pFaceFrameSources[i] = nullptr; + m_pFaceFrameReaders[i] = nullptr; + } + + // create heap storage for color pixel data in RGBX format + m_pColorRGBX = new RGBQUAD[cColorWidth * cColorHeight]; +} + +KinectFaceTracker::~KinectFaceTracker() +{ + if (m_pColorRGBX) + { + delete[] m_pColorRGBX; + m_pColorRGBX = nullptr; + } + + // clean up Direct2D + //SafeRelease(m_pD2DFactory); + + // done with face sources and readers + for (int i = 0; i < BODY_COUNT; i++) + { + SafeRelease(m_pFaceFrameSources[i]); + SafeRelease(m_pFaceFrameReaders[i]); + } + + // done with body frame reader + SafeRelease(m_pBodyFrameReader); + + // done with color frame reader + SafeRelease(m_pColorFrameReader); + + // done with coordinate mapper + SafeRelease(m_pCoordinateMapper); + + // close the Kinect Sensor + if (m_pKinectSensor) + { + m_pKinectSensor->Close(); + } + + SafeRelease(m_pKinectSensor); +} + +module_status KinectFaceTracker::start_tracker(QFrame*) +{ + t.start(); + + if (SUCCEEDED(InitializeDefaultSensor())) + { + return status_ok(); + } + + return error("Kinect init failed!"); +} + +#ifdef EMIT_NAN +# include <cstdlib> +#endif + +void KinectFaceTracker::data(double *data) +{ + const double dt = t.elapsed_seconds(); + t.start(); + +#ifdef EMIT_NAN + if ((rand() % 4) == 0) + { + for (int i = 0; i < 6; i++) + data[i] = 0. / 0.; + } + else +#endif + for (int i = 0; i < 6; i++) + { + double x = last_x[i] + incr[i] * dt; + if (x > 180) + x = -360 + x; + else if (x < -180) + x = 360 + x; + x = copysign(fmod(fabs(x), 360), x); + last_x[i] = x; + + if (i >= 3) + { + data[i] = x; + } + else + { + data[i] = x * 100 / 180.; + } + } + + + Update(); + //TODO: check if data is valid + data[0] = 0; + data[1] = 0; + data[2] = 0; + ExtractFaceRotationInDegrees(&faceRotation,&data[3], &data[4], &data[5]); + +} + + +/// <summary> +/// Converts rotation quaternion to Euler angles +/// And then maps them to a specified range of values to control the refresh rate +/// </summary> +/// <param name="pQuaternion">face rotation quaternion</param> +/// <param name="pPitch">rotation about the X-axis</param> +/// <param name="pYaw">rotation about the Y-axis</param> +/// <param name="pRoll">rotation about the Z-axis</param> +void KinectFaceTracker::ExtractFaceRotationInDegrees(const Vector4* pQuaternion, double* pYaw, double* pPitch, double* pRoll) +{ + double x = pQuaternion->x; + double y = pQuaternion->y; + double z = pQuaternion->z; + double w = pQuaternion->w; + + // convert face rotation quaternion to Euler angles in degrees + double dPitch, dYaw, dRoll; + dPitch = atan2(2 * (y * z + w * x), w * w - x * x - y * y + z * z) / M_PI * 180.0; + dYaw = asin(2 * (w * y - x * z)) / M_PI * 180.0; + dRoll = atan2(2 * (x * y + w * z), w * w + x * x - y * y - z * z) / M_PI * 180.0; + + // clamp rotation values in degrees to a specified range of values to control the refresh rate + /* + double increment = c_FaceRotationIncrementInDegrees; + *pPitch = static_cast<int>(floor((dPitch + increment/2.0 * (dPitch > 0 ? 1.0 : -1.0)) / increment) * increment); + *pYaw = static_cast<int>(floor((dYaw + increment/2.0 * (dYaw > 0 ? 1.0 : -1.0)) / increment) * increment); + *pRoll = static_cast<int>(floor((dRoll + increment/2.0 * (dRoll > 0 ? 1.0 : -1.0)) / increment) * increment); + */ + + *pPitch = dPitch; + *pYaw = dYaw; + *pRoll = dRoll; + + +} + + +/// <summary> +/// Initializes the default Kinect sensor +/// </summary> +/// <returns>S_OK on success else the failure code</returns> +HRESULT KinectFaceTracker::InitializeDefaultSensor() +{ + HRESULT hr; + + hr = GetDefaultKinectSensor(&m_pKinectSensor); + if (FAILED(hr)) + { + return hr; + } + + if (m_pKinectSensor) + { + // Initialize Kinect and get color, body and face readers + IColorFrameSource* pColorFrameSource = nullptr; + IBodyFrameSource* pBodyFrameSource = nullptr; + + hr = m_pKinectSensor->Open(); + + if (SUCCEEDED(hr)) + { + hr = m_pKinectSensor->get_CoordinateMapper(&m_pCoordinateMapper); + } + + if (SUCCEEDED(hr)) + { + hr = m_pKinectSensor->get_ColorFrameSource(&pColorFrameSource); + } + + if (SUCCEEDED(hr)) + { + hr = pColorFrameSource->OpenReader(&m_pColorFrameReader); + } + + if (SUCCEEDED(hr)) + { + hr = m_pKinectSensor->get_BodyFrameSource(&pBodyFrameSource); + } + + if (SUCCEEDED(hr)) + { + hr = pBodyFrameSource->OpenReader(&m_pBodyFrameReader); + } + + if (SUCCEEDED(hr)) + { + // create a face frame source + reader to track each body in the fov + for (int i = 0; i < BODY_COUNT; i++) + { + if (SUCCEEDED(hr)) + { + // create the face frame source by specifying the required face frame features + hr = CreateFaceFrameSource(m_pKinectSensor, 0, c_FaceFrameFeatures, &m_pFaceFrameSources[i]); + } + if (SUCCEEDED(hr)) + { + // open the corresponding reader + hr = m_pFaceFrameSources[i]->OpenReader(&m_pFaceFrameReaders[i]); + } + } + } + + SafeRelease(pColorFrameSource); + SafeRelease(pBodyFrameSource); + } + + if (!m_pKinectSensor || FAILED(hr)) + { + //SetStatusMessage(L"No ready Kinect found!", 10000, true); + return E_FAIL; + } + + return hr; +} + +/// <summary> +/// Main processing function +/// </summary> +void KinectFaceTracker::Update() +{ + if (!m_pColorFrameReader || !m_pBodyFrameReader) + { + return; + } + + IColorFrame* pColorFrame = nullptr; + HRESULT hr = m_pColorFrameReader->AcquireLatestFrame(&pColorFrame); + + if (SUCCEEDED(hr)) + { + INT64 nTime = 0; + IFrameDescription* pFrameDescription = nullptr; + int nWidth = 0; + int nHeight = 0; + ColorImageFormat imageFormat = ColorImageFormat_None; + UINT nBufferSize = 0; + RGBQUAD *pBuffer = nullptr; + + hr = pColorFrame->get_RelativeTime(&nTime); + + if (SUCCEEDED(hr)) + { + hr = pColorFrame->get_FrameDescription(&pFrameDescription); + } + + if (SUCCEEDED(hr)) + { + hr = pFrameDescription->get_Width(&nWidth); + } + + if (SUCCEEDED(hr)) + { + hr = pFrameDescription->get_Height(&nHeight); + } + + if (SUCCEEDED(hr)) + { + hr = pColorFrame->get_RawColorImageFormat(&imageFormat); + } + + if (SUCCEEDED(hr)) + { + if (imageFormat == ColorImageFormat_Bgra) + { + hr = pColorFrame->AccessRawUnderlyingBuffer(&nBufferSize, reinterpret_cast<BYTE**>(&pBuffer)); + } + else if (m_pColorRGBX) + { + pBuffer = m_pColorRGBX; + nBufferSize = cColorWidth * cColorHeight * sizeof(RGBQUAD); + hr = pColorFrame->CopyConvertedFrameDataToArray(nBufferSize, reinterpret_cast<BYTE*>(pBuffer), ColorImageFormat_Bgra); + } + else + { + hr = E_FAIL; + } + } + + if (SUCCEEDED(hr)) + { + //DrawStreams(nTime, pBuffer, nWidth, nHeight); + ProcessFaces(); + } + + SafeRelease(pFrameDescription); + } + + SafeRelease(pColorFrame); +} + + +/// <summary> +/// Updates body data +/// </summary> +/// <param name="ppBodies">pointer to the body data storage</param> +/// <returns>indicates success or failure</returns> +HRESULT KinectFaceTracker::UpdateBodyData(IBody** ppBodies) +{ + HRESULT hr = E_FAIL; + + if (m_pBodyFrameReader != nullptr) + { + IBodyFrame* pBodyFrame = nullptr; + hr = m_pBodyFrameReader->AcquireLatestFrame(&pBodyFrame); + if (SUCCEEDED(hr)) + { + hr = pBodyFrame->GetAndRefreshBodyData(BODY_COUNT, ppBodies); + } + SafeRelease(pBodyFrame); + } + + return hr; +} + + + +/// <summary> +/// Processes new face frames +/// </summary> +void KinectFaceTracker::ProcessFaces() +{ + HRESULT hr; + IBody* ppBodies[BODY_COUNT] = { 0 }; + bool bHaveBodyData = SUCCEEDED(UpdateBodyData(ppBodies)); + + // iterate through each face reader + for (int iFace = 0; iFace < BODY_COUNT; ++iFace) + { + // retrieve the latest face frame from this reader + IFaceFrame* pFaceFrame = nullptr; + hr = m_pFaceFrameReaders[iFace]->AcquireLatestFrame(&pFaceFrame); + + BOOLEAN bFaceTracked = false; + if (SUCCEEDED(hr) && nullptr != pFaceFrame) + { + // check if a valid face is tracked in this face frame + hr = pFaceFrame->get_IsTrackingIdValid(&bFaceTracked); + } + + if (SUCCEEDED(hr)) + { + if (bFaceTracked) + { + IFaceFrameResult* pFaceFrameResult = nullptr; + RectI faceBox = { 0 }; + PointF facePoints[FacePointType::FacePointType_Count]; + DetectionResult faceProperties[FaceProperty::FaceProperty_Count]; + //D2D1_POINT_2F faceTextLayout; + + hr = pFaceFrame->get_FaceFrameResult(&pFaceFrameResult); + + // need to verify if pFaceFrameResult contains data before trying to access it + if (SUCCEEDED(hr) && pFaceFrameResult != nullptr) + { + hr = pFaceFrameResult->get_FaceBoundingBoxInColorSpace(&faceBox); + + if (SUCCEEDED(hr)) + { + hr = pFaceFrameResult->GetFacePointsInColorSpace(FacePointType::FacePointType_Count, facePoints); + } + + if (SUCCEEDED(hr)) + { + hr = pFaceFrameResult->get_FaceRotationQuaternion(&faceRotation); + } + + if (SUCCEEDED(hr)) + { + hr = pFaceFrameResult->GetFaceProperties(FaceProperty::FaceProperty_Count, faceProperties); + } + + if (SUCCEEDED(hr)) + { + //hr = GetFaceTextPositionInColorSpace(ppBodies[iFace], &faceTextLayout); + } + + if (SUCCEEDED(hr)) + { + // draw face frame results + //m_pDrawDataStreams->DrawFaceFrameResults(iFace, &faceBox, facePoints, &faceRotation, faceProperties, &faceTextLayout); + } + } + + SafeRelease(pFaceFrameResult); + } + else + { + // face tracking is not valid - attempt to fix the issue + // a valid body is required to perform this step + if (bHaveBodyData) + { + // check if the corresponding body is tracked + // if this is true then update the face frame source to track this body + IBody* pBody = ppBodies[iFace]; + if (pBody != nullptr) + { + BOOLEAN bTracked = false; + hr = pBody->get_IsTracked(&bTracked); + + UINT64 bodyTId; + if (SUCCEEDED(hr) && bTracked) + { + // get the tracking ID of this body + hr = pBody->get_TrackingId(&bodyTId); + if (SUCCEEDED(hr)) + { + // update the face frame source with the tracking ID + m_pFaceFrameSources[iFace]->put_TrackingId(bodyTId); + } + } + } + } + } + } + + SafeRelease(pFaceFrame); + } + + if (bHaveBodyData) + { + for (int i = 0; i < _countof(ppBodies); ++i) + { + SafeRelease(ppBodies[i]); + } + } +} diff --git a/tracker-kinect-face/tracker.h b/tracker-kinect-face/tracker.h new file mode 100644 index 00000000..88243b1f --- /dev/null +++ b/tracker-kinect-face/tracker.h @@ -0,0 +1,90 @@ + + + +#include <cmath> + +#include "api/plugin-api.hpp" +#include "compat/timer.hpp" +#include "compat/macros.hpp" + +// Kinect Header files +#include <Kinect.h> +#include <Kinect.Face.h> + +#pragma once + +// Safe release for interfaces +template<class Interface> +inline void SafeRelease(Interface *& pInterfaceToRelease) +{ + if (pInterfaceToRelease != nullptr) + { + pInterfaceToRelease->Release(); + pInterfaceToRelease = nullptr; + } +} + + +class KinectFaceTracker : public ITracker +{ +public: + KinectFaceTracker(); + ~KinectFaceTracker() override; + module_status start_tracker(QFrame *) override; + void data(double *data) override; + +private: + static const double incr[6]; + double last_x[6]{}; + Timer t; + + // Kinect stuff + + // define the face frame features required to be computed by this application + static const DWORD c_FaceFrameFeatures = + FaceFrameFeatures::FaceFrameFeatures_BoundingBoxInColorSpace + | FaceFrameFeatures::FaceFrameFeatures_PointsInColorSpace + | FaceFrameFeatures::FaceFrameFeatures_RotationOrientation + | FaceFrameFeatures::FaceFrameFeatures_Happy + | FaceFrameFeatures::FaceFrameFeatures_RightEyeClosed + | FaceFrameFeatures::FaceFrameFeatures_LeftEyeClosed + | FaceFrameFeatures::FaceFrameFeatures_MouthOpen + | FaceFrameFeatures::FaceFrameFeatures_MouthMoved + | FaceFrameFeatures::FaceFrameFeatures_LookingAway + | FaceFrameFeatures::FaceFrameFeatures_Glasses + | FaceFrameFeatures::FaceFrameFeatures_FaceEngagement; + + static const int cColorWidth = 1920; + static const int cColorHeight = 1080; + + + void Update(); + HRESULT InitializeDefaultSensor(); + void ProcessFaces(); + HRESULT UpdateBodyData(IBody** ppBodies); + void ExtractFaceRotationInDegrees(const Vector4* pQuaternion, double* pPitch, double* pYaw, double* pRoll); + + // Current Kinect + IKinectSensor* m_pKinectSensor; + + // Coordinate mapper + ICoordinateMapper* m_pCoordinateMapper; + + // Color reader + IColorFrameReader* m_pColorFrameReader; + + // Body reader + IBodyFrameReader* m_pBodyFrameReader; + + // Face sources + IFaceFrameSource* m_pFaceFrameSources[BODY_COUNT]; + + // Face readers + IFaceFrameReader* m_pFaceFrameReaders[BODY_COUNT]; + + // + RGBQUAD* m_pColorRGBX; + + Vector4 faceRotation; + +}; |