GestureRecognitionToolkit  Version: 1.0 Revision: 04-03-15
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
KMeansQuantizer.cpp
1 /*
2  GRT MIT License
3  Copyright (c) <2012> <Nicholas Gillian, Media Lab, MIT>
4 
5  Permission is hereby granted, free of charge, to any person obtaining a copy of this software
6  and associated documentation files (the "Software"), to deal in the Software without restriction,
7  including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
9  subject to the following conditions:
10 
11  The above copyright notice and this permission notice shall be included in all copies or substantial
12  portions of the Software.
13 
14  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "KMeansQuantizer.h"
22 
23 namespace GRT{
24 
25 //Register your module with the FeatureExtraction base class
26 RegisterFeatureExtractionModule< KMeansQuantizer > KMeansQuantizer::registerModule("KMeansQuantizer");
27 
28 KMeansQuantizer::KMeansQuantizer(const UINT numClusters){
29 
30  this->numClusters = numClusters;
31  classType = "KMeansQuantizer";
32  featureExtractionType = classType;
33 
34  debugLog.setProceedingText("[DEBUG KMeansQuantizer]");
35  errorLog.setProceedingText("[ERROR KMeansQuantizer]");
36  warningLog.setProceedingText("[WARNING KMeansQuantizer]");
37 }
38 
40 
41  classType = "KMeansQuantizer";
42  featureExtractionType = classType;
43 
44  debugLog.setProceedingText("[DEBUG KMeansQuantizer]");
45  errorLog.setProceedingText("[ERROR KMeansQuantizer]");
46  warningLog.setProceedingText("[WARNING KMeansQuantizer]");
47 
48  //Invoke the equals operator to copy the data from the rhs instance to this instance
49  *this = rhs;
50 }
51 
53 }
54 
56  if(this!=&rhs){
57  //Copy any class variables from the rhs instance to this instance
58  this->numClusters = rhs.numClusters;
59  this->clusters = rhs.clusters;
60  this->quantizationDistances = rhs.quantizationDistances;
61 
62  //Copy the base variables
64  }
65  return *this;
66 }
67 
68 bool KMeansQuantizer::deepCopyFrom(const FeatureExtraction *featureExtraction){
69 
70  if( featureExtraction == NULL ) return false;
71 
72  if( this->getFeatureExtractionType() == featureExtraction->getFeatureExtractionType() ){
73 
74  //Cast the feature extraction pointer to a pointer to your custom feature extraction module
75  //Then invoke the equals operator
76  *this = *(KMeansQuantizer*)featureExtraction;
77 
78  return true;
79  }
80 
81  errorLog << "clone(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << endl;
82 
83  return false;
84 }
85 
86 bool KMeansQuantizer::computeFeatures(const VectorDouble &inputVector){
87 
88  //Run the quantize algorithm
89  quantize( inputVector );
90 
91  return true;
92 }
93 
95 
97 
98  if( trained ){
99  std::fill(quantizationDistances.begin(),quantizationDistances.end(),0);
100  }
101 
102  return true;
103 }
104 
106 
108 
109  clusters.clear();
110  quantizationDistances.clear();
111  quantizationDistances.clear();
112 
113  return true;
114 }
115 
116 bool KMeansQuantizer::saveModelToFile(fstream &file) const{
117 
118  if( !file.is_open() ){
119  errorLog << "saveModelToFile(fstream &file) - The file is not open!" << endl;
120  return false;
121  }
122 
123  //Save the header
124  file << "KMEANS_QUANTIZER_FILE_V1.0" << endl;
125 
126  //Save the feature extraction base class settings
128  errorLog << "saveModelToFile(fstream &file) - Failed to save base feature extraction settings to file!" << endl;
129  return false;
130  }
131 
132  //Save the KMeansQuantizer settings
133  file << "QuantizerTrained: " << trained << endl;
134  file << "NumClusters: " << numClusters << endl;
135 
136  if( trained ){
137  file << "Clusters: \n";
138  for(UINT k=0; k<numClusters; k++){
139  for(UINT j=0; j<numInputDimensions; j++){
140  file << clusters[k][j];
141  if( j != numInputDimensions-1 ) file << "\t";
142  else file << endl;
143  }
144  }
145  }
146 
147  return true;
148 }
149 
151 
152  //Clear any previouly built model and settings
153  clear();
154 
155  if( !file.is_open() ){
156  errorLog << "loadModelFromFile(fstream &file) - The file is not open!" << endl;
157  return false;
158  }
159 
160  string word;
161 
162  //First, you should read and validate the header
163  file >> word;
164  if( word != "KMEANS_QUANTIZER_FILE_V1.0" ){
165  errorLog << "loadModelFromFile(fstream &file) - Invalid file format!" << endl;
166  return false;
167  }
168 
169  //Second, you should load the base feature extraction settings to the file
171  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << endl;
172  return false;
173  }
174 
175  file >> word;
176  if( word != "QuantizerTrained:" ){
177  errorLog << "loadModelFromFile(fstream &file) - Failed to load QuantizerTrained!" << endl;
178  return false;
179  }
180  file >> trained;
181 
182  file >> word;
183  if( word != "NumClusters:" ){
184  errorLog << "loadModelFromFile(fstream &file) - Failed to load NumClusters!" << endl;
185  return false;
186  }
187  file >> numClusters;
188 
189  if( trained ){
190  clusters.resize(numClusters, numInputDimensions);
191  file >> word;
192  if( word != "Clusters:" ){
193  errorLog << "loadModelFromFile(fstream &file) - Failed to load Clusters!" << endl;
194  return false;
195  }
196 
197  for(UINT k=0; k<numClusters; k++){
198  for(UINT j=0; j<numInputDimensions; j++){
199  file >> clusters[k][j];
200  }
201  }
202 
203  initialized = true;
204  featureDataReady = false;
205  quantizationDistances.resize(numClusters,0);
206  }
207 
208  return true;
209 }
210 
212  MatrixDouble data = trainingData.getDataAsMatrixDouble();
213  return train( data );
214 }
215 
217  MatrixDouble data = trainingData.getDataAsMatrixDouble();
218  return train( data );
219 }
220 
222  MatrixDouble data = trainingData.getDataAsMatrixDouble();
223  return train( data );
224 }
225 
227  MatrixDouble data = trainingData.getDataAsMatrixDouble();
228  return train( data );
229 }
230 
232 
233  //Clear any previous model
234  clear();
235 
236  //Train the KMeans model
237  KMeans kmeans;
238  kmeans.setNumClusters(numClusters);
239  kmeans.setComputeTheta( true );
240  kmeans.setMinChange( minChange );
241  kmeans.setMinNumEpochs( minNumEpochs );
242  kmeans.setMaxNumEpochs( maxNumEpochs );
243 
244  if( !kmeans.train_(trainingData) ){
245  errorLog << "train_(MatrixDouble &trainingData) - Failed to train quantizer!" << endl;
246  return false;
247  }
248 
249  trained = true;
250  initialized = true;
251  numInputDimensions = trainingData.getNumCols();
252  numOutputDimensions = 1; //This is always 1 for the KMeansQuantizer
253  featureVector.resize(numOutputDimensions,0);
254  clusters = kmeans.getClusters();
255  quantizationDistances.resize(numClusters,0);
256 
257  return true;
258 }
259 
260 UINT KMeansQuantizer::quantize(double inputValue){
261  return quantize( VectorDouble(1,inputValue) );
262 }
263 
264 UINT KMeansQuantizer::quantize(const VectorDouble &inputVector){
265 
266  if( !trained ){
267  errorLog << "computeFeatures(const VectorDouble &inputVector) - The quantizer has not been trained!" << endl;
268  return 0;
269  }
270 
271  if( inputVector.size() != numInputDimensions ){
272  errorLog << "computeFeatures(const VectorDouble &inputVector) - The size of the inputVector (" << inputVector.size() << ") does not match that of the filter (" << numInputDimensions << ")!" << endl;
273  return 0;
274  }
275 
276  //Find the minimum cluster
277  double minDist = numeric_limits<double>::max();
278  UINT quantizedValue = 0;
279 
280  for(UINT k=0; k<numClusters; k++){
281  //Compute the squared Euclidean distance
282  quantizationDistances[k] = 0;
283  for(UINT i=0; i<numInputDimensions; i++){
284  quantizationDistances[k] += SQR( inputVector[i]-clusters[k][i] );
285  }
286  if( quantizationDistances[k] < minDist ){
287  minDist = quantizationDistances[k];
288  quantizedValue = k;
289  }
290  }
291 
292  featureVector[0] = quantizedValue;
293  featureDataReady = true;
294 
295  return quantizedValue;
296 }
297 
299  return numClusters;
300 }
301 
302 bool KMeansQuantizer::setNumClusters(const UINT numClusters){
303  clear();
304  this->numClusters = numClusters;
305  return true;
306 }
307 
308 }//End of namespace GRT
KMeansQuantizer & operator=(const KMeansQuantizer &rhs)
bool setMaxNumEpochs(const UINT maxNumEpochs)
Definition: MLBase.cpp:237
Definition: AdaBoost.cpp:25
unsigned int getNumCols() const
Definition: Matrix.h:538
virtual bool train(ClassificationData trainingData)
Definition: MLBase.cpp:80
bool setMinChange(const double minChange)
Definition: MLBase.cpp:251
bool setNumClusters(const UINT numClusters)
Definition: Clusterer.cpp:263
string getFeatureExtractionType() const
bool setNumClusters(const UINT numClusters)
KMeansQuantizer(const UINT numClusters=10)
virtual bool computeFeatures(const VectorDouble &inputVector)
MatrixDouble getDataAsMatrixDouble() const
virtual bool loadModelFromFile(fstream &file)
The KMeansQuantizer module quantizes the N-dimensional input vector to a 1-dimensional discrete value...
bool loadFeatureExtractionSettingsFromFile(fstream &file)
UINT getNumClusters() const
void clear()
Definition: Matrix.h:511
MatrixDouble getDataAsMatrixDouble() const
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
virtual bool train_(MatrixDouble &data)
Definition: KMeans.cpp:162
UINT quantize(double inputValue)
bool train_(ClassificationData &trainingData)
bool saveFeatureExtractionSettingsToFile(fstream &file) const
bool setMinNumEpochs(const UINT minNumEpochs)
Definition: MLBase.cpp:246
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
virtual bool resize(const unsigned int r, const unsigned int c)
Definition: Matrix.h:234
virtual bool saveModelToFile(fstream &file) const