JD2022-TU1/main/extern/KinectGesture/Src/GestureDetector.h

562 lines
26 KiB
C++

//--------------------------------------------------------------------------------------
// GestureDetector.h
//
// Definitions for the gesture detector and gesture detector trainer, as well definitions
// for weak and strong classifiers. The gesture detector trainer uses the AdaBoost
// learning alogorith.
//
// Advanced Technology Group (ATG)
// Copyright (C) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#pragma once
#if defined( GESTURE_TRAINER )
#ifdef GESTURE_EVALUATOR
#include "MacrosAndTypes.h"
#include "OpticalFlowTracker.h"
#endif
#if defined( TARGET_X360 )
#include <windows.h>
#elif defined( TARGET_DURANGO )
#include <windows.h>
#elif defined( TARGET_ORBIS )
#include "SK_iisu/PS4/include/HumanTrackingCTypes.h"
#include "Kinect/PS4/commontypes.h"
#else
#error unsuported platform
#endif
#else // defined( GESTURE_TRAINER )
#if defined( _XBOX ) || defined( ITF_X360 )
#include <xtl.h>
#elif defined( DURANGO ) || defined( ITF_DURANGO )
#include <windows.h>
#elif defined( __ORBIS__ ) || defined( ITF_ORBIS )
#include "SK_iisu/PS4/include/HumanTrackingCTypes.h"
#include "Kinect/PS4/commontypes.h"
#elif defined ( WIN32 ) ||defined( ITF_WIN32)
#include <windows.h>
#else
#error unsuported platform
#endif
#endif
#include <vector>
#include <deque>
#include <stdio.h>
#include "Common.h"
#include "ClassifierData.h"
#include "NuiTypes.h"
#ifdef WIN64
#undef WIN32
#endif
namespace KinectGesture
{
//--------------------------------------------------------------------------------------
// Defines and constants
//--------------------------------------------------------------------------------------
// For optimization reasons we use _fsel() on XBox, which uses double's, but on PC we
// want to make sure there are no floating point errors when comparing 1 and -1, so we
// simply use int
#if defined(_XBOX)
static const DOUBLE g_fClassificationLabelCorrect = 1.0f;
static const DOUBLE g_fClassificationLabelIncorrect = -1.0f;
#else
static const INT8 g_iClassificationLabelCorrect = 1;
static const INT8 g_iClassificationLabelIncorrect = -1;
#endif
// Version history
//static const FLOAT g_fCurrentVersion = 1.0f; // First version
//static const FLOAT g_fCurrentVersion = 1.1f; // Added LoadFromMemory() method, and alloc skeleton data as 16 byte aligned
//static const FLOAT g_fCurrentVersion = 1.2f; // Minor bug fixes, adding namespace and improvements to automatically finding filtering parameters
static const FLOAT g_fVersion_1_3 = 1.3f; // Added statistics in strong classifier
static const FLOAT g_fCurrentVersion = 1.4f; // Added energy statistics in strong classifier
static const FLOAT g_fVersionEpsilon = 0.01f; // I have no idea why we're using floats for version numbers.
const CHAR** getGestureFileIDs();
const CHAR* getLabeledExampleFileID();
const int getLabeledExampleFileIDLen();
//--------------------------------------------------------------------------------------
// External functions
//--------------------------------------------------------------------------------------
extern void Assert( bool expression, const char* message );
extern void* AllocateAligned( unsigned int size, unsigned int alignment );
extern void FreeAligned( void* memory );
//--------------------------------------------------------------------------------------
// Name: DecisionStump
// Desc: A simple decision stump from which weak classifiers are derived
//--------------------------------------------------------------------------------------
class DecisionStump
{
public:
DecisionStump();
inline VOID SetThreshold( const FLOAT fThreshold ) { m_fThreshold = fThreshold; }
inline FLOAT GetThreshold() const { return m_fThreshold; }
#if !defined(_XBOX) && !defined(ITF_X360) &&\
!defined(DURANGO) && !defined(ITF_DURANGO) &&\
!defined(__ORBIS__) && !defined(ITF_ORBIS)&&\
!defined ( WIN32 ) && !defined( ITF_WIN32)
inline VOID SetIsReversed( const BOOL bReverse ) { m_iReverse = bReverse ? -1 : 1; }
inline BOOL GetIsReversed() const { return ( m_iReverse == -1 ); }
inline INT8 GetReverseValue() const { return m_iReverse; }
#endif
// For optimization reason, we return a float value which can be multiplied by the floating point weight value. If we
// used integer as on PC, we introduce a LHS to for the integeter to float conversion. Also, on Xbox we bake m_iReverse
// into m_fAlpha, and we can use __fsel intrinsic
#if defined(_XBOX) || defined(ITF_X360)
__forceinline FLOAT Classify( const FLOAT fValue ) const
{
return (FLOAT)__fsel( fValue - m_fThreshold, g_fClassificationLabelCorrect, g_fClassificationLabelIncorrect );
}
#elif defined(DURANGO) || defined(ITF_DURANGO) || defined(__ORBIS__) || defined(ITF_ORBIS)||defined ( WIN32 ) ||defined( ITF_WIN32)
// on durango & orbis we still bake in m_iReverse
__forceinline INT8 Classify( const FLOAT fValue ) const
{
return ( ( ( fValue - m_fThreshold ) >= 0.0f ) ? g_iClassificationLabelCorrect : g_iClassificationLabelIncorrect );
}
#else
__forceinline INT8 Classify( const FLOAT fValue ) const
{
return ( ( ( fValue - m_fThreshold ) >= 0.0f ) ? g_iClassificationLabelCorrect : g_iClassificationLabelIncorrect ) * m_iReverse;
}
#endif
HRESULT Read( FILE* pFile );
HRESULT Read( VOID* pBuffer );
HRESULT Write( FILE* pFile );
protected:
FLOAT m_fThreshold; // The classifier threshold value
#if !defined(_XBOX) && !defined(ITF_X360) &&\
!defined(DURANGO) && !defined(ITF_DURANGO) &&\
!defined(__ORBIS__) && !defined(ITF_ORBIS)&&\
!defined ( WIN32 ) && !defined( ITF_WIN32)
INT8 m_iReverse; // To reverse the classification we can multiply the result by -1
#endif
};
//--------------------------------------------------------------------------------------
// Name: WeakClassifier
// Desc: A weak classifier implemented as h(x), with x as example input data, and
// h(x) returning either +1 or -1
//--------------------------------------------------------------------------------------
class ClassifierData;
class WeakClassifier : public DecisionStump
{
public:
WeakClassifier();
HRESULT Read( FILE* pFile, UINT* pDataID );
HRESULT Read( VOID* pBuffer, UINT* pDataID );
HRESULT Write( FILE* pFile );
inline VOID SetAlpha( const FLOAT fAlpha ) { m_fAlpha = fAlpha; }
inline FLOAT GetAlpha() const { return m_fAlpha; }
// inline VOID SetData( ClassifierData* pData ) { m_pData = pData; }
// inline ClassifierData* GetData() const { return m_pData; }
inline VOID SetDataIndex( UINT index ) { m_uDataIndex = index; }
inline UINT GetDataIndex() const { return m_uDataIndex; }
// Sort based on fAlpha, the confidence of the classifier
inline bool operator < (const WeakClassifier& weakClassifier ) { return ( m_fAlpha < weakClassifier.m_fAlpha ); }
WeakClassifier& operator = ( const WeakClassifier& source )
{
SetThreshold( source.GetThreshold() );
#if !defined(_XBOX) && !defined(ITF_X360) &&\
!defined(DURANGO) && !defined(ITF_DURANGO) &&\
!defined(__ORBIS__) && !defined(ITF_ORBIS)&&\
!defined ( WIN32 ) &&!defined( ITF_WIN32)
SetIsReversed( source.GetIsReversed() );
#endif
SetAlpha( source.GetAlpha() );
// SetData( source.GetData() );
SetDataIndex( source.GetDataIndex() );
return *this;
}
protected:
FLOAT m_fAlpha; // Confidence of weak classifier
// ClassifierData* m_pData; // Pointer to value that will be compared to threshold (why not directly data index?)
UINT m_uDataIndex;
friend class DebugOutput;
};
//--------------------------------------------------------------------------------------
// Name: StrongClassifier
// Desc: A strong classifier implemented as H(x) as the weighted sum of the weak
// classifiers h(x)
//--------------------------------------------------------------------------------------
class StrongClassifier
{
public:
enum Label
{
eLabel_Correct = 0,
eLabel_Incorrect = 1,
eLabel_Count,
};
struct Results
{
#ifdef GESTURE_EVALUATOR
public:
#endif
FLOAT m_fConfidence; // The confidence calculated from the normalized weighted sum
BOOL m_bDetected; // Detected a gesture
BOOL m_bFirstFrameDetected; // Detection can occur over several frames. If it's the first frame, this value is true
};
public:
StrongClassifier();
~StrongClassifier();
HRESULT Initialize( const UINT nNumWeakClassifiers );
inline VOID Reset( const UINT uPlayerIdx ) { m_fClassificationHistory[ uPlayerIdx ].clear(); }
HRESULT Read( FILE* pFile, BOOL bUsesEnergyStatistics );
HRESULT Read( VOID* pBuffer, BOOL bUsesEnergyStatistics );
HRESULT Write( FILE* pFile );
HRESULT Read( FILE* pFile, const UINT uWeakClassifierIndex, UINT* pDataID );
HRESULT Read( VOID* pBuffer, const UINT uWeakClassifierIndex, UINT* pDataID );
HRESULT Write( FILE* pFile, const UINT uWeakClassifierIndex );
#if defined(_XBOX) || defined(ITF_X360) ||\
defined(DURANGO) || defined(ITF_DURANGO) ||\
defined(__ORBIS__) || defined(ITF_ORBIS)||\
defined ( WIN32 ) ||defined( ITF_WIN32)
inline UINT GetNumWeakClassifiers() const { return m_nNumWeakClassifiers; }
BOOL Detect( const UINT uPlayerIdx, ClassifierData** __restrict classifierData, Results* pResults, const BOOL bFilterResults );
#else
inline UINT GetNumWeakClassifiers() const { return (UINT)m_WeakClassifiers.size(); }
BOOL Detect( const UINT uPlayerIdx, const std::vector<ClassifierData*>& classifierData, Results* pResults, const BOOL bFilterResults );
inline VOID Add( const WeakClassifier weakClassifier ) { m_WeakClassifiers.push_back( weakClassifier ); }
#endif
VOID FilterDetectionResults( const UINT uPlayerIdx, const FLOAT fConfidence, Results* pResults );
#if defined(_XBOX) || defined(ITF_X360) ||\
defined(DURANGO) || defined(ITF_DURANGO) ||\
defined(__ORBIS__) || defined(ITF_ORBIS)||\
defined ( WIN32 ) ||defined( ITF_WIN32)
VOID GetBoneWeights( ClassifierData** __restrict classifierData, FLOAT *weights, UINT numWeights );
VOID CalculateUsedRanges( ClassifierData** __restrict classifierData, float *fRangeMin, float *fRangeMax, float *fSumAlpha );
#else
VOID GetBoneWeights( const std::vector<ClassifierData*>& classifierData, FLOAT *weights, UINT numWeights );
VOID CalculateUsedRanges( const std::vector<ClassifierData*>& classifierData, float *fRangeMin, float *fRangeMax, float *fSumAlpha );
#endif
inline WeakClassifier* GetWeakClassifierAt( const UINT uWeakClassifierIndex ) { return &m_WeakClassifiers[ uWeakClassifierIndex ]; }
inline VOID SetTotalAlpha( const FLOAT fTotalAlpha ) { m_fTotalAlpha = fTotalAlpha; }
inline VOID SetDetectionThreshold( const FLOAT fThreshold ) { m_fFilterPerFrameResultsThreshold = fThreshold; }
inline FLOAT GetDetectionThreshold() const { return m_fFilterPerFrameResultsThreshold; }
inline VOID SetNumFramesToFilter( const UINT nNumFramesToFilter ) { m_nFilterPerFrameResultsNumFrames = nNumFramesToFilter; }
inline UINT GetNumFramesToFilter() const { return m_nFilterPerFrameResultsNumFrames; }
inline VOID SetRangeMax( const FLOAT fRangeMax, const Label eLabel ) { m_fRangeMax[eLabel] = fRangeMax; }
inline FLOAT GetRangeMax( const Label eLabel ) const { return m_fRangeMax[eLabel]; }
inline VOID SetRangeMin( const FLOAT fRangeMin, const Label eLabel ) { m_fRangeMin[eLabel] = fRangeMin; }
inline FLOAT GetRangeMin( const Label eLabel ) const { return m_fRangeMin[eLabel]; }
inline VOID SetMean( const FLOAT fMean, const Label eLabel ) { m_fMean[eLabel] = fMean; }
inline FLOAT GetMean( const Label eLabel ) const { return m_fMean[eLabel]; }
inline VOID SetStdDev( const FLOAT fStdDev, const Label eLabel ) { m_fStdDev[eLabel] = fStdDev; }
inline FLOAT GetStdDev( const Label eLabel ) const { return m_fStdDev[eLabel]; }
// Energy-related stuff
inline VOID SetEnergyMean( const FLOAT fMean ) { m_fEnergyMean = fMean; }
inline FLOAT GetEnergyMean() const { return m_fEnergyMean; }
inline VOID SetEnergyStdDev( const FLOAT fStdDev ) { m_fEnergyStdDev = fStdDev; }
inline FLOAT GetEnergyStdDev() const { return m_fEnergyStdDev; }
#if !defined(_XBOX) && !defined(ITF_X360) &&\
!defined(DURANGO) && !defined(ITF_DURANGO) &&\
!defined(__ORBIS__) && !defined(ITF_ORBIS)&&\
!defined ( WIN32 ) && !defined( ITF_WIN32)
VOID Optimize( const UINT nMaxNumClassifers, const BOOL bBakeReverseInAlpha = TRUE );
#endif
protected:
#if defined(_XBOX) || defined(ITF_X360) ||\
defined(DURANGO) || defined(ITF_DURANGO) ||\
defined(__ORBIS__) || defined(ITF_ORBIS)||\
defined ( WIN32 ) ||defined( ITF_WIN32)
WeakClassifier* m_WeakClassifiers;
UINT m_nNumWeakClassifiers;
#else
std::vector<WeakClassifier> m_WeakClassifiers;
#endif
std::deque<FLOAT> m_fClassificationHistory[ KINECT_GESTURE_MAX_SIMULTANEOUS_GESTURES ];
FLOAT m_fTotalAlpha; // Sum of all alpha values of all valid weak classifiers
FLOAT m_fFilterPerFrameResultsThreshold; // Per frame filtering detection threshold
UINT m_nFilterPerFrameResultsNumFrames; // Size of the sliding window when filtering per frame results
// scale values so we can score an accuracy range
FLOAT m_fRangeMax[eLabel_Count];
FLOAT m_fRangeMin[eLabel_Count];
FLOAT m_fMean[eLabel_Count];
FLOAT m_fStdDev[eLabel_Count];
// energy values
FLOAT m_fEnergyMean;
FLOAT m_fEnergyStdDev;
#if defined(_XBOX) || defined(ITF_X360) ||\
defined(DURANGO) || defined(ITF_DURANGO) ||\
defined(__ORBIS__) || defined(ITF_ORBIS)||\
defined ( WIN32 ) ||defined( ITF_WIN32)
INT Classify( const UINT uPlayerIdx, ClassifierData** __restrict classifierData, FLOAT* pConfidence );
#else
INT8 Classify( const UINT uPlayerIdx, const std::vector<ClassifierData*>& classifierData, FLOAT* pConfidence );
#endif
friend class DebugOutput;
};
//--------------------------------------------------------------------------------------
// Name: GestureDetector
// Desc: The gesture detector that can be run on the PC or Xbox
//--------------------------------------------------------------------------------------
class GestureDetector
{
public:
typedef StrongClassifier::Results Results;
VelocityGrid* m_velocityGrid;
public:
GestureDetector();
~GestureDetector();
HRESULT Load( const CHAR* szFileName );
HRESULT LoadFromMemory( VOID* pBuffer );
#ifdef GESTURE_EVALUATOR
OpticalFlowCell m_opticalFlowGrid[OPTICALFLOW_FULLSCREENGRID_X][OPTICALFLOW_FULLSCREENGRID_Y];
bool Update( const UINT uPlayerIdx, const GESTURE_SKELETON_TYPE* pSkeletonData, const LARGE_INTEGER& liTimeStampFromNuiFrame);
static BOOL Update( const UINT uPlayerIdx, const GESTURE_SKELETON_TYPE* pSkeletonData, const float fDeltaTimeInSeconds, BOOL bReset, const VelocityGrid* opticalFlowGrid );
#endif
static BOOL Update( const UINT uPlayerIdx, const GESTURE_SKELETON_TYPE* pSkeletonData, const LARGE_INTEGER& liTimeStampFromNuiFrame, const XMVECTOR& vNormalToGravity );
static BOOL Update( const UINT uPlayerIdx, const GESTURE_SKELETON_TYPE* pSkeletonData, const float fDeltaTimeInSeconds, const XMVECTOR& vNormalToGravity, BOOL bReset, const VelocityGrid* opticalFlowGrid );
static VOID ResetPlayer( const UINT uPlayerIdx, const GESTURE_SKELETON_TYPE* pSkeletonData, const XMVECTOR& vNormalToGravity );
BOOL Detect( const UINT uPlayerIdx, Results* pResults, const BOOL bFilterResults );
static FLOAT GetEnergyLevel( const UINT uPlayerIdx );
VOID GetBoneWeights( FLOAT *weights, UINT numWeights );
VOID CalculateUsedRanges( float *fRangeMin, float *fRangeMax, float *fSumAlpha );
inline VOID SetDetectionThreshold( const FLOAT fThreshold ) { m_StrongClassifier.SetDetectionThreshold( fThreshold ); }
inline FLOAT GetDetectionThreshold() const { return m_StrongClassifier.GetDetectionThreshold(); }
inline VOID SetNumFramesToFilter( const UINT nNumFramesToFilter ) { m_StrongClassifier.SetNumFramesToFilter( nNumFramesToFilter ); }
inline UINT GetNumFramesToFilter() const { return m_StrongClassifier.GetNumFramesToFilter(); }
inline VOID SetRangeMax( const FLOAT fRangeMax, const StrongClassifier::Label eLabel ) { m_StrongClassifier.SetRangeMax( fRangeMax, eLabel ); }
inline FLOAT GetRangeMax( const StrongClassifier::Label eLabel ) const { return m_StrongClassifier.GetRangeMax( eLabel ); }
inline VOID SetRangeMin( const FLOAT fRangeMin, const StrongClassifier::Label eLabel ) { m_StrongClassifier.SetRangeMin( fRangeMin, eLabel ); }
inline FLOAT GetRangeMin( const StrongClassifier::Label eLabel ) const { return m_StrongClassifier.GetRangeMin( eLabel ); }
inline VOID SetMean( const FLOAT fMean, const StrongClassifier::Label eLabel ) { m_StrongClassifier.SetMean( fMean, eLabel ); }
inline FLOAT GetMean( const StrongClassifier::Label eLabel ) const { return m_StrongClassifier.GetMean( eLabel ); }
inline VOID SetStdDev( const FLOAT fStdDev, const StrongClassifier::Label eLabel ) { m_StrongClassifier.SetStdDev( fStdDev, eLabel ); }
inline FLOAT GetStdDev( const StrongClassifier::Label eLabel ) const { return m_StrongClassifier.GetStdDev( eLabel ); }
// Energy-related stuff
inline VOID SetEnergyMean( const FLOAT fMean ) { m_StrongClassifier.SetEnergyMean( fMean ); }
inline FLOAT GetEnergyMean() const { return m_StrongClassifier.GetEnergyMean(); }
inline VOID SetEnergyStdDev( const FLOAT fStdDev ) { m_StrongClassifier.SetEnergyStdDev( fStdDev ); }
inline FLOAT GetEnergyStdDev() const { return m_StrongClassifier.GetEnergyStdDev(); }
HRESULT Initialize( const UINT nNumWeakClassifiers, UINT nNumClassifierData );
static VOID FreeClassifierData();
#ifdef GESTURE_EVALUATOR
static float clamp(float val, float min, float max);
static void GaussianBlurKernel( float* weights, int kernelSize );
vector2 mapCameraSpaceToDepthSpace(mathLib_vector4 cameraSpaceVector);
//Optical Flow Specifics
f32 opticalFlowCloseCellsWeight[3][3];
void opticalFlow_getPositionVelocityGrid(mathLib_vector4 pos, VelocityGrid* velocityGrid);
vector3& opticalFlow_getRegionVelocity(vector3 min, vector3 max);
void setOpticalFlowCloseCellWeights();
void opticalflowUpdateDepthMap(unsigned short* _pDepthMapData, int _pitch);
u16 opticalFlow_getDepthFromDepthMapLine(unsigned short* _line, u16 _x);
void opticalFlow_update(f32 timeStamp);
#endif
protected:
StrongClassifier m_StrongClassifier;
static XMVECTOR vUp;
static XMVECTOR vAverageNormalToGravity[ KINECT_GESTURE_MAX_SIMULTANEOUS_GESTURES ];
#if defined(_XBOX) || defined(ITF_X360) ||\
defined(DURANGO) || defined(ITF_DURANGO) ||\
defined(__ORBIS__) || defined(ITF_ORBIS)||\
defined ( WIN32 ) ||defined( ITF_WIN32)
static ClassifierData** m_ClassifierData;
static UINT m_nNumClassifierData;
#else
static std::vector<ClassifierData*> m_ClassifierData;
#endif
static UINT m_nNumInstances;
static UINT64 m_uPreviousTimeStamp;
WeakClassifier* GetWeakClassifierAt( const UINT uWeakClassiferIndex ) { return m_StrongClassifier.GetWeakClassifierAt( uWeakClassiferIndex ); }
static VOID ApplyTiltCorrection( const UINT uPlayerIdx, GESTURE_SKELETON_TYPE* pDstSkeleton, const GESTURE_SKELETON_TYPE* pSrcSkeleton, const XMVECTOR& vNormalToGravity, BOOL bReset );
static BOOL ValidateHeader( CHAR* szHeader );
friend class DebugOutput;
};
#if defined( GESTURE_TRAINER )
//--------------------------------------------------------------------------------------
// Name: GestureDetectorTrainer
// Desc: The gesture detector trainer that uses the AdaBoost machine learning algorithm
//--------------------------------------------------------------------------------------
class GestureDetectorTrainer : public GestureDetector
{
public:
struct LabeledExamples
{
std::vector<GESTURE_SKELETON_TYPE*> m_pExamples; // Each tracked skeleton is an example
std::vector<INT8> m_iLabels; // 1 for true, -1 for false
std::vector<UINT64> m_uTimeStamps; // Event time stamp from the example file
};
public:
GestureDetectorTrainer();
~GestureDetectorTrainer();
VOID Reset();
HRESULT Save( const CHAR* szFileName );
HRESULT Load( const CHAR* szFileName ) { return GestureDetector::Load( szFileName ); }
HRESULT LoadFromMemory( VOID* pBuffer ) { return GestureDetector::LoadFromMemory( pBuffer ); }
HRESULT Train( CHAR* const* szLeFiles, const UINT uiLeFileCount, const DOUBLE fAccuracyLevel, const UINT nNumWeakClassifiersAtRuntime
, const FLOAT fWeightOfFalsePositivesWhenFiltering, const BOOL bOnlyRetrainDetectionParameters
, const UINT uCPUAvailableForTraining, BOOL useSkeleton, BOOL useOpticalFlow, UINT framesToSkip );
HRESULT Test( const CHAR* szPath, const BOOL bTestOnTrainingData );
HRESULT GenerateLabeledExamples( const CHAR* szGestureName, CHAR* const* szExampleFiles, const UINT uiExampleFileCount, const CHAR* szDestPath, const BOOL bUseRawSkeletonData, const INT iSkeletonIndexToProcess, INT8 iLabels[] = NULL, CHAR* const* szOutputFiles = NULL );
UINT GetNumWeakClassifiers() { return m_StrongClassifier.GetNumWeakClassifiers(); }
UINT GetNumExamples() { return (UINT)m_LabeledExamples.m_pExamples.size(); }
UINT GetNumPositiveExamples();
UINT GetNumNegativeExamples() { return GetNumExamples() - GetNumPositiveExamples(); }
UINT GetNumGestures() const { return m_nTotalNumGestures; }
UINT GetNumTrainingGestures() const { return m_nNumTrainingGestures; }
INT8 GetLabel( const UINT uIndex ) const { return m_LabeledExamples.m_iLabels[ uIndex ]; }
BOOL m_bUseSkeleton;
BOOL m_bUseOpticalFlow;
UINT m_nFramesToSkip;
protected:
LabeledExamples m_LabeledExamples; // Labeled examples used as ground truth during training and testing
UINT m_nTotalNumGestures; // Total number of gestures
UINT m_nNumTrainingGestures; // Total number of gestures which we're training on
UINT m_nNumThreadsForTraining; // Total number of threads the user allows for training
UINT m_nMaxNumThreads; // Total threads available on PC
UINT m_nNumWeakClassifiersAtRuntime; // Total number of weak classifiers at runtime
DOUBLE m_fErrorThreshold; // Error threshold in AdaBoost, with max value 0.5, since weak classifiers need to be better that 50/50 chance
HRESULT GenerateLabeledExamplesFromRawSkeleton( const CHAR* szGestureName, const CHAR* szExampleFileName, INT iSkeletonIndexToProcess, INT8 iExampleLabel = 0 );
HRESULT SaveLabeledExamples( const CHAR* szFileName );
HRESULT LoadLabeledExamples( const CHAR* szFileName );
HRESULT GenerateWeakClassifiers( ClassifierData::EType classifierDataType = ClassifierData::NUM_FEATURES );
HRESULT GenerateWeakClassifiers( ClassifierData* pClassifierData, const FLOAT fMin, const FLOAT fMax, const FLOAT fStep, const BOOL bUseReject = TRUE );
VOID CombineWeakClassifiers( GestureDetectorTrainer* pGestureDetectorTrainers, const UINT nNumTrainers );
HRESULT TrainWeakClassifiers();
HRESULT TrainWeakClassifiers( ClassifierData::EType classifierDataType, LabeledExamples& labeledExamples, const DOUBLE fErrorThreshold );
HRESULT TrainStrongClassifier( const BOOL bFinalPass );
VOID Optimize( const UINT nMaxNumClassifers, const BOOL bBakeReverseInAlpha = TRUE ) { m_StrongClassifier.Optimize( nMaxNumClassifers, bBakeReverseInAlpha ); }
VOID OptimizeDetectionParameters( const FLOAT fWeightOfFalsePositivesWhenFiltering );
VOID Test( FLOAT* pTruePositives, FLOAT* pFalsePositives, std::vector<FLOAT>& fRawClassificationResults );
//VOID ByteSwapSkeletonDataRead( GESTURE_SKELETON_TYPE* pSkeletonData );
VOID MirrorSkeletonData( GESTURE_SKELETON_TYPE* pSkeletonData );
};
#endif
//--------------------------------------------------------------------------------------
// Name: DebugOutput
// Desc: Simple class that outputs text information for debuggin purposes and
// knowledge extraction puroposes
//--------------------------------------------------------------------------------------
class DebugOutput
{
public:
CHAR* Print( const ClassifierData::EType type );
CHAR* Print( const GESTURE_JOINT_INDEX joint );
CHAR* Print( const ClassifierData* pClassifierData );
CHAR* Print( const WeakClassifier* pWeakClassifier, const ClassifierData* pClassifierData );
CHAR* Print( GestureDetector* pGestureDetector, const UINT uWeakClassiferIndex );
protected:
CHAR m_szBuffer[ MAX_PATH ];
};
}