diff options
Diffstat (limited to 'tracker-kinect-face')
-rw-r--r-- | tracker-kinect-face/CMakeLists.txt | 42 | ||||
-rw-r--r-- | tracker-kinect-face/images/kinect.png | bin | 0 -> 217 bytes | |||
-rw-r--r-- | tracker-kinect-face/kinect_face.qrc | 5 | ||||
-rw-r--r-- | tracker-kinect-face/kinect_face_settings.cpp | 47 | ||||
-rw-r--r-- | tracker-kinect-face/kinect_face_settings.h | 28 | ||||
-rw-r--r-- | tracker-kinect-face/kinect_face_settings.ui | 65 | ||||
-rw-r--r-- | tracker-kinect-face/kinect_face_tracker.cpp | 606 | ||||
-rw-r--r-- | tracker-kinect-face/kinect_face_tracker.h | 117 | ||||
-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 |
12 files changed, 998 insertions, 0 deletions
diff --git a/tracker-kinect-face/CMakeLists.txt b/tracker-kinect-face/CMakeLists.txt new file mode 100644 index 00000000..690f82e7 --- /dev/null +++ b/tracker-kinect-face/CMakeLists.txt @@ -0,0 +1,42 @@ +# Kinect SDK is Windows only +if (WIN32) + find_package(OpenCV QUIET) + if(OpenCV_FOUND) + # Setup cache variable to Kinect SDK path + if(DEFINED ENV{KINECTSDK20_DIR}) + set(SDK_KINECT20 $ENV{KINECTSDK20_DIR} CACHE PATH $ENV{KINECTSDK20_DIR}) + else() + set(SDK_KINECT20 $ENV{KINECTSDK20_DIR} CACHE PATH "") + endif() + + # If we have a valid SDK path, try build that tracker + if(EXISTS ${SDK_KINECT20}) + # Register our module + otr_module(tracker-kinect-face) + + # Add include path to Kinect SDK + target_include_directories(opentrack-tracker-kinect-face SYSTEM PUBLIC "${SDK_KINECT20}/inc") + + # Check processor architecture + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + # 32 bits + set (kinect-arch-dir "x86") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + # 64 bits + set (kinect-arch-dir "x64") + else() + message(FATAL_ERROR "Kinect: architecture not supported!") + endif() + + # Link against Kinect SDK libraries + target_link_libraries(opentrack-tracker-kinect-face "${SDK_KINECT20}/lib/${kinect-arch-dir}/Kinect20.lib" "${SDK_KINECT20}/lib/${kinect-arch-dir}/Kinect20.Face.lib") + # Link against OpenCV stuff, needed for video preview + target_link_libraries(opentrack-tracker-kinect-face opencv_imgproc opentrack-cv opencv_core) + + # Install Kinect Face DLL + install(FILES "${SDK_KINECT20}/Redist/Face/${kinect-arch-dir}/Kinect20.Face.dll" DESTINATION "./modules/" PERMISSIONS ${opentrack-perms-exec}) + # Install Kinect Face Database + install(DIRECTORY "${SDK_KINECT20}/Redist/Face/${kinect-arch-dir}/NuiDatabase" DESTINATION "./modules/") + endif(EXISTS ${SDK_KINECT20}) + endif(OpenCV_FOUND) +endif(WIN32)
\ No newline at end of file diff --git a/tracker-kinect-face/images/kinect.png b/tracker-kinect-face/images/kinect.png Binary files differnew file mode 100644 index 00000000..fd8f5f77 --- /dev/null +++ b/tracker-kinect-face/images/kinect.png diff --git a/tracker-kinect-face/kinect_face.qrc b/tracker-kinect-face/kinect_face.qrc new file mode 100644 index 00000000..8b27c81e --- /dev/null +++ b/tracker-kinect-face/kinect_face.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>images/kinect.png</file> + </qresource> +</RCC> diff --git a/tracker-kinect-face/kinect_face_settings.cpp b/tracker-kinect-face/kinect_face_settings.cpp new file mode 100644 index 00000000..238a3da6 --- /dev/null +++ b/tracker-kinect-face/kinect_face_settings.cpp @@ -0,0 +1,47 @@ +/* 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 "kinect_face_settings.h" +#include "kinect_face_tracker.h" +#include "api/plugin-api.hpp" +#include "compat/math-imports.hpp" + +#include <QPushButton> + +#include <cmath> +#include <QDebug> + + +KinectFaceSettings::KinectFaceSettings() +{ + 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 KinectFaceSettings::doOK() +{ + //s.b->save(); + close(); +} + +void KinectFaceSettings::doCancel() +{ + close(); +} + +OPENTRACK_DECLARE_TRACKER(KinectFaceTracker, KinectFaceSettings, KinectFaceMetadata) diff --git a/tracker-kinect-face/kinect_face_settings.h b/tracker-kinect-face/kinect_face_settings.h new file mode 100644 index 00000000..647aa754 --- /dev/null +++ b/tracker-kinect-face/kinect_face_settings.h @@ -0,0 +1,28 @@ +#pragma once +#include "ui_kinect_face_settings.h" +#include "compat/macros.hpp" +#include "api/plugin-api.hpp" + + +class KinectFaceSettings : public ITrackerDialog +{ + Q_OBJECT + + Ui::KinectFaceUi ui; +public: + KinectFaceSettings(); + void register_tracker(ITracker *) override {} + void unregister_tracker() override {} +private slots: + void doOK(); + void doCancel(); +}; + +class KinectFaceMetadata : public Metadata +{ + Q_OBJECT + + QString name() { return tr("Kinect Face 0.1"); } + QIcon icon() { return QIcon(":/images/kinect.png"); } +}; + diff --git a/tracker-kinect-face/kinect_face_settings.ui b/tracker-kinect-face/kinect_face_settings.ui new file mode 100644 index 00000000..a6192d9b --- /dev/null +++ b/tracker-kinect-face/kinect_face_settings.ui @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>KinectFaceUi</class> + <widget class="QWidget" name="KinectFaceUi"> + <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>Kinect Face Tracker</string> + </property> + <property name="windowIcon"> + <iconset> + <normaloff>:/images/kinect.png</normaloff>:/images/kinect.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>Start OpenTrack to check if Kinect Face Tracker is working.</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/kinect_face_tracker.cpp b/tracker-kinect-face/kinect_face_tracker.cpp new file mode 100644 index 00000000..104ecda8 --- /dev/null +++ b/tracker-kinect-face/kinect_face_tracker.cpp @@ -0,0 +1,606 @@ + + +#include "kinect_face_tracker.h" + +#include <QLayout> +#include <QPainter> + +#include "compat/check-visible.hpp" + +static const int KColorWidth = 1920; +static const int KColorHeight = 1080; + +/// +bool IsValidRect(const RectI& aRect) +{ + if (aRect.Bottom != 0) + { + return true; + } + + if (aRect.Left != 0) + { + return true; + } + + if (aRect.Right != 0) + { + return true; + } + + if (aRect.Top != 0) + { + return true; + } + + return false; +} + +/// +bool IsNullVetor(const Vector4& aVector) +{ + if (aVector.w != 0) + { + return false; + } + + if (aVector.x != 0) + { + return false; + } + + if (aVector.y != 0) + { + return false; + } + + if (aVector.z != 0) + { + return false; + } + + return true; +} + +/// +bool IsNullPoint(const CameraSpacePoint& aPoint) +{ + if (aPoint.X != 0) + { + return false; + } + + if (aPoint.Y != 0) + { + return false; + } + + if (aPoint.Z != 0) + { + return false; + } + + return true; +} + + +KinectFaceTracker::KinectFaceTracker() +{ + // create heap storage for color pixel data in RGBX format + iColorRGBX = new RGBQUAD[KColorWidth * KColorHeight]; +} + +KinectFaceTracker::~KinectFaceTracker() +{ + if (iColorRGBX) + { + delete[] iColorRGBX; + iColorRGBX = nullptr; + } + + // clean up Direct2D + //SafeRelease(m_pD2DFactory); + + // done with face sources and readers + SafeRelease(iFaceFrameSource); + SafeRelease(iFaceFrameReader); + + // done with body frame reader + SafeRelease(iBodyFrameReader); + + // done with color frame reader + SafeRelease(iColorFrameReader); + + // close the Kinect Sensor + if (iKinectSensor) + { + iKinectSensor->Close(); + } + + SafeRelease(iKinectSensor); +} + +module_status KinectFaceTracker::start_tracker(QFrame* aFrame) +{ + iTimer.start(); + + if (SUCCEEDED(InitializeDefaultSensor())) + { + // Setup our video preview widget + iVideoWidget = std::make_unique<cv_video_widget>(aFrame); + iLayout = std::make_unique<QHBoxLayout>(aFrame); + iLayout->setContentsMargins(0, 0, 0, 0); + iLayout->addWidget(iVideoWidget.get()); + aFrame->setLayout(iLayout.get()); + //video_widget->resize(video_frame->width(), video_frame->height()); + aFrame->show(); + + return status_ok(); + } + + return error("Kinect init failed!"); +} + + +bool KinectFaceTracker::center() +{ + // Mark our center + iFacePositionCenter = iFacePosition; + iFaceRotationCenter = iFaceRotation; + return true; +} + +// +// +// +void KinectFaceTracker::data(double *data) +{ + const double dt = iTimer.elapsed_seconds(); + + const double KMinDelayInSeconds = 1.0 / 30.0; // Pointless running faster than Kinect hardware itself + if (dt > KMinDelayInSeconds) + { + iTimer.start(); // Reset our timer + //OutputDebugStringA("Updating frame!\n"); + Update(); + ExtractFaceRotationInDegrees(&iFaceRotationQuaternion, &iFaceRotation.X, &iFaceRotation.Y, &iFaceRotation.Z); + //Check if data is valid + if (IsValidRect(iFaceBox)) + { + // We have valid tracking retain position and rotation + iLastFacePosition = iFacePosition; + iLastFaceRotation = iFaceRotation; + } + else + { + //TODO: after like 5s without tracking reset position to zero + //TODO: Instead of hardcoding that delay add it to our settings + } + } + else + { + //OutputDebugStringA("Skipping frame!\n"); + } + + // Feed our framework our last valid position and rotation + data[0] = (iLastFacePosition.X - iFacePositionCenter.X) * 100; // Convert to centimer to be in a range that suites OpenTrack. + data[1] = (iLastFacePosition.Y - iFacePositionCenter.Y) * 100; + data[2] = (iLastFacePosition.Z - iFacePositionCenter.Z) * 100; + + // Yaw, Picth, Roll + data[3] = -(iLastFaceRotation.X - iFaceRotationCenter.X); // Invert to be compatible with ED out-of-the-box + data[4] = (iLastFaceRotation.Y - iFaceRotationCenter.Y); + data[5] = (iLastFaceRotation.Z - iFaceRotationCenter.Z); +} + + +/// <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, float* pYaw, float* pPitch, float* 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; + + // Get and open Kinect sensor + hr = GetDefaultKinectSensor(&iKinectSensor); + if (SUCCEEDED(hr)) + { + hr = iKinectSensor->Open(); + } + + // Create color frame reader + if (SUCCEEDED(hr)) + { + UniqueInterface<IColorFrameSource> colorFrameSource; + hr = iKinectSensor->get_ColorFrameSource(colorFrameSource.PtrPtr()); + colorFrameSource.Reset(); + + if (SUCCEEDED(hr)) + { + hr = colorFrameSource->OpenReader(&iColorFrameReader); + } + } + + // Create body frame reader + if (SUCCEEDED(hr)) + { + UniqueInterface<IBodyFrameSource> bodyFrameSource; + hr = iKinectSensor->get_BodyFrameSource(bodyFrameSource.PtrPtr()); + bodyFrameSource.Reset(); + + if (SUCCEEDED(hr)) + { + hr = bodyFrameSource->OpenReader(&iBodyFrameReader); + } + } + + // Create HD face frame source + if (SUCCEEDED(hr)) + { + // create the face frame source by specifying the required face frame features + hr = CreateHighDefinitionFaceFrameSource(iKinectSensor, &iFaceFrameSource); + } + + // Create HD face frame reader + if (SUCCEEDED(hr)) + { + // open the corresponding reader + hr = iFaceFrameSource->OpenReader(&iFaceFrameReader); + } + + return hr; +} + + + +/// <summary> +/// Main processing function +/// </summary> +void KinectFaceTracker::Update() +{ + if (!iColorFrameReader || !iBodyFrameReader) + { + return; + } + + IColorFrame* pColorFrame = nullptr; + HRESULT hr = iColorFrameReader->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)) + { + //DrawStreams(nTime, pBuffer, nWidth, nHeight); + ProcessFaces(); + } + + if (check_is_visible()) + { + //OutputDebugStringA("Widget visible!\n"); + // If our widget is visible we feed it our frame + if (SUCCEEDED(hr)) + { + // Fetch color buffer + if (imageFormat == ColorImageFormat_Rgba) + { + hr = pColorFrame->AccessRawUnderlyingBuffer(&nBufferSize, reinterpret_cast<BYTE**>(&pBuffer)); + } + else if (iColorRGBX) + { + pBuffer = iColorRGBX; + nBufferSize = KColorWidth * KColorHeight * sizeof(RGBQUAD); + hr = pColorFrame->CopyConvertedFrameDataToArray(nBufferSize, reinterpret_cast<BYTE*>(pBuffer), ColorImageFormat_Rgba); + } + else + { + hr = E_FAIL; + } + + } + + if (SUCCEEDED(hr)) + { + // Setup our image + QImage image((const unsigned char*)pBuffer, KColorWidth, KColorHeight, sizeof(RGBQUAD)*KColorWidth, QImage::Format_RGBA8888); + if (IsValidRect(iFaceBox)) + { + // Draw our face bounding box + QPainter painter(&image); + painter.setBrush(Qt::NoBrush); + painter.setPen(QPen(Qt::red, 8)); + painter.drawRect(iFaceBox.Left, iFaceBox.Top, iFaceBox.Right - iFaceBox.Left, iFaceBox.Bottom - iFaceBox.Top); + bool bEnd = painter.end(); + } + + // Update our video preview + iVideoWidget->update_image(image); + } + + } + + + 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 (iBodyFrameReader != nullptr) + { + IBodyFrame* pBodyFrame = nullptr; + hr = iBodyFrameReader->AcquireLatestFrame(&pBodyFrame); + if (SUCCEEDED(hr)) + { + hr = pBodyFrame->GetAndRefreshBodyData(BODY_COUNT, ppBodies); + } + SafeRelease(pBodyFrame); + } + + return hr; +} + + +float VectorLengthSquared(CameraSpacePoint point) +{ + float lenghtSquared = pow(point.X, 2) + pow(point.Y, 2) + pow(point.Z, 2); + + //result = Math.Sqrt(result); + return lenghtSquared; +} + +// +// Finds the closest body from the sensor if any +// +IBody* KinectFaceTracker::FindClosestBody(IBody** aBodies) +{ + IBody* result = nullptr; + float closestBodyDistance = std::numeric_limits<float>::max(); + + for(int i=0;i<BODY_COUNT;i++) + { + BOOLEAN tracked; + aBodies[i]->get_IsTracked(&tracked); + + if (tracked) + { + Joint joints[JointType_Count]; + HRESULT hr = aBodies[i]->GetJoints(JointType_Count,joints); + if (FAILED(hr)) + { + continue; + } + + auto currentLocation = joints[JointType_SpineBase].Position; + auto currentDistance = VectorLengthSquared(currentLocation); + + if (result == nullptr || currentDistance < closestBodyDistance) + { + result = aBodies[i]; + closestBodyDistance = currentDistance; + } + } + } + + return result; +} + +// +// Search our list of body for the one matching our id +// +IBody* KinectFaceTracker::FindTrackedBodyById(IBody** aBodies, UINT64 aTrackingId) +{ + float closestBodyDistance = std::numeric_limits<float>::max(); + + for (int i = 0; i < BODY_COUNT; i++) + { + BOOLEAN tracked; + HRESULT hr = aBodies[i]->get_IsTracked(&tracked); + + if (tracked) + { + if (SUCCEEDED(hr) && tracked) + { + UINT64 trackingId = 0; + hr = aBodies[i]->get_TrackingId(&trackingId); + + if (SUCCEEDED(hr) && aTrackingId == trackingId) + { + return aBodies[i]; + } + } + } + } + + return nullptr; +} + + +/// <summary> +/// Processes new face frames +/// </summary> +void KinectFaceTracker::ProcessFaces() +{ + HRESULT hr=0; + IBody* bodies[BODY_COUNT] = { 0 }; // Each bodies will need to be released + bool bHaveBodyData = SUCCEEDED(UpdateBodyData(bodies)); + if (!bHaveBodyData) + { + return; + } + + // Try keep tracking the same body + IBody* body = FindTrackedBodyById(bodies, iTrackingId); + if (body == nullptr) + { + // The body we were tracking is gone, try tracking the closest body if any + body = FindClosestBody(bodies); + if (body != nullptr) + { + // Update our face source with our new body id + hr = body->get_TrackingId(&iTrackingId); + if (SUCCEEDED(hr)) + { + // Tell our face source to use the given body id + hr = iFaceFrameSource->put_TrackingId(iTrackingId); + //OutputDebugStringA("Tracking new body!\n"); + } + } + } + + // retrieve the latest face frame from this reader + IHighDefinitionFaceFrame* pFaceFrame = nullptr; + if (SUCCEEDED(hr)) + { + hr = iFaceFrameReader->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) + { + //OutputDebugStringA("Tracking face!\n"); + + //IFaceFrameResult* pFaceFrameResult = nullptr; + IFaceAlignment* pFaceAlignment = nullptr; + CreateFaceAlignment(&pFaceAlignment); // TODO: check return? + //D2D1_POINT_2F faceTextLayout; + + //hr = pFaceFrame->get_FaceFrameResult(&pFaceFrameResult); + + hr = pFaceFrame->GetAndRefreshFaceAlignmentResult(pFaceAlignment); + + // need to verify if pFaceFrameResult contains data before trying to access it + if (SUCCEEDED(hr) && pFaceAlignment != nullptr) + { + hr = pFaceAlignment->get_FaceBoundingBox(&iFaceBox); + //pFaceFrameResult->get_FaceBoundingBoxInColorSpace(); + + if (SUCCEEDED(hr)) + { + //hr = pFaceFrameResult->GetFacePointsInColorSpace(FacePointType::FacePointType_Count, facePoints); + hr = pFaceAlignment->get_HeadPivotPoint(&iFacePosition); + } + + if (SUCCEEDED(hr)) + { + //hr = pFaceFrameResult->get_FaceRotationQuaternion(&faceRotation); + hr = pFaceAlignment->get_FaceOrientation(&iFaceRotationQuaternion); + } + + if (SUCCEEDED(hr)) + { + //hr = pFaceFrameResult->GetFaceProperties(FaceProperty::FaceProperty_Count, faceProperties); + } + + if (SUCCEEDED(hr)) + { + //hr = GetFaceTextPositionInColorSpace(ppBodies[0], &faceTextLayout); + } + + if (SUCCEEDED(hr)) + { + // draw face frame results + //m_pDrawDataStreams->DrawFaceFrameResults(0, &faceBox, facePoints, &faceRotation, faceProperties, &faceTextLayout); + } + } + + SafeRelease(pFaceAlignment); + } + + SafeRelease(pFaceFrame); + } + + if (bHaveBodyData) + { + for (int i = 0; i < _countof(bodies); ++i) + { + SafeRelease(bodies[i]); + } + } +} + + diff --git a/tracker-kinect-face/kinect_face_tracker.h b/tracker-kinect-face/kinect_face_tracker.h new file mode 100644 index 00000000..6273cba1 --- /dev/null +++ b/tracker-kinect-face/kinect_face_tracker.h @@ -0,0 +1,117 @@ + + + +#include <cmath> + +#include "api/plugin-api.hpp" +#include "compat/timer.hpp" +#include "compat/macros.hpp" +#include "cv/video-widget.hpp" + +// Kinect Header files +#include <Kinect.h> +#include <Kinect.Face.h> + +#pragma once + +// @deprecated Use UniqueInterface instead. Remove it at some point. +template<class Interface> +inline void SafeRelease(Interface *& pInterfaceToRelease) +{ + if (pInterfaceToRelease != nullptr) + { + pInterfaceToRelease->Release(); + pInterfaceToRelease = nullptr; + } +} + +template<class Interface> +inline void ReleaseInterface(Interface* pInterfaceToRelease) +{ + if (pInterfaceToRelease != nullptr) + { + pInterfaceToRelease->Release(); + } +} + +// Safely use Microsoft interfaces. +template<typename T> +class UniqueInterface : public std::unique_ptr<T, decltype(&ReleaseInterface<T>)> ///**/ +{ +public: + UniqueInterface() : std::unique_ptr<T, decltype(&ReleaseInterface<T>)>(nullptr, ReleaseInterface<T>){} + // Access pointer, typically for creation + T** PtrPtr() { return &iPtr; }; + // Called this once the pointer was created + void Reset() { std::unique_ptr<T, decltype(&ReleaseInterface<T>)>::reset(iPtr); } + // If ever you want to release that interface before the object is deleted + void Free() { iPtr = nullptr; Reset(); } +private: + T* iPtr = nullptr; +}; + + +// +// +// +class KinectFaceTracker : public ITracker +{ +public: + KinectFaceTracker(); + ~KinectFaceTracker() override; + module_status start_tracker(QFrame* aFrame) override; + void data(double *data) override; + bool center() override; + +private: + + + // Kinect stuff + void Update(); + HRESULT InitializeDefaultSensor(); + void ProcessFaces(); + HRESULT UpdateBodyData(IBody** ppBodies); + void ExtractFaceRotationInDegrees(const Vector4* pQuaternion, float* pPitch, float* pYaw, float* pRoll); + static IBody* FindClosestBody(IBody** aBodies); + static IBody* FindTrackedBodyById(IBody** aBodies,UINT64 aTrackingId); + + // + Timer iTimer; + + // Current Kinect + IKinectSensor* iKinectSensor = nullptr; + + // Color reader + IColorFrameReader* iColorFrameReader = nullptr; + + // Body reader + IBodyFrameReader* iBodyFrameReader = nullptr; + + // Face sources + IHighDefinitionFaceFrameSource* iFaceFrameSource = nullptr; + + // Face readers + IHighDefinitionFaceFrameReader* iFaceFrameReader = nullptr; + + // + RGBQUAD* iColorRGBX = nullptr; + + RectI iFaceBox = { 0 }; + + // Face position + CameraSpacePoint iLastFacePosition = { 0 }; + CameraSpacePoint iFacePosition = { 0 }; + CameraSpacePoint iFacePositionCenter = { 0 }; + + Vector4 iFaceRotationQuaternion = { 0 }; + // As Yaw, Pitch, Roll + CameraSpacePoint iLastFaceRotation = { 0 }; + CameraSpacePoint iFaceRotation = { 0 }; + CameraSpacePoint iFaceRotationCenter = { 0 }; + // + std::unique_ptr<cv_video_widget> iVideoWidget; + std::unique_ptr<QLayout> iLayout; + + // Id of the body currently being tracked + UINT64 iTrackingId = 0; +}; diff --git a/tracker-kinect-face/lang/nl_NL.ts b/tracker-kinect-face/lang/nl_NL.ts new file mode 100644 index 00000000..a0a737ee --- /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>KinectFaceMetadata</name> + <message> + <source>Kinect Face 0.1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>KinectFaceUi</name> + <message> + <source>Kinect Face Tracker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start OpenTrack to check if Kinect Face Tracker is working.</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..72f91367 --- /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>KinectFaceMetadata</name> + <message> + <source>Kinect Face 0.1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>KinectFaceUi</name> + <message> + <source>Kinect Face Tracker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start OpenTrack to check if Kinect Face Tracker is working.</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..055ec4e1 --- /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>KinectFaceMetadata</name> + <message> + <source>Kinect Face 0.1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>KinectFaceUi</name> + <message> + <source>Kinect Face Tracker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start OpenTrack to check if Kinect Face Tracker is working.</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..055ec4e1 --- /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>KinectFaceMetadata</name> + <message> + <source>Kinect Face 0.1</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>KinectFaceUi</name> + <message> + <source>Kinect Face Tracker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start OpenTrack to check if Kinect Face Tracker is working.</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> |