增加多屏显示,视频播放
This commit is contained in:
+68
@@ -0,0 +1,68 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
using System.IO;
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class NeoKinectUnreal : ModuleRules
|
||||
{
|
||||
public NeoKinectUnreal(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PrivateIncludePaths.AddRange(new[]
|
||||
{
|
||||
"NeoKinectUnreal/Private"
|
||||
// ... add other private include paths required here ...
|
||||
});
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new[]
|
||||
{
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
// ... add other public dependencies that you statically link with here ...
|
||||
});
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new[]
|
||||
{
|
||||
"Engine",
|
||||
"RenderCore",
|
||||
"RHI",
|
||||
// ... add private dependencies that you statically link with here ...
|
||||
});
|
||||
|
||||
string thirdPartyPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "../ThirdParty/"));
|
||||
|
||||
string neoKinectPath = Path.Combine(thirdPartyPath, "NeoKinect");
|
||||
string kinectPath = Path.Combine(thirdPartyPath, "Kinect");
|
||||
|
||||
PublicSystemLibraryPaths.Add(Path.Combine(neoKinectPath, "Lib"));
|
||||
PublicIncludePaths.Add(Path.Combine(neoKinectPath, "Inc"));
|
||||
PublicSystemLibraryPaths.Add(Path.Combine(kinectPath, "Lib"));
|
||||
PublicIncludePaths.Add(Path.Combine(kinectPath, "Inc"));
|
||||
|
||||
const string FaceLibraryName = "Kinect20.Face";
|
||||
|
||||
// Add static libraries
|
||||
PublicSystemLibraries.AddRange(new[]
|
||||
{
|
||||
"NeoKinect.lib",
|
||||
"Kinect20.lib",
|
||||
FaceLibraryName + ".lib"
|
||||
});
|
||||
|
||||
// Add dynamic libraries
|
||||
const string KinectFaceDllName = FaceLibraryName + ".dll";
|
||||
PublicDelayLoadDLLs.AddRange(new[]
|
||||
{
|
||||
KinectFaceDllName
|
||||
});
|
||||
|
||||
// Define library name for code to be able to check for its presence
|
||||
PrivateDefinitions.Add("KINECT_FACE_DLL_NAME=\"" + KinectFaceDllName + "\"");
|
||||
|
||||
// Stage face library files when packaging
|
||||
const string ProjectDLLDir = "$(ProjectDir)/Binaries/Win64";
|
||||
RuntimeDependencies.Add(Path.Combine(ProjectDLLDir, KinectFaceDllName));
|
||||
RuntimeDependencies.Add(Path.Combine(ProjectDLLDir, "NuiDatabase/..."), StagedFileType.NonUFS);
|
||||
}
|
||||
}
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#include "KinectThread.h"
|
||||
|
||||
#include "HAL/RunnableThread.h"
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
ThreadFrameBuffer
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
using namespace NeoKinect;
|
||||
|
||||
FThreadFrameBuffer::~FThreadFrameBuffer()
|
||||
{
|
||||
DeallocateBuffers();
|
||||
}
|
||||
|
||||
void FThreadFrameBuffer::Configure(
|
||||
KinectFrameType Frame,
|
||||
KinectPixelFormat Format,
|
||||
KinectCoordinateSpace Space,
|
||||
bool IsRemapped)
|
||||
{
|
||||
this->FrameType = Frame;
|
||||
this->PixelFormat = Format;
|
||||
this->TargetSpace = Space;
|
||||
this->bRemapped = IsRemapped;
|
||||
}
|
||||
|
||||
bool FThreadFrameBuffer::AllocateBuffers(uint32 Size)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*FString::Printf(TEXT("Kinect_AllocateBuffers_%d"), FrameType));
|
||||
|
||||
if (IsAllocated())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Buffer = new uint8[Size];
|
||||
BackBuffer = new uint8[Size];
|
||||
return Buffer && BackBuffer;
|
||||
}
|
||||
|
||||
void FThreadFrameBuffer::DeallocateBuffers()
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*FString::Printf(TEXT("Kinect_DeallocateBuffers_%d"), FrameType));
|
||||
|
||||
bIsNew = false;
|
||||
|
||||
if (Buffer)
|
||||
{
|
||||
Lock();
|
||||
delete[] Buffer;
|
||||
Buffer = nullptr;
|
||||
Unlock();
|
||||
}
|
||||
|
||||
if (BackBuffer)
|
||||
{
|
||||
LockWrite();
|
||||
delete[] BackBuffer;
|
||||
BackBuffer = nullptr;
|
||||
UnlockWrite();
|
||||
}
|
||||
}
|
||||
|
||||
bool FThreadFrameBuffer::IsAllocated() const
|
||||
{
|
||||
return Buffer && BackBuffer;
|
||||
}
|
||||
|
||||
const uint8* FThreadFrameBuffer::GetReadBuffer(bool bConsume /*= true*/)
|
||||
{
|
||||
if (bConsume)
|
||||
{
|
||||
if (Buffer && bIsNew)
|
||||
{
|
||||
bIsNew = false;
|
||||
return Buffer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
uint8* FThreadFrameBuffer::GetWriteBuffer() const
|
||||
{
|
||||
return BackBuffer;
|
||||
}
|
||||
|
||||
void FThreadFrameBuffer::SetDirty()
|
||||
{
|
||||
SwapBuffers();
|
||||
bIsNew = true;
|
||||
}
|
||||
|
||||
void FThreadFrameBuffer::SwapBuffers()
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*FString::Printf(TEXT("Kinect_SwapBuffers_%d"), FrameType));
|
||||
|
||||
Lock();
|
||||
|
||||
uint8* Temp = Buffer;
|
||||
Buffer = BackBuffer;
|
||||
BackBuffer = Temp;
|
||||
|
||||
Unlock();
|
||||
}
|
||||
|
||||
bool FThreadFrameBuffer::TryLock()
|
||||
{
|
||||
return ReadMutex.TryLock();
|
||||
}
|
||||
|
||||
void FThreadFrameBuffer::Lock()
|
||||
{
|
||||
ReadMutex.Lock();
|
||||
}
|
||||
|
||||
void FThreadFrameBuffer::Unlock()
|
||||
{
|
||||
ReadMutex.Unlock();
|
||||
}
|
||||
|
||||
void FThreadFrameBuffer::LockWrite()
|
||||
{
|
||||
WriteMutex.Lock();
|
||||
}
|
||||
|
||||
void FThreadFrameBuffer::UnlockWrite()
|
||||
{
|
||||
WriteMutex.Unlock();
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
KinectThread
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
FKinectThread* FKinectThread::Runnable = nullptr;
|
||||
FCriticalSection FKinectThread::BodiesFacesCritSec;
|
||||
|
||||
FThreadFrameBuffer FKinectThread::FrameBuffers[static_cast<uint64>(EKinectFrame::Count)];
|
||||
bool FKinectThread::bUseBodyTracking = false;
|
||||
bool FKinectThread::bUseFaceTracking = false;
|
||||
|
||||
FKinectThread::FKinectThread(KinectSensor *pSensor) :
|
||||
pKinect(pSensor),
|
||||
bBodiesDirty(false),
|
||||
bFacesDirty(false)
|
||||
{
|
||||
Thread = FRunnableThread::Create(this, TEXT("FKinectThread")); // Windows give 8MB memory by default
|
||||
if (!Thread)
|
||||
UE_LOG(KinectThreadLog, Error, TEXT("Failed to create Kinect thread!"));
|
||||
}
|
||||
|
||||
FKinectThread::~FKinectThread()
|
||||
{
|
||||
if (Thread) delete Thread;
|
||||
Thread = nullptr;
|
||||
}
|
||||
|
||||
FKinectThread* FKinectThread::InitKinectPolling(KinectSensor *pSensor)
|
||||
{
|
||||
// Create new instance of thread if it does not exist and the platform
|
||||
// supports multi threading.
|
||||
if (!Runnable && FPlatformProcess::SupportsMultithreading())
|
||||
{
|
||||
Runnable = new FKinectThread(pSensor);
|
||||
}
|
||||
return Runnable;
|
||||
}
|
||||
|
||||
void FKinectThread::EnsureCompletion()
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(Kinect_EnsureThreadCompletion)
|
||||
|
||||
Stop();
|
||||
if (Thread)
|
||||
Thread->WaitForCompletion();
|
||||
}
|
||||
|
||||
void FKinectThread::Shutdown()
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(Kinect_ShutdownThread)
|
||||
|
||||
if (Runnable)
|
||||
{
|
||||
Runnable->EnsureCompletion();
|
||||
delete Runnable;
|
||||
Runnable = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const KinectBody* FKinectThread::GetBodiesData()
|
||||
{
|
||||
if (bBodiesDirty)
|
||||
{
|
||||
bBodiesDirty = false;
|
||||
return Bodies;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const KinectFace* FKinectThread::GetFacesData()
|
||||
{
|
||||
if (bFacesDirty)
|
||||
{
|
||||
bFacesDirty = false;
|
||||
return Faces;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FKinectThread::Init()
|
||||
{
|
||||
UE_LOG(KinectThreadLog, Log, TEXT("Kinect thread initialized."));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 FKinectThread::Run()
|
||||
{
|
||||
constexpr float UpdateInterval = 1.f / cDesiredFPS;
|
||||
|
||||
UE_LOG(KinectThreadLog, Log, TEXT("Kinect thread running."));
|
||||
|
||||
// while not told to stop this thread
|
||||
while (StopTaskCounter.GetValue() == 0)
|
||||
{
|
||||
// try locking any frames necessary
|
||||
constexpr int FrameTypesCount = static_cast<int>(KinectFrameType::Count);
|
||||
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(KinectThread_Run)
|
||||
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(Kinect_LockFrames)
|
||||
for (int i = 0; i < FrameTypesCount; ++i)
|
||||
{
|
||||
const KinectFrameType FrameType = static_cast<KinectFrameType>(i);
|
||||
if (pKinect->GetIsUsingFrame(FrameType))
|
||||
{
|
||||
pKinect->LockLatestFrame(FrameType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bUseBodyTracking)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(Kinect_GetBodyData)
|
||||
// process bodies before face tracking - face tracking depends on bodies data
|
||||
BodiesFacesCritSec.Lock();
|
||||
if (pKinect->GetLatestFrameData(Bodies))
|
||||
{
|
||||
bBodiesDirty = true;
|
||||
}
|
||||
BodiesFacesCritSec.Unlock();
|
||||
}
|
||||
|
||||
if (bUseFaceTracking)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(Kinect_GetFaceData)
|
||||
// process face tracking
|
||||
BodiesFacesCritSec.Lock();
|
||||
if (pKinect->GetLatestFrameData(Faces))
|
||||
{
|
||||
bFacesDirty = true;
|
||||
}
|
||||
BodiesFacesCritSec.Unlock();
|
||||
}
|
||||
|
||||
// update any necessary buffers
|
||||
for (FThreadFrameBuffer& FrameBuffer : FrameBuffers)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*FString::Printf(TEXT("Kinect_UpdateBuffer_%d"), FrameBuffer.FrameType));
|
||||
if (FrameBuffer.IsAllocated() && pKinect->GetIsFrameLocked(FrameBuffer.FrameType))
|
||||
{
|
||||
FrameBuffer.LockWrite();
|
||||
// If this is a remapped type, use the correct function.
|
||||
// If the update works, marks buffer as new
|
||||
if (FrameBuffer.bRemapped)
|
||||
{
|
||||
if (pKinect->GetRemappedFrameData(
|
||||
FrameBuffer.FrameType, FrameBuffer.TargetSpace,
|
||||
FrameBuffer.GetWriteBuffer(), FrameBuffer.PixelFormat))
|
||||
{
|
||||
FrameBuffer.SetDirty();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8* Buffer = FrameBuffer.GetWriteBuffer();
|
||||
if (pKinect->GetLatestFrameData(
|
||||
FrameBuffer.FrameType, Buffer,
|
||||
FrameBuffer.PixelFormat))
|
||||
{
|
||||
FrameBuffer.SetDirty();
|
||||
}
|
||||
}
|
||||
FrameBuffer.UnlockWrite();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(Kinect_UnlockFrames)
|
||||
// unlock frames
|
||||
for (int i = 0; i < FrameTypesCount; ++i)
|
||||
{
|
||||
pKinect->UnlockLatestFrame(static_cast<KinectFrameType>(i));
|
||||
}
|
||||
}
|
||||
|
||||
// give time for Kinect to update its frames.
|
||||
FPlatformProcess::Sleep(UpdateInterval);
|
||||
}
|
||||
|
||||
// ended successfully!
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FKinectThread::Stop()
|
||||
{
|
||||
StopTaskCounter.Increment();
|
||||
}
|
||||
|
||||
void FKinectThread::Exit()
|
||||
{
|
||||
UE_LOG(KinectThreadLog, Log, TEXT("Kinect thread ended."));
|
||||
}
|
||||
+547
@@ -0,0 +1,547 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#include "NeoKinectBody.h"
|
||||
|
||||
#include "Helpers/GuardedNeoKinect.h"
|
||||
|
||||
#include "NeoKinectManager.h"
|
||||
|
||||
UNeoKinectBody::UNeoKinectBody()
|
||||
: BodyIndex(0),
|
||||
TrackingId(0),
|
||||
bIsTracked(false),
|
||||
bIsRestricted(false),
|
||||
HandLeftState(EKinectHandState::NotTracked),
|
||||
HandLeftTrackingState(EKinectTrackingState::NotTracked),
|
||||
HandRightState(EKinectHandState::NotTracked),
|
||||
HandRightTrackingState(EKinectTrackingState::NotTracked),
|
||||
LeanTrackingState(EKinectTrackingState::NotTracked),
|
||||
Lean(FVector2D(0.f, 0.f))
|
||||
{
|
||||
using namespace NeoKinect;
|
||||
|
||||
Joints.SetNum(KinectJointCount);
|
||||
|
||||
for (int32 JointIdx = 0; JointIdx < KinectJointCount; ++JointIdx)
|
||||
{
|
||||
Joints[JointIdx].Type = static_cast<EKinectJointType>(JointIdx);
|
||||
}
|
||||
}
|
||||
|
||||
UNeoKinectBody::~UNeoKinectBody()
|
||||
{
|
||||
Joints.Empty();
|
||||
}
|
||||
|
||||
void UNeoKinectBody::GetHandStateAsExec(EKinectBodySide Hand, EKinectHandState& States)
|
||||
{
|
||||
if (Hand == EKinectBodySide::Left)
|
||||
{
|
||||
States = HandLeftState;
|
||||
}
|
||||
else
|
||||
{
|
||||
States = HandRightState;
|
||||
}
|
||||
}
|
||||
|
||||
EKinectHandState UNeoKinectBody::GetHandState(EKinectBodySide Hand) const
|
||||
{
|
||||
if (Hand == EKinectBodySide::Left)
|
||||
return HandLeftState;
|
||||
else
|
||||
return HandRightState;
|
||||
}
|
||||
|
||||
void UNeoKinectBody::GetHandConfidenceAsExec(EKinectBodySide Hand, EKinectTrackingState& States)
|
||||
{
|
||||
if (Hand == EKinectBodySide::Left)
|
||||
{
|
||||
States = HandLeftTrackingState;
|
||||
}
|
||||
else
|
||||
{
|
||||
States = HandRightTrackingState;
|
||||
}
|
||||
}
|
||||
|
||||
EKinectTrackingState UNeoKinectBody::GetHandConfidence(EKinectBodySide Hand) const
|
||||
{
|
||||
if (Hand == EKinectBodySide::Left)
|
||||
return HandLeftTrackingState;
|
||||
else
|
||||
return HandRightTrackingState;
|
||||
}
|
||||
|
||||
void UNeoKinectBody::GetLeanConfidenceAsExec(EKinectTrackingState& States)
|
||||
{
|
||||
States = LeanTrackingState;
|
||||
}
|
||||
|
||||
TArray<FKinectJoint> UNeoKinectBody::GetJoints()
|
||||
{
|
||||
return Joints;
|
||||
}
|
||||
|
||||
FVector UNeoKinectBody::GetJointLocation(EKinectJointType Joint)
|
||||
{
|
||||
return Joints[static_cast<int32>(Joint)].Location;
|
||||
}
|
||||
|
||||
FRotator UNeoKinectBody::GetJointOrientation(EKinectJointType Joint)
|
||||
{
|
||||
return Joints[static_cast<int32>(Joint)].Orientation;
|
||||
}
|
||||
|
||||
FVector UNeoKinectBody::GetJointLocationColor(EKinectJointType Joint)
|
||||
{
|
||||
return Joints[static_cast<int32>(Joint)].ColorLocation;
|
||||
}
|
||||
|
||||
FRotator UNeoKinectBody::GetJointOrientationColor(EKinectJointType Joint)
|
||||
{
|
||||
return Joints[static_cast<int32>(Joint)].ColorOrientation;
|
||||
}
|
||||
|
||||
void UNeoKinectBody::GetJointConfidenceAsExec(EKinectJointType Joint, EKinectTrackingState& States)
|
||||
{
|
||||
States = Joints[static_cast<int32>(Joint)].Confidence;
|
||||
}
|
||||
|
||||
EKinectTrackingState UNeoKinectBody::GetJointConfidence(EKinectJointType Joint)
|
||||
{
|
||||
return Joints[static_cast<int32>(Joint)].Confidence;
|
||||
}
|
||||
|
||||
float UNeoKinectBody::GetJointsDistance(EKinectJointType JointA, EKinectJointType JointB)
|
||||
{
|
||||
return FVector::Dist(Joints[static_cast<int32>(JointB)].Location, Joints[static_cast<int32>(JointA)].Location);
|
||||
}
|
||||
|
||||
float UNeoKinectBody::GetBoneLength(EKinectJointType Joint)
|
||||
{
|
||||
const FVector p1 = Joints[static_cast<int32>(Joint)].Location;
|
||||
switch (Joint)
|
||||
{
|
||||
case EKinectJointType::SpineBase:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::SpineMid)].Location);
|
||||
case EKinectJointType::SpineMid:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::SpineBase)].Location);
|
||||
case EKinectJointType::Neck:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::SpineShoulder)].Location);
|
||||
case EKinectJointType::Head:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::Neck)].Location);
|
||||
case EKinectJointType::ShoulderLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::SpineShoulder)].Location);
|
||||
case EKinectJointType::ElbowLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::ShoulderLeft)].Location);
|
||||
case EKinectJointType::WristLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::ElbowLeft)].Location);
|
||||
case EKinectJointType::HandLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::WristLeft)].Location);
|
||||
case EKinectJointType::ShoulderRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::SpineShoulder)].Location);
|
||||
case EKinectJointType::ElbowRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::ShoulderRight)].Location);
|
||||
case EKinectJointType::WristRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::ElbowRight)].Location);
|
||||
case EKinectJointType::HandRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::WristRight)].Location);
|
||||
case EKinectJointType::HipLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::SpineBase)].Location);
|
||||
case EKinectJointType::KneeLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::HipLeft)].Location);
|
||||
case EKinectJointType::AnkleLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::KneeLeft)].Location);
|
||||
case EKinectJointType::FootLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::AnkleLeft)].Location);
|
||||
case EKinectJointType::HipRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::SpineBase)].Location);
|
||||
case EKinectJointType::KneeRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::HipRight)].Location);
|
||||
case EKinectJointType::AnkleRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::KneeRight)].Location);
|
||||
case EKinectJointType::FootRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::AnkleRight)].Location);
|
||||
case EKinectJointType::SpineShoulder:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::SpineMid)].Location);
|
||||
case EKinectJointType::HandTipLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::WristLeft)].Location);
|
||||
case EKinectJointType::ThumbLeft:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::HandLeft)].Location);
|
||||
case EKinectJointType::HandTipRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::WristRight)].Location);
|
||||
case EKinectJointType::ThumbRight:
|
||||
return FVector::Dist(p1, Joints[static_cast<int32>(EKinectJointType::HandRight)].Location);
|
||||
default:
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
float UNeoKinectBody::JointDotVector(EKinectJointType Joint, FVector Vector)
|
||||
{
|
||||
Vector.Normalize();
|
||||
return FVector::DotProduct(
|
||||
Vector,
|
||||
FRotationMatrix(Joints[static_cast<int32>(Joint)].Orientation).GetScaledAxis(EAxis::Z));
|
||||
}
|
||||
|
||||
void UNeoKinectBody::UpdateFromKinectBody(const NeoKinect::KinectBody& kBody, const NeoKinect::KinectSensor& Sensor)
|
||||
{
|
||||
using namespace NeoKinect;
|
||||
|
||||
// For throwing BeginTrack/Lost events after update
|
||||
bool bWasTracked = bIsTracked;
|
||||
|
||||
ClippedEdges.Left = kBody.clippedEdges.left;
|
||||
ClippedEdges.Right = kBody.clippedEdges.right;
|
||||
ClippedEdges.Top = kBody.clippedEdges.top;
|
||||
ClippedEdges.Bottom = kBody.clippedEdges.bottom;
|
||||
|
||||
bIsTracked = kBody.isTracked;
|
||||
bIsRestricted = kBody.isRestricted;
|
||||
TrackingId = kBody.trackingId;
|
||||
|
||||
HandLeftState = static_cast<EKinectHandState>(kBody.handLeftState);
|
||||
HandLeftTrackingState = static_cast<EKinectTrackingState>(kBody.handLeftTrackingState);
|
||||
|
||||
HandRightState = static_cast<EKinectHandState>(kBody.handRightState);
|
||||
HandRightTrackingState = static_cast<EKinectTrackingState>(kBody.handRightTrackingState);
|
||||
|
||||
LeanTrackingState = static_cast<EKinectTrackingState>(kBody.leanTrackingState);
|
||||
Lean.Set(kBody.lean.x, kBody.lean.y);
|
||||
|
||||
// update joints only if being tracked
|
||||
if (bIsTracked)
|
||||
{
|
||||
// camera space joints transforms
|
||||
for (int32 j = 0; j < KinectJointCount; ++j)
|
||||
{
|
||||
FKinectJoint& uJoint = Joints[j];
|
||||
KinectJoint joint = kBody.joints[j];
|
||||
|
||||
uJoint.Confidence = static_cast<EKinectTrackingState>(joint.trackingState);
|
||||
uJoint.Location.Set(
|
||||
joint.position.Z * 100.f,
|
||||
-joint.position.X * 100.f,
|
||||
joint.position.Y * 100.f);
|
||||
|
||||
// Quaternion conversion from Kinect camera's coord system to Unreal's
|
||||
FQuat Quat = FQuat(
|
||||
-joint.orientation.z,
|
||||
joint.orientation.x,
|
||||
-joint.orientation.y,
|
||||
joint.orientation.w
|
||||
);
|
||||
// In order to match the joints orientations to Unreal Mannequin, we
|
||||
// still have some problems:
|
||||
// - Kinect's bones extend along its UP axis, which is Z in Unreal.
|
||||
// But Unreal's Mannequin skeleton's bones extend along X (as it is
|
||||
// in Maya). So we re-create the orientation swapping the axes.
|
||||
//
|
||||
// - Some bones extend towards X, some against it. That's good for doing
|
||||
// mirrored rotations in the animation software, so we'll keep it here
|
||||
// by flipping some axes.
|
||||
//
|
||||
// - The pelvis and spine bones front axis is the same as the limbs side axis.
|
||||
// In the Mannequin these match up, so we'll have to invert some here.
|
||||
#define JNT_ID(Name) static_cast<uint8>(EKinectJointType::Name)
|
||||
|
||||
uint8 JointIndex = static_cast<uint8>(uJoint.Type);
|
||||
|
||||
if (JointIndex <= JNT_ID(Head) || JointIndex == JNT_ID(SpineShoulder))
|
||||
{ // for spine bones
|
||||
uJoint.Orientation = FRotationMatrix::MakeFromXZ(
|
||||
Quat.GetAxisZ(),
|
||||
Quat.GetAxisY()).Rotator();
|
||||
}
|
||||
else if (JointIndex <= JNT_ID(WristLeft)
|
||||
|| JointIndex >= JNT_ID(HipRight) && JointIndex <= JNT_ID(FootRight))
|
||||
{ // for left arm and right leg
|
||||
uJoint.Orientation = FRotationMatrix::MakeFromXZ(
|
||||
Quat.GetAxisZ(),
|
||||
Quat.GetAxisX()).Rotator();
|
||||
}
|
||||
else if ( (JointIndex >= JNT_ID(ShoulderRight) && JointIndex <= JNT_ID(WristRight))
|
||||
|| (JointIndex >= JNT_ID(HipLeft) && JointIndex <= JNT_ID(FootLeft))
|
||||
|| JointIndex == JNT_ID(HandTipRight) || JointIndex == JNT_ID(ThumbRight)
|
||||
)
|
||||
{ // for right arm and left leg
|
||||
uJoint.Orientation = FRotationMatrix::MakeFromXZ(
|
||||
-Quat.GetAxisZ(),
|
||||
-Quat.GetAxisX()).Rotator();
|
||||
}
|
||||
else if (JointIndex == JNT_ID(HandTipLeft) || JointIndex == JNT_ID(ThumbLeft))
|
||||
{ // Left hand
|
||||
uJoint.Orientation = FRotationMatrix::MakeFromXZ(
|
||||
Quat.GetAxisZ(),
|
||||
Quat.GetAxisX()).Rotator();
|
||||
}
|
||||
else if (JointIndex == JNT_ID(HandLeft))
|
||||
{ // left hand
|
||||
uJoint.Orientation = FRotationMatrix::MakeFromXZ(
|
||||
Quat.GetAxisZ(),
|
||||
-Quat.GetAxisX()).Rotator();
|
||||
}
|
||||
else if (JointIndex == JNT_ID(HandRight))
|
||||
{ // right hand
|
||||
uJoint.Orientation = FRotationMatrix::MakeFromXZ(
|
||||
-Quat.GetAxisZ(),
|
||||
Quat.GetAxisX()).Rotator();
|
||||
}
|
||||
#undef JNT_ID
|
||||
|
||||
} // camera space joints transforms
|
||||
|
||||
if (UNeoKinectManager::IsUsingJointsColorSpaceTransforms())
|
||||
{
|
||||
// color space with depth joints transforms
|
||||
for (int32 j = 0; j < KinectJointCount; ++j)
|
||||
{
|
||||
FKinectJoint& uJoint = Joints[j];
|
||||
KinectJoint joint = kBody.joints[j];
|
||||
|
||||
// Convert camera space location to color space with depth
|
||||
Vector3 ColorDepthLocation = UNeoKinectManager::CameraLocationToColorWithDepth(Vector3(joint.position));
|
||||
if (ColorDepthLocation.IsZero())
|
||||
{
|
||||
// fallback for when the joint can not be seen in color camera
|
||||
if (uJoint.Type == EKinectJointType::SpineBase) // oh shit! Our reference is gone!
|
||||
{
|
||||
uJoint.ColorLocation = uJoint.Location;
|
||||
continue;
|
||||
}
|
||||
|
||||
FKinectJoint &SpineBase = Joints[static_cast<int32>(EKinectJointType::SpineBase)];
|
||||
uJoint.ColorLocation = SpineBase.ColorLocation + uJoint.Location - SpineBase.Location;
|
||||
continue;
|
||||
}
|
||||
|
||||
uJoint.ColorLocation.Set(
|
||||
ColorDepthLocation.z * 100.0f,
|
||||
-ColorDepthLocation.x * 100.0f,
|
||||
ColorDepthLocation.y * 100.0f);
|
||||
} // color space with depth joints transforms
|
||||
|
||||
// orientations in color space with depth
|
||||
#define JOINT(Name) Joints[static_cast<int32>(EKinectJointType::Name)]
|
||||
#define J_DIR(FromJoint, ToJoint) JOINT(ToJoint).ColorLocation - JOINT(FromJoint).ColorLocation
|
||||
#define J_ROT(JointName, Twist) JOINT(JointName).ColorOrientation = FRotationMatrix::MakeFromX##Twist(XDir, Twist##Dir).Rotator()
|
||||
|
||||
FVector XDir, YDir, ZDir, Dir1, Dir2;
|
||||
FQuat Rot1, Rot2, RLerp;
|
||||
float JointsDot;
|
||||
|
||||
// Spine Base
|
||||
XDir = J_DIR(SpineBase, SpineMid);
|
||||
ZDir = J_DIR(HipLeft, HipRight);
|
||||
J_ROT(SpineBase, Z);
|
||||
|
||||
// Spine Middle
|
||||
// same XDir
|
||||
ZDir = (ZDir + J_DIR(ShoulderLeft, ShoulderRight)) / 2.0f; // intermediary between hip and shoulders twist
|
||||
J_ROT(SpineMid, Z);
|
||||
|
||||
// Spine Shoulder
|
||||
XDir = J_DIR(SpineMid, SpineShoulder);
|
||||
ZDir = J_DIR(ShoulderLeft, ShoulderRight);
|
||||
J_ROT(SpineShoulder, Z);
|
||||
|
||||
// Neck
|
||||
XDir = J_DIR(SpineShoulder, Neck);
|
||||
// same ZDir
|
||||
J_ROT(Neck, Z);
|
||||
|
||||
// Head
|
||||
XDir = J_DIR(Neck, Head);
|
||||
// same ZDir
|
||||
J_ROT(Head, Z);
|
||||
|
||||
// shoulder left
|
||||
XDir = J_DIR(SpineShoulder, ShoulderLeft);
|
||||
ZDir = J_DIR(SpineMid, SpineShoulder);
|
||||
J_ROT(ShoulderLeft, Z);
|
||||
|
||||
// elbow left
|
||||
XDir = J_DIR(ShoulderLeft, ElbowLeft);
|
||||
// interpolate between a rot for fully stretched arm and one for bent
|
||||
Dir1 = FVector::CrossProduct(J_DIR(ElbowLeft, WristLeft), J_DIR(ElbowLeft, ShoulderLeft)); // bent
|
||||
Rot1 = FRotationMatrix::MakeFromXZ(XDir, Dir1).ToQuat(); // bent
|
||||
Dir2 = FRotationMatrix(JOINT(ShoulderLeft).ColorOrientation).GetScaledAxis(EAxis::Y); // stretched
|
||||
Rot2 = FRotationMatrix::MakeFromXY(XDir, Dir2).ToQuat(); // stretched
|
||||
Dir1 = J_DIR(ShoulderLeft, ElbowLeft); Dir2 = J_DIR(ElbowLeft, WristLeft);
|
||||
Dir1.Normalize(); Dir2.Normalize();
|
||||
JointsDot = FVector::DotProduct(Dir1, Dir2);
|
||||
RLerp = FQuat::Slerp(Rot2, Rot1,
|
||||
FMath::Clamp(FMath::Acos(JointsDot) / 0.349f /*~20°*/, 0.f, 1.f)
|
||||
);
|
||||
RLerp.Normalize();
|
||||
JOINT(ElbowLeft).ColorOrientation = RLerp.Rotator();
|
||||
|
||||
// wrist left
|
||||
XDir = J_DIR(ElbowLeft, WristLeft);
|
||||
YDir = J_DIR(HandLeft, ThumbLeft);
|
||||
J_ROT(WristLeft, Y);
|
||||
|
||||
// hand left
|
||||
XDir = J_DIR(WristLeft, HandTipLeft);
|
||||
ZDir = J_DIR(ThumbLeft, HandLeft);
|
||||
J_ROT(HandLeft, Z);
|
||||
|
||||
// hand tip Left
|
||||
JOINT(HandTipLeft).ColorOrientation = JOINT(HandLeft).ColorOrientation;
|
||||
|
||||
// thumb left
|
||||
XDir = J_DIR(HandLeft, ThumbLeft);
|
||||
YDir = FRotationMatrix(JOINT(HandLeft).ColorOrientation).GetScaledAxis(EAxis::Y);
|
||||
J_ROT(ThumbLeft, Y);
|
||||
|
||||
// shoulder right
|
||||
XDir = J_DIR(ShoulderRight, SpineShoulder);
|
||||
ZDir = J_DIR(SpineShoulder, SpineMid);
|
||||
J_ROT(ShoulderRight, Z);
|
||||
|
||||
// elbow right
|
||||
XDir = J_DIR(ElbowRight, ShoulderRight);
|
||||
// interpolate between a rot for fully stretched arm and one for bent
|
||||
Dir1 = FVector::CrossProduct(J_DIR(ElbowRight, WristRight), J_DIR(ElbowRight, ShoulderRight)); // bent
|
||||
Rot1 = FRotationMatrix::MakeFromXZ(XDir, Dir1).ToQuat(); // bent
|
||||
Dir2 = FRotationMatrix(JOINT(ShoulderRight).ColorOrientation).GetScaledAxis(EAxis::Y); // stretched
|
||||
Rot2 = FRotationMatrix::MakeFromXY(XDir, Dir2).ToQuat(); // stretched
|
||||
Dir1 = J_DIR(ShoulderRight, ElbowRight); Dir2 = J_DIR(ElbowRight, WristRight);
|
||||
Dir1.Normalize(); Dir2.Normalize();
|
||||
JointsDot = FVector::DotProduct(Dir1, Dir2);
|
||||
RLerp = FQuat::Slerp(Rot2, Rot1,
|
||||
FMath::Clamp(FMath::Acos(JointsDot) / 0.349f /*~20°*/, 0.f, 1.f)
|
||||
);
|
||||
RLerp.Normalize();
|
||||
JOINT(ElbowRight).ColorOrientation = RLerp.Rotator();
|
||||
|
||||
// wrist right
|
||||
XDir = J_DIR(WristRight, ElbowRight);
|
||||
YDir = J_DIR(ThumbRight, HandRight);
|
||||
J_ROT(WristRight, Y);
|
||||
|
||||
// hand right
|
||||
XDir = J_DIR(HandTipRight, WristRight);
|
||||
ZDir = -YDir;
|
||||
J_ROT(HandRight, Z);
|
||||
|
||||
// hand tip right
|
||||
JOINT(HandTipRight).ColorOrientation = JOINT(HandRight).ColorOrientation;
|
||||
|
||||
// thumb right
|
||||
XDir = J_DIR(ThumbRight, HandRight);
|
||||
YDir = FRotationMatrix(JOINT(HandRight).ColorOrientation).GetScaledAxis(EAxis::Y);
|
||||
J_ROT(ThumbRight, Y);
|
||||
|
||||
// Hip Left
|
||||
XDir = J_DIR(HipLeft, SpineBase);
|
||||
ZDir = J_DIR(SpineMid, SpineBase);
|
||||
J_ROT(HipLeft, Z);
|
||||
|
||||
// Knee left
|
||||
XDir = J_DIR(KneeLeft, HipLeft);
|
||||
Dir1 = FVector::CrossProduct(J_DIR(KneeLeft, AnkleLeft), J_DIR(KneeLeft, HipLeft)); // bent
|
||||
Rot1 = FRotationMatrix::MakeFromXZ(XDir, Dir1).ToQuat(); // bent
|
||||
Dir2 = FRotationMatrix(JOINT(SpineMid).ColorOrientation).GetScaledAxis(EAxis::Y); // stretched
|
||||
Rot2 = FRotationMatrix::MakeFromXY(XDir, Dir2).ToQuat(); // stretched
|
||||
Dir1 = J_DIR(HipLeft, KneeLeft); Dir2 = J_DIR(KneeLeft, AnkleLeft);
|
||||
Dir1.Normalize(); Dir2.Normalize();
|
||||
JointsDot = FVector::DotProduct(Dir1, Dir2);
|
||||
RLerp = FQuat::Slerp(Rot2, Rot1, FMath::Clamp((FMath::Acos(JointsDot) - 0.2618f) / 0.5236f, 0.f, 1.f));
|
||||
RLerp.Normalize();
|
||||
JOINT(KneeLeft).ColorOrientation = RLerp.Rotator();
|
||||
|
||||
// ankle left
|
||||
XDir = J_DIR(AnkleLeft, KneeLeft);
|
||||
ZDir = FRotationMatrix(JOINT(KneeLeft).ColorOrientation).GetScaledAxis(EAxis::Z);
|
||||
J_ROT(AnkleLeft, Z);
|
||||
|
||||
// foot left
|
||||
// same X and Z dirs
|
||||
J_ROT(FootLeft, Z);
|
||||
|
||||
// hip right
|
||||
XDir = J_DIR(SpineBase, HipRight);
|
||||
ZDir = J_DIR(SpineBase, SpineMid);
|
||||
J_ROT(HipRight, Z);
|
||||
|
||||
// Knee Right
|
||||
XDir = J_DIR(HipRight, KneeRight);
|
||||
Dir1 = FVector::CrossProduct(J_DIR(KneeRight, AnkleRight), J_DIR(KneeRight, HipRight)); // bent
|
||||
Rot1 = FRotationMatrix::MakeFromXZ(XDir, Dir1).ToQuat(); // bent
|
||||
Dir2 = -FRotationMatrix(JOINT(SpineMid).ColorOrientation).GetScaledAxis(EAxis::Y); // stretched
|
||||
Rot2 = FRotationMatrix::MakeFromXY(XDir, Dir2).ToQuat(); // stretched
|
||||
Dir1 = J_DIR(HipRight, KneeRight); Dir2 = J_DIR(KneeRight, AnkleRight);
|
||||
Dir1.Normalize(); Dir2.Normalize();
|
||||
JointsDot = FVector::DotProduct(Dir1, Dir2);
|
||||
RLerp = FQuat::Slerp(Rot2, Rot1, FMath::Clamp((FMath::Acos(JointsDot) - 0.2618f) / 0.5236f, 0.f, 1.f));
|
||||
RLerp.Normalize();
|
||||
JOINT(KneeRight).ColorOrientation = RLerp.Rotator();
|
||||
|
||||
// Ankle right
|
||||
XDir = J_DIR(KneeRight, AnkleRight);
|
||||
ZDir = FRotationMatrix(JOINT(KneeRight).ColorOrientation).GetScaledAxis(EAxis::Z);
|
||||
J_ROT(AnkleRight, Z);
|
||||
|
||||
// foot right
|
||||
// same X and Z dirs
|
||||
J_ROT(FootRight, Z);
|
||||
#undef JOINT
|
||||
#undef J_DIR
|
||||
#undef J_ROT
|
||||
} // if (bUsingJointsColorSpaceTransforms)
|
||||
} // if (bIsTracked)
|
||||
|
||||
if (bWasTracked != bIsTracked)
|
||||
{
|
||||
if (bIsTracked)
|
||||
OnBodyBeginTrack.Broadcast(BodyIndex);
|
||||
else
|
||||
OnBodyLost.Broadcast(BodyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void UNeoKinectBody::Reset()
|
||||
{
|
||||
using namespace NeoKinect;
|
||||
|
||||
ClippedEdges.Left =
|
||||
ClippedEdges.Right =
|
||||
ClippedEdges.Top =
|
||||
ClippedEdges.Bottom = false;
|
||||
|
||||
bIsTracked = false;
|
||||
bIsRestricted = false;
|
||||
TrackingId = 0Ui64;
|
||||
|
||||
HandLeftState = EKinectHandState::NotTracked;
|
||||
HandLeftTrackingState = EKinectTrackingState::NotTracked;
|
||||
|
||||
HandRightState = EKinectHandState::NotTracked;
|
||||
HandRightTrackingState = EKinectTrackingState::NotTracked;
|
||||
|
||||
LeanTrackingState = EKinectTrackingState::NotTracked;
|
||||
Lean.Set(0.f, 0.f);
|
||||
|
||||
if (Joints.Num() != KinectJointCount)
|
||||
return;
|
||||
|
||||
for (int32 j = 0; j < KinectJointCount; ++j)
|
||||
{
|
||||
if (!Joints.IsValidIndex(j))
|
||||
continue;
|
||||
FKinectJoint& Joint = Joints[j];
|
||||
|
||||
Joint.Confidence = EKinectTrackingState::NotTracked;
|
||||
Joint.Location.Set(0.f, 0.f, 0.f);
|
||||
Joint.ColorLocation.Set(0.f, 0.f, 0.f);
|
||||
Joint.Orientation.Roll =
|
||||
Joint.Orientation.Pitch =
|
||||
Joint.Orientation.Yaw = 0.f;
|
||||
Joint.ColorOrientation.Roll =
|
||||
Joint.ColorOrientation.Pitch =
|
||||
Joint.ColorOrientation.Yaw = 0.f;
|
||||
}
|
||||
}
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#include "NeoKinectFace.h"
|
||||
#include "NeoKinectBody.h"
|
||||
#include "NeoKinectManager.h"
|
||||
|
||||
void FIntBoundingBox::FromRectI(const RectI& Rect)
|
||||
{
|
||||
Left = Rect.Left;
|
||||
Top = Rect.Top;
|
||||
Right = Rect.Right;
|
||||
Bottom = Rect.Bottom;
|
||||
}
|
||||
|
||||
void FFacePoints2D::FromKinectFacePoints(const NeoKinect::KinectFacePoints& Points)
|
||||
{
|
||||
LeftEye.X = Points.leftEye.x;
|
||||
LeftEye.Y = Points.leftEye.y;
|
||||
|
||||
RightEye.X = Points.rightEye.x;
|
||||
RightEye.Y = Points.rightEye.y;
|
||||
|
||||
Nose.X = Points.nose.x;
|
||||
Nose.Y = Points.nose.y;
|
||||
|
||||
LeftMouthCorner.X = Points.leftMouthCorner.x;
|
||||
LeftMouthCorner.Y = Points.leftMouthCorner.y;
|
||||
|
||||
RightMouthCorner.X = Points.rightMouthCorner.x;
|
||||
RightMouthCorner.Y = Points.rightMouthCorner.y;
|
||||
}
|
||||
|
||||
void FFacePoints3D::FromKinectFacePoints(const NeoKinect::KinectFacePoints& ColorPoints)
|
||||
{
|
||||
NeoKinect::Vector3 Location = UNeoKinectManager::ColorWithDepthFromColorOnly(ColorPoints.leftEye) * 100.f;
|
||||
LeftEye.Set(-Location.z, Location.x, Location.y);
|
||||
|
||||
Location = UNeoKinectManager::ColorWithDepthFromColorOnly(ColorPoints.rightEye) * 100.f;
|
||||
RightEye.Set(-Location.z, Location.x, Location.y);
|
||||
|
||||
Location = UNeoKinectManager::ColorWithDepthFromColorOnly(ColorPoints.nose) * 100.f;
|
||||
Nose.Set(-Location.z, Location.x, Location.y);
|
||||
|
||||
Location = UNeoKinectManager::ColorWithDepthFromColorOnly(ColorPoints.leftMouthCorner) * 100.f;
|
||||
LeftMouthCorner.Set(-Location.z, Location.x, Location.y);
|
||||
|
||||
Location = UNeoKinectManager::ColorWithDepthFromColorOnly(ColorPoints.rightMouthCorner) * 100.f;
|
||||
RightMouthCorner.Set(-Location.z, Location.x, Location.y);
|
||||
}
|
||||
|
||||
UNeoKinectFace::UNeoKinectFace()
|
||||
: Index(INDEX_NONE)
|
||||
, bIsTracked(false)
|
||||
, TrackingId(INDEX_NONE)
|
||||
, IsEngaged(EDetectionResult::Unknown)
|
||||
, IsHappy(EDetectionResult::Unknown)
|
||||
, IsLookingAway(EDetectionResult::Unknown)
|
||||
, IsMouthMoved(EDetectionResult::Unknown)
|
||||
, IsMouthOpen(EDetectionResult::Unknown)
|
||||
, IsLeftEyeClosed(EDetectionResult::Unknown)
|
||||
, IsRightEyeClosed(EDetectionResult::Unknown)
|
||||
, IsWearingGlasses(EDetectionResult::Unknown)
|
||||
{}
|
||||
|
||||
UNeoKinectFace::~UNeoKinectFace()
|
||||
{}
|
||||
|
||||
void UNeoKinectFace::GetEyeClosedAsExec(EKinectBodySide Eye, EDetectionResult& Result)
|
||||
{
|
||||
if (Eye == EKinectBodySide::Left)
|
||||
{
|
||||
Result = IsLeftEyeClosed;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = IsRightEyeClosed;
|
||||
}
|
||||
}
|
||||
|
||||
EDetectionResult UNeoKinectFace::GetEyeClosed(EKinectBodySide Eye) const
|
||||
{
|
||||
if (Eye == EKinectBodySide::Left)
|
||||
return IsLeftEyeClosed;
|
||||
|
||||
return IsRightEyeClosed;
|
||||
}
|
||||
|
||||
void UNeoKinectFace::GetIsEngagedAsExec(EDetectionResult& Result)
|
||||
{
|
||||
Result = IsEngaged;
|
||||
}
|
||||
|
||||
void UNeoKinectFace::GetIsHappyAsExec(EDetectionResult& Result)
|
||||
{
|
||||
Result = IsHappy;
|
||||
}
|
||||
|
||||
void UNeoKinectFace::GetIsLookingAwayAsExec(EDetectionResult& Result)
|
||||
{
|
||||
Result = IsLookingAway;
|
||||
}
|
||||
|
||||
void UNeoKinectFace::GetIsMouthMovedAsExec(EDetectionResult& Result)
|
||||
{
|
||||
Result = IsMouthMoved;
|
||||
}
|
||||
|
||||
void UNeoKinectFace::GetIsMouthOpenAsExec(EDetectionResult& Result)
|
||||
{
|
||||
Result = IsMouthOpen;
|
||||
}
|
||||
|
||||
void UNeoKinectFace::GetIsWearingGlassesAsExec(EDetectionResult& Result)
|
||||
{
|
||||
Result = IsWearingGlasses;
|
||||
}
|
||||
|
||||
bool UNeoKinectFace::IsFromBody(const UNeoKinectBody* Body) const
|
||||
{
|
||||
return Body->TrackingId == TrackingId;
|
||||
}
|
||||
|
||||
void UNeoKinectFace::UpdateFromKinectFace(const NeoKinect::KinectFace& kFace)
|
||||
{
|
||||
const bool bWasTracked = bIsTracked;
|
||||
|
||||
bIsTracked = kFace.bIsTracked;
|
||||
TrackingId = kFace.trackingId;
|
||||
|
||||
ColorBoundingBox.FromRectI(kFace.boxColor);
|
||||
InfraredBoundingBox.FromRectI(kFace.boxInfrared);
|
||||
|
||||
ColorAlignmentPoints.FromKinectFacePoints(kFace.pointsColor);
|
||||
InfraredAlignmentPoints.FromKinectFacePoints(kFace.pointsInfrared);
|
||||
ColorWithDepthAlignmentPoints.FromKinectFacePoints(kFace.pointsColor);
|
||||
|
||||
/* Camera space face transform */
|
||||
Location.Set(
|
||||
kFace.pivot.Z * 100.f,
|
||||
-kFace.pivot.X * 100.f,
|
||||
kFace.pivot.Y * 100.f);
|
||||
|
||||
const FQuat Quat = FQuat(
|
||||
-kFace.rotation.z,
|
||||
kFace.rotation.x,
|
||||
-kFace.rotation.y,
|
||||
kFace.rotation.w
|
||||
);
|
||||
Orientation = FRotationMatrix::MakeFromXZ(
|
||||
Quat.GetAxisZ(),
|
||||
-Quat.GetAxisY()).Rotator();
|
||||
|
||||
/* Color space face location */
|
||||
if (UNeoKinectManager::IsUsingJointsColorSpaceTransforms())
|
||||
{
|
||||
using namespace NeoKinect;
|
||||
// Convert camera space location to color space with depth
|
||||
const Vector3 ColorDepthLocation = UNeoKinectManager::CameraLocationToColorWithDepth(Vector3(kFace.pivot));
|
||||
if (ColorDepthLocation.IsZero())
|
||||
{
|
||||
ColorLocation = Location;
|
||||
}
|
||||
else
|
||||
{
|
||||
ColorLocation.Set(
|
||||
ColorDepthLocation.z * 100.0f,
|
||||
-ColorDepthLocation.x * 100.0f,
|
||||
ColorDepthLocation.y * 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
IsEngaged = static_cast<EDetectionResult>(kFace.isEngaged);
|
||||
IsHappy = static_cast<EDetectionResult>(kFace.isHappy);
|
||||
IsLookingAway = static_cast<EDetectionResult>(kFace.isLookingAway);
|
||||
IsMouthMoved = static_cast<EDetectionResult>(kFace.isMouthMoved);
|
||||
IsMouthOpen = static_cast<EDetectionResult>(kFace.isMouthOpen);
|
||||
IsLeftEyeClosed = static_cast<EDetectionResult>(kFace.isLeftEyeClosed);
|
||||
IsRightEyeClosed = static_cast<EDetectionResult>(kFace.isRightEyeClosed);
|
||||
IsWearingGlasses = static_cast<EDetectionResult>(kFace.isWearingGlasses);
|
||||
|
||||
if (bWasTracked != bIsTracked)
|
||||
{
|
||||
if (bIsTracked)
|
||||
OnFaceBeginTrack.Broadcast(Index);
|
||||
else
|
||||
OnFaceLost.Broadcast(Index);
|
||||
}
|
||||
}
|
||||
|
||||
void UNeoKinectFace::Reset()
|
||||
{
|
||||
bIsTracked = false;
|
||||
TrackingId = 0ULL;
|
||||
|
||||
ColorBoundingBox = FIntBoundingBox();
|
||||
InfraredBoundingBox = FIntBoundingBox();
|
||||
|
||||
ColorAlignmentPoints = FFacePoints2D();
|
||||
InfraredAlignmentPoints = FFacePoints2D();
|
||||
|
||||
Location.Set(0.f, 0.f, 0.f);
|
||||
ColorLocation = Location;
|
||||
|
||||
Orientation.Yaw =
|
||||
Orientation.Pitch =
|
||||
Orientation.Roll = 0.f;
|
||||
|
||||
IsEngaged =
|
||||
IsHappy =
|
||||
IsLookingAway =
|
||||
IsMouthMoved =
|
||||
IsMouthOpen =
|
||||
IsLeftEyeClosed =
|
||||
IsRightEyeClosed =
|
||||
IsWearingGlasses = EDetectionResult::Unknown;
|
||||
}
|
||||
+1311
File diff suppressed because it is too large
Load Diff
+5
@@ -0,0 +1,5 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
IMPLEMENT_MODULE(FDefaultModuleImpl, NeoKinectUnreal)
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4471)
|
||||
#include "NeoKinect.h"
|
||||
#pragma warning(pop)
|
||||
#include "Windows/HideWindowsPlatformTypes.h"
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Helpers/GuardedNeoKinect.h"
|
||||
#include "NeoKinectEnums.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "HAL/Runnable.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_CLASS(KinectThreadLog, Log, All);
|
||||
|
||||
struct FThreadFrameBuffer
|
||||
{
|
||||
NeoKinect::KinectFrameType FrameType = NeoKinect::KinectFrameType::Count;
|
||||
NeoKinect::KinectPixelFormat PixelFormat = NeoKinect::KinectPixelFormat::None;
|
||||
NeoKinect::KinectCoordinateSpace TargetSpace = NeoKinect::KinectCoordinateSpace::Count;
|
||||
bool bRemapped = false;
|
||||
|
||||
~FThreadFrameBuffer();
|
||||
|
||||
void Configure(
|
||||
NeoKinect::KinectFrameType Frame,
|
||||
NeoKinect::KinectPixelFormat PixelFormat,
|
||||
NeoKinect::KinectCoordinateSpace Space,
|
||||
bool IsRemapped);
|
||||
bool AllocateBuffers(uint32 Size);
|
||||
void DeallocateBuffers();
|
||||
bool IsAllocated() const;
|
||||
|
||||
// Returns an updated buffer. If it was already consumed, return nullptr
|
||||
const uint8* GetReadBuffer(bool bConsume = true);
|
||||
uint8* GetWriteBuffer() const;
|
||||
|
||||
void SetDirty();
|
||||
|
||||
bool TryLock();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
void LockWrite();
|
||||
void UnlockWrite();
|
||||
|
||||
private:
|
||||
std::atomic<bool> bIsNew = false;
|
||||
uint8 *Buffer = nullptr;
|
||||
uint8 *BackBuffer = nullptr;
|
||||
FCriticalSection ReadMutex;
|
||||
FCriticalSection WriteMutex;
|
||||
|
||||
void SwapBuffers();
|
||||
};
|
||||
|
||||
// Kinect polling thread
|
||||
class FKinectThread : public FRunnable
|
||||
{
|
||||
private:
|
||||
/*
|
||||
Kinect updates its frames, at most, at 30fps.
|
||||
But, as some of them will be available at slightly different times, I'll poll
|
||||
it at double that rate to be sure.
|
||||
*/
|
||||
static constexpr float cDesiredFPS = 60.f;
|
||||
|
||||
// Singleton instance, can access the thread any time via static accessor, if it is active
|
||||
static FKinectThread *Runnable;
|
||||
// Thread to run FRunnable on
|
||||
FRunnableThread *Thread;
|
||||
// Stop this thread? Uses Thread Safe Counter
|
||||
FThreadSafeCounter StopTaskCounter;
|
||||
|
||||
// Kinect sensor
|
||||
NeoKinect::KinectSensor *pKinect;
|
||||
|
||||
// Bodies data
|
||||
NeoKinect::KinectBody Bodies[NeoKinect::KinectBodyCount];
|
||||
|
||||
// Face tracking data
|
||||
NeoKinect::KinectFace Faces[NeoKinect::KinectBodyCount];
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
FKinectThread(NeoKinect::KinectSensor *pSensor);
|
||||
// Destructor
|
||||
~FKinectThread() override;
|
||||
|
||||
// Frames data. These control which frame buffers should or not be updated.
|
||||
static FThreadFrameBuffer FrameBuffers[static_cast<uint64>(EKinectFrame::Count)];
|
||||
// Controls whether body data should be read
|
||||
static bool bUseBodyTracking;
|
||||
// True if body data was updated since last reading
|
||||
bool bBodiesDirty;
|
||||
// Controls whether face tracking data should be read
|
||||
static bool bUseFaceTracking;
|
||||
// True if faces data was updated since last reading
|
||||
bool bFacesDirty;
|
||||
|
||||
// Mutex for body/face data thread safety
|
||||
static FCriticalSection BodiesFacesCritSec;
|
||||
|
||||
/*
|
||||
Start the thread and the worker from static (easy access)
|
||||
This code ensures only 1 KinectThread will be able to run at a time.
|
||||
This function returns a handle to the newly started instance.
|
||||
*/
|
||||
static FKinectThread *InitKinectPolling(NeoKinect::KinectSensor *pSensor);
|
||||
|
||||
// Makes sure this thread has stopped properly
|
||||
void EnsureCompletion();
|
||||
|
||||
// Shuts down the thread. Static so it can easily be called from outside the thread context
|
||||
static void Shutdown();
|
||||
|
||||
// Gets last polled bodies data. Returns nullptr if no new data
|
||||
const NeoKinect::KinectBody *GetBodiesData();
|
||||
// Gets last polled faces data. Returns nullptr if no new data
|
||||
const NeoKinect::KinectFace *GetFacesData();
|
||||
|
||||
// Begin FRunnable interface
|
||||
virtual bool Init() override;
|
||||
virtual uint32 Run() override;
|
||||
virtual void Stop() override;
|
||||
virtual void Exit() override;
|
||||
// End FRunnable interface
|
||||
};
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "NeoKinectEnums.h"
|
||||
|
||||
#include "NeoKinectBody.generated.h"
|
||||
|
||||
namespace NeoKinect
|
||||
{
|
||||
struct KinectBody;
|
||||
class KinectSensor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joint properties.
|
||||
*
|
||||
* The Location and Orientation of joints, by default, is given in camera space,
|
||||
* which center is a point in the Kinect sensor not matching the color camera.
|
||||
* So, to use joints over the color frame image, these coordinates must be reprojected.
|
||||
* To get these reprojected values, use ColorLocation and ColorOrientation.
|
||||
*/
|
||||
USTRUCT(BlueprintType, Category = "NeoKinect|Structs")
|
||||
struct FKinectJoint
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Joint type. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Joints")
|
||||
EKinectJointType Type;
|
||||
/** Joint tracking confidence. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Joints")
|
||||
EKinectTrackingState Confidence;
|
||||
|
||||
/** Joint location relative to Kinect sensor in camera space. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "position translation transform camera"))
|
||||
FVector Location;
|
||||
/** Joint orientation relative to Kinect sensor in camera space. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "transform rotation angles camera"))
|
||||
FRotator Orientation;
|
||||
|
||||
/** Joint location relative to Kinect sensor in color space with depth. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "position translation transform color"))
|
||||
FVector ColorLocation;
|
||||
/** Joint orientation relative to Kinect sensor in color space. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "transform rotation angles color"))
|
||||
FRotator ColorOrientation;
|
||||
|
||||
FKinectJoint() :
|
||||
Type(EKinectJointType::AnkleLeft),
|
||||
Confidence(EKinectTrackingState::NotTracked),
|
||||
Location(FVector::ZeroVector),
|
||||
Orientation(FRotator::ZeroRotator),
|
||||
ColorLocation(FVector::ZeroVector),
|
||||
ColorOrientation(FRotator::ZeroRotator)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* Which edges are clipping a body on the view frustum.
|
||||
*/
|
||||
USTRUCT(BlueprintType, Category = "NeoKinect|Structs")
|
||||
struct FKinectClippedEdges
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body")
|
||||
bool Left;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body")
|
||||
bool Right;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body")
|
||||
bool Top;
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body")
|
||||
bool Bottom;
|
||||
|
||||
FKinectClippedEdges() :
|
||||
Left(false), Right(false), Top(false), Bottom(false)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a trackable body.
|
||||
*/
|
||||
UCLASS(BlueprintType, Category = "NeoKinect|Body")
|
||||
class NEOKINECTUNREAL_API UNeoKinectBody : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBodyTrackDelegate, int32, BodyIndex);
|
||||
|
||||
UNeoKinectBody();
|
||||
~UNeoKinectBody() override;
|
||||
|
||||
/** Retrieves this body index (0~5). */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body")
|
||||
int32 BodyIndex;
|
||||
/** Body's unique Tracking ID. */
|
||||
UPROPERTY()
|
||||
int64 TrackingId;
|
||||
|
||||
/** Body clipped edges from the sensor's view. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body", Meta = (Keywords = "cut borders"))
|
||||
FKinectClippedEdges ClippedEdges;
|
||||
|
||||
/** If this body represents a tracked user. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body")
|
||||
bool bIsTracked;
|
||||
/** If body's movement is restricted somehow. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body")
|
||||
bool bIsRestricted;
|
||||
|
||||
/** Left hand pose */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Hands")
|
||||
EKinectHandState HandLeftState;
|
||||
/** Left hand tracking state */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Hands")
|
||||
EKinectTrackingState HandLeftTrackingState;
|
||||
|
||||
/** Right hand pose */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Hands")
|
||||
EKinectHandState HandRightState;
|
||||
/** Right hand tracking state */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body|Hands")
|
||||
EKinectTrackingState HandRightTrackingState;
|
||||
|
||||
/** Body lean tracking confidence. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body")
|
||||
EKinectTrackingState LeanTrackingState;
|
||||
/**
|
||||
* Body lean.
|
||||
* Ranges from -1 to 1 being left to right in X and back to front in Y.
|
||||
* Values of -1 and 1 represent roughly 45 degrees of inclination.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Body", Meta = (Keywords = "inclination"))
|
||||
FVector2D Lean;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<FKinectJoint> Joints;
|
||||
|
||||
/** Called when this Body object starts tracking an user */
|
||||
UPROPERTY(BlueprintAssignable, Category = "NeoKinect|Body")
|
||||
FBodyTrackDelegate OnBodyBeginTrack;
|
||||
|
||||
/** Called when this Body object loses track of its user */
|
||||
UPROPERTY(BlueprintAssignable, Category = "NeoKinect|Body")
|
||||
FBodyTrackDelegate OnBodyLost;
|
||||
|
||||
/**
|
||||
* Get Left/Right hand state as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param Hand Which hand?
|
||||
* @param States Current Hand state.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Body|Hands", Meta = (ExpandEnumAsExecs = "States"))
|
||||
void GetHandStateAsExec(EKinectBodySide Hand, EKinectHandState& States);
|
||||
|
||||
/**
|
||||
* Get Left/Right hand state.
|
||||
*
|
||||
* @param Hand Which hand?
|
||||
* @return Current Hand state.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "SamrtKinect|Body|Hands")
|
||||
EKinectHandState GetHandState(EKinectBodySide Hand) const;
|
||||
|
||||
/**
|
||||
* Get Left/Right hand tracking state as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param Hand Which hand?
|
||||
* @param States Current Hand tracking state.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Body|Hands", Meta = (ExpandEnumAsExecs = "States"))
|
||||
void GetHandConfidenceAsExec(EKinectBodySide Hand, EKinectTrackingState& States);
|
||||
|
||||
/**
|
||||
* Get Left/Right hand tracking state.
|
||||
*
|
||||
* @param Hand Which hand?
|
||||
* @return Current Hand tracking state.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Hands")
|
||||
EKinectTrackingState GetHandConfidence(EKinectBodySide Hand) const;
|
||||
|
||||
/**
|
||||
* Get body lean tracking confidence as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param States Lean tracking state.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Body", Meta = (ExpandEnumAsExecs = "States", Keywords = "inclination"))
|
||||
void GetLeanConfidenceAsExec(EKinectTrackingState& States);
|
||||
|
||||
/**
|
||||
* Contains this body's each joint tracking state and transform.
|
||||
*
|
||||
* @return This body's each joint tracking state and transform.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints")
|
||||
TArray<FKinectJoint> GetJoints();
|
||||
|
||||
/**
|
||||
* Get a Joint's location relative to Kinect sensor.
|
||||
*
|
||||
* @param Joint The joint type.
|
||||
* @return Joint's location relative to Kinect sensor.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "position translation transform"))
|
||||
FVector GetJointLocation(EKinectJointType Joint);
|
||||
|
||||
/**
|
||||
* Get a Joint's orientation relative to Kinect sensor.
|
||||
*
|
||||
* @param Joint The joint type.
|
||||
* @return Joint's orientation relative to Kinect sensor.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "rotation angles transform"))
|
||||
FRotator GetJointOrientation(EKinectJointType Joint);
|
||||
|
||||
/**
|
||||
* Get a Joint's location relative to Kinect sensor aligned with the Color frame.
|
||||
* So, if a camera is created with the same FOV as the Kinect Color camera's and
|
||||
* the Color frame texture is used as background, this location will align perfectly
|
||||
* with the corresponding joint in the Color image.
|
||||
*
|
||||
* @param Joint The joint type.
|
||||
* @return Joint's location relative to Kinect sensor.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "position translation transform"))
|
||||
FVector GetJointLocationColor(EKinectJointType Joint);
|
||||
|
||||
/**
|
||||
* Get a Joint's orientation relative to Kinect sensor aligned with the Color
|
||||
* aligned joint location.
|
||||
*
|
||||
* @param Joint The joint type.
|
||||
* @return Joint's orientation relative to Kinect sensor.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "rotation angles transform"))
|
||||
FRotator GetJointOrientationColor(EKinectJointType Joint);
|
||||
|
||||
/**
|
||||
* Get a Joint's tracking confidence as exec pins.
|
||||
* Useful for redirecting the code path, like the Branch node.
|
||||
*
|
||||
* @param Joint The joint type.
|
||||
* @param States Joint's tracking confidence.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Body|Joints", Meta = (ExpandEnumAsExecs = "States"))
|
||||
void GetJointConfidenceAsExec(EKinectJointType Joint, EKinectTrackingState& States);
|
||||
|
||||
/**
|
||||
* Get a Joint's tracking confidence.
|
||||
*
|
||||
* @param Joint The joint type.
|
||||
* @return Joint's tracking confidence.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints")
|
||||
EKinectTrackingState GetJointConfidence(EKinectJointType Joint);
|
||||
|
||||
/**
|
||||
* Calculate the distance between two joints in the Kinect sensor space.
|
||||
*
|
||||
* @param JointA First joint.
|
||||
* @param JointB Second joint.
|
||||
* @return Distance between the two joints.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "size length"))
|
||||
float GetJointsDistance(EKinectJointType JointA, EKinectJointType JointB);
|
||||
|
||||
/**
|
||||
* Calculate the distance from a Joint's location to it's parent's location.
|
||||
* Useful for getting bone sizes. Eg.: for Left Elbow, the result will be the
|
||||
* distance from Left Elbow to Left Shoulder. Spine Base is the skeleton's root,
|
||||
* so it will return 0.
|
||||
*
|
||||
* @param Joint The joint type.
|
||||
* @return Distance from Joint to it's parent.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "size length"))
|
||||
float GetBoneLength(EKinectJointType Joint);
|
||||
|
||||
/**
|
||||
* The Dot product between a Joint direction and a Vector.
|
||||
*
|
||||
* @return -1 ~ 1: 1 = same direction as vector. -1 = opposite from vector.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints", Meta = (Keywords = "pointing direction lookat"))
|
||||
float JointDotVector(EKinectJointType Joint, FVector Vector);
|
||||
|
||||
void UpdateFromKinectBody(const NeoKinect::KinectBody& kBody, const NeoKinect::KinectSensor& Sensor);
|
||||
|
||||
void Reset();
|
||||
};
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "NeoKinectEnums.generated.h"
|
||||
|
||||
/**
|
||||
* The types of frames that can be read from the Kinect sensor.
|
||||
*/
|
||||
UENUM(BlueprintType, Category = "NeoKinect|Enums")
|
||||
enum class EKinectFrame : uint8
|
||||
{
|
||||
/** Normal camera texture. Standard RGBA format (alpha = 1) */
|
||||
Color = 0,
|
||||
/** Depth sensor texture. Red channel only. Values are in millimeters */
|
||||
Depth = 1,
|
||||
/** Depth sensor ranging from 0 to 1. Standard RGBA format (alpha = 1) */
|
||||
NormalizedDepth = 2,
|
||||
/** Body index value in Red channel. In material editor, multiply Red by 255
|
||||
* to get actual index value (0~5) */
|
||||
BodyIndex = 3,
|
||||
/** Body indexes with a color for each index. Standard RGBA format.
|
||||
* Alpha = 1 where there's a body, 0 otherwise */
|
||||
BodyIndexColor = 4 UMETA(DisplayName = "Colored Body Index"),
|
||||
/** Not implemented */
|
||||
Color_DepthSpace = 5 UMETA(DisplayName = "Color in Depth Space"),
|
||||
/** Depth sensor image remapped to fit the color frame. Red channel only.
|
||||
* Values in millimeters, 0 where remapping is not possible. */
|
||||
Depth_ColorSpace = 6 UMETA(DisplayName = "Depth in Color Space"),
|
||||
/** Body index values remapped to fit the bodies in the color frame.
|
||||
* Red channel only. In material editor, multiply Red by 255 to get actual
|
||||
* index value (0~5). */
|
||||
BodyIndex_ColorSpace= 7 UMETA(DisplayName = "Body Index in Color Space"),
|
||||
/** Infrared sensor image. Red channel only, usually very dark. */
|
||||
Infrared = 8,
|
||||
/** Long exposure infrared sensor image. Red channel only. Can lower the
|
||||
* sensor's FPS to get brighter image */
|
||||
LongExposureInfrared= 9,
|
||||
/** Cast to int to get the number of frame types */
|
||||
Count = 10
|
||||
};
|
||||
|
||||
/**
|
||||
* Body sides.
|
||||
*/
|
||||
UENUM(BlueprintType, Category = "NeoKinect|Enums")
|
||||
enum class EKinectBodySide : uint8
|
||||
{
|
||||
Left = 0,
|
||||
Right = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible hand states
|
||||
*/
|
||||
UENUM(BlueprintType, Category = "NeoKinect|Enums")
|
||||
enum class EKinectHandState : uint8
|
||||
{
|
||||
/** Pretty close to NotTracked. */
|
||||
Unknown = 0,
|
||||
NotTracked = 1,
|
||||
Open = 2,
|
||||
Closed = 3,
|
||||
/** Closed hand with index and middle fingers pointing up, near each other */
|
||||
Lasso = 4
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracking confidence.
|
||||
*/
|
||||
UENUM(BlueprintType, Category = "NeoKinect|Enums")
|
||||
enum class EKinectTrackingState : uint8
|
||||
{
|
||||
NotTracked = 0,
|
||||
/** Tracked by deduction. Sometimes good, many times terrible. */
|
||||
Inferred = 1,
|
||||
Tracked = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* The joints that the Kinect sensor tracks on each body. 25 total.
|
||||
*/
|
||||
UENUM(BlueprintType, Category = "NeoKinect|Enums")
|
||||
enum class EKinectJointType : uint8
|
||||
{
|
||||
/** Near the pelvis */
|
||||
SpineBase = 0,
|
||||
/** Near the stomach */
|
||||
SpineMid = 1 UMETA(DisplayName = "Spine Middle"),
|
||||
Neck = 2,
|
||||
Head = 3,
|
||||
ShoulderLeft = 4 UMETA(DisplayName = "Left Shoulder"),
|
||||
ElbowLeft = 5 UMETA(DisplayName = "Left Elbow"),
|
||||
WristLeft = 6 UMETA(DisplayName = "Left Wrist"),
|
||||
/** In the palm center */
|
||||
HandLeft = 7 UMETA(DisplayName = "Left Hand"),
|
||||
ShoulderRight = 8 UMETA(DisplayName = "Right Shoulder"),
|
||||
ElbowRight = 9 UMETA(DisplayName = "Right Elbow"),
|
||||
WristRight = 10 UMETA(DisplayName = "Right Wrist"),
|
||||
/** In the palm center */
|
||||
HandRight = 11 UMETA(DisplayName = "Right Hand"),
|
||||
/** Femur/Hip joint */
|
||||
HipLeft = 12 UMETA(DisplayName = "Left Hip"),
|
||||
KneeLeft = 13 UMETA(DisplayName = "Left Knee"),
|
||||
AnkleLeft = 14 UMETA(DisplayName = "Left Ankle"),
|
||||
/** Tip of the foot */
|
||||
FootLeft = 15 UMETA(DisplayName = "Left Foot"),
|
||||
/** Femur/Hip joint */
|
||||
HipRight = 16 UMETA(DisplayName = "Right Hip"),
|
||||
KneeRight = 17 UMETA(DisplayName = "Right Knee"),
|
||||
AnkleRight = 18 UMETA(DisplayName = "Right Ankle"),
|
||||
/** Tip of the foot */
|
||||
FootRight = 19 UMETA(DisplayName = "Right Foot"),
|
||||
/** Between the collar bones */
|
||||
SpineShoulder = 20,
|
||||
HandTipLeft = 21 UMETA(DisplayName = "Left Hand Tip"),
|
||||
ThumbLeft = 22 UMETA(DisplayName = "Left Thumb"),
|
||||
HandTipRight = 23 UMETA(DisplayName = "Right Hand Tip"),
|
||||
ThumbRight = 24 UMETA(DisplayName = "Right Thumb")
|
||||
};
|
||||
|
||||
/**
|
||||
* Face properties detection results
|
||||
*/
|
||||
UENUM(BlueprintType, Category = "NeoKinect|Enums")
|
||||
enum class EDetectionResult : uint8
|
||||
{
|
||||
Unknown = 0,
|
||||
No = 1,
|
||||
/** Consider it more as a "No" */
|
||||
Maybe = 2,
|
||||
Yes = 3
|
||||
};
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NeoKinectEnums.h"
|
||||
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4471)
|
||||
#include "Kinect.Face.h"
|
||||
#pragma warning(pop)
|
||||
#include "Windows/HideWindowsPlatformTypes.h"
|
||||
|
||||
#include "NeoKinectFace.generated.h"
|
||||
|
||||
class UNeoKinectBody;
|
||||
|
||||
namespace NeoKinect
|
||||
{
|
||||
struct KinectFace;
|
||||
struct KinectFacePoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the edges of a rectangle in a texture (int values)
|
||||
*/
|
||||
USTRUCT(BlueprintType, Category = "NeoKinect|Structs")
|
||||
struct FIntBoundingBox
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// Left rectangle edge
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
int32 Left = 0;
|
||||
// Top rectangle edge
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
int32 Top = 0;
|
||||
// Right rectangle edge
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
int32 Right = 0;
|
||||
// Bottom rectangle edge
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
int32 Bottom = 0;
|
||||
|
||||
void FromRectI(const RectI& Rect);
|
||||
};
|
||||
|
||||
/**
|
||||
* Lists the 2D of each face alignment point.
|
||||
*/
|
||||
USTRUCT(BlueprintType, Category = "NeoKinect|Structs")
|
||||
struct FFacePoints2D
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// Left eye location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector2D LeftEye = FVector2D::Zero();
|
||||
// Right eye location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector2D RightEye = FVector2D::Zero();
|
||||
// Nose location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector2D Nose = FVector2D::Zero();
|
||||
// Left mouth corner location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector2D LeftMouthCorner = FVector2D::Zero();
|
||||
// Right mouth corner location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector2D RightMouthCorner = FVector2D::Zero();
|
||||
|
||||
void FromKinectFacePoints(const NeoKinect::KinectFacePoints& Points);
|
||||
};
|
||||
|
||||
/**
|
||||
* Lists the 3D locations of each face alignment point.
|
||||
*/
|
||||
USTRUCT(BlueprintType, Category = "NeoKinect|Structs")
|
||||
struct FFacePoints3D
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// Left eye location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector LeftEye = FVector::Zero();
|
||||
// Right eye location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector RightEye = FVector::Zero();
|
||||
// Nose location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector Nose = FVector::Zero();
|
||||
// Left mouth corner location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector LeftMouthCorner = FVector::Zero();
|
||||
// Right mouth corner location
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector RightMouthCorner = FVector::Zero();
|
||||
|
||||
void FromKinectFacePoints(const NeoKinect::KinectFacePoints& ColorPoints);
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a trackable body's face.
|
||||
*/
|
||||
UCLASS(BlueprintType, Category = "NeoKinect|Face")
|
||||
class NEOKINECTUNREAL_API UNeoKinectFace : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FFaceTrackDelegate, int32, FaceIndex);
|
||||
|
||||
UNeoKinectFace();
|
||||
~UNeoKinectFace() override;
|
||||
|
||||
// This face's index in the faces array
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
int32 Index;
|
||||
|
||||
// If this face is being tracked.
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
bool bIsTracked;
|
||||
|
||||
// Face tracking Id. Matches it's body TrackingId.
|
||||
UPROPERTY()
|
||||
int64 TrackingId;
|
||||
|
||||
// The face bounding box in Color space.
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FIntBoundingBox ColorBoundingBox;
|
||||
|
||||
// The face bounding box in Depth space.
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FIntBoundingBox InfraredBoundingBox;
|
||||
|
||||
// The face alignment points in Color space.
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FFacePoints2D ColorAlignmentPoints;
|
||||
|
||||
// The face alignment points in Depth space.
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FFacePoints2D InfraredAlignmentPoints;
|
||||
|
||||
/**
|
||||
* The face alignment points aligned with the Color frame from the camera's
|
||||
* point of view, at a distance taken from Depth frame.
|
||||
* For this to have valid values the remapped Depth in Color Space frame must be activated.
|
||||
*/
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FFacePoints3D ColorWithDepthAlignmentPoints;
|
||||
|
||||
// The face rotation.
|
||||
UPROPERTY(BlueprintReadOnly, Meta = (Keywords = "rotation quaternion angles transform"), Category = "NeoKinect|Face")
|
||||
FRotator Orientation;
|
||||
|
||||
// The head pivot location.
|
||||
UPROPERTY(BlueprintReadOnly, Meta = (Keywords = "location position center head translation transform"), Category = "NeoKinect|Face")
|
||||
FVector Location;
|
||||
|
||||
/** Head location aligned with the Color frame and with depth.
|
||||
* Only valid if color transforms were activated using SetUseJointsColorSpaceTransforms */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
FVector ColorLocation;
|
||||
|
||||
// Is the user engaged?
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
EDetectionResult IsEngaged;
|
||||
|
||||
// Does the user looks happy?
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
EDetectionResult IsHappy;
|
||||
|
||||
// Is the user looking away?
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
EDetectionResult IsLookingAway;
|
||||
|
||||
// Did the user mouth move?
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
EDetectionResult IsMouthMoved;
|
||||
|
||||
// Is the user mouth opened?
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
EDetectionResult IsMouthOpen;
|
||||
|
||||
// Is the user left eye closed?
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
EDetectionResult IsLeftEyeClosed;
|
||||
|
||||
// Is the user right eye closed?
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
EDetectionResult IsRightEyeClosed;
|
||||
|
||||
// Is the user wearing glasses?
|
||||
UPROPERTY(BlueprintReadOnly, Category = "NeoKinect|Face")
|
||||
EDetectionResult IsWearingGlasses;
|
||||
|
||||
/** Called when this face object starts tracking a user's face */
|
||||
UPROPERTY(BlueprintAssignable, Category = "NeoKinect|Face")
|
||||
FFaceTrackDelegate OnFaceBeginTrack;
|
||||
|
||||
/** Called when this face object loses its user's face */
|
||||
UPROPERTY(BlueprintAssignable, Category = "NeoKinect|Face")
|
||||
FFaceTrackDelegate OnFaceLost;
|
||||
|
||||
/**
|
||||
* Checks if left/right eye is closed and use the result as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param Eye Which eye?
|
||||
* @param Result Is selected eye closed? Consider 'Maybe' more as a 'No'.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Face", Meta = (ExpandEnumAsExecs = "Result"))
|
||||
void GetEyeClosedAsExec(EKinectBodySide Eye, EDetectionResult& Result);
|
||||
|
||||
/**
|
||||
* Checks if left/right eye is closed.
|
||||
*
|
||||
* @param Eye Which eye?
|
||||
* @return Is selected eye closed? Consider 'Maybe' more as a 'No'.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Face")
|
||||
EDetectionResult GetEyeClosed(EKinectBodySide Eye) const;
|
||||
|
||||
/**
|
||||
* Get IsEngaged as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param Result Consider 'Maybe' more as a 'No'.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Face", Meta = (ExpandEnumAsExecs = "Result"))
|
||||
void GetIsEngagedAsExec(EDetectionResult& Result);
|
||||
|
||||
/**
|
||||
* Gets IsHappy as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param Result Consider 'Maybe' more as a 'No'.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Face", Meta = (ExpandEnumAsExecs = "Result"))
|
||||
void GetIsHappyAsExec(EDetectionResult& Result);
|
||||
|
||||
/**
|
||||
* Gets IsLookingAway as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param Result Consider 'Maybe' more as a 'No'.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Face", Meta = (ExpandEnumAsExecs = "Result"))
|
||||
void GetIsLookingAwayAsExec(EDetectionResult& Result);
|
||||
|
||||
/**
|
||||
* Gets IsMouthMoved as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param Result Consider 'Maybe' more as a 'No'.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Face", Meta = (ExpandEnumAsExecs = "Result"))
|
||||
void GetIsMouthMovedAsExec(EDetectionResult& Result);
|
||||
|
||||
/**
|
||||
* Gets IsMouthOpen as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param Result Consider 'Maybe' more as a 'No'.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Face", Meta = (ExpandEnumAsExecs = "Result"))
|
||||
void GetIsMouthOpenAsExec(EDetectionResult& Result);
|
||||
|
||||
/**
|
||||
* Gets IsWearingGlasses as execution pins.
|
||||
* Useful for redirecting code path, like the Branch node.
|
||||
*
|
||||
* @param Result Consider 'Maybe' more as a 'No'.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Face", Meta = (ExpandEnumAsExecs = "Result"))
|
||||
void GetIsWearingGlassesAsExec(EDetectionResult& Result);
|
||||
|
||||
/**
|
||||
* Checks if this face belongs to the passed Body instance.
|
||||
*
|
||||
* @param Body The body to test from.
|
||||
* @return True if this face belongs to the passed body.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Face")
|
||||
bool IsFromBody(const UNeoKinectBody* Body) const;
|
||||
|
||||
void UpdateFromKinectFace(const NeoKinect::KinectFace& kFace);
|
||||
|
||||
void Reset();
|
||||
};
|
||||
+612
@@ -0,0 +1,612 @@
|
||||
// Copyright 2015-2023 Rodrigo Villani Pereira
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Helpers/GuardedNeoKinect.h"
|
||||
|
||||
#include "NeoKinectEnums.h"
|
||||
#include "PixelFormat.h"
|
||||
#include "Containers/Ticker.h"
|
||||
|
||||
#include "NeoKinectManager.generated.h"
|
||||
|
||||
class FKinectThread;
|
||||
class UNeoKinectBody;
|
||||
class UNeoKinectFace;
|
||||
class UTextureRenderTarget2D;
|
||||
|
||||
DECLARE_LOG_CATEGORY_CLASS(NeoKinectLog, Log, All);
|
||||
|
||||
/** Structure to manage Kinect frame types lifetime and updating */
|
||||
struct FFrameTextureData
|
||||
{
|
||||
UTextureRenderTarget2D *Texture = nullptr;
|
||||
uint32 Width = 0;
|
||||
uint32 Height = 0;
|
||||
uint32 PixelSize = 0;
|
||||
uint32 BufferSize = 0;
|
||||
EPixelFormat UPixelFormat = EPixelFormat::PF_Unknown;
|
||||
NeoKinect::KinectPixelFormat KPixelFormat = NeoKinect::KinectPixelFormat::None;
|
||||
EKinectFrame UFrameType = EKinectFrame::Count;
|
||||
NeoKinect::KinectFrameType KFrameType = NeoKinect::KinectFrameType::Count;
|
||||
NeoKinect::KinectCoordinateSpace TargetSpace = NeoKinect::KinectCoordinateSpace::Count;
|
||||
bool bIsSRGB = false;
|
||||
bool bRemapped = false;
|
||||
|
||||
~FFrameTextureData();
|
||||
|
||||
inline bool IsTextureValid() const;
|
||||
void Release();
|
||||
NeoKinect::FrameDescription GetFrameDescription(const NeoKinect::KinectSensor *Kinect) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Access the Kinect v2 sensor capabilities.
|
||||
*
|
||||
* When using any Remapped type of frame or any Coordinate Remapping methods,
|
||||
* Depth frame use will automatically be switched on, since those functionalities
|
||||
* depend on it. But don't worry about performance. The depth frame will only
|
||||
* get written and updated to a texture on the GPU if the user explicitly
|
||||
* asks for it using SetUseFrame().
|
||||
*
|
||||
* When using Face Tracking, Body Tracking will also be automatically switched on.
|
||||
* Face Tracking depends on Body Tracking for the head pivot position and for
|
||||
* fixing issues when looking for a Face.
|
||||
*/
|
||||
UCLASS(Category = "NeoKinect", BlueprintType)
|
||||
class NEOKINECTUNREAL_API UNeoKinectManager : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
/** Stores the bodies that Kinect can track. The array is created only once
|
||||
* and lasts until the end of the program. */
|
||||
static TArray<UNeoKinectBody*> Bodies;
|
||||
/** Stores the faces that Kinect can track. The array is created only once
|
||||
* and lasts until the end of the program. */
|
||||
static TArray<UNeoKinectFace*> Faces;
|
||||
/** Stores all the possible frame types Kinect or the program can create.
|
||||
* The array is created only once and lasts until the end of the program. */
|
||||
static FFrameTextureData FramesData[static_cast<int32>(EKinectFrame::Count)];
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBodyTrackDelegate, UNeoKinectBody*, Body);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FFaceTrackDelegate, UNeoKinectFace*, Face);
|
||||
|
||||
/** Constructor: used only to bind the static dispatcher to the bodies/faces
|
||||
* tracking events. */
|
||||
UNeoKinectManager();
|
||||
/** Destructor: unbind the static dispatcher events and makes sure to
|
||||
* un-initialize the Kinect sensor before the program exits. */
|
||||
~UNeoKinectManager() override;
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
EVENTS
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
private:
|
||||
/** Class singleton used to give Blueprints access to the tracking events. */
|
||||
static UNeoKinectManager* EventsDispatcher;
|
||||
|
||||
public:
|
||||
/** Called when the Kinect sensor has just detected a new user's body. */
|
||||
UPROPERTY(BlueprintAssignable, Category = "NeoKinect")
|
||||
FBodyTrackDelegate OnBodyBeginTrack;
|
||||
|
||||
/** Called when the Kinect sensor has just lost track of a user's body. */
|
||||
UPROPERTY(BlueprintAssignable, Category = "NeoKinect")
|
||||
FBodyTrackDelegate OnBodyLost;
|
||||
|
||||
/** Called when the Kinect sensor has just detected a new user's face. */
|
||||
UPROPERTY(BlueprintAssignable, Category = "NeoKinect")
|
||||
FFaceTrackDelegate OnFaceBeginTrack;
|
||||
|
||||
/** Called when the Kinect sensor has just lost track of a user's face. */
|
||||
UPROPERTY(BlueprintAssignable, Category = "NeoKinect")
|
||||
FFaceTrackDelegate OnFaceLost;
|
||||
|
||||
/**
|
||||
* Use the object result of this function to bind to the Kinect body/face
|
||||
* tracking events. You can also bind to individual bodies/faces using their
|
||||
* respective objects.
|
||||
*
|
||||
* @return Kinect events dispatcher object.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect")
|
||||
static UNeoKinectManager* GetKinectEventsDispatcher();
|
||||
|
||||
/*////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BLUEPRINT FUNCTIONS
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/*
|
||||
* BASICS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initializes the Kinect sensor.
|
||||
*
|
||||
* Even though this function always works without errors, check if the sensor
|
||||
* has really started by calling IsKinectAvailable. It can take a while, so
|
||||
* check in intervals until it does.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Init Kinect Sensor", Keywords = "turn on initialize enable start begin"), Category = "NeoKinect")
|
||||
static void InitSensor();
|
||||
|
||||
/**
|
||||
* Returns if sensor is already on.
|
||||
*
|
||||
* It may take a while for the sensor to initialize, so keep checking. If it
|
||||
* takes too long, either there's no connected sensor or it's malfunctioning.
|
||||
*
|
||||
* @return true if Sensor is available and operational.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, meta = (Keywords = "on working works usable"), Category = "NeoKinect")
|
||||
static bool IsKinectAvailable();
|
||||
|
||||
/**
|
||||
* Use very carefully! Will shutdown the sensor and also invalidate any of its
|
||||
* frame textures (color, depth etc). Make sure you call this when none of them
|
||||
* are in use (preferably when quitting the game). Remember: with great power,
|
||||
* comes great responsibility!
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Uninit Kinect Sensor", Keywords = "turn off uninitialize disable end"), Category = "NeoKinect")
|
||||
static void UninitSensor();
|
||||
|
||||
/**
|
||||
* Retrieves the Kinect sensor or NULL if not initialized.
|
||||
*
|
||||
* @return The Kinect sensor or NULL if not initialized.
|
||||
*/
|
||||
static NeoKinect::KinectSensor* GetSensor();
|
||||
|
||||
/**
|
||||
* Gets sensor tilt in degrees. It represents the pitch of the sensor in Unreal
|
||||
* coordinates (X pointing the same direction as the Kinect camera). Negative
|
||||
* values mean it's pointing down.
|
||||
*
|
||||
* @return Kinect sensor tilt in degrees. Negative values mean it's pointing down.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect", meta = (DisplayName = "Get Kinect Tilt"))
|
||||
static float GetSensorTilt();
|
||||
|
||||
/**
|
||||
* Kinect height from the ground and ground normal. Only works if the sensor
|
||||
* can see the ground.
|
||||
* Bodies reading must be in use, as this data is read from the Body frames.
|
||||
*
|
||||
* @param Height Kinect distance from the ground
|
||||
* @return Ground normal
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect", meta = (DisplayName = "Get Kinect Ground Plane", Keywords = "height normal location floor"))
|
||||
static FVector GetGroundPlane(float &Height);
|
||||
|
||||
/*
|
||||
* EXPOSURE CONTROL
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fully automatic exposure setting with exposure compensation. Only affects the Color frame.
|
||||
* @param exposureCompensation Negative value gives an underexposed image,
|
||||
* positive gives an overexposed image.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|ColorExposure", meta = (DisplayName = "Set Kinect to Auto Exposure", Keywords = "image frame color brightness"))
|
||||
static void SetAutoExposure(float exposureCompensation = 0.0f);
|
||||
|
||||
/*
|
||||
* Sets a pseudo-exposure time in ms. Only affects the Color frame.
|
||||
*
|
||||
* The actual frame integration time is set to a multiple of fluorescent light period
|
||||
* that is shorter than the requested time e.g. requesting 16 ms will set 10 ms
|
||||
* in Australia (100Hz), 8.33 ms in USA (120Hz).
|
||||
* The gain is automatically set to compensate for the reduced integration time.
|
||||
*
|
||||
* Requesting less than a single fluorescent light period will set the integration time
|
||||
* to the requested value.
|
||||
*
|
||||
* To set the shortest non-flickering integration period for any country, simply set
|
||||
* a pseudo-exposure time of between (10.0, 16.667) ms, which will automatically drop
|
||||
* the integration time to 10 or 8.3 ms depending on country, while setting the analog
|
||||
* gain control to a brighter value.
|
||||
*
|
||||
* @param pseudoExposureTime Pseudo-exposure time in ms. [0.0, 640]ms
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|ColorExposure", meta = (DisplayName = "Set Kinect to Semi Auto Exposure", Keywords = "image frame color brightness"))
|
||||
static void SetSemiAutoExposure(float pseudoExposureTime);
|
||||
|
||||
/*
|
||||
* Manually set frame exposure time in ms and analog gain. Only affects the Color frame.
|
||||
* @param frameExposureTime Time of exposure for each frame, in ms. [0.0, 640]ms
|
||||
* @param analogGain Exposure analog gain.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|ColorExposure", meta = (DisplayName = "Set Kinect to Manual Exposure", Keywords = "image frame color brightness"))
|
||||
static void SetManualExposure(float frameExposureTime, float analogGain);
|
||||
|
||||
/*
|
||||
* COORDINATE REMAPPING
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts a 3D location in Camera space to Color space with depth, so the new
|
||||
* location matches the Color frame position from camera's point of view
|
||||
* without turning into 2D.
|
||||
*
|
||||
* @param CameraLocation The 3D Camera space coordinate to be converted (in Unreal units)
|
||||
* @return Realigned 3D coordinate that matches the Color frame from the camera's
|
||||
* point of view (in Unreal units)
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Remapping", Meta = (Keywords = "convert coordinate space remap"))
|
||||
static FVector CameraLocationToColorWithDepth(const FVector& CameraLocation);
|
||||
/** Native NeoKinect implementation of the above */
|
||||
static NeoKinect::Vector3 CameraLocationToColorWithDepth(NeoKinect::Vector3 CameraLocation);
|
||||
|
||||
/**
|
||||
* Remaps a 3D camera location to a 2D point in the Color frame.
|
||||
*
|
||||
* @param CameraLocation The 3D Camera space coordinate to be remapped (in Unreal units)
|
||||
* @return The point location in the Color frame that matches the Camera
|
||||
* location input (in pixels)
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Remapping", Meta = (Keywords = "convert coordinate space remap"))
|
||||
static FVector2D CameraLocationToColorPoint(const FVector& CameraLocation);
|
||||
|
||||
/**
|
||||
* Remaps a 3D camera location to a point in the Depth frame.
|
||||
*
|
||||
* @param CameraLocation The 3D Camera space coordinate to be remapped (in Unreal units)
|
||||
* @return The point location in the Depth frame that matches the Camera
|
||||
* location input (in pixels)
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Remapping", Meta = (Keywords = "convert coordinate space remap"))
|
||||
static FVector2D CameraLocationToDepthPoint(const FVector& CameraLocation);
|
||||
|
||||
/**
|
||||
* Creates a Color with depth point from a Color point only. Viewed from the
|
||||
* camera perspective, this point aligns with the Color frame without losing
|
||||
* it's depth.
|
||||
*
|
||||
* This method uses the remapped Color buffer in Depth space so, for it to
|
||||
* work, the Depth in Color Space frame must be in use.
|
||||
*
|
||||
* @param ColorLocation A point in the Color frame to be remapped (in pixels)
|
||||
* @return The 3D version of the Color point (in Unreal units)
|
||||
*/
|
||||
static NeoKinect::Vector3 ColorWithDepthFromColorOnly(const NeoKinect::Vector2& ColorLocation);
|
||||
|
||||
/**
|
||||
* Remaps a point location from the Depth frame to the Color frame.
|
||||
*
|
||||
* @param DepthPoint A point in the Depth frame (in pixels)
|
||||
* @return Remapped Depth frame point to a Color frame point (in pixels)
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Remapping", Meta = (Keywords = "convert coordinate space remap"))
|
||||
static FVector2D DepthPointToColorPoint(FVector2D DepthPoint);
|
||||
|
||||
/**
|
||||
* Remaps a point location from the Depth frame to the 3D camera space.
|
||||
*
|
||||
* @param DepthPoint A point in the Depth frame (in pixels)
|
||||
* @return Remapped Depth frame point to a 3D Camera location (in Unreal units)
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Remapping", Meta = (Keywords = "convert coordinate space remap"))
|
||||
static FVector DepthPointToCameraLocation(FVector2D DepthPoint);
|
||||
|
||||
/**
|
||||
* Remaps a point from the Color frame to the Depth frame.
|
||||
*
|
||||
* @param ColorPoint A point in the Color frame (in pixels)
|
||||
* @return Color point remapped to its related location in the Depth frame (in pixels)
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Remapping", Meta = (Keywords = "convert coordinate space remap"))
|
||||
static FVector2D ColorPointToDepthPoint(FVector2D ColorPoint);
|
||||
|
||||
|
||||
/*
|
||||
* TEXTURES (Color, Depth etc)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get a frame horizontal and vertical field of view.
|
||||
*
|
||||
* @param FrameType The frame type to request the FOV from.
|
||||
* @return x = horizontal FOV, y = vertical FOV
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Frames", Meta = (Keywords = "width height FOV texture angle field of view", DisplayName = "Get Kinect FOV"))
|
||||
static FVector2D GetFrameFieldOfView(EKinectFrame FrameType);
|
||||
|
||||
/**
|
||||
* Get a frame texture width and height in pixels.
|
||||
*
|
||||
* @param FrameType The frame type to request the size from.
|
||||
* @return x = width, y = height
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Frames", Meta = (Keywords = "width height texture resolution", DisplayName = "Get Kinect Frame Size"))
|
||||
static FIntPoint GetFrameSize(EKinectFrame FrameType);
|
||||
|
||||
/**
|
||||
* Enables or disables updating of a Kinect frame type.
|
||||
*
|
||||
* @param FrameType The frame type to enable/disable
|
||||
* @param bEnable If the selected frame type should be enabled
|
||||
* @return The Frame texture. Null if Enable = false.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Frames", Meta = (Keywords = "texture sensor camera enable disable toggle", DisplayName = "Set Use Kinect Frame"))
|
||||
static UTextureRenderTarget2D* SetUseFrame(EKinectFrame FrameType, bool bEnable);
|
||||
|
||||
/**
|
||||
* Returns if a Kinect frame type is enabled. If it is, it means you can get
|
||||
* it's texture with GetFrame.
|
||||
*
|
||||
* @param FrameType The frame type to ask for.
|
||||
* @return If FrameType is enabled or not.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Frames", Meta = (Keywords = "texture sensor camera enabled", DisplayName = "Get Is Using Kinect Frame"))
|
||||
static bool GetIsUsingFrame(EKinectFrame FrameType);
|
||||
|
||||
/**
|
||||
* Get the texture that represents the requested frame type.
|
||||
*
|
||||
* @param FrameType The frame type to get the texture from.
|
||||
* @return The texture that represents the requested frame type. Null if it has
|
||||
* not been enabled.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Frames", Meta = (Keywords = "texture sensor camera", DisplayName = "Get Kinect Frame"))
|
||||
static UTextureRenderTarget2D* GetFrame(EKinectFrame FrameType);
|
||||
|
||||
/**
|
||||
* Gets the depth value from a specific pixel on the Depth frame.
|
||||
*
|
||||
* @param Coordinate A point in the Depth frame (in pixels)
|
||||
* @return The Depth value (distance from the Kinect sensor) in the input point
|
||||
* (in centimeters)
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Frames", Meta = (Keywords = "sample texture sensor camera"))
|
||||
static float GetDepthFramePixel(FVector2D Coordinate);
|
||||
|
||||
/**
|
||||
* Gets the depth value from a specific pixel on the Color frame
|
||||
*
|
||||
* @param Coordinate A point in the Color frame (in pixels)
|
||||
* @return The Depth value (distance from the Kinect sensor) in the input point
|
||||
* (in centimeters)
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Frames", Meta = (Keywords = "sample texture remap"))
|
||||
static float GetDepthFromColorFramePixel(FVector2D Coordinate);
|
||||
|
||||
/**
|
||||
* Gets the color value from a specific pixel on the Color frame.
|
||||
*
|
||||
* @param Coordinate A point in the Color frame (in pixels)
|
||||
* @return The Color value in the input point
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Frames", Meta = (Keywords = "sample texture sensor camera"))
|
||||
static FLinearColor GetColorFramePixel(FVector2D Coordinate);
|
||||
|
||||
/*
|
||||
* BODIES / JOINTS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Array of all bodies (tracked and not tracked).
|
||||
* The bodies in the array are updated automatically, so you don't need to
|
||||
* request the array more than once.
|
||||
*
|
||||
* @return Bodies array.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body", meta = (DisplayName = "Get Kinect Bodies"))
|
||||
static TArray<UNeoKinectBody*> GetBodies();
|
||||
|
||||
/**
|
||||
* Array with only the currently tracked bodies.
|
||||
*
|
||||
* @return The currently tracked bodies.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body", meta = (DisplayName = "Get Kinect Tracked Bodies"))
|
||||
static TArray<UNeoKinectBody*> GetTrackedBodies();
|
||||
|
||||
/**
|
||||
* Gets tracked body whose Spine Base joint is nearest to the Kinect sensor.
|
||||
*
|
||||
* @param HasBody If there's at least one tracked body.
|
||||
* @return The nearest body from the sensor. Null if no bodies are tracked.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body", meta = (DisplayName = "Get Kinect Nearest Body"))
|
||||
static UNeoKinectBody* GetNearestBody(bool& HasBody);
|
||||
|
||||
/**
|
||||
* Toggle the use of Color texture aligned joint locations and orientations.
|
||||
*
|
||||
* Calculating these remapped transforms introduce a small overhead, so it's
|
||||
* disabled by default and reading the Color values from a Joint will return
|
||||
* Zero values until this is enabled.
|
||||
*
|
||||
* @param bUse Enable usage of Joints' Color space transforms?
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "NeoKinect|Body", meta = (Keywords = "joints remap"))
|
||||
static void SetUseJointsColorSpaceTransforms(const bool bUse);
|
||||
|
||||
/**
|
||||
* Return if Joints' Color space transforms usage is enabled
|
||||
*
|
||||
* @return True if Joints' Color space transforms usage is enabled
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body")
|
||||
static bool IsUsingJointsColorSpaceTransforms();
|
||||
|
||||
/**
|
||||
* Cast a Body in the bodies array to its index number.
|
||||
*
|
||||
* @param Body The body instance.
|
||||
* @return Body index.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body", Meta = (CompactNodeTitle = "->", Keywords = "convert cast"))
|
||||
static int32 BodyToIndex(const UNeoKinectBody* Body);
|
||||
|
||||
/**
|
||||
* Cast an index to a body from the bodies array.
|
||||
*
|
||||
* @param Index Index.
|
||||
* @return Body instance. If index > 5 or index < 0, it's the body at index 0.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body", Meta = (CompactNodeTitle = "->", Keywords = "convert cast"))
|
||||
static UNeoKinectBody* IndexToBody(const int32 Index);
|
||||
|
||||
/**
|
||||
* Cast the Joint type to its joint index number.
|
||||
*
|
||||
* @param Joint Joint type.
|
||||
* @return Index.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints", Meta = (CompactNodeTitle = "->", Keywords = "convert cast", BlueprintThreadSafe))
|
||||
static int32 JointToIndex(const EKinectJointType Joint);
|
||||
|
||||
/**
|
||||
* Cast a joint index to its Joint type.
|
||||
*
|
||||
* @param Index Index.
|
||||
* @return Joint type. If index >= joint count or index < 0, it's Spine Base joint.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Body|Joints", Meta = (CompactNodeTitle = "->", Keywords = "convert cast"))
|
||||
static EKinectJointType IndexToJoint(const int32 Index);
|
||||
|
||||
/*
|
||||
* FACE TRACKING
|
||||
*/
|
||||
|
||||
/**
|
||||
* Array of faces (tracked and not tracked). The faces instances are updated
|
||||
* automatically, so you don't need to request the array more than once.
|
||||
*
|
||||
* @return Faces array.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Face", meta = (DisplayName = "Get Kinect Faces"))
|
||||
static TArray<UNeoKinectFace*> GetFaces();
|
||||
|
||||
/**
|
||||
* Array with only the currently tracked faces.
|
||||
*
|
||||
* @return The currently tracked faces.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Face", meta = (DisplayName = "Get Kinect Tracked Faces"))
|
||||
static TArray<UNeoKinectFace*> GetTrackedFaces();
|
||||
|
||||
/**
|
||||
* Gets tracked face whose Head joint is nearest from the sensor.
|
||||
*
|
||||
* @param bHasAnyFace If there's at least one tracked face.
|
||||
* @return The nearest face from the sensor. Null if no faces are tracked.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Face", meta = (DisplayName = "Get Kinect Nearest Face"))
|
||||
static UNeoKinectFace* GetNearestFace(bool& bHasAnyFace);
|
||||
|
||||
/**
|
||||
* Cast a Face to its index number.
|
||||
*
|
||||
* @param Face The face instance.
|
||||
* @return Face index.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Face", Meta = (CompactNodeTitle = "->", Keywords = "convert cast"))
|
||||
static int32 FaceToIndex(const UNeoKinectFace* Face);
|
||||
|
||||
/**
|
||||
* Cast a face index to a Face object.
|
||||
*
|
||||
* @param Index Index.
|
||||
* @return Face instance. If index > 5 or index < 0, it's the face at index 0.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Face", Meta = (CompactNodeTitle = "->", Keywords = "convert cast"))
|
||||
static UNeoKinectFace* IndexToFace(const int32 Index);
|
||||
|
||||
/*
|
||||
* CONSTANTS
|
||||
*/
|
||||
|
||||
/**
|
||||
* The number of bodies the Kinect device can track simultaneously.
|
||||
*
|
||||
* @return The number of bodies the Kinect device can track simultaneously.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Constants", meta = (Keywords = "length number size capability"))
|
||||
static int32 GetTrackableBodyCount();
|
||||
|
||||
/**
|
||||
* The number of faces the Kinect device can track simultaneously.
|
||||
*
|
||||
* @return The number of faces the Kinect device can track simultaneously.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Constants", meta = (Keywords = "length number size capability"))
|
||||
static int32 GetTrackableFaceCount();
|
||||
|
||||
/**
|
||||
* The number of joints the Kinect device can track in each tracked body.
|
||||
*
|
||||
* @return The number of joints the Kinect device can track in each tracked body.
|
||||
*/
|
||||
UFUNCTION(BlueprintPure, Category = "NeoKinect|Constants", meta = (Keywords = "length number size capability"))
|
||||
static int32 GetJointCount();
|
||||
|
||||
/*////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BLUEPRINT FUNCTIONS END
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
|
||||
private:
|
||||
/** NeoKinect API sensor */
|
||||
static NeoKinect::KinectSensor* Kinect;
|
||||
/** Does the sensor polling */
|
||||
static FKinectThread* KinectThread;
|
||||
/** FTicker handle so we can stop ticking after disconnecting from the sensor */
|
||||
static FTSTicker::FDelegateHandle TickerHandle;
|
||||
|
||||
//TODO: figure out a way to know when a level is unloaded
|
||||
//static bool bAutoShutdown;
|
||||
|
||||
/** Should we read and update the bodies data each frame? */
|
||||
static bool bUsingBodyFrame;
|
||||
/** Should we remap the bodies transforms into 3D Color space each frame? */
|
||||
static bool bUsingJointsColorSpaceTransforms;
|
||||
/** Should we read and update the faces data each frame? */
|
||||
static bool bUsingFaceFrame;
|
||||
|
||||
/** Initialize the bodies, faces and frames arrays */
|
||||
static void InitStatics();
|
||||
/** Updates bodies, faces and frames each frame */
|
||||
static bool OnTick(float DeltaTime);
|
||||
|
||||
static bool IsUsingDepth();
|
||||
static bool IsUsingBodyIndex();
|
||||
static bool IsUsingColor();
|
||||
/** Creates a 2D dynamic texture for frames usage */
|
||||
static UTextureRenderTarget2D* CreateTexture(int32 Width, int32 Height, EPixelFormat PixelFormat, bool sRGB);
|
||||
/** Updates all currently enabled frames. Executed in the Render thread */
|
||||
static void UpdateFrames();
|
||||
/** Delete frames textures memory */
|
||||
static void ReleaseFrameResources(FFrameTextureData&);
|
||||
|
||||
/** Enable/disable bodies frame reading */
|
||||
static void SetUseBodyFrame(bool bUse = true);
|
||||
/** Converts bodies joints transforms to Unreal coordinate space */
|
||||
static void ProcessBodies(const NeoKinect::KinectBody* KBodies);
|
||||
/** Zero all bodies values. Used when disconnecting from the sensor */
|
||||
static void ResetBodies();
|
||||
|
||||
/** Enable/disable faces frame reading */
|
||||
static void SetUseFaceFrame(bool bUse = true);
|
||||
/** Converts faces points transforms to Unreal coordinate space */
|
||||
static void ProcessFaces(const NeoKinect::KinectFace* KFaces);
|
||||
/** Zero all faces values. Used when disconnecting from the sensor */
|
||||
static void ResetFaces();
|
||||
|
||||
UFUNCTION()
|
||||
void BodyBeginTrackBroadcast(int32 BodyIndex);
|
||||
UFUNCTION()
|
||||
void BodyLostBroadcast(int32 BodyIndex);
|
||||
UFUNCTION()
|
||||
void FaceBeginTrackBroadcast(int32 FaceIndex);
|
||||
UFUNCTION()
|
||||
void FaceLostBroadcast(int32 FaceIndex);
|
||||
};
|
||||
+3096
File diff suppressed because it is too large
Load Diff
+298
@@ -0,0 +1,298 @@
|
||||
|
||||
|
||||
/* this ALWAYS GENERATED file contains the definitions for the interfaces */
|
||||
|
||||
|
||||
/* File created by MIDL compiler version 8.00.0595 */
|
||||
/* at Sun Oct 19 12:54:09 2014
|
||||
*/
|
||||
/* Compiler settings for ..\..\idl\Kinect.INPC.idl:
|
||||
Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0595
|
||||
protocol : dce , ms_ext, c_ext, robust
|
||||
error checks: allocation ref bounds_check enum stub_data
|
||||
VC __declspec() decoration level:
|
||||
__declspec(uuid()), __declspec(selectany), __declspec(novtable)
|
||||
DECLSPEC_UUID(), MIDL_INTERFACE()
|
||||
*/
|
||||
/* @@MIDL_FILE_HEADING( ) */
|
||||
|
||||
#pragma warning( disable: 4049 ) /* more than 64k source lines */
|
||||
|
||||
|
||||
/* verify that the <rpcndr.h> version is high enough to compile this file*/
|
||||
#ifndef __REQUIRED_RPCNDR_H_VERSION__
|
||||
#define __REQUIRED_RPCNDR_H_VERSION__ 475
|
||||
#endif
|
||||
|
||||
/* verify that the <rpcsal.h> version is high enough to compile this file*/
|
||||
#ifndef __REQUIRED_RPCSAL_H_VERSION__
|
||||
#define __REQUIRED_RPCSAL_H_VERSION__ 100
|
||||
#endif
|
||||
|
||||
#include "rpc.h"
|
||||
#include "rpcndr.h"
|
||||
|
||||
#ifndef __RPCNDR_H_VERSION__
|
||||
#error this stub requires an updated version of <rpcndr.h>
|
||||
#endif // __RPCNDR_H_VERSION__
|
||||
|
||||
#ifndef COM_NO_WINDOWS_H
|
||||
#include "windows.h"
|
||||
#include "ole2.h"
|
||||
#endif /*COM_NO_WINDOWS_H*/
|
||||
|
||||
#ifndef __Kinect2EINPC_h__
|
||||
#define __Kinect2EINPC_h__
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
/* Forward Declarations */
|
||||
|
||||
#ifndef __INotifyPropertyChanged_FWD_DEFINED__
|
||||
#define __INotifyPropertyChanged_FWD_DEFINED__
|
||||
typedef interface INotifyPropertyChanged INotifyPropertyChanged;
|
||||
|
||||
#endif /* __INotifyPropertyChanged_FWD_DEFINED__ */
|
||||
|
||||
|
||||
#ifndef __IPropertyChangedEventArgs_FWD_DEFINED__
|
||||
#define __IPropertyChangedEventArgs_FWD_DEFINED__
|
||||
typedef interface IPropertyChangedEventArgs IPropertyChangedEventArgs;
|
||||
|
||||
#endif /* __IPropertyChangedEventArgs_FWD_DEFINED__ */
|
||||
|
||||
|
||||
/* header files for imported files */
|
||||
#include "oaidl.h"
|
||||
#include "ocidl.h"
|
||||
#include "mmreg.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
|
||||
/* interface __MIDL_itf_Kinect2EINPC_0000_0000 */
|
||||
/* [local] */
|
||||
|
||||
|
||||
typedef INT_PTR WAITABLE_HANDLE;
|
||||
|
||||
typedef INT64 TIMESPAN;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern RPC_IF_HANDLE __MIDL_itf_Kinect2EINPC_0000_0000_v0_0_c_ifspec;
|
||||
extern RPC_IF_HANDLE __MIDL_itf_Kinect2EINPC_0000_0000_v0_0_s_ifspec;
|
||||
|
||||
#ifndef __INotifyPropertyChanged_INTERFACE_DEFINED__
|
||||
#define __INotifyPropertyChanged_INTERFACE_DEFINED__
|
||||
|
||||
/* interface INotifyPropertyChanged */
|
||||
/* [object][local][uuid] */
|
||||
|
||||
|
||||
EXTERN_C const IID IID_INotifyPropertyChanged;
|
||||
|
||||
#if defined(__cplusplus) && !defined(CINTERFACE)
|
||||
|
||||
MIDL_INTERFACE("D27A5C77-32E9-4283-A046-9D693E29E3E7")
|
||||
INotifyPropertyChanged : public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE SubscribePropertyChanged(
|
||||
/* [annotation][out][retval] */
|
||||
_Out_ WAITABLE_HANDLE *waitableHandle) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE UnsubscribePropertyChanged(
|
||||
/* [annotation][in] */
|
||||
_In_ WAITABLE_HANDLE waitableHandle) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE GetPropertyChangedEventData(
|
||||
/* [annotation][in] */
|
||||
_In_ WAITABLE_HANDLE waitableHandle,
|
||||
UINT bufferSize,
|
||||
/* [annotation][out][retval] */
|
||||
_Out_writes_z_(bufferSize) WCHAR *propertyName) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#else /* C style interface */
|
||||
|
||||
typedef struct INotifyPropertyChangedVtbl
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
|
||||
INotifyPropertyChanged * This,
|
||||
/* [in] */ REFIID riid,
|
||||
/* [annotation][iid_is][out] */
|
||||
_COM_Outptr_ void **ppvObject);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *AddRef )(
|
||||
INotifyPropertyChanged * This);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *Release )(
|
||||
INotifyPropertyChanged * This);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *SubscribePropertyChanged )(
|
||||
INotifyPropertyChanged * This,
|
||||
/* [annotation][out][retval] */
|
||||
_Out_ WAITABLE_HANDLE *waitableHandle);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *UnsubscribePropertyChanged )(
|
||||
INotifyPropertyChanged * This,
|
||||
/* [annotation][in] */
|
||||
_In_ WAITABLE_HANDLE waitableHandle);
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *GetPropertyChangedEventData )(
|
||||
INotifyPropertyChanged * This,
|
||||
/* [annotation][in] */
|
||||
_In_ WAITABLE_HANDLE waitableHandle,
|
||||
UINT bufferSize,
|
||||
/* [annotation][out][retval] */
|
||||
_Out_writes_z_(bufferSize) WCHAR *propertyName);
|
||||
|
||||
END_INTERFACE
|
||||
} INotifyPropertyChangedVtbl;
|
||||
|
||||
interface INotifyPropertyChanged
|
||||
{
|
||||
CONST_VTBL struct INotifyPropertyChangedVtbl *lpVtbl;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef COBJMACROS
|
||||
|
||||
|
||||
#define INotifyPropertyChanged_QueryInterface(This,riid,ppvObject) \
|
||||
( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
|
||||
|
||||
#define INotifyPropertyChanged_AddRef(This) \
|
||||
( (This)->lpVtbl -> AddRef(This) )
|
||||
|
||||
#define INotifyPropertyChanged_Release(This) \
|
||||
( (This)->lpVtbl -> Release(This) )
|
||||
|
||||
|
||||
#define INotifyPropertyChanged_SubscribePropertyChanged(This,waitableHandle) \
|
||||
( (This)->lpVtbl -> SubscribePropertyChanged(This,waitableHandle) )
|
||||
|
||||
#define INotifyPropertyChanged_UnsubscribePropertyChanged(This,waitableHandle) \
|
||||
( (This)->lpVtbl -> UnsubscribePropertyChanged(This,waitableHandle) )
|
||||
|
||||
#define INotifyPropertyChanged_GetPropertyChangedEventData(This,waitableHandle,bufferSize,propertyName) \
|
||||
( (This)->lpVtbl -> GetPropertyChangedEventData(This,waitableHandle,bufferSize,propertyName) )
|
||||
|
||||
#endif /* COBJMACROS */
|
||||
|
||||
|
||||
#endif /* C style interface */
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* __INotifyPropertyChanged_INTERFACE_DEFINED__ */
|
||||
|
||||
|
||||
#ifndef __IPropertyChangedEventArgs_INTERFACE_DEFINED__
|
||||
#define __IPropertyChangedEventArgs_INTERFACE_DEFINED__
|
||||
|
||||
/* interface IPropertyChangedEventArgs */
|
||||
/* [object][local][uuid] */
|
||||
|
||||
|
||||
EXTERN_C const IID IID_IPropertyChangedEventArgs;
|
||||
|
||||
#if defined(__cplusplus) && !defined(CINTERFACE)
|
||||
|
||||
MIDL_INTERFACE("574E9321-9DD9-41C8-BC51-C11F3F38D6B5")
|
||||
IPropertyChangedEventArgs : public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_PropertyName(
|
||||
UINT bufferSize,
|
||||
/* [annotation][out][retval] */
|
||||
_Out_writes_z_(bufferSize) WCHAR *propertyName) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#else /* C style interface */
|
||||
|
||||
typedef struct IPropertyChangedEventArgsVtbl
|
||||
{
|
||||
BEGIN_INTERFACE
|
||||
|
||||
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
|
||||
IPropertyChangedEventArgs * This,
|
||||
/* [in] */ REFIID riid,
|
||||
/* [annotation][iid_is][out] */
|
||||
_COM_Outptr_ void **ppvObject);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *AddRef )(
|
||||
IPropertyChangedEventArgs * This);
|
||||
|
||||
ULONG ( STDMETHODCALLTYPE *Release )(
|
||||
IPropertyChangedEventArgs * This);
|
||||
|
||||
/* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_PropertyName )(
|
||||
IPropertyChangedEventArgs * This,
|
||||
UINT bufferSize,
|
||||
/* [annotation][out][retval] */
|
||||
_Out_writes_z_(bufferSize) WCHAR *propertyName);
|
||||
|
||||
END_INTERFACE
|
||||
} IPropertyChangedEventArgsVtbl;
|
||||
|
||||
interface IPropertyChangedEventArgs
|
||||
{
|
||||
CONST_VTBL struct IPropertyChangedEventArgsVtbl *lpVtbl;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef COBJMACROS
|
||||
|
||||
|
||||
#define IPropertyChangedEventArgs_QueryInterface(This,riid,ppvObject) \
|
||||
( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
|
||||
|
||||
#define IPropertyChangedEventArgs_AddRef(This) \
|
||||
( (This)->lpVtbl -> AddRef(This) )
|
||||
|
||||
#define IPropertyChangedEventArgs_Release(This) \
|
||||
( (This)->lpVtbl -> Release(This) )
|
||||
|
||||
|
||||
#define IPropertyChangedEventArgs_get_PropertyName(This,bufferSize,propertyName) \
|
||||
( (This)->lpVtbl -> get_PropertyName(This,bufferSize,propertyName) )
|
||||
|
||||
#endif /* COBJMACROS */
|
||||
|
||||
|
||||
#endif /* C style interface */
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* __IPropertyChangedEventArgs_INTERFACE_DEFINED__ */
|
||||
|
||||
|
||||
/* Additional Prototypes for ALL interfaces */
|
||||
|
||||
/* end of Additional Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+10667
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
BIN
Binary file not shown.
+68
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "NuiSensor.h"
|
||||
#include "Lockable.h"
|
||||
|
||||
namespace Xbox { namespace Kinect { class NuiSensor; } }
|
||||
|
||||
class KinectExposure
|
||||
{
|
||||
public:
|
||||
KinectExposure() = default;
|
||||
|
||||
// Fully automatic exposure setting.
|
||||
// Exposure compensation: negative value gives an underexposed image,
|
||||
// positive gives an overexposed image.
|
||||
void SetAutoExposure(float exposure_compensation = 0);
|
||||
|
||||
// Sets a pseudo-exposure time in ms, value in range [0.0, 640] ms.
|
||||
//
|
||||
// The actual frame integration time is set to a multiple of fluorescent light period
|
||||
// that is shorter than the requested time e.g. requesting 16 ms will set 10 ms
|
||||
// in Australia (100Hz), 8.33 ms in USA (120Hz).
|
||||
// The gain is automatically set to compensate for the reduced integration time.
|
||||
//
|
||||
// Requesting less than a single fluorescent light period will set the integration time
|
||||
// to the requested value.
|
||||
//
|
||||
// To set the shortest non-flickering integration period for any country, simply set
|
||||
// a pseudo-exposure time of between (10.0, 16.667) ms, which will automatically drop
|
||||
// the integration time to 10 or 8.3 ms depending on country, while setting the analog
|
||||
// gain control to a brighter value.
|
||||
void SetSemiAutoExposure(float pseudo_exposure_time_ms);
|
||||
|
||||
// Manually set true exposure time and analog gain.
|
||||
void SetManualExposure(float integration_time_ms, float analog_gain);
|
||||
|
||||
// Use one of the SET commands.
|
||||
void SetFloat(Xbox::Kinect::NUISENSOR_RGB_COMMAND_TYPE command, float value);
|
||||
void SetUint(Xbox::Kinect::NUISENSOR_RGB_COMMAND_TYPE command, uint32_t value);
|
||||
|
||||
// Use one of the GET commands.
|
||||
uint32_t GetCommand(Xbox::Kinect::NUISENSOR_RGB_COMMAND_TYPE command);
|
||||
float GetCommandFloat(Xbox::Kinect::NUISENSOR_RGB_COMMAND_TYPE command);
|
||||
|
||||
private:
|
||||
LockableSharedPtr<Xbox::Kinect::NuiSensor> _sensor;
|
||||
|
||||
void Connect();
|
||||
|
||||
//private Dictionary<NUISENSOR_RGB_COMMAND_TYPE, uint> GetCommands(NUISENSOR_RGB_COMMAND_TYPE[] commands)
|
||||
//{
|
||||
// NUISENSOR_RGB_CHANGE_STREAM_SETTING setting;
|
||||
// NUISENSOR_RGB_CHANGE_STREAM_SETTING_REPLY reply;
|
||||
|
||||
// setting.SequenceId = 0;
|
||||
// setting.Commands = commands.Select(command = > new NUISENSOR_RGB_CHANGE_SETTING_CMD{ Cmd = (uint)command, Arg = 0 }).ToArray();
|
||||
|
||||
// lock(_sensor)
|
||||
// {
|
||||
// _sensor.ColorChangeCameraSettings(ref setting, out reply);
|
||||
// }
|
||||
|
||||
// return commands.Zip(reply.Status, (c, r) = > { return Tuple.Create(c, r.Data); }).ToDictionary(t = > t.Item1, t = > t.Item2);
|
||||
//}
|
||||
|
||||
uint32_t SetCommand(Xbox::Kinect::NUISENSOR_RGB_COMMAND_TYPE command, uint32_t argument);
|
||||
void SetCommand(Xbox::Kinect::NUISENSOR_RGB_COMMAND_TYPE command, float argument);
|
||||
};
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
#ifndef LOCKABLE_H_
|
||||
#define LOCKABLE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
// Acts like a pointer to the locked object, but holds a lock for the given variable.
|
||||
template<typename T>
|
||||
class Locked
|
||||
{
|
||||
public:
|
||||
Locked(T& obj, std::mutex& mutex) : _obj(obj), _mutex(mutex) { _mutex.lock(); }
|
||||
Locked& operator=(const Locked&) = delete;
|
||||
~Locked() { _mutex.unlock(); }
|
||||
// Access members of the locked value.
|
||||
const T* operator->() const noexcept { return &_obj; }
|
||||
// Access members of the locked value.
|
||||
T* operator->() noexcept { return &_obj; }
|
||||
// Access the locked value.
|
||||
const T& operator*() const noexcept { return _obj; }
|
||||
// Access the locked value.
|
||||
T& operator*() noexcept { return _obj; }
|
||||
|
||||
private:
|
||||
T& _obj;
|
||||
std::mutex& _mutex;
|
||||
};
|
||||
|
||||
// Lockable value type.
|
||||
template<typename T>
|
||||
class Lockable
|
||||
{
|
||||
public:
|
||||
// Only exists if T() exists.
|
||||
Lockable() = default;
|
||||
explicit Lockable(T obj) : _obj(std::move(obj)) {}
|
||||
// Lock-guards the value for the lifetime of the returned object.
|
||||
auto lock() const noexcept { return Locked<const T>(_obj, _mutex); }
|
||||
// Lock-guards the value for the lifetime of the returned object.
|
||||
auto lock() noexcept { return Locked<T>(_obj, _mutex); }
|
||||
|
||||
private:
|
||||
T _obj;
|
||||
mutable std::mutex _mutex;
|
||||
};
|
||||
|
||||
|
||||
// Acts like a shared_ptr, but holds a lock for the given pointer.
|
||||
template<typename TPtr>
|
||||
class LockedPtr
|
||||
{
|
||||
public:
|
||||
LockedPtr(TPtr& obj, std::mutex& mutex) : _obj(obj), _mutex(mutex) { _mutex.lock(); }
|
||||
LockedPtr& operator=(const LockedPtr&) = delete;
|
||||
~LockedPtr() { _mutex.unlock(); }
|
||||
// Access members of the locked shared_ptr.
|
||||
auto* operator->() const noexcept { return _obj.get(); }
|
||||
// Dereference the locked shared_ptr.
|
||||
auto& operator*() const noexcept { return *_obj; }
|
||||
// Test if the locked shared_ptr is null.
|
||||
explicit operator bool() const noexcept { return bool(_obj); }
|
||||
// Assign to the locked shared_ptr (assigns the shared_ptr, not the inner T value).
|
||||
void operator=(TPtr obj) { _obj = std::move(obj); }
|
||||
// Reset the locked shared_ptr.
|
||||
void reset() noexcept { _obj.reset(); }
|
||||
// Get the pointer type.
|
||||
// WARNING: this is potentially unsafe since the data can be passed around unlocked.
|
||||
TPtr value() const noexcept { return _obj; }
|
||||
|
||||
private:
|
||||
TPtr& _obj;
|
||||
std::mutex& _mutex;
|
||||
};
|
||||
|
||||
// Lockable templated pointer type.
|
||||
template<typename TPtr>
|
||||
class LockablePtr
|
||||
{
|
||||
public:
|
||||
LockablePtr()
|
||||
: _obj()
|
||||
, _mutex(std::make_shared<std::mutex>())
|
||||
{
|
||||
}
|
||||
explicit LockablePtr(TPtr obj)
|
||||
: _obj(std::move(obj))
|
||||
, _mutex(std::make_shared<std::mutex>())
|
||||
{
|
||||
}
|
||||
// Lock-guards the pointer for the lifetime of the returned object.
|
||||
auto lock() const noexcept { return LockedPtr<const TPtr>(_obj, *_mutex); }
|
||||
// Lock-guards the pointer for the lifetime of the returned object.
|
||||
auto lock() noexcept { return LockedPtr<TPtr>(_obj, *_mutex); }
|
||||
|
||||
private:
|
||||
TPtr _obj;
|
||||
mutable std::shared_ptr<std::mutex> _mutex; // Shared so object is copyable e.g. TPtr is shared_ptr<T>
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
using LockableSharedPtr = LockablePtr<std::shared_ptr<T>>;
|
||||
|
||||
template<typename T>
|
||||
using LockableUniquePtr = LockablePtr<std::unique_ptr<T>>;
|
||||
|
||||
#endif // LOCKABLE_H_
|
||||
+479
@@ -0,0 +1,479 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <Ole2.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Kinect.h>
|
||||
#include <Kinect.Face.h>
|
||||
|
||||
#include <KinectExposure.h>
|
||||
|
||||
namespace NeoKinect
|
||||
{
|
||||
constexpr unsigned int KinectColorWidth = 1920;
|
||||
constexpr unsigned int KinectColorHeight = 1080;
|
||||
|
||||
constexpr unsigned int KinectDepthWidth = 512;
|
||||
constexpr unsigned int KinectDepthHeight = 424;
|
||||
|
||||
constexpr unsigned int KinectBodyCount = BODY_COUNT;
|
||||
constexpr unsigned int KinectJointCount = JointType_Count;
|
||||
|
||||
struct Vector2
|
||||
{
|
||||
float x, y;
|
||||
|
||||
Vector2() : x(0.f), y(0.f) {}
|
||||
Vector2(float xy) : x(xy), y(xy) {}
|
||||
Vector2(float x, float y) : x(x), y(y) {}
|
||||
explicit Vector2(const DepthSpacePoint& dsp) : x(dsp.X), y(dsp.Y) {}
|
||||
explicit Vector2(const ColorSpacePoint& csp) : x(csp.X), y(csp.Y) {}
|
||||
explicit Vector2(const PointF& pf) : x(pf.X), y(pf.Y) {}
|
||||
|
||||
template<typename T>
|
||||
inline Vector2& operator=(const T& b);
|
||||
|
||||
inline DepthSpacePoint toDepthSpacePoint() const;
|
||||
inline ColorSpacePoint toColorSpacePoint() const;
|
||||
};
|
||||
|
||||
struct Vector3
|
||||
{
|
||||
float x, y, z;
|
||||
|
||||
Vector3() : x(0.f), y(0.f), z(0.f) {}
|
||||
Vector3(float xyz) : x(xyz), y(xyz), z(xyz) {}
|
||||
Vector3(float x, float y, float z) : x(x), y(y), z(z) {}
|
||||
explicit Vector3(const CameraSpacePoint& csp) : x(csp.X), y(csp.Y), z(csp.Z) {}
|
||||
|
||||
inline Vector3& operator=(const CameraSpacePoint& b);
|
||||
inline Vector3& operator/=(const float& b);
|
||||
inline const Vector3 operator/(const float& b) const;
|
||||
inline Vector3& operator*=(const float& b);
|
||||
inline const Vector3 operator*(const float& b) const;
|
||||
|
||||
inline bool IsZero() const;
|
||||
float magnitude() const; // not inline as it uses math header and I didn't want to polute the headers
|
||||
inline Vector3 normalized() const;
|
||||
|
||||
inline CameraSpacePoint toCameraSpacePoint() const;
|
||||
};
|
||||
|
||||
enum class KinectFrameType : BYTE
|
||||
{
|
||||
Color = 0,
|
||||
Depth = 1,
|
||||
Body = 2,
|
||||
BodyIndex = 3,
|
||||
Infrared = 4,
|
||||
LongExposureInfrared = 5,
|
||||
Face = 6,
|
||||
Count = 7
|
||||
};
|
||||
|
||||
enum class KinectCoordinateSpace : BYTE
|
||||
{
|
||||
Camera = 0,
|
||||
Depth = 1,
|
||||
Color = 2,
|
||||
Count = 3
|
||||
};
|
||||
|
||||
enum class KinectPixelFormat : BYTE
|
||||
{
|
||||
B8G8R8A8 = 0,
|
||||
G8 = 1,
|
||||
G16 = 2,
|
||||
Bayer = 3,
|
||||
None = 4,
|
||||
Count = 5
|
||||
};
|
||||
|
||||
struct KinectJoint
|
||||
{
|
||||
Vector4 orientation;
|
||||
CameraSpacePoint position;
|
||||
TrackingState trackingState;
|
||||
JointType type;
|
||||
};
|
||||
|
||||
struct KinectBodyEdges
|
||||
{
|
||||
bool left, right, top, bottom;
|
||||
};
|
||||
|
||||
struct KinectBody
|
||||
{
|
||||
UINT64 trackingId;
|
||||
bool isTracked, isRestricted;
|
||||
|
||||
KinectBodyEdges clippedEdges;
|
||||
|
||||
HandState handLeftState;
|
||||
TrackingState handLeftTrackingState;
|
||||
|
||||
HandState handRightState;
|
||||
TrackingState handRightTrackingState;
|
||||
|
||||
TrackingState leanTrackingState;
|
||||
Vector2 lean;
|
||||
|
||||
KinectJoint joints[JointType_Count];
|
||||
};
|
||||
|
||||
struct KinectFacePoints
|
||||
{
|
||||
Vector2 leftEye;
|
||||
Vector2 rightEye;
|
||||
Vector2 nose;
|
||||
Vector2 leftMouthCorner;
|
||||
Vector2 rightMouthCorner;
|
||||
};
|
||||
|
||||
struct KinectFace
|
||||
{
|
||||
UINT64 trackingId;
|
||||
// face bounding box in color space
|
||||
RectI boxColor;
|
||||
// face bounding box in infrared space
|
||||
RectI boxInfrared;
|
||||
// face rotation in quaternion
|
||||
Vector4 rotation;
|
||||
// face pivot point. The same as the skeleton head joint. It's here for conveninence.
|
||||
CameraSpacePoint pivot;
|
||||
// face alignment points in color space
|
||||
KinectFacePoints pointsColor;
|
||||
// face alignment points in infrared space
|
||||
KinectFacePoints pointsInfrared;
|
||||
|
||||
DetectionResult isEngaged;
|
||||
DetectionResult isHappy;
|
||||
DetectionResult isLookingAway;
|
||||
DetectionResult isMouthMoved;
|
||||
DetectionResult isMouthOpen;
|
||||
DetectionResult isLeftEyeClosed;
|
||||
DetectionResult isRightEyeClosed;
|
||||
DetectionResult isWearingGlasses;
|
||||
|
||||
bool bIsTracked;
|
||||
};
|
||||
|
||||
struct FrameDescription
|
||||
{
|
||||
bool valid;
|
||||
|
||||
float diagonalFieldOfView,
|
||||
horizontalFieldOfView,
|
||||
verticalFieldOfView;
|
||||
|
||||
UINT bytesPerPixel;
|
||||
UINT lengthInPixels;
|
||||
int width, height;
|
||||
|
||||
FrameDescription() : valid(false) {}
|
||||
};
|
||||
|
||||
class KinectSensor
|
||||
{
|
||||
public:
|
||||
KinectSensor();
|
||||
~KinectSensor();
|
||||
|
||||
/*
|
||||
Opens the Microsoft API to the sensor.
|
||||
@return Is the sensor API working?
|
||||
*/
|
||||
bool InitSensor();
|
||||
/*
|
||||
Is the sensor on already?
|
||||
It may take some time for the sensor to effectivelly turn on. Keep trying.
|
||||
If it's taking too long, there's probably no connected sensor or it's not working.
|
||||
@return True if the sensor is on.
|
||||
*/
|
||||
bool IsSensorAvailable();
|
||||
/*
|
||||
Is the Microsoft Kinect API responding?
|
||||
@return True if the sensor API is working.
|
||||
*/
|
||||
bool IsSensorOpen();
|
||||
/*
|
||||
Shuts the sensor down and closes the Microsoft API to it.
|
||||
@return True if it worked.
|
||||
*/
|
||||
bool UninitSensor();
|
||||
|
||||
|
||||
/*
|
||||
A Vector4 containing the floor normal (xyz) and height (w).
|
||||
Valid only if frequently locking and unlocking Body frame. That's when
|
||||
it gets updated.
|
||||
@return A Vector4 containing the floor normal (xyz) and height (w).
|
||||
*/
|
||||
Vector4 GetFloorClipPlane();
|
||||
/*
|
||||
Uses the floor clip plane to calculate how much the sensor is tilted.
|
||||
@return The sensor tilt in degrees. Looking down gives negative values.
|
||||
*/
|
||||
float GetSensorTilt();
|
||||
|
||||
FrameDescription GetFrameDescription(const KinectFrameType frameType) const;
|
||||
|
||||
bool SetUseFrame(const KinectFrameType frameType, const bool use = true);
|
||||
bool GetIsUsingFrame(const KinectFrameType frameType) const;
|
||||
bool LockLatestFrame(KinectFrameType frameType);
|
||||
void UnlockLatestFrame(KinectFrameType frameType);
|
||||
bool GetIsFrameLocked(KinectFrameType frameType) const;
|
||||
bool GetLatestFrameData(const KinectFrameType frameType, BYTE *& buffer, const KinectPixelFormat pixelFormat = KinectPixelFormat::None);
|
||||
bool GetLatestFrameData(KinectBody bodies[BODY_COUNT]);
|
||||
bool GetLatestFrameData(KinectFace faces[BODY_COUNT]);
|
||||
|
||||
/*
|
||||
Gets a frame remapped to another coordinate system.
|
||||
All the remapping methods depend on the Depth frame. So make sure you're
|
||||
frequently locking and unlocking it.
|
||||
@return True if it worked.
|
||||
*/
|
||||
bool GetRemappedFrameData(
|
||||
const KinectFrameType frameType, const KinectCoordinateSpace targetSpace,
|
||||
BYTE *const buffer, const KinectPixelFormat pixelFormat);
|
||||
/*
|
||||
Gets a point remapped to another coordinate system.
|
||||
All the remapping methods depend on the Depth frame. So make sure you're
|
||||
frequently locking and unlocking it.
|
||||
@return True if it worked.
|
||||
*/
|
||||
bool GetRemappedPoint(
|
||||
const KinectCoordinateSpace fromSpace, const KinectCoordinateSpace toSpace,
|
||||
const Vector2& srcPoint, Vector2& resultPoint);
|
||||
bool GetRemappedPoint(
|
||||
const KinectCoordinateSpace fromSpace, const KinectCoordinateSpace toSpace,
|
||||
const Vector2& srcPoint, Vector3& resultPoint) const;
|
||||
bool GetRemappedPoint(
|
||||
const KinectCoordinateSpace fromSpace, const KinectCoordinateSpace toSpace,
|
||||
const Vector3& srcPoint, Vector2& resultPoint) const;
|
||||
|
||||
/*
|
||||
Samples distance from the Depth frame.
|
||||
The pixel used will be the round result of X and Y.
|
||||
Note: this only works if the Depth frame is used and is being locked and
|
||||
unlocked frequently.
|
||||
*/
|
||||
UINT16 SampleDepthFrame(const Vector2& point);
|
||||
/*
|
||||
Samples distance from the Depth frame using a coordinate from the Color frame.
|
||||
The pixel used will be the round result of X and Y after remapped to the Depth frame.
|
||||
Note: this only works if the 'Depth' and 'Depth remapped to Color' frames are both
|
||||
used and are being locked and unlocked frequently.
|
||||
*/
|
||||
UINT16 SampleDepthFromColorCoords(const Vector2& colorPoint);
|
||||
|
||||
/*
|
||||
Fully automatic exposure setting.
|
||||
@param exposureCompensation Negative value gives an underexposed image,
|
||||
positive gives an overexposed image.
|
||||
*/
|
||||
void SetAutoExposure(float exposureCompensation = 0);
|
||||
|
||||
/*
|
||||
Sets a pseudo-exposure time in ms.
|
||||
|
||||
The actual frame integration time is set to a multiple of fluorescent light period
|
||||
that is shorter than the requested time e.g. requesting 16 ms will set 10 ms
|
||||
in Australia (100Hz), 8.33 ms in USA (120Hz).
|
||||
The gain is automatically set to compensate for the reduced integration time.
|
||||
|
||||
Requesting less than a single fluorescent light period will set the integration time
|
||||
to the requested value.
|
||||
|
||||
To set the shortest non-flickering integration period for any country, simply set
|
||||
a pseudo-exposure time of between (10.0, 16.667) ms, which will automatically drop
|
||||
the integration time to 10 or 8.3 ms depending on country, while setting the analog
|
||||
gain control to a brighter value.
|
||||
|
||||
@param pseudoExposureTime Pseudo-exposure time in ms. [0.0, 640]ms
|
||||
*/
|
||||
void SetSemiAutoExposure(float pseudoExposureTime);
|
||||
|
||||
/*
|
||||
Manually set true exposure time and analog gain.
|
||||
@param frameExposureTime Time of exposure for each frame, in ms. [0.0, 640]ms
|
||||
@param analogGain Exposure analog gain.
|
||||
*/
|
||||
void SetManualExposure(float frameExposureTime, float analogGain);
|
||||
|
||||
private:
|
||||
IKinectSensor *pSensor; // Kinect sensor
|
||||
//IMultiSourceFrameReader *pMultiFrameReader;
|
||||
//IMultiSourceFrame *pMultiFrame;
|
||||
|
||||
KinectExposure exposureControl;
|
||||
|
||||
// Frame types
|
||||
#define FRAME_VAR(name) I ##name## Frame *p ##name## Frame; I ##name## FrameReader *p ##name## FrameReader;
|
||||
FRAME_VAR(Body);
|
||||
FRAME_VAR(BodyIndex);
|
||||
FRAME_VAR(Color);
|
||||
FRAME_VAR(Depth);
|
||||
FRAME_VAR(Infrared);
|
||||
FRAME_VAR(LongExposureInfrared);
|
||||
#undef FRAME_VAR
|
||||
|
||||
// Face frame resources
|
||||
/* Features we'll use from face frames */
|
||||
static const DWORD cFaceFrameFeatures =
|
||||
FaceFrameFeatures_FaceEngagement
|
||||
| FaceFrameFeatures_Happy
|
||||
| FaceFrameFeatures_LookingAway
|
||||
| FaceFrameFeatures_Glasses
|
||||
| FaceFrameFeatures_LeftEyeClosed
|
||||
| FaceFrameFeatures_RightEyeClosed
|
||||
| FaceFrameFeatures_MouthMoved
|
||||
| FaceFrameFeatures_MouthOpen
|
||||
| FaceFrameFeatures_RotationOrientation
|
||||
| FaceFrameFeatures_PointsInColorSpace
|
||||
| FaceFrameFeatures_PointsInInfraredSpace
|
||||
| FaceFrameFeatures_BoundingBoxInColorSpace
|
||||
| FaceFrameFeatures_BoundingBoxInInfraredSpace;
|
||||
IFaceFrameSource *pFaceFrameSources[BODY_COUNT];
|
||||
IFaceFrameReader *pFaceFrameReaders[BODY_COUNT];
|
||||
IFaceFrame *pFaceFrames[BODY_COUNT];
|
||||
|
||||
// Converts between depth, color and 3d coords
|
||||
ICoordinateMapper *pMapper;
|
||||
DepthSpacePoint *pColorMappedToDepth;
|
||||
bool bIsColorMappedToDepthDirty;
|
||||
/* We keep a copy of the latest depth frame so the user can convert points
|
||||
between spaces anytime, not only when the depth frame is locked.
|
||||
This copy is updated everytime the frame is locked. Because of it, some
|
||||
coordinate space convertions may not work if the depth frame is not in use
|
||||
nor locked frequently. */
|
||||
UINT16 *pDepthRawCopy;
|
||||
|
||||
IBody *bodies[BODY_COUNT];
|
||||
Joint joints[JointType_Count]; // keep joints array in memory to avoid frequent allocations
|
||||
JointOrientation jointOrientations[JointType_Count];
|
||||
Vector4 floorClipPlane;
|
||||
|
||||
inline bool InitMapper();
|
||||
inline void UpdateColorMappedToDepth();
|
||||
inline int IndexFromXY(int pitch, float x, float y) const;
|
||||
};
|
||||
|
||||
/* Print formatted string to the Output window */
|
||||
void Printf(const char *szFormat, ...);
|
||||
void LogFailedHResult(const HRESULT hr, const char *functionName, const int line, const char *action = "");
|
||||
template <typename T>
|
||||
inline void SafeRelease(T*& pointer);
|
||||
template <typename T>
|
||||
inline void SafeReleaseArray(T*& pointer);
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Templates and inlines implementation
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
template<typename T>
|
||||
Vector2& Vector2::operator=(const T& b)
|
||||
{
|
||||
if (this != &b)
|
||||
{
|
||||
this->x = b.X;
|
||||
this->y = b.Y;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
DepthSpacePoint Vector2::toDepthSpacePoint() const
|
||||
{
|
||||
DepthSpacePoint b;
|
||||
b.X = this->x;
|
||||
b.Y = this->y;
|
||||
return b;
|
||||
}
|
||||
|
||||
ColorSpacePoint Vector2::toColorSpacePoint() const
|
||||
{
|
||||
ColorSpacePoint b;
|
||||
b.X = this->x;
|
||||
b.Y = this->y;
|
||||
return b;
|
||||
}
|
||||
|
||||
Vector3& Vector3::operator=(const CameraSpacePoint& b)
|
||||
{
|
||||
this->x = b.X;
|
||||
this->y = b.Y;
|
||||
this->z = b.Z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3& Vector3::operator/=(const float& other)
|
||||
{
|
||||
x /= other;
|
||||
y /= other;
|
||||
z /= other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Vector3 Vector3::operator/(const float& other) const
|
||||
{
|
||||
Vector3 result(*this);
|
||||
return result /= other;
|
||||
}
|
||||
|
||||
Vector3& Vector3::operator*=(const float& other)
|
||||
{
|
||||
x *= other;
|
||||
y *= other;
|
||||
z *= other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Vector3 Vector3::operator*(const float& other) const
|
||||
{
|
||||
Vector3 result(*this);
|
||||
return result *= other;
|
||||
}
|
||||
|
||||
bool Vector3::IsZero() const
|
||||
{
|
||||
return x == 0.f && y == 0.f && z == 0.f;
|
||||
}
|
||||
|
||||
Vector3 Vector3::normalized() const
|
||||
{
|
||||
if (IsZero())
|
||||
return Vector3();
|
||||
return (*this / magnitude());
|
||||
}
|
||||
|
||||
CameraSpacePoint Vector3::toCameraSpacePoint() const
|
||||
{
|
||||
CameraSpacePoint b;
|
||||
b.X = this->x;
|
||||
b.Y = this->y;
|
||||
b.Z = this->z;
|
||||
return b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void SafeRelease(T*& pointer)
|
||||
{
|
||||
if (pointer)
|
||||
{
|
||||
pointer->Release();
|
||||
}
|
||||
pointer = nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void SafeReleaseArray(T*& pointer)
|
||||
{
|
||||
if (pointer)
|
||||
{
|
||||
delete[] pointer;
|
||||
}
|
||||
pointer = nullptr;
|
||||
}
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
// Conversion from the original C++/CLI implementation.
|
||||
|
||||
#pragma once
|
||||
#include <vector>
|
||||
typedef struct _NUISENSOR_HANDLE *NUISENSOR_HANDLE, **PNUISENSOR_HANDLE;
|
||||
|
||||
//using namespace System;
|
||||
//using namespace System::Runtime::InteropServices;
|
||||
|
||||
namespace Xbox
|
||||
{
|
||||
namespace Kinect
|
||||
{
|
||||
|
||||
enum NUISENSOR_RGB_COMMAND_TYPE
|
||||
{
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_MODE = 0,
|
||||
NUISENSOR_RGB_COMMAND_SET_INTEGRATION_TIME = 1,
|
||||
NUISENSOR_RGB_COMMAND_GET_INTEGRATION_TIME = 2,
|
||||
|
||||
NUISENSOR_RGB_COMMAND_SET_WHITE_BALANCE_MODE = 10,
|
||||
NUISENSOR_RGB_COMMAND_SET_RED_CHANNEL_GAIN = 11,
|
||||
NUISENSOR_RGB_COMMAND_SET_GREEN_CHANNEL_GAIN = 12,
|
||||
NUISENSOR_RGB_COMMAND_SET_BLUE_CHANNEL_GAIN = 13,
|
||||
NUISENSOR_RGB_COMMAND_GET_RED_CHANNEL_GAIN = 14,
|
||||
NUISENSOR_RGB_COMMAND_GET_GREEN_CHANNEL_GAIN = 15,
|
||||
NUISENSOR_RGB_COMMAND_GET_BLUE_CHANNEL_GAIN = 16,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_TIME_MS = 17,
|
||||
NUISENSOR_RGB_COMMAND_GET_EXPOSURE_TIME_MS = 18,
|
||||
NUISENSOR_RGB_COMMAND_SET_DIGITAL_GAIN = 19,
|
||||
NUISENSOR_RGB_COMMAND_GET_DIGITAL_GAIN = 20,
|
||||
NUISENSOR_RGB_COMMAND_SET_ANALOG_GAIN = 21,
|
||||
NUISENSOR_RGB_COMMAND_GET_ANALOG_GAIN = 22,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_COMPENSATION = 23,
|
||||
NUISENSOR_RGB_COMMAND_GET_EXPOSURE_COMPENSATION = 24,
|
||||
NUISENSOR_RGB_COMMAND_SET_ACS = 25,
|
||||
NUISENSOR_RGB_COMMAND_GET_ACS = 26,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_MODE = 27,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONES = 28,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_0_WEIGHT = 29,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_1_WEIGHT = 30,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_2_WEIGHT = 31,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_3_WEIGHT = 32,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_4_WEIGHT = 33,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_5_WEIGHT = 34,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_6_WEIGHT = 35,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_7_WEIGHT = 36,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_8_WEIGHT = 37,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_9_WEIGHT = 38,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_10_WEIGHT = 39,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_11_WEIGHT = 40,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_12_WEIGHT = 41,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_13_WEIGHT = 42,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_14_WEIGHT = 43,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_15_WEIGHT = 44,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_16_WEIGHT = 45,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_17_WEIGHT = 46,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_18_WEIGHT = 47,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_19_WEIGHT = 48,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_20_WEIGHT = 49,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_21_WEIGHT = 50,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_22_WEIGHT = 51,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_23_WEIGHT = 52,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_24_WEIGHT = 53,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_25_WEIGHT = 54,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_26_WEIGHT = 55,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_27_WEIGHT = 56,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_28_WEIGHT = 57,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_29_WEIGHT = 58,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_30_WEIGHT = 59,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_31_WEIGHT = 60,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_32_WEIGHT = 61,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_33_WEIGHT = 62,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_34_WEIGHT = 63,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_35_WEIGHT = 64,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_36_WEIGHT = 65,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_37_WEIGHT = 66,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_38_WEIGHT = 67,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_39_WEIGHT = 68,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_40_WEIGHT = 69,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_41_WEIGHT = 70,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_42_WEIGHT = 71,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_43_WEIGHT = 72,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_44_WEIGHT = 73,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_45_WEIGHT = 74,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_46_WEIGHT = 75,
|
||||
NUISENSOR_RGB_COMMAND_SET_EXPOSURE_METERING_ZONE_47_WEIGHT = 76,
|
||||
NUISENSOR_RGB_COMMAND_SET_MAX_ANALOG_GAIN_CAP = 77,
|
||||
NUISENSOR_RGB_COMMAND_SET_MAX_DIGITAL_GAIN_CAP = 78,
|
||||
NUISENSOR_RGB_COMMAND_SET_FLICKER_FREE_FREQUENCY = 79,
|
||||
NUISENSOR_RGB_COMMAND_GET_EXPOSURE_MODE = 80,
|
||||
NUISENSOR_RGB_COMMAND_GET_WHITE_BALANCE_MODE = 81,
|
||||
NUISENSOR_RGB_COMMAND_SET_FRAME_RATE = 82,
|
||||
NUISENSOR_RGB_COMMAND_GET_FRAME_RATE = 83,
|
||||
|
||||
// This range is reserved. Do not re-use.
|
||||
NUISENSOR_RGB_COMMAND_RESERVED_BASE = 400,
|
||||
NUISENSOR_RGB_COMMAND_RESERVED_END = NUISENSOR_RGB_COMMAND_RESERVED_BASE + 200,
|
||||
// End of reserved region
|
||||
|
||||
};
|
||||
|
||||
struct NUISENSOR_RGB_CHANGE_SETTING_CMD
|
||||
{
|
||||
uint32_t Cmd;
|
||||
uint32_t Arg;
|
||||
};
|
||||
|
||||
struct NUISENSOR_RGB_CHANGE_STREAM_SETTING
|
||||
{
|
||||
uint32_t SequenceId;
|
||||
std::vector<NUISENSOR_RGB_CHANGE_SETTING_CMD> Commands;
|
||||
};
|
||||
|
||||
struct NUISENSOR_RGB_CHANGE_STREAM_SETTING_REPLY_STATUS
|
||||
{
|
||||
uint32_t Status;
|
||||
uint32_t Data;
|
||||
};
|
||||
|
||||
struct NUISENSOR_RGB_CHANGE_STREAM_SETTING_REPLY
|
||||
{
|
||||
uint32_t CommandListStatus;
|
||||
std::vector<NUISENSOR_RGB_CHANGE_STREAM_SETTING_REPLY_STATUS> Status;
|
||||
};
|
||||
|
||||
|
||||
class NuiSensor
|
||||
{
|
||||
public:
|
||||
NuiSensor();
|
||||
~NuiSensor();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
void ColorChangeCameraSettings(const NUISENSOR_RGB_CHANGE_STREAM_SETTING& settings, NUISENSOR_RGB_CHANGE_STREAM_SETTING_REPLY* p_reply);
|
||||
|
||||
private:
|
||||
void TestResult(int success);
|
||||
|
||||
NUISENSOR_HANDLE _sensor = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
Reference in New Issue
Block a user