26 RegisterFeatureExtractionModule< MovementTrajectoryFeatures > MovementTrajectoryFeatures::registerModule(
"MovementTrajectoryFeatures");
30 classType =
"MovementTrajectoryFeatures";
31 featureExtractionType = classType;
32 debugLog.setProceedingText(
"[DEBUG MovementTrajectoryFeatures]");
33 errorLog.setProceedingText(
"[ERROR MovementTrajectoryFeatures]");
34 warningLog.setProceedingText(
"[WARNING ZeroCrossingCounter]");
36 init(trajectoryLength,numCentroids,featureMode,numHistogramBins,numDimensions,useTrajStartAndEndValues,useWeightedMagnitudeValues);
41 classType =
"MovementTrajectoryFeatures";
42 featureExtractionType = classType;
43 debugLog.setProceedingText(
"[DEBUG MovementTrajectoryFeatures]");
44 errorLog.setProceedingText(
"[ERROR MovementTrajectoryFeatures]");
45 warningLog.setProceedingText(
"[WARNING ZeroCrossingCounter]");
57 this->trajectoryLength = rhs.trajectoryLength;
58 this->numCentroids = rhs.numCentroids;
59 this->featureMode = rhs.featureMode;
60 this->numHistogramBins = rhs.numHistogramBins;
61 this->useTrajStartAndEndValues = rhs.useTrajStartAndEndValues;
62 this->useWeightedMagnitudeValues = rhs.useWeightedMagnitudeValues;
63 this->trajectoryDataBuffer = rhs.trajectoryDataBuffer;
64 this->centroids = rhs.centroids;
74 if( featureExtraction == NULL )
return false;
84 errorLog <<
"clone(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << endl;
92 errorLog <<
"computeFeatures(const VectorDouble &inputVector) - Not initialized!" << endl;
96 if( inputVector.size() != numInputDimensions ){
97 errorLog <<
"computeFeatures(const VectorDouble &inputVector) - The size of the inputVector (" << inputVector.size() <<
") does not match that of the filter (" << numInputDimensions <<
")!" << endl;
101 featureVector =
update( inputVector );
108 return init(trajectoryLength,numCentroids,featureMode,numHistogramBins,numInputDimensions,useTrajStartAndEndValues,useWeightedMagnitudeValues);
116 file.open(filename.c_str(), std::ios::out);
130 file.open(filename.c_str(), std::ios::in);
144 if( !file.is_open() ){
145 errorLog <<
"saveModelToFile(fstream &file) - The file is not open!" << endl;
150 file <<
"GRT_MOVEMENT_TRAJECTORY_FEATURES_FILE_V1.0" << endl;
154 errorLog <<
"saveFeatureExtractionSettingsToFile(fstream &file) - Failed to save base feature extraction settings to file!" << endl;
159 file <<
"TrajectoryLength: " << trajectoryLength << endl;
160 file <<
"NumCentroids: " << numCentroids << endl;
161 file <<
"FeatureMode: " << featureMode << endl;
162 file <<
"NumHistogramBins: " << numHistogramBins << endl;
163 file <<
"UseTrajStartAndEndValues: " << useTrajStartAndEndValues << endl;
164 file <<
"UseWeightedMagnitudeValues: " << useWeightedMagnitudeValues << endl;
171 if( !file.is_open() ){
172 errorLog <<
"loadModelFromFile(fstream &file) - The file is not open!" << endl;
181 if( word !=
"GRT_MOVEMENT_TRAJECTORY_FEATURES_FILE_V1.0" ){
182 errorLog <<
"loadModelFromFile(fstream &file) - Invalid file format!" << endl;
187 errorLog <<
"loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << endl;
193 if( word !=
"TrajectoryLength:" ){
194 errorLog <<
"loadModelFromFile(fstream &file) - Failed to read TrajectoryLength header!" << endl;
197 file >> trajectoryLength;
201 if( word !=
"NumCentroids:" ){
202 errorLog <<
"loadModelFromFile(fstream &file) - Failed to read NumCentroids header!" << endl;
205 file >> numCentroids;
209 if( word !=
"FeatureMode:" ){
210 errorLog <<
"loadModelFromFile(fstream &file) - Failed to read FeatureMode header!" << endl;
217 if( word !=
"NumHistogramBins:" ){
218 errorLog <<
"loadModelFromFile(fstream &file) - Failed to read NumHistogramBins header!" << endl;
221 file >> numHistogramBins;
225 if( word !=
"UseTrajStartAndEndValues:" ){
226 errorLog <<
"loadModelFromFile(fstream &file) - Failed to read UseTrajStartAndEndValues header!" << endl;
229 file >> useTrajStartAndEndValues;
233 if( word !=
"UseWeightedMagnitudeValues:" ){
234 errorLog <<
"loadModelFromFile(fstream &file) - Failed to read UseWeightedMagnitudeValues header!" << endl;
237 file >> useWeightedMagnitudeValues;
240 return init(trajectoryLength,numCentroids,featureMode,numHistogramBins,numInputDimensions,useTrajStartAndEndValues,useWeightedMagnitudeValues);
243 bool MovementTrajectoryFeatures::init(UINT trajectoryLength,UINT numCentroids,UINT featureMode,UINT numHistogramBins,UINT numDimensions,
bool useTrajStartAndEndValues,
bool useWeightedMagnitudeValues){
247 if( numCentroids > trajectoryLength ){
248 errorLog <<
"init(...) - The number of centroids parameter can not be larger than the trajectory length parameter!" << endl;
251 if( trajectoryLength % numCentroids != 0 ){
252 errorLog <<
"init(...) - The trajectory length parameter must be divisible with no remainders by the number of centroids parameter!" << endl;
256 if( featureMode == CENTROID_ANGLE_2D && numDimensions % 2 != 0 ){
257 errorLog <<
"init(...) - If the featureMode is CENTROID_ANGLE_2D then the numberOfDimensions should be divisble by 2 (as each pair of points should represent {x,y})!" << endl;
261 if( numHistogramBins == 0 && featureMode == CENTROID_ANGLE_2D ){
262 errorLog <<
"init(...) - If the featureMode is CENTROID_ANGLE_2D then the numHistogramBins parameter must greater than 0!" << endl;
267 this->trajectoryLength = trajectoryLength;
268 this->numCentroids = numCentroids;
269 this->featureMode = featureMode;
270 this->numHistogramBins = numHistogramBins;
271 this->numInputDimensions = numDimensions;
272 this->useTrajStartAndEndValues = useTrajStartAndEndValues;
273 this->useWeightedMagnitudeValues = useWeightedMagnitudeValues;
274 featureDataReady =
false;
277 numOutputDimensions = 0;
278 switch( featureMode ){
281 numOutputDimensions = numInputDimensions*numCentroids;
283 case NORMALIZED_CENTROID_VALUE:
284 numOutputDimensions = numInputDimensions*numCentroids;
285 if( useTrajStartAndEndValues ){
286 numOutputDimensions += numInputDimensions*2;
289 case CENTROID_DERIVATIVE:
290 numOutputDimensions = numInputDimensions*(numCentroids-1);
291 if( useTrajStartAndEndValues ){
292 numOutputDimensions += numInputDimensions*2;
295 case CENTROID_ANGLE_2D:
296 numOutputDimensions = numHistogramBins*(numDimensions/2);
299 errorLog <<
"init(...)- Unknown featureMode!" << endl;
304 if( numOutputDimensions == 0 ){
305 errorLog <<
"init(...) - The numOutputDimensions is zero!" << endl;
310 featureVector.resize(numOutputDimensions);
313 trajectoryDataBuffer.
resize( trajectoryLength, VectorDouble(numInputDimensions,0) );
316 centroids.
resize(numCentroids,numInputDimensions);
325 return update(VectorDouble(1,x));
331 errorLog <<
"update(const VectorDouble &x) - Not Initialized!" << endl;
332 return vector<double>();
335 if( x.size() != numInputDimensions ){
336 errorLog <<
"update(const VectorDouble &x)- The Number Of Input Dimensions (" << numInputDimensions <<
") does not match the size of the input vector (" << x.size() <<
")!" << endl;
337 return vector<double>();
345 featureDataReady =
true;
346 }
else featureDataReady =
false;
351 UINT dataBufferIndex = 0;
352 UINT numValuesPerCentroid = (UINT)floor(
double(trajectoryLength/numCentroids));
353 for(UINT n=0; n<numInputDimensions; n++){
355 for(UINT i=0; i<numCentroids; i++){
356 for(UINT j=0; j<numValuesPerCentroid; j++){
357 centroids[i][n] += trajectoryDataBuffer[dataBufferIndex++][n];
359 centroids[i][n] /= double(numValuesPerCentroid);
364 UINT featureIndex = 0;
365 vector< MinMax > centroidNormValues(numInputDimensions);
366 VectorDouble histSumValues;
367 vector< vector< AngleMagnitude > > angleMagnitudeValues;
368 switch( featureMode ){
371 for(UINT n=0; n<numInputDimensions; n++){
372 for(UINT i=0; i<numCentroids; i++){
373 featureVector[ featureIndex++ ] = centroids[i][n];
377 case NORMALIZED_CENTROID_VALUE:
378 for(UINT n=0; n<numInputDimensions; n++){
381 for(UINT i=0; i<numCentroids; i++){
382 centroidNormValues[n].updateMinMax( centroids[i][n] );
386 for(UINT i=0; i<numCentroids; i++){
387 if( centroidNormValues[n].maxValue != centroidNormValues[n].minValue ){
388 featureVector[ featureIndex++ ] =
Util::scale(centroids[i][n],centroidNormValues[n].minValue,centroidNormValues[n].maxValue,0,1);
389 }
else featureVector[ featureIndex++ ] = 0;
393 if( useTrajStartAndEndValues ){
394 featureVector[ featureIndex++ ] = centroids[0][n];
395 featureVector[ featureIndex++ ] = centroids[numCentroids-1][n];
399 case CENTROID_DERIVATIVE:
400 for(UINT n=0; n<numInputDimensions; n++){
403 for(UINT i=0; i<numCentroids-1; i++){
404 featureVector[ featureIndex++ ] = centroids[i+1][n]-centroids[i][n];
408 if( useTrajStartAndEndValues ){
409 featureVector[ featureIndex++ ] = centroids[0][n];
410 featureVector[ featureIndex++ ] = centroids[numCentroids-1][n];
414 case CENTROID_ANGLE_2D:
415 histSumValues.resize( numInputDimensions/2, 0);
416 angleMagnitudeValues.resize( numInputDimensions/2 );
419 fill(featureVector.begin(),featureVector.end(),0);
422 for(UINT n=0; n<numInputDimensions/2; n++){
424 angleMagnitudeValues[n].resize(numCentroids-1);
425 for(UINT i=0; i<numCentroids-1; i++){
426 Util::cartToPolar(centroids[i+1][n*2]-centroids[i][n*2], centroids[i+1][n*2+1]-centroids[i][n*2+1], angleMagnitudeValues[n][i].magnitude, angleMagnitudeValues[n][i].angle);
430 for(UINT i=0; i<numCentroids-1; i++){
432 double degreesPerBin = 360.0/numHistogramBins;
433 double binStartValue = 0;
434 double binEndValue = degreesPerBin;
436 if( angleMagnitudeValues[n][i].angle < 0 || angleMagnitudeValues[n][i].angle > 360.0 ){
437 warningLog <<
"The angle of a point is not between [0 360]. Angle: " << angleMagnitudeValues[n][i].angle << endl;
438 return vector<double>();
443 if( angleMagnitudeValues[n][i].angle >= binStartValue && angleMagnitudeValues[n][i].angle < binEndValue ){
447 binStartValue += degreesPerBin;
448 binEndValue += degreesPerBin;
451 histSumValues[ n ] += useWeightedMagnitudeValues ? angleMagnitudeValues[n][i].magnitude : 1;
452 featureVector[ n*numHistogramBins + histBin ] += useWeightedMagnitudeValues ? angleMagnitudeValues[n][i].magnitude : 1;
456 for(UINT n=0; n<numInputDimensions/2; n++){
457 if( histSumValues[ n ] > 0 ){
458 for(UINT i=0; i<numHistogramBins; i++){
459 featureVector[ n*numHistogramBins + i ] /= histSumValues[ n ];
466 errorLog <<
"update(VectorDouble x)- Unknown featureMode!" << endl;
467 return featureVector;
471 return featureVector;
476 return trajectoryDataBuffer;
bool setAllValues(const T &value)
MovementTrajectoryFeatures & operator=(const MovementTrajectoryFeatures &rhs)
virtual ~MovementTrajectoryFeatures()
static double scale(const double &x, const double &minSource, const double &maxSource, const double &minTarget, const double &maxTarget, const bool constrain=false)
virtual bool saveModelToFile(string filename) const
This class implements the MovementTrajectory feature extraction module.
bool push_back(const T &value)
MovementTrajectoryFeatures(UINT trajectoryLength=100, UINT numCentroids=10, UINT featureMode=CENTROID_VALUE, UINT numHistogramBins=10, UINT numDimensions=1, bool useTrajStartAndEndValues=false, bool useWeightedMagnitudeValues=true)
bool resize(const unsigned int newBufferSize)
static void cartToPolar(const double x, const double y, double &r, double &theta)
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
CircularBuffer< VectorDouble > getTrajectoryData()
virtual bool loadModelFromFile(string filename)
bool getBufferFilled() const
MatrixDouble getCentroids()
virtual bool resize(const unsigned int r, const unsigned int c)
VectorDouble update(double x)
virtual bool computeFeatures(const VectorDouble &inputVector)