diff --git a/GVF/GVF.cpp b/GVF/GVF.cpp deleted file mode 100755 index 36ef7d53af50be299a2295bd55d14d3585ea0ea1..0000000000000000000000000000000000000000 --- a/GVF/GVF.cpp +++ /dev/null @@ -1,1375 +0,0 @@ -/** - * Gesture Variation Follower class allows for early gesture recognition and variation tracking - * - * @details Original algorithm designed and implemented in 2011 at Ircam Centre Pompidou - * by Baptiste Caramiaux and Nicola Montecchio. The library has been created and is maintained by Baptiste Caramiaux - * - * Copyright (C) 2015 Baptiste Caramiaux, Nicola Montecchio - * STMS lab Ircam-CRNS-UPMC, University of Padova, Goldsmiths College University of London - * - * The library is under the GNU Lesser General Public License (LGPL v3) - */ - -#include "GVF.h" -#include <string.h> -#include <stdio.h> -#include <iostream> -#include <fstream> -#include <sstream> -#include <memory> -#include <algorithm> -#include <numeric> - -//debug max -//#include "ext.h" - - -using namespace std; - -//-------------------------------------------------------------- -GVF::GVF() -{ - config.inputDimensions = 2; - config.translate = true; - config.segmentation = false; - - parameters.numberParticles = 1000; - parameters.tolerance = 0.2f; - parameters.resamplingThreshold = 250; - parameters.distribution = 0.0f; - parameters.alignmentVariance = sqrt(0.000001f); - parameters.dynamicsVariance = vector<float>(1,sqrt(0.001f)); - parameters.scalingsVariance = vector<float>(1,sqrt(0.00001f)); - parameters.rotationsVariance = vector<float>(1,sqrt(0.0f)); - parameters.predictionSteps = 1; - parameters.dimWeights = vector<float>(1,sqrt(1.0f)); - parameters.alignmentSpreadingCenter = 0.0; - parameters.alignmentSpreadingRange = 0.2; - parameters.dynamicsSpreadingCenter = 1.0; - parameters.dynamicsSpreadingRange = 0.3; - parameters.scalingsSpreadingCenter = 1.0; - parameters.scalingsSpreadingRange = 0.3; - parameters.rotationsSpreadingCenter = 0.0; - parameters.rotationsSpreadingRange = 0.5; - - tolerancesetmanually = false; - learningGesture = -1; - - normgen = std::mt19937(rd()); - rndnorm = new std::normal_distribution<float>(0.0,1.0); - unifgen = std::default_random_engine(rd()); - rndunif = new std::uniform_real_distribution<float>(0.0,1.0); - -} - -////-------------------------------------------------------------- -//GVF::GVF(GVFConfig _config){ -// setup(_config); -//} -// -////-------------------------------------------------------------- -//GVF::GVF(GVFConfig _config, GVFParameters _parameters){ -// setup(_config, _parameters); -//} -// -////-------------------------------------------------------------- -//void GVF::setup(){ -// -// // use defualt parameters -// GVFConfig defaultConfig; -// -// defaultConfig.inputDimensions = 2; -// defaultConfig.translate = true; -// defaultConfig.segmentation = false; -// -// setup(defaultConfig); -//} -// -////-------------------------------------------------------------- -//void GVF::setup(GVFConfig _config){ -// -// clear(); // just in case -// -// learningGesture = -1; -// -// // Set configuration: -// config = _config; -// -// // default parameters -// GVFParameters defaultParameters; -// defaultParameters.numberParticles = 1000; -// defaultParameters.tolerance = 0.2f; -// defaultParameters.resamplingThreshold = 250; -// defaultParameters.distribution = 0.0f; -// defaultParameters.alignmentVariance = sqrt(0.000001f); -// defaultParameters.dynamicsVariance = vector<float>(1,sqrt(0.001f)); -// defaultParameters.scalingsVariance = vector<float>(1,sqrt(0.00001f)); -// defaultParameters.rotationsVariance = vector<float>(1,sqrt(0.0f)); -// defaultParameters.predictionSteps = 1; -// defaultParameters.dimWeights = vector<float>(1,sqrt(1.0f)); -// -// // default spreading -// defaultParameters.alignmentSpreadingCenter = 0.0; -// defaultParameters.alignmentSpreadingRange = 0.2; -// -// defaultParameters.dynamicsSpreadingCenter = 1.0; -// defaultParameters.dynamicsSpreadingRange = 0.3; -// -// defaultParameters.scalingsSpreadingCenter = 1.0; -// defaultParameters.scalingsSpreadingRange = 0.3; -// -// defaultParameters.rotationsSpreadingCenter = 0.0; -// defaultParameters.rotationsSpreadingRange = 0.0; -// -// tolerancesetmanually = false; -// -// setup(_config, defaultParameters); -// -//} -// -////-------------------------------------------------------------- -//void GVF::setup(GVFConfig _config, GVFParameters _parameters) -//{ -// clear(); // just in case -// // Set configuration and parameters -// config = _config; -// parameters = _parameters; -// // Init random generators -// normgen = std::mt19937(rd()); -// rndnorm = new std::normal_distribution<float>(0.0,1.0); -// unifgen = std::default_random_engine(rd()); -// rndunif = new std::uniform_real_distribution<float>(0.0,1.0); -//} - -//-------------------------------------------------------------- -GVF::~GVF() -{ - if (rndnorm != NULL) - delete (rndnorm); - clear(); // not really necessary but it's polite ;) -} - -//-------------------------------------------------------------- -void GVF::clear() -{ - state = STATE_CLEAR; - gestureTemplates.clear(); - mostProbableIndex = -1; -} - -//-------------------------------------------------------------- -void GVF::startGesture() -{ - if (state==STATE_FOLLOWING) - { - restart(); - } - else if (state==STATE_LEARNING) - { - if (theGesture.getNumberOfTemplates()>0) - { - if (theGesture.getTemplateLength()>0) - addGestureTemplate(theGesture); - } - theGesture.clear(); - } -} - -//-------------------------------------------------------------- -void GVF::addObservation(vector<float> data) -{ - theGesture.addObservation(data); -} - -//-------------------------------------------------------------- -void GVF::addGestureTemplate(GVFGesture & gestureTemplate) -{ - - // if (getState() != GVF::STATE_LEARNING) - // setState(GVF::STATE_LEARNING); - - int inputDimension = gestureTemplate.getNumberDimensions(); - config.inputDimensions = inputDimension; - - gestureTemplates.push_back(gestureTemplate); - activeGestures.push_back(gestureTemplates.size()); - - if(minRange.size() == 0){ - minRange.resize(inputDimension); - maxRange.resize(inputDimension); - } - - for(int j = 0; j < inputDimension; j++){ - minRange[j] = INFINITY; - maxRange[j] = -INFINITY; - } - - // compute min/max from the data - for(int i = 0; i < gestureTemplates.size(); i++){ - GVFGesture& tGestureTemplate = gestureTemplates[i]; - vector<float>& tMinRange = tGestureTemplate.getMinRange(); - vector<float>& tMaxRange = tGestureTemplate.getMaxRange(); - for(int j = 0; j < inputDimension; j++){ - if(tMinRange[j] < minRange[j]) minRange[j] = tMinRange[j]; - if(tMaxRange[j] > maxRange[j]) maxRange[j] = tMaxRange[j]; - } - } - - for(int i = 0; i < gestureTemplates.size(); i++){ - GVFGesture& tGestureTemplate = gestureTemplates[i]; - tGestureTemplate.setMinRange(minRange); - tGestureTemplate.setMaxRange(maxRange); - } - train(); - -} - -//-------------------------------------------------------------- -void GVF::replaceGestureTemplate(GVFGesture & gestureTemplate, int index) -{ - if(gestureTemplate.getNumberDimensions()!=config.inputDimensions) - return; - if(minRange.size() == 0) - { - minRange.resize(config.inputDimensions); - maxRange.resize(config.inputDimensions); - } - for(int j = 0; j < config.inputDimensions; j++) - { - minRange[j] = INFINITY; - maxRange[j] = -INFINITY; - } - if (index<=gestureTemplates.size()) - gestureTemplates[index-1]=gestureTemplate; - for(int i = 0; i < gestureTemplates.size(); i++) - { - GVFGesture& tGestureTemplate = gestureTemplates[i]; - vector<float>& tMinRange = tGestureTemplate.getMinRange(); - vector<float>& tMaxRange = tGestureTemplate.getMaxRange(); - for(int j = 0; j < config.inputDimensions; j++){ - if(tMinRange[j] < minRange[j]) minRange[j] = tMinRange[j]; - if(tMaxRange[j] > maxRange[j]) maxRange[j] = tMaxRange[j]; - } - } - for(int i = 0; i < gestureTemplates.size(); i++) - { - GVFGesture& tGestureTemplate = gestureTemplates[i]; - tGestureTemplate.setMinRange(minRange); - tGestureTemplate.setMaxRange(maxRange); - } -} - -////-------------------------------------------------------------- -//vector<float>& GVF::getGestureTemplateSample(int gestureIndex, float cursor) -//{ -// int frameindex = min((int)(gestureTemplates[gestureIndex].getTemplateLength() - 1), -// (int)(floor(cursor * gestureTemplates[gestureIndex].getTemplateLength() ) ) ); -// return gestureTemplates[gestureIndex].getTemplate()[frameindex]; -//} - -//-------------------------------------------------------------- -GVFGesture & GVF::getGestureTemplate(int index){ - assert(index < gestureTemplates.size()); - return gestureTemplates[index]; -} - -//-------------------------------------------------------------- -vector<GVFGesture> & GVF::getAllGestureTemplates(){ - return gestureTemplates; -} - -//-------------------------------------------------------------- -int GVF::getNumberOfGestureTemplates(){ - return (int)gestureTemplates.size(); -} - -//-------------------------------------------------------------- -void GVF::removeGestureTemplate(int index){ - assert(index < gestureTemplates.size()); - gestureTemplates.erase(gestureTemplates.begin() + index); -} - -//-------------------------------------------------------------- -void GVF::removeAllGestureTemplates(){ - gestureTemplates.clear(); -} - -//---------------------------------------------- -void GVF::train(){ - - if (gestureTemplates.size() > 0) - { - - // get the number of dimension in templates - config.inputDimensions = gestureTemplates[0].getTemplateDimension(); - - dynamicsDim = 2; // hard coded: just speed now - scalingsDim = config.inputDimensions; - - // manage orientation - if (config.inputDimensions==2) rotationsDim=1; - else if (config.inputDimensions==3) rotationsDim=3; - else rotationsDim=0; - - // Init state space - initVec(classes, parameters.numberParticles); // Vector of gesture class - initVec(alignment, parameters.numberParticles); // Vector of phase values (alignment) - initMat(dynamics, parameters.numberParticles, dynamicsDim); // Matric of dynamics - initMat(scalings, parameters.numberParticles, scalingsDim); // Matrix of scaling - if (rotationsDim!=0) initMat(rotations, parameters.numberParticles, rotationsDim); // Matrix of rotations - initMat(offsets, parameters.numberParticles, config.inputDimensions); - initVec(weights, parameters.numberParticles); // Weights - - initMat(particles, parameters.numberParticles, 3); - // std::cout << particles.size() << " " << parameters.numberParticles << std::endl; - - // bayesian elements - initVec(prior, parameters.numberParticles); - initVec(posterior, parameters.numberParticles); - initVec(likelihood, parameters.numberParticles); - - - initPrior(); // prior on init state values - initNoiseParameters(); // init noise parameters (transition and likelihood) - - - // weighted dimensions in case: default is not weighted - if (parameters.dimWeights.size()!=config.inputDimensions){ - parameters.dimWeights = vector<float> (config.inputDimensions); - for(int k = 0; k < config.inputDimensions; k++) parameters.dimWeights[k] = 1.0 / config.inputDimensions; - } - - // NORMALIZATION -// if (config.normalization) { // update the global normaliation factor -// globalNormalizationFactor = -1.0; -// // loop on previous gestures already learned -// // take the max of all the gesture learned ... -// for (int k=0; k<getNumberOfGestureTemplates() ; k++){ -// for(int j = 0; j < config.inputDimensions; j++){ -// float rangetmp = fabs(getGestureTemplate(k).getMaxRange()[j]-getGestureTemplate(k).getMinRange()[j]); -// if (rangetmp > globalNormalizationFactor) -// globalNormalizationFactor=rangetmp; -// } -// } -// } -// // only for logs -// if (config.logOn) { -// vecRef = vector<vector<float> > (parameters.numberParticles); -// vecObs = vector<float> (config.inputDimensions); -// stateNoiseDist = vector<float> (parameters.numberParticles); -// } - } -} - -//-------------------------------------------------------------- -//void GVF::initPrior() -//{ -// -// // PATICLE FILTERING -// for (int k = 0; k < parameters.numberParticles; k++) -// { -// initPrior(k); -// -// classes[k] = activeGestures[k % activeGestures.size()] - 1; -// } -// -//} - -//-------------------------------------------------------------- -void GVF::initPrior() //int pf_n) -{ - for (int pf_n = 0; pf_n < parameters.numberParticles; pf_n++) - { - // alignment - alignment[pf_n] = ((*rndunif)(unifgen) - 0.5) * parameters.alignmentSpreadingRange + parameters.alignmentSpreadingCenter; // spread phase - - - // dynamics - dynamics[pf_n][0] = ((*rndunif)(unifgen) - 0.5) * parameters.dynamicsSpreadingRange + parameters.dynamicsSpreadingCenter; // spread speed - if (dynamics[pf_n].size()>1) - { - dynamics[pf_n][1] = ((*rndunif)(unifgen) - 0.5) * parameters.dynamicsSpreadingRange; // spread accel - } - - // scalings - for(int l = 0; l < scalings[pf_n].size(); l++) { - scalings[pf_n][l] = ((*rndunif)(unifgen) - 0.5) * parameters.scalingsSpreadingRange + parameters.scalingsSpreadingCenter; // spread scalings - } - - // rotations - if (rotationsDim!=0) - for(int l = 0; l < rotations[pf_n].size(); l++) - rotations[pf_n][l] = ((*rndunif)(unifgen) - 0.5) * parameters.rotationsSpreadingRange + parameters.rotationsSpreadingCenter; // spread rotations - - if (config.translate) for(int l = 0; l < offsets[pf_n].size(); l++) offsets[pf_n][l] = 0.0; - - - prior[pf_n] = 1.0 / (float) parameters.numberParticles; - - // set the posterior to the prior at the initialization - posterior[pf_n] = prior[pf_n]; - - classes[pf_n] = activeGestures[pf_n % activeGestures.size()] - 1; - } - -} - -//-------------------------------------------------------------- -void GVF::initNoiseParameters() { - - // NOISE (ADDITIVE GAUSSIAN NOISE) - // --------------------------- - - if (parameters.dynamicsVariance.size() != dynamicsDim) - { - float variance = parameters.dynamicsVariance[0]; - parameters.dynamicsVariance.resize(dynamicsDim); - for (int k=0; k<dynamicsDim; k++) - parameters.dynamicsVariance[k] = variance; - } - - if (parameters.scalingsVariance.size() != scalingsDim) - { - float variance = parameters.scalingsVariance[0]; - parameters.scalingsVariance.resize(scalingsDim); - for (int k=0; k<scalingsDim; k++) - parameters.scalingsVariance[k] = variance; - } - - if (rotationsDim!=0) - { - if (parameters.rotationsVariance.size() != rotationsDim) - { - float variance = parameters.rotationsVariance[0]; - parameters.rotationsVariance.resize(rotationsDim); - for (int k=0; k<rotationsDim; k++) - parameters.rotationsVariance[k] = variance; - } - } - - // ADAPTATION OF THE TOLERANCE IF DEFAULT PARAMTERS - // --------------------------- - if (!tolerancesetmanually){ - float obsMeanRange = 0.0f; - for (int gt=0; gt<gestureTemplates.size(); gt++) { - for (int d=0; d<config.inputDimensions; d++) - obsMeanRange += (gestureTemplates[gt].getMaxRange()[d] - gestureTemplates[gt].getMinRange()[d]) - /config.inputDimensions; - } - obsMeanRange /= gestureTemplates.size(); - parameters.tolerance = obsMeanRange / 4.0f; // dividing by an heuristic factor [to be learned?] - } -} - -//-------------------------------------------------------------- -void GVF::setState(GVFState _state, vector<int> indexes) -{ - switch (_state) - { - case STATE_CLEAR: - clear(); - theGesture.clear(); - break; - - case STATE_LEARNING: - if ((state==STATE_LEARNING) && (theGesture.getNumberOfTemplates()>0)) - { - if (learningGesture==-1) - addGestureTemplate(theGesture); - else - { - replaceGestureTemplate(theGesture, learningGesture); - learningGesture=-1; - } - if (indexes.size()!=0) - learningGesture=indexes[0]; - } - state = _state; - theGesture.clear(); - break; - - case STATE_FOLLOWING: - if ((state==STATE_LEARNING) && (theGesture.getNumberOfTemplates()>0)) - { - if (learningGesture==-1) - addGestureTemplate(theGesture); - else - { - replaceGestureTemplate(theGesture, learningGesture); - learningGesture=-1; - } - } - if (gestureTemplates.size() > 0) - { - train(); - state = _state; - } - else - state = STATE_CLEAR; - theGesture.clear(); - break; - - default: - theGesture.clear(); - break; - } -} - -//-------------------------------------------------------------- -GVF::GVFState GVF::getState() -{ - return state; -} - -////-------------------------------------------------------------- -//int GVF::getDynamicsDimension(){ -// return dynamicsDim; -//} - -//-------------------------------------------------------------- -vector<int> GVF::getGestureClasses() -{ - return classes; -} - -////-------------------------------------------------------------- -//vector<float> GVF::getAlignment(){ -// return alignment; -//} -// -////-------------------------------------------------------------- -//vector<float> GVF::getEstimatedAlignment(){ -// return estimatedAlignment; -//} -// -////-------------------------------------------------------------- -//vector< vector<float> > GVF::getDynamics(){ -// return dynamics; -//} -// -////-------------------------------------------------------------- -//vector< vector<float> > GVF::getEstimatedDynamics(){ -// return estimatedDynamics; -//} -// -////-------------------------------------------------------------- -//vector< vector<float> > GVF::getScalings(){ -// return scalings; -//} -// -////-------------------------------------------------------------- -//vector< vector<float> > GVF::getEstimatedScalings(){ -// return estimatedScalings; -//} -// -////-------------------------------------------------------------- -//vector< vector<float> > GVF::getRotations(){ -// return rotations; -//} -// -////-------------------------------------------------------------- -//vector< vector<float> > GVF::getEstimatedRotations(){ -// return estimatedRotations; -//} - -////-------------------------------------------------------------- -//vector<float> GVF::getEstimatedProbabilities(){ -// return estimatedProbabilities; -//} -// -////-------------------------------------------------------------- -//vector<float> GVF::getEstimatedLikelihoods(){ -// return estimatedLikelihoods; -//} -// -////-------------------------------------------------------------- -//vector<float> GVF::getWeights(){ -// return weights; -//} -// -////-------------------------------------------------------------- -//vector<float> GVF::getPrior(){ -// return prior; -//} - -////-------------------------------------------------------------- -//vector<vector<float> > GVF::getVecRef() { -// return vecRef; -//} -// -////-------------------------------------------------------------- -//vector<float> GVF::getVecObs() { -// return vecObs; -//} -// -////-------------------------------------------------------------- -//vector<float> GVF::getStateNoiseDist(){ -// return stateNoiseDist; -//} - -////-------------------------------------------------------------- -//int GVF::getScalingsDim(){ -// return scalingsDim; -//} -// -////-------------------------------------------------------------- -//int GVF::getRotationsDim(){ -// return rotationsDim; -//} - -//-------------------------------------------------------------- -void GVF::restart() -{ - theGesture.clear(); - initPrior(); -} - -#pragma mark - PARTICLE FILTERING - -//-------------------------------------------------------------- -void GVF::updatePrior(int n) { - - // Update alignment / dynamics / scalings - float L = gestureTemplates[classes[n]].getTemplateLength(); - alignment[n] += (*rndnorm)(normgen) * parameters.alignmentVariance + dynamics[n][0]/L; // + dynamics[n][1]/(L*L); - - if (dynamics[n].size()>1){ - dynamics[n][0] += (*rndnorm)(normgen) * parameters.dynamicsVariance[0] + dynamics[n][1]/L; - dynamics[n][1] += (*rndnorm)(normgen) * parameters.dynamicsVariance[1]; - } - else { - dynamics[n][0] += (*rndnorm)(normgen) * parameters.dynamicsVariance[0]; - } - - // for(int l= 0; l < dynamics[n].size(); l++) dynamics[n][l] += (*rndnorm)(normgen) * parameters.dynamicsVariance[l]; - for(int l= 0; l < scalings[n].size(); l++) scalings[n][l] += (*rndnorm)(normgen) * parameters.scalingsVariance[l]; - if (rotationsDim!=0) for(int l= 0; l < rotations[n].size(); l++) rotations[n][l] += (*rndnorm)(normgen) * parameters.rotationsVariance[l]; - - // update prior (bayesian incremental inference) - prior[n] = posterior[n]; -} - -//-------------------------------------------------------------- -void GVF::updateLikelihood(vector<float> obs, int n) -{ - -// if (config.normalization) for (int kk=0; kk<vobs.size(); kk++) vobs[kk] = vobs[kk] / globalNormalizationFactor; - - if(alignment[n] < 0.0) - { - alignment[n] = fabs(alignment[n]); // re-spread at the beginning -// if (config.segmentation) -// classes[n] = n % getNumberOfGestureTemplates(); - } - else if(alignment[n] > 1.0) - { - if (config.segmentation) - { -// alignment[n] = fabs(1.0-alignment[n]); // re-spread at the beginning - alignment[n] = fabs((*rndunif)(unifgen) * 0.5); // - classes[n] = n % getNumberOfGestureTemplates(); - offsets[n] = obs; - // dynamics - dynamics[n][0] = ((*rndunif)(unifgen) - 0.5) * parameters.dynamicsSpreadingRange + parameters.dynamicsSpreadingCenter; // spread speed - if (dynamics[n].size()>1) - dynamics[n][1] = ((*rndunif)(unifgen) - 0.5) * parameters.dynamicsSpreadingRange; - // scalings - for(int l = 0; l < scalings[n].size(); l++) - scalings[n][l] = ((*rndunif)(unifgen) - 0.5) * parameters.scalingsSpreadingRange + parameters.scalingsSpreadingCenter; // spread scalings - // rotations - if (rotationsDim!=0) - for(int l = 0; l < rotations[n].size(); l++) - rotations[n][l] = ((*rndunif)(unifgen) - 0.5) * parameters.rotationsSpreadingRange + parameters.rotationsSpreadingCenter; // spread rotations - // prior - prior[n] = 1/(float)parameters.numberParticles; - } - else{ - alignment[n] = fabs(2.0-alignment[n]); // re-spread at the end - } - } - - vector<float> vobs(config.inputDimensions); - setVec(vobs, obs); - - if (config.translate) - for (int j=0; j < config.inputDimensions; j++) - vobs[j] = vobs[j] - offsets[n][j]; - - - // take vref from template at the given alignment - int gestureIndex = classes[n]; - float cursor = alignment[n]; - int frameindex = min((int)(gestureTemplates[gestureIndex].getTemplateLength() - 1), - (int)(floor(cursor * gestureTemplates[gestureIndex].getTemplateLength() ) ) ); -// return gestureTemplates[gestureIndex].getTemplate()[frameindex]; - vector<float> vref = gestureTemplates[gestureIndex].getTemplate()[frameindex];; //getGestureTemplateSample(classes[n], alignment[n]); - - // Apply scaling coefficients - for (int k=0;k < config.inputDimensions; k++) - { -// if (config.normalization) vref[k] = vref[k] / globalNormalizationFactor; - vref[k] *= scalings[n][k]; - } - - // Apply rotation coefficients - if (config.inputDimensions==2) { - float tmp0=vref[0]; float tmp1=vref[1]; - vref[0] = cos(rotations[n][0])*tmp0 - sin(rotations[n][0])*tmp1; - vref[1] = sin(rotations[n][0])*tmp0 + cos(rotations[n][0])*tmp1; - } - else if (config.inputDimensions==3) { - // Rotate template sample according to the estimated angles of rotations (3d) - vector<vector< float> > RotMatrix = getRotationMatrix3d(rotations[n][0],rotations[n][1],rotations[n][2]); - vref = multiplyMat(RotMatrix, vref); - } - - // weighted euclidean distance - float dist = distance_weightedEuclidean(vref,vobs,parameters.dimWeights); - - if(parameters.distribution == 0.0f){ // Gaussian distribution - likelihood[n] = exp(- dist * 1 / (parameters.tolerance * parameters.tolerance)); - } - else { // Student's distribution - likelihood[n] = pow(dist/parameters.distribution + 1, -parameters.distribution/2 - 1); // dimension is 2 .. pay attention if editing] - } -// // if log on keep track on vref and vobs -// if (config.logOn){ -// vecRef.push_back(vref); -// vecObs = vobs; -// } -} - -//-------------------------------------------------------------- -void GVF::updatePosterior(int n) { - posterior[n] = prior[n] * likelihood[n]; -} - -//-------------------------------------------------------------- -GVFOutcomes & GVF::update(vector<float> & observation) -{ - - if (state != GVF::STATE_FOLLOWING) setState(GVF::STATE_FOLLOWING); - - theGesture.addObservation(observation); - vector<float> obs = theGesture.getLastObservation(); - - // std::cout << obs[0] << " " << obs[0] << " " - // << gestureTemplates[0].getTemplate()[20][0] << " " << gestureTemplates[0].getTemplate()[20][1] << " " - // << gestureTemplates[1].getTemplate()[20][0] << " " << gestureTemplates[1].getTemplate()[20][1] << std::endl; - - - // for each particle: perform updates of state space / likelihood / prior (weights) - float sumw = 0.0; - for(int n = 0; n< parameters.numberParticles; n++) - { - - for (int m=0; m<parameters.predictionSteps; m++) - { - updatePrior(n); - updateLikelihood(obs, n); - updatePosterior(n); - } - - sumw += posterior[n]; // sum posterior to normalise the distrib afterwards - - particles[n][0] = alignment[n]; - particles[n][1] = scalings[n][0]; - particles[n][2] = classes[n]; - } - - // normalize the weights and compute the resampling criterion - float dotProdw = 0.0; - for (int k = 0; k < parameters.numberParticles; k++){ - posterior[k] /= sumw; - dotProdw += posterior[k] * posterior[k]; - } - // avoid degeneracy (no particles active, i.e. weight = 0) by resampling - if( (1./dotProdw) < parameters.resamplingThreshold) - resampleAccordingToWeights(obs); - - // estimate outcomes - estimates(); - - return outcomes; - -} - -//-------------------------------------------------------------- -void GVF::resampleAccordingToWeights(vector<float> obs) -{ - // covennient - int numOfPart = parameters.numberParticles; - - // cumulative dist - vector<float> c(numOfPart); - - // tmp matrices - vector<int> oldClasses; - vector<float> oldAlignment; - vector< vector<float> > oldDynamics; - vector< vector<float> > oldScalings; - vector< vector<float> > oldRotations; - - setVec(oldClasses, classes); - setVec(oldAlignment, alignment); - setMat(oldDynamics, dynamics); - setMat(oldScalings, scalings); - if (rotationsDim!=0) setMat(oldRotations, rotations); - - - c[0] = 0; - for(int i = 1; i < numOfPart; i++) c[i] = c[i-1] + posterior[i]; - - - float u0 = (*rndunif)(unifgen)/numOfPart; - - int i = 0; - for (int j = 0; j < numOfPart; j++) - { - float uj = u0 + (j + 0.) / numOfPart; - - while (uj > c[i] && i < numOfPart - 1){ - i++; - } - - classes[j] = oldClasses[i]; - alignment[j] = oldAlignment[i]; - - for (int l=0;l<dynamicsDim;l++) dynamics[j][l] = oldDynamics[i][l]; - for (int l=0;l<scalingsDim;l++) scalings[j][l] = oldScalings[i][l]; - if (rotationsDim!=0) for (int l=0;l<rotationsDim;l++) rotations[j][l] = oldRotations[i][l]; - - // update posterior (partilces' weights) - posterior[j] = 1.0/(float)numOfPart; - } - -} - - -//-------------------------------------------------------------- -void GVF::estimates(){ - - - int numOfPart = parameters.numberParticles; - vector<float> probabilityNormalisation(getNumberOfGestureTemplates()); - setVec(probabilityNormalisation, 0.0f, getNumberOfGestureTemplates()); // rows are gestures - setVec(estimatedAlignment, 0.0f, getNumberOfGestureTemplates()); // rows are gestures - setMat(estimatedDynamics, 0.0f, getNumberOfGestureTemplates(), dynamicsDim); // rows are gestures, cols are features + probabilities - setMat(estimatedScalings, 0.0f, getNumberOfGestureTemplates(), scalingsDim); // rows are gestures, cols are features + probabilities - if (rotationsDim!=0) setMat(estimatedRotations, 0.0f, getNumberOfGestureTemplates(), rotationsDim); // .. - setVec(estimatedProbabilities, 0.0f, getNumberOfGestureTemplates()); // rows are gestures - setVec(estimatedLikelihoods, 0.0f, getNumberOfGestureTemplates()); // rows are gestures - - // float sumposterior = 0.; - - for(int n = 0; n < numOfPart; n++) - { - probabilityNormalisation[classes[n]] += posterior[n]; - } - - - // compute the estimated features and likelihoods - for(int n = 0; n < numOfPart; n++) - { - - // sumposterior += posterior[n]; - estimatedAlignment[classes[n]] += alignment[n] * posterior[n]; - - for(int m = 0; m < dynamicsDim; m++) - estimatedDynamics[classes[n]][m] += dynamics[n][m] * (posterior[n]/probabilityNormalisation[classes[n]]); - - for(int m = 0; m < scalingsDim; m++) - estimatedScalings[classes[n]][m] += scalings[n][m] * (posterior[n]/probabilityNormalisation[classes[n]]); - - if (rotationsDim!=0) - for(int m = 0; m < rotationsDim; m++) - estimatedRotations[classes[n]][m] += rotations[n][m] * (posterior[n]/probabilityNormalisation[classes[n]]); - - if (!isnan(posterior[n])) - estimatedProbabilities[classes[n]] += posterior[n]; - estimatedLikelihoods[classes[n]] += likelihood[n]; - } - - // calculate most probable index during scaling... - float maxProbability = 0.0f; - mostProbableIndex = -1; - - for(int gi = 0; gi < getNumberOfGestureTemplates(); gi++) - { - if(estimatedProbabilities[gi] > maxProbability){ - maxProbability = estimatedProbabilities[gi]; - mostProbableIndex = gi; - } - } - // std::cout << estimatedProbabilities[0] << " " << estimatedProbabilities[1] << std::endl; - - // outcomes.estimations.clear(); - outcomes.likelihoods.clear(); - outcomes.alignments.clear(); - outcomes.scalings.clear(); - outcomes.dynamics.clear(); - outcomes.rotations.clear(); - - // most probable gesture index - outcomes.likeliestGesture = mostProbableIndex; - - // Fill estimation for each gesture - for (int gi = 0; gi < gestureTemplates.size(); ++gi) { - - // GVFEstimation estimation; - outcomes.likelihoods.push_back(estimatedProbabilities[gi]); - outcomes.alignments.push_back(estimatedAlignment[gi]); - // estimation.probability = estimatedProbabilities[gi]; - // estimation.alignment = estimatedAlignment[gi]; - - - vector<float> gDynamics(dynamicsDim, 0.0); - for (int j = 0; j < dynamicsDim; ++j) gDynamics[j] = estimatedDynamics[gi][j]; - outcomes.dynamics.push_back(gDynamics); - - vector<float> gScalings(scalingsDim, 0.0); - for (int j = 0; j < scalingsDim; ++j) gScalings[j] = estimatedScalings[gi][j]; - outcomes.scalings.push_back(gScalings); - - vector<float> gRotations; - if (rotationsDim!=0) - { - gRotations.resize(rotationsDim); - for (int j = 0; j < rotationsDim; ++j) gRotations[j] = estimatedRotations[gi][j]; - outcomes.rotations.push_back(gRotations); - } - - // estimation.likelihood = estimatedLikelihoods[gi]; - - // push estimation for gesture gi in outcomes - // outcomes.estimations.push_back(estimation); - } - - - // assert(outcomes.estimations.size() == gestureTemplates.size()); - -} - -////-------------------------------------------------------------- -//int GVF::getMostProbableGestureIndex() -//{ -// return mostProbableIndex; -//} - -////-------------------------------------------------------------- -//GVFOutcomes GVF::getOutcomes() -//{ -// return outcomes; -//} - -////-------------------------------------------------------------- -//GVFEstimation GVF::getTemplateRecogInfo(int templateNumber) -//{ -// if (getOutcomes().estimations.size() <= templateNumber) { -// GVFEstimation estimation; -// return estimation; // blank -// } -// else -// return getOutcomes().estimations[templateNumber]; -//} -// -////-------------------------------------------------------------- -//GVFEstimation GVF::getRecogInfoOfMostProbable() // FIXME: Rename! -//{ -// int indexMostProbable = getMostProbableGestureIndex(); -// -// if ((getState() == GVF::STATE_FOLLOWING) && (getMostProbableGestureIndex() != -1)) { -// return getTemplateRecogInfo(indexMostProbable); -// } -// else { -// GVFEstimation estimation; -// return estimation; // blank -// } -//} - - -////-------------------------------------------------------------- -//vector<float> & GVF::getGestureProbabilities() -//{ -// gestureProbabilities.resize(getNumberOfGestureTemplates()); -// setVec(gestureProbabilities, 0.0f); -// for(int n = 0; n < parameters.numberParticles; n++) -// gestureProbabilities[classes[n]] += posterior[n]; -// -// return gestureProbabilities; -//} - -//-------------------------------------------------------------- -const vector<vector<float> > & GVF::getParticlesPositions(){ - return particles; -} - -////-------------------------------------------------------------- -//void GVF::setParameters(GVFParameters _parameters){ -// -// // if the number of particles has changed, we have to re-allocate matrices -// if (_parameters.numberParticles != parameters.numberParticles) -// { -// parameters = _parameters; -// -// // minimum number of particles allowed -// if (parameters.numberParticles < 4) parameters.numberParticles = 4; -// -// // re-learn -// train(); -// -// // adapt the resampling threshold in case if RT < NS -// if (parameters.numberParticles <= parameters.resamplingThreshold) -// parameters.resamplingThreshold = parameters.numberParticles / 4; -// -// } -// else -// parameters = _parameters; -// -// -//} -// -//GVFParameters GVF::getParameters(){ -// return parameters; -//} - -//-------------------------------------------------------------- -// Update the number of particles -void GVF::setNumberOfParticles(int numberOfParticles){ - - parameters.numberParticles = numberOfParticles; - - if (parameters.numberParticles < 4) // minimum number of particles allowed - parameters.numberParticles = 4; - - train(); - - if (parameters.numberParticles <= parameters.resamplingThreshold) { - parameters.resamplingThreshold = parameters.numberParticles / 4; - } - -} - -//-------------------------------------------------------------- -int GVF::getNumberOfParticles(){ - return parameters.numberParticles; // Return the number of particles -} - -//-------------------------------------------------------------- -void GVF::setActiveGestures(vector<int> activeGestureIds) -{ - int argmax = *std::max_element(activeGestureIds.begin(), activeGestureIds.end()); - if (activeGestureIds[argmax] <= gestureTemplates.size()) - { - activeGestures = activeGestureIds; - } - else - { - activeGestures.resize(gestureTemplates.size()); - std::iota(activeGestures.begin(), activeGestures.end(), 1); - } -} - -//-------------------------------------------------------------- -void GVF::setPredictionSteps(int predictionSteps) -{ - if (predictionSteps<1) - parameters.predictionSteps = 1; - else - parameters.predictionSteps = predictionSteps; -} - -//-------------------------------------------------------------- -int GVF::getPredictionSteps() -{ - return parameters.predictionSteps; // Return the number of particles -} - -//-------------------------------------------------------------- -// Update the resampling threshold used to avoid degeneracy problem -void GVF::setResamplingThreshold(int _resamplingThreshold){ - if (_resamplingThreshold >= parameters.numberParticles) - _resamplingThreshold = floor(parameters.numberParticles/2.0f); - parameters.resamplingThreshold = _resamplingThreshold; -} - -//-------------------------------------------------------------- -// Return the resampling threshold used to avoid degeneracy problem -int GVF::getResamplingThreshold(){ - return parameters.resamplingThreshold; -} - -//-------------------------------------------------------------- -// Update the standard deviation of the observation distribution -// this value acts as a tolerance for the algorithm -// low value: less tolerant so more precise but can diverge -// high value: more tolerant so less precise but converge more easily -void GVF::setTolerance(float _tolerance){ - if (_tolerance <= 0.0) _tolerance = 0.1; - parameters.tolerance = _tolerance; - tolerancesetmanually = true; -} - -//-------------------------------------------------------------- -float GVF::getTolerance(){ - return parameters.tolerance; -} - -////-------------------------------------------------------------- -void GVF::setDistribution(float _distribution){ - //nu = _distribution; - parameters.distribution = _distribution; -} -// -////-------------------------------------------------------------- -//float GVF::getDistribution(){ -// return parameters.distribution; -//} - -//void GVF::setDimWeights(vector<float> dimWeights){ -// if (dimWeights.size()!=parameters.dimWeights.size()) -// parameters.dimWeights.resize(dimWeights.size()); -// parameters.dimWeights = dimWeights; -//} -// -//vector<float> GVF::getDimWeights(){ -// return parameters.dimWeights; -//} - - -//// VARIANCE COEFFICIENTS: PHASE -////-------------------------------------------------------------- -//void GVF::setAlignmentVariance(float alignmentVariance){ -// parameters.alignmentVariance = sqrt(alignmentVariance); -//} -////-------------------------------------------------------------- -//float GVF::getAlignmentVariance(){ -// return parameters.alignmentVariance; -//} - - -// VARIANCE COEFFICIENTS: DYNAMICS -//-------------------------------------------------------------- -//void GVF::setDynamicsVariance(float dynVariance) -//{ -// for (int k=0; k< parameters.dynamicsVariance.size(); k++) -// parameters.dynamicsVariance[k] = dynVariance; -//} -//-------------------------------------------------------------- -void GVF::setDynamicsVariance(float dynVariance, int dim) -{ - if (dim == -1) - { - for (int k=0; k< parameters.dynamicsVariance.size(); k++) - parameters.dynamicsVariance[k] = dynVariance; - } - else - { - if (dim<parameters.dynamicsVariance.size()) - parameters.dynamicsVariance[dim-1] = dynVariance; - } -} - -//-------------------------------------------------------------- -void GVF::setDynamicsVariance(vector<float> dynVariance) -{ - parameters.dynamicsVariance = dynVariance; -} -//-------------------------------------------------------------- -vector<float> GVF::getDynamicsVariance() -{ - return parameters.dynamicsVariance; -} - -//-------------------------------------------------------------- -void GVF::setScalingsVariance(float scaleVariance, int dim) -{ - if (dim == -1) - { - for (int k=0; k< parameters.scalingsVariance.size(); k++) - parameters.scalingsVariance[k] = scaleVariance; - } - else - { - if (dim<parameters.scalingsVariance.size()) - parameters.scalingsVariance[dim-1] = scaleVariance; - } -} - -//-------------------------------------------------------------- -void GVF::setScalingsVariance(vector<float> scaleVariance) -{ - parameters.scaleVariance = scaleVariance; -} - -//-------------------------------------------------------------- -vector<float> GVF::getScalingsVariance() -{ - return parameters.scalingsVariance; -} - -//-------------------------------------------------------------- -void GVF::setRotationsVariance(float rotationVariance, int dim) -{ - if (dim == -1) - { - for (int k=0; k< parameters.rotationsVariance.size(); k++) - parameters.rotationsVariance[k] = rotationVariance; - } - else - { - if (dim<parameters.rotationsVariance.size()) - parameters.scalingsVariance[dim-1] = rotationVariance; - } -} - -//-------------------------------------------------------------- -void GVF::setRotationsVariance(vector<float> rotationVariance) -{ - parameters.scaleVariance = rotationVariance; -} - -//-------------------------------------------------------------- -vector<float> GVF::getRotationsVariance() -{ - return parameters.rotationsVariance; -} - -//-------------------------------------------------------------- -void GVF::setSpreadDynamics(float center, float range, int dim) -{ - parameters.dynamicsSpreadingCenter = center; - parameters.dynamicsSpreadingRange = range; -} - -//-------------------------------------------------------------- -void GVF::setSpreadScalings(float center, float range, int dim) -{ - parameters.scalingsSpreadingCenter = center; - parameters.scalingsSpreadingRange = range; -} - -//-------------------------------------------------------------- -void GVF::setSpreadRotations(float center, float range, int dim) -{ - parameters.rotationsSpreadingCenter = center; - parameters.rotationsSpreadingRange = range; -} - -//-------------------------------------------------------------- -void GVF::translate(bool translateFlag) -{ - config.translate = translateFlag; -} - -//-------------------------------------------------------------- -void GVF::segmentation(bool segmentationFlag) -{ - config.segmentation = segmentationFlag; -} - - -// UTILITIES - -//-------------------------------------------------------------- -// Save function. This function is used by applications to save the -// vocabulary in a text file given by filename (filename is also the complete path + filename) -void GVF::saveTemplates(string filename){ - - std::string directory = filename; - - std::ofstream file_write(directory.c_str()); - - for(int i=0; i < gestureTemplates.size(); i++) // Number of gesture templates - { - file_write << "template " << i << " " << config.inputDimensions << endl; - vector<vector<float> > templateTmp = gestureTemplates[i].getTemplate(); - for(int j = 0; j < templateTmp.size(); j++) - { - for(int k = 0; k < config.inputDimensions; k++) - file_write << templateTmp[j][k] << " "; - file_write << endl; - } - } - file_write.close(); - -} - - - - -//-------------------------------------------------------------- -// Load function. This function is used by applications to load a vocabulary -// given by filename (filename is also the complete path + filename) -void GVF::loadTemplates(string filename){ - // clear(); - // - - GVFGesture loadedGesture; - loadedGesture.clear(); - - ifstream infile; - stringstream doung; - - infile.open (filename.c_str(), ifstream::in); - // - string line; - vector<string> list; - int cl = -1; - while(!infile.eof()) - { - cl++; - infile >> line; - - list.push_back(line); - } - - int k = 0; - int template_id = -1; - int template_dim = 0; - - - while (k < (list.size() - 1)){ // TODO to be changed if dim>2 - - - if (!strcmp(list[k].c_str(),"template")) - { - template_id = atoi(list[k+1].c_str()); - template_dim = atoi(list[k+2].c_str()); - k = k + 3; - - if (loadedGesture.getNumberOfTemplates() > 0){ - addGestureTemplate(loadedGesture); - loadedGesture.clear(); - } - } - - if (template_dim <= 0){ - //post("bug dim = -1"); - } - else{ - - vector<float> vect(template_dim); - - for (int kk = 0; kk < template_dim; kk++) - vect[kk] = (float) atof(list[k + kk].c_str()); - - loadedGesture.addObservation(vect); - } - k += template_dim; - - } - - if (loadedGesture.getTemplateLength() > 0){ - addGestureTemplate(loadedGesture); - loadedGesture.clear(); - } - - infile.close(); -} - - - - - - diff --git a/GVF/GVF.h b/GVF/GVF.h deleted file mode 100755 index 647fe7c6ea372e9ec8fc265a946fb3a44c91abcc..0000000000000000000000000000000000000000 --- a/GVF/GVF.h +++ /dev/null @@ -1,487 +0,0 @@ -/** - * Gesture Variation Follower class allows for early gesture recognition and variation tracking - * - * @details Original algorithm designed and implemented in 2011 at Ircam Centre Pompidou - * by Baptiste Caramiaux and Nicola Montecchio. The library has been created and is maintained by Baptiste Caramiaux - * - * Copyright (C) 2015 Baptiste Caramiaux, Nicola Montecchio - * STMS lab Ircam-CRNS-UPMC, University of Padova, Goldsmiths College University of London - * - * The library is under the GNU Lesser General Public License (LGPL v3) - */ - - -#ifndef _H_GVF -#define _H_GVF - -#include "GVFUtils.h" -#include "GVFGesture.h" -#include <random> -#include <iostream> -#include <iomanip> -#include <string> -#include <map> -#include <random> -#include <cmath> - - -using namespace std; - -class GVF -{ - -public: - - /** - * GVF possible states - */ - enum GVFState - { - STATE_CLEAR = 0, /**< STATE_CLEAR: clear the GVF and be in standby */ - STATE_LEARNING, /**< STATE_LEARNING: recording mode, input gestures are added to the templates */ - STATE_FOLLOWING, /**< STATE_FOLLOWING: tracking mode, input gestures are classifed and their variations tracked (need the GVF to be trained) */ - STATE_BYPASS /**< STATE_BYPASS: by pass GVF but does not erase templates or training */ - }; - - -#pragma mark - Constructors - - /** - * GVF default constructor - * @details use default configuration and parameters, can be changed using accessors - */ - GVF(); - - /** - * GVF default destructor - */ - ~GVF(); - -#pragma mark - Gesture templates - - /** - * Start a gesture either to be recorded or followed - */ - void startGesture(); - - /** - * Add an observation to a gesture template - * @details - * @param data vector of features - */ - void addObservation(vector<float> data); - - /** - * Add gesture template to the vocabulary - * - * @details a gesture template is a GVFGesture object and can be added directly to the vocabulqry or - * recorded gesture templates by using this method - * @param gestureTemplate the gesture template to be recorded - */ - void addGestureTemplate(GVFGesture & gestureTemplate); - - /** - * Replace a specific gesture template by another - * - * @param gestureTemplate the gesture template to be used - * @param index the gesture index (as integer) to be replaced - */ - void replaceGestureTemplate(GVFGesture & gestureTemplate, int index); - - /** - * Remove a specific template - * - * @param index the gesture index (as integer) to be removed - */ - void removeGestureTemplate(int index); - - /** - * Remove every recorded gesture template - */ - void removeAllGestureTemplates(); - - /** - * Get a specific gesture template a gesture template by another - * - * @param index the index of the template to be returned - * @return the template - */ - GVFGesture & getGestureTemplate(int index); - - /** - * Get every recorded gesture template - * - * @return the vecotr of gesture templates - */ - vector<GVFGesture> & getAllGestureTemplates(); - - /** - * Get number of gesture templates in the vocabulary - * @return the number of templates - */ - int getNumberOfGestureTemplates(); - - /** - * Get gesture classes - */ - vector<int> getGestureClasses(); - - -#pragma mark - Recognition and tracking - - /** - * Set the state of GVF - * @param _state the state to be given to GVF, it is a GVFState - * @param indexes an optional argument providing a list of gesture index. - * In learning mode the index of the gesture being recorded can be given as an argument - * since the type is vector<int>, it should be something like '{3}'. In following mode, the list of indexes - * is the list of active gestures to be considered in the recognition/tracking. - */ - void setState(GVFState _state, vector<int> indexes = vector<int>()); - - /** - * Return the current state of GVF - * @return GVFState the current state - */ - GVFState getState(); - - /** - * Compute the estimated gesture and its potential variations - * - * @details infers the probability that the current observation belongs to - * one of the recorded gesture template and track the variations of this gesture - * according to each template - * - * @param observation vector of the observation data at current time - * @return the estimated probabilities and variaitons relative to each template - */ - GVFOutcomes & update(vector<float> & observation); - - /** - * Define a subset of gesture templates on which to perform the recognition - * and variation tracking - * - * @details By default every recorded gesture template is considered - * @param set of gesture template index to consider - */ - void setActiveGestures(vector<int> activeGestureIds); - - /** - * Restart GVF - * @details re-sample particles at the origin (i.e. initial prior) - */ - void restart(); - - /** - * Clear GVF - * @details delete templates - */ - void clear(); - - /** - * Translate data according to the first point - * @details substract each gesture feature by the first point of the gesture - * @param boolean to activate or deactivate translation - */ - void translate(bool translateFlag); - - /** - * Segment gestures within a continuous gesture stream - * @details if segmentation is true, the method will segment a continuous gesture into a sequence - * of gestures. In other words no need to call the method startGesture(), it is done automatically - * @param segmentationFlag boolean to activate or deactivate segmentation - */ - void segmentation(bool segmentationFlag); - -#pragma mark - [ Accessors ] -#pragma mark > Parameters - /** - * Set tolerance between observation and estimation - * @details tolerance depends on the range of the data - * typially tolerance = (data range)/3.0; - * @param tolerance value - */ - void setTolerance(float tolerance); - - /** - * Get the obervation tolerance value - * @details see setTolerance(float tolerance) - * @return the current toleranc value - */ - float getTolerance(); - - void setDistribution(float _distribution); - - /** - * Set number of particles used in estimation - * @details default valye is 1000, note that the computational - * cost directly depends on the number of particles - * @param new number of particles - */ - void setNumberOfParticles(int numberOfParticles); - - /** - * Get the current number of particles - * @return the current number of particles - */ - int getNumberOfParticles(); - - /** - * Number of prediciton steps - * @details it is possible to leave GVF to perform few steps of prediction - * ahead which can be useful to estimate more fastly the variations. Default value is 1 - * which means no prediction ahead - * @param the number of prediction steps - */ - void setPredictionSteps(int predictionSteps); - - /** - * Get the current number of prediction steps - * @return current number of prediciton steps - */ - int getPredictionSteps(); - - /** - * Set resampling threshold - * @details resampling threshold is the minimum number of active particles - * before resampling all the particles by the estimated posterior distribution. - * in other words, it re-targets particles around the best current estimates - * @param the minimum number of particles (default is (number of particles)/2) - */ - void setResamplingThreshold(int resamplingThreshold); - - /** - * Get the current resampling threshold - * @return resampling threshold - */ - int getResamplingThreshold(); - -#pragma mark > Dynamics - /** - * Change variance of adaptation in dynamics - * @details if dynamics adaptation variance is high the method will adapt faster to - * fast changes in dynamics. Dynamics is 2-dimensional: the first dimension is the speed - * The second dimension is the acceleration. - * - * Typically the variance is the average amount the speed or acceleration can change from - * one sample to another. As an example, if the relative estimated speed can change from 1.1 to 1.2 - * from one sample to another, the variance should allow a change of 0.1 in speed. So the variance - * should be set to 0.1*0.1 = 0.01 - * - * @param dynVariance dynamics variance value - * @param dim optional dimension of the dynamics for which the change of variance is applied (default value is 1) - */ - void setDynamicsVariance(float dynVariance, int dim = -1); - - /** - * Change variance of adaptation in dynamics - * @details See setDynamicsVariance(float dynVariance, int dim) for more details - * @param dynVariance vector of dynamics variances, each vector index is the variance to be applied to - * each dynamics dimension (consequently the vector should be 2-dimensional). - */ - void setDynamicsVariance(vector<float> dynVariance); - - /** - * Get dynamics variances - * @return the vector of variances (the returned vector is 2-dimensional) - */ - vector<float> getDynamicsVariance(); - -#pragma mark > Scalings - /** - * Change variance of adaptation in scalings - * @details if scalings adaptation variance is high the method will adapt faster to - * fast changes in relative sizes. There is one scaling variance for each dimension - * of the input gesture. If the gesture is 2-dimensional, the scalings variances will - * also be 2-dimensional. - * - * Typically the variance is the average amount the size can change from - * one sample to another. As an example, if the relative estimated size changes from 1.1 to 1.15 - * from one sample to another, the variance should allow a change of 0.05 in size. So the variance - * should be set to 0.05*0.05 = 0.0025 - * - * @param scalings variance value - * @param dimension of the scalings for which the change of variance is applied - */ - void setScalingsVariance(float scaleVariance, int dim = -1); - - /** - * Change variance of adaptation in dynamics - * @details See setScalingsVariance(float scaleVariance, int dim) for more details - * @param vector of scalings variances, each vector index is the variance to be applied to - * each scaling dimension. - * @param vector of variances (should be the size of the template gestures dimension) - */ - void setScalingsVariance(vector<float> scaleVariance); - - /** - * Get scalings variances - * @return the vector of variances - */ - vector<float> getScalingsVariance(); - -#pragma mark > Rotations - /** - * Change variance of adaptation in orientation - * @details if rotation adaptation variance is high the method will adapt faster to - * fast changes in relative orientation. If the gesture is 2-dimensional, there is - * one variance value since the rotation can be defined by only one angle of rotation. If - * the gesture is 3-dimensional, there are 3 variance values since the rotation in 3-d is - * defined by 3 rotation angles. For any other dimension, the rotation is not defined. - * - * The variance is the average amount the orientation can change from one sample to another. - * As an example, if the relative orientation in rad changes from 0.1 to 0.2 from one observation - * to another, the variance should allow a change of 0.1 in rotation angle. So the variance - * should be set to 0.1*0.1 = 0.01 - * - * @param rotationsVariance rotation variance value - * @param dim optional dimension of the rotation for which the change of variance is applied - */ - void setRotationsVariance(float rotationsVariance, int dim = -1); - - /** - * Change variance of adaptation in orientation - * @details See setRotationsVariance(float rotationsVariance, int dim) for more details - * @param vector of rotation variances, each vector index is the variance to be applied to - * each rotation angle (1 or 3) - * @param vector of variances (should be 1 if the the template gestures are 2-dim or 3 if - * they are 3-dim) - */ - void setRotationsVariance(vector<float> rotationsVariance); - - /** - * Get rotation variances - * @return the vector of variances - */ - vector<float> getRotationsVariance(); - - -#pragma mark > Others - - /** - * Get particle values - * @return vector of list of estimated particles - */ - const vector<vector<float> > & getParticlesPositions(); - - /** - * Set the interval on which the dynamics values should be spread at the beginning (before adaptation) - * @details this interval can be used to concentrate the potential dynamics value on a narrow interval, - * typically around 1 (the default value), for instance between -0.05 and 0.05, or to allow at the very - * beginning, high changes in dynamics by spreading, for instance between 0.0 and 2.0 - * @param min lower value of the inital values for dynamics - * @param max higher value of the inital values for dynamics - * @param dim the dimension on which the change of initial interval should be applied (optional) - */ - void setSpreadDynamics(float min, float max, int dim = -1); - - /** - * Set the interval on which the scalings values should be spread at the beginning (before adaptation) - * @details this interval can be used to concentrate the potential scalings value on a narrow interval, - * typically around 1.0 (the default value), for instance between 0.95 and 1.05, or to allow at the very - * beginning high changes in dynamics by spreading, for instance, between 0.0 and 2.0 - * @param min lower value of the inital values for scalings - * @param max higher value of the inital values for scalings - * @param dim the dimension on which the change of initial interval should be applied (optional) - */ - void setSpreadScalings(float min, float max, int dim = -1); - - /** - * Set the interval on which the angle of rotation values should be spread at the beginning (before adaptation) - * @details this interval can be used to concentrate the potential angle values on a narrow interval, - * typically around 0.0 (the default value), for instance between -0.05 and 0.05, or to allow at the very - * beginning, high changes in orientation by spreading, for instance, between -0.5 and 0.5 - * @param min lower value of the inital values for angle of rotation - * @param max higher value of the inital values for angle of rotation - * @param dim the dimension on which the change of initial interval should be applied (optional) - */ - void setSpreadRotations(float min, float max, int dim = -1); - -#pragma mark - Import/Export templates - /** - * Export template data in a filename - * @param filename file name as a string - */ - void saveTemplates(string filename); - - /** - * Import template data in a filename - * @details needs to respect a given format provided by saveTemplates() - * @param file name as a string - */ - void loadTemplates(string filename); - -protected: - - GVFConfig config; // Structure storing the configuration of GVF (in GVFUtils.h) - GVFParameters parameters; // Structure storing the parameters of GVF (in GVFUtils.h) - GVFOutcomes outcomes; // Structure storing the outputs of GVF (in GVFUtils.h) - GVFState state; // State (defined above) - GVFGesture theGesture; // GVFGesture object to handle incoming data in learning and following modes - - vector<GVFGesture> gestureTemplates; // vector storing the gesture templates recorded when using the methods addObservation(vector<float> data) or addGestureTemplate(GVFGesture & gestureTemplate) - - vector<float> dimWeights; // TOOD: to be put in parameters? - vector<float> maxRange; - vector<float> minRange; - int dynamicsDim; // dynamics state dimension - int scalingsDim; // scalings state dimension - int rotationsDim; // rotation state dimension - float globalNormalizationFactor; // flagged if normalization - int mostProbableIndex; // cached most probable index - int learningGesture; - - vector<int> classes; // gesture index for each particle [ns x 1] - vector<float > alignment; // alignment index (between 0 and 1) [ns x 1] - vector<vector<float> > dynamics; // dynamics estimation [ns x 2] - vector<vector<float> > scalings; // scalings estimation [ns x D] - vector<vector<float> > rotations; // rotations estimation [ns x A] - vector<float> weights; // weight of each particle [ns x 1] - vector<float> prior; // prior of each particle [ns x 1] - vector<float> posterior; // poserior of each particle [ns x 1] - vector<float> likelihood; // likelihood of each particle [ns x 1] - - // estimations - vector<float> estimatedGesture; // .. - vector<float> estimatedAlignment; // .. - vector<vector<float> > estimatedDynamics; // .. - vector<vector<float> > estimatedScalings; // .. - vector<vector<float> > estimatedRotations; // .. - vector<float> estimatedProbabilities; // .. - vector<float> estimatedLikelihoods; // .. - vector<float> absoluteLikelihoods; // .. - - bool tolerancesetmanually; - - - vector<vector<float> > offsets; // translation offset - - vector<int> activeGestures; - - vector<float> gestureProbabilities; - vector< vector<float> > particles; - -private: - - // random number generator - std::random_device rd; - std::mt19937 normgen; - std::normal_distribution<float> *rndnorm; - std::default_random_engine unifgen; - std::uniform_real_distribution<float> *rndunif; - -#pragma mark - Private methods for model mechanics - void initPrior(); - void initNoiseParameters(); - void updateLikelihood(vector<float> obs, int n); - void updatePrior(int n); - void updatePosterior(int n); - void resampleAccordingToWeights(vector<float> obs); - void estimates(); // update estimated outcome - void train(); - - -}; - - -#endif \ No newline at end of file diff --git a/GVF/GVFGesture.h b/GVF/GVFGesture.h deleted file mode 100644 index d556fb0a9ed0f9ff84f7f09e48a157fd6357ab3b..0000000000000000000000000000000000000000 --- a/GVF/GVFGesture.h +++ /dev/null @@ -1,240 +0,0 @@ -// -// GVFGesture.h -// gvf -// -// Created by Baptiste Caramiaux on 22/01/16. -// -// - -#ifndef GVFGesture_h -#define GVFGesture_h - -#ifndef MAX -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif - - -class GVFGesture -{ -public: - - GVFGesture() - { - inputDimensions = 2; - setAutoAdjustRanges(true); - templatesRaw = vector<vector<vector<float > > >(); - templatesNormal = vector<vector<vector<float > > >(); - clear(); - } - - GVFGesture(int inputDimension){ - inputDimensions = inputDimension; - setAutoAdjustRanges(true); - templatesRaw = vector<vector<vector<float > > >(); - templatesNormal = vector<vector<vector<float > > >(); - clear(); - } - - ~GVFGesture(){ - clear(); - } - - void setNumberDimensions(int dimensions){ - assert(dimensions > 0); - inputDimensions = dimensions; - } - - void setAutoAdjustRanges(bool b){ - // if(b) bIsRangeMinSet = bIsRangeMaxSet = false; - bAutoAdjustNormalRange = b; - } - - void setMax(float x, float y){ - assert(inputDimensions == 2); - vector<float> r(2); - r[0] = x; r[1] = y; - setMaxRange(r); - } - - void setMin(float x, float y){ - assert(inputDimensions == 2); - vector<float> r(2); - r[0] = x; r[1] = y; - setMinRange(r); - } - - void setMax(float x, float y, float z){ - assert(inputDimensions == 3); - vector<float> r(3); - r[0] = x; r[1] = y; r[2] = z; - setMaxRange(r); - } - - void setMin(float x, float y, float z){ - assert(inputDimensions == 3); - vector<float> r(3); - r[0] = x; r[1] = y; r[2] = z; - setMinRange(r); - } - - void setMaxRange(vector<float> observationRangeMax){ - this->observationRangeMax = observationRangeMax; - // bIsRangeMaxSet = true; - normalise(); - } - - void setMinRange(vector<float> observationRangeMin){ - this->observationRangeMin = observationRangeMin; - // bIsRangeMinSet = true; - normalise(); - } - - vector<float>& getMaxRange(){ - return observationRangeMax; - } - - vector<float>& getMinRange(){ - return observationRangeMin; - } - - void autoAdjustMinMax(vector<float> & observation){ - if(observationRangeMax.size() < inputDimensions){ - observationRangeMax.assign(inputDimensions, -INFINITY); - observationRangeMin.assign(inputDimensions, INFINITY); - } - for(int i = 0; i < inputDimensions; i++){ - observationRangeMax[i] = MAX(observationRangeMax[i], observation[i]); - observationRangeMin[i] = MIN(observationRangeMin[i], observation[i]); - } - } - - void addObservation(vector<float> observation, int templateIndex = 0){ - if (observation.size() != inputDimensions) - inputDimensions = observation.size(); - - // check we have a valid templateIndex and correct number of input dimensions - assert(templateIndex <= templatesRaw.size()); - assert(observation.size() == inputDimensions); - - // if the template index is same as the number of temlates make a new template - if(templateIndex == templatesRaw.size()){ // make a new template - - // reserve space in raw and normal template storage - templatesRaw.resize(templatesRaw.size() + 1); - templatesNormal.resize(templatesNormal.size() + 1); - - } - - if(templatesRaw[templateIndex].size() == 0) - { - templateInitialObservation = observation; - templateInitialNormal = observation; - } - - for(int j = 0; j < observation.size(); j++) - observation[j] = observation[j] - templateInitialObservation[j]; - - // store the raw observation - templatesRaw[templateIndex].push_back(observation); - - autoAdjustMinMax(observation); - - normalise(); - } - - - - void normalise() - { - templatesNormal.resize(templatesRaw.size()); - for(int t = 0; t < templatesRaw.size(); t++) - { - templatesNormal[t].resize(templatesRaw[t].size()); - for(int o = 0; o < templatesRaw[t].size(); o++) - { - templatesNormal[t][o].resize(inputDimensions); - for(int d = 0; d < inputDimensions; d++) - { - templatesNormal[t][o][d] = templatesRaw[t][o][d] / (observationRangeMax[d] - observationRangeMin[d]); - templateInitialNormal[d] = templateInitialObservation[d] / (observationRangeMax[d] - observationRangeMin[d]); - } - } - } - } - - void setTemplate(vector< vector<float> > & observations, int templateIndex = 0){ - for(int i = 0; i < observations.size(); i++){ - addObservation(observations[i], templateIndex); - } - } - - vector< vector<float> > & getTemplate(int templateIndex = 0){ - assert(templateIndex < templatesRaw.size()); - return templatesRaw[templateIndex]; - } - - int getNumberOfTemplates(){ - return templatesRaw.size(); - } - - int getNumberDimensions(){ - return inputDimensions; - } - - int getTemplateLength(int templateIndex = 0){ - return templatesRaw[templateIndex].size(); - } - - int getTemplateDimension(int templateIndex = 0){ - return templatesRaw[templateIndex][0].size(); - } - - vector<float>& getLastObservation(int templateIndex = 0){ - return templatesRaw[templateIndex][templatesRaw[templateIndex].size() - 1]; - } - - vector< vector< vector<float> > >& getTemplates(){ - return templatesRaw; - } - - vector<float>& getInitialObservation(){ - return templateInitialObservation; - } - - void deleteTemplate(int templateIndex = 0) - { - assert(templateIndex < templatesRaw.size()); - templatesRaw[templateIndex].clear(); - templatesNormal[templateIndex].clear(); - } - - void clear() - { - templatesRaw.clear(); - templatesNormal.clear(); - observationRangeMax.assign(inputDimensions, -INFINITY); - observationRangeMin.assign(inputDimensions, INFINITY); - } - -private: - - int inputDimensions; - bool bAutoAdjustNormalRange; - - vector<float> observationRangeMax; - vector<float> observationRangeMin; - - vector<float> templateInitialObservation; - vector<float> templateInitialNormal; - - vector< vector< vector<float> > > templatesRaw; - vector< vector< vector<float> > > templatesNormal; - - vector<vector<float> > gestureDataFromFile; -}; - -#endif /* GVFGesture_h */ diff --git a/GVF/GVFUtils.h b/GVF/GVFUtils.h deleted file mode 100755 index 125676c29c01593c17833a180171f22199f17ee1..0000000000000000000000000000000000000000 --- a/GVF/GVFUtils.h +++ /dev/null @@ -1,309 +0,0 @@ -// -// GVFTypesAndUtils.h -// -// -// - -#ifndef __H_GVFTYPES -#define __H_GVFTYPES - -#include <map> -#include <vector> -#include <iostream> -#include <random> -#include <iostream> -#include <math.h> -#include <assert.h> - -using namespace std; - -/** - * Configuration structure - */ -typedef struct -{ - int inputDimensions; /**< input dimesnion */ - bool translate; /**< translate flag */ - bool segmentation; /**< segmentation flag */ -} GVFConfig; - -/** - * Parameters structure - */ -typedef struct -{ - float tolerance; /**< input dimesnion */ - float distribution; - int numberParticles; - int resamplingThreshold; - float alignmentVariance; - float speedVariance; - vector<float> scaleVariance; - vector<float> dynamicsVariance; - vector<float> scalingsVariance; - vector<float> rotationsVariance; - // spreadings - float alignmentSpreadingCenter; - float alignmentSpreadingRange; - float dynamicsSpreadingCenter; - float dynamicsSpreadingRange; - float scalingsSpreadingCenter; - float scalingsSpreadingRange; - float rotationsSpreadingCenter; - float rotationsSpreadingRange; - - int predictionSteps; - vector<float> dimWeights; -} GVFParameters; - -// Outcomes structure -typedef struct -{ - int likeliestGesture; - vector<float> likelihoods; - vector<float> alignments; - vector<vector<float> > dynamics; - vector<vector<float> > scalings; - vector<vector<float> > rotations; -} GVFOutcomes; - - -//-------------------------------------------------------------- -// init matrix by allocating memory -template <typename T> -inline void initMat(vector< vector<T> > & M, int rows, int cols){ - M.resize(rows); - for (int n=0; n<rows; n++){ - M[n].resize(cols); - } -} - -//-------------------------------------------------------------- -// init matrix and copy values from another matrix -template <typename T> -inline void setMat(vector< vector<T> > & C, vector< vector<float> > & M){ - int rows = M.size(); - int cols = M[0].size(); - //C.resize(rows); - C = vector<vector<T> >(rows); - for (int n=0; n<rows; n++){ - //C[n].resize(cols); - C[n] = vector<T>(cols); - for (int m=0;m<cols;m++){ - C[n][m] = M[n][m]; - } - } -} - -//-------------------------------------------------------------- -// init matrix by allocating memory and fill with T value -template <typename T> -inline void setMat(vector< vector<T> > & M, T value, int rows, int cols){ - M.resize(rows); - for (int n=0; n<rows; n++){ - M[n].resize(cols); - for (int m=0; m<cols; m++){ - M[n][m] = value; - } - } -} - -//-------------------------------------------------------------- -// set matrix filled with T value -template <typename T> -inline void setMat(vector< vector<T> > & M, T value){ - for (int n=0; n<M.size(); n++){ - for (int m=0; m<M[n].size(); m++){ - M[n][m] = value; - } - } -} - -//-------------------------------------------------------------- -template <typename T> -inline void printMat(vector< vector<T> > & M){ - for (int k=0; k<M.size(); k++){ - cout << k << ": "; - for (int l=0; l<M[0].size(); l++){ - cout << M[k][l] << " "; - } - cout << endl; - } - cout << endl; -} - -//-------------------------------------------------------------- -template <typename T> -inline void printVec(vector<T> & V){ - for (int k=0; k<V.size(); k++){ - cout << k << ": " << V[k] << (k == V.size() - 1 ? "" : " ,"); - } - cout << endl; -} - -//-------------------------------------------------------------- -template <typename T> -inline void initVec(vector<T> & V, int rows){ - V.resize(rows); -} - -//-------------------------------------------------------------- -template <typename T> -inline void setVec(vector<T> & C, vector<int> &V){ - int rows = V.size(); - C = vector<T>(rows); - //C.resize(rows); - for (int n=0; n<rows; n++){ - C[n] = V[n]; - } -} - -//-------------------------------------------------------------- -template <typename T> -inline void setVec(vector<T> & C, vector<float> & V){ - int rows = V.size(); - C.resize(rows); - for (int n=0; n<rows; n++){ - C[n] = V[n]; - } -} - -//-------------------------------------------------------------- -template <typename T> -inline void setVec(vector<T> & V, T value){ - for (int n=0; n<V.size(); n++){ - V[n] = value; - } -} - -//-------------------------------------------------------------- -template <typename T> -inline void setVec(vector<T> & V, T value, int rows){ - V.resize(rows); - setVec(V, value); -} - -//-------------------------------------------------------------- -template <typename T> -inline vector< vector<T> > dotMat(vector< vector<T> > & M1, vector< vector<T> > & M2){ - // TODO(Baptiste) -} - -//-------------------------------------------------------------- -template <typename T> -inline vector< vector<T> > multiplyMatf(vector< vector<T> > & M1, T v){ - vector< vector<T> > multiply; - initMat(multiply, M1.size(), M1[0].size()); - for (int i=0; i<M1.size(); i++){ - for (int j=0; j<M1[i].size(); j++){ - multiply[i][j] = M1[i][j] * v; - } - } - return multiply; -} - -//-------------------------------------------------------------- -template <typename T> -inline vector< vector<T> > multiplyMatf(vector< vector<T> > & M1, vector< vector<T> > & M2){ - assert(M1[0].size() == M2.size()); // columns in M1 == rows in M2 - vector< vector<T> > multiply; - initMat(multiply, M1.size(), M2[0].size()); // rows in M1 x cols in M2 - for (int i=0; i<M1.size(); i++){ - for (int j=0; j<M2[i].size(); j++){ - multiply[i][j] = 0.0f; - for(int k=0; k<M1[0].size(); k++){ - multiply[i][j] += M1[i][k] * M2[k][j]; - } - - } - } - return multiply; -} - -//-------------------------------------------------------------- -template <typename T> -inline vector<T> multiplyMat(vector< vector<T> > & M1, vector< T> & Vect){ - assert(Vect.size() == M1[0].size()); // columns in M1 == rows in Vect - vector<T> multiply; - initVec(multiply, Vect.size()); - for (int i=0; i<M1.size(); i++){ - multiply[i] = 0.0f; - for (int j=0; j<M1[i].size(); j++){ - multiply[i] += M1[i][j] * Vect[j]; - } - } - return multiply; -} - -//-------------------------------------------------------------- -template <typename T> -inline float getMeanVec(vector<T>& V){ - float tSum = 0.0f; - for (int n=0; n<V.size(); n++){ - tSum += V[n]; - } - return tSum / (float)V.size(); -} - -template <typename T> -inline vector<vector<float> > getRotationMatrix3d(T phi, T theta, T psi) -{ - vector< vector<float> > M; - initMat(M,3,3); - - M[0][0] = cos(theta)*cos(psi); - M[0][1] = -cos(phi)*sin(psi)+sin(phi)*sin(theta)*cos(psi); - M[0][2] = sin(phi)*sin(psi)+cos(phi)*sin(theta)*cos(psi); - - M[1][0] = cos(theta)*sin(psi); - M[1][1] = cos(phi)*cos(psi)+sin(phi)*sin(theta)*sin(psi); - M[1][2] = -sin(phi)*cos(psi)+cos(phi)*sin(theta)*sin(psi); - - M[2][0] = -sin(theta); - M[2][1] = sin(phi)*cos(theta); - M[2][2] = cos(phi)*cos(theta); - - return M; -} - -template <typename T> -float distance_weightedEuclidean(vector<T> x, vector<T> y, vector<T> w) -{ - int count = x.size(); - if (count <= 0) return 0; - float dist = 0.0; - for(int k = 0; k < count; k++) dist += w[k] * pow((x[k] - y[k]), 2); - return dist; -} - -////-------------------------------------------------------------- -//vector<vector<float> > getRotationMatrix3d(float phi, float theta, float psi) -//{ -// vector< vector<float> > M; -// initMat(M,3,3); -// -// M[0][0] = cos(theta)*cos(psi); -// M[0][1] = -cos(phi)*sin(psi)+sin(phi)*sin(theta)*cos(psi); -// M[0][2] = sin(phi)*sin(psi)+cos(phi)*sin(theta)*cos(psi); -// -// M[1][0] = cos(theta)*sin(psi); -// M[1][1] = cos(phi)*cos(psi)+sin(phi)*sin(theta)*sin(psi); -// M[1][2] = -sin(phi)*cos(psi)+cos(phi)*sin(theta)*sin(psi); -// -// M[2][0] = -sin(theta); -// M[2][1] = sin(phi)*cos(theta); -// M[2][2] = cos(phi)*cos(theta); -// -// return M; -//} - -//float distance_weightedEuclidean(vector<float> x, vector<float> y, vector<float> w) -//{ -// int count = x.size(); -// if (count <= 0) return 0; -// float dist = 0.0; -// for(int k = 0; k < count; k++) dist += w[k] * pow((x[k] - y[k]), 2); -// return dist; -//} - -#endif