//-------------------------------------------------------------------------------------- // 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 #elif defined( TARGET_DURANGO ) #include #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 #elif defined( DURANGO ) || defined( ITF_DURANGO ) #include #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 #else #error unsuported platform #endif #endif #include #include #include #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, 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, FLOAT *weights, UINT numWeights ); VOID CalculateUsedRanges( const std::vector& 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 m_WeakClassifiers; #endif std::deque 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, 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 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 m_pExamples; // Each tracked skeleton is an example std::vector m_iLabels; // 1 for true, -1 for false std::vector 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& 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 ]; }; }