GestureRecognitionToolkit  Version: 0.2.5
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 #define GRT_DLL_EXPORTS
22 #include "KMeansQuantizer.h"
23 
24 GRT_BEGIN_NAMESPACE
25 
26 //Define the string that will be used to identify the object
27 std::string KMeansQuantizer::id = "KMeansQuantizer";
28 std::string KMeansQuantizer::getId() { return KMeansQuantizer::id; }
29 
30 //Register your module with the FeatureExtraction base class
32 
34 {
35  this->numClusters = numClusters;
36 }
37 
39 {
40  //Invoke the equals operator to copy the data from the rhs instance to this instance
41  *this = rhs;
42 }
43 
45 }
46 
48  if(this!=&rhs){
49  //Copy any class variables from the rhs instance to this instance
50  this->numClusters = rhs.numClusters;
51  this->clusters = rhs.clusters;
52  this->quantizationDistances = rhs.quantizationDistances;
53 
54  //Copy the base variables
56  }
57  return *this;
58 }
59 
60 bool KMeansQuantizer::deepCopyFrom(const FeatureExtraction *featureExtraction){
61 
62  if( featureExtraction == NULL ) return false;
63 
64  if( this->getId() == featureExtraction->getId() ){
65 
66  //Cast the feature extraction pointer to a pointer to your custom feature extraction module
67  //Then invoke the equals operator
68  *this = *dynamic_cast<const KMeansQuantizer*>(featureExtraction);
69 
70  return true;
71  }
72 
73  errorLog << "deepCopyFrom(FeatureExtraction *featureExtraction) - FeatureExtraction Types Do Not Match!" << std::endl;
74 
75  return false;
76 }
77 
79 
80  //Run the quantize algorithm
81  quantize( inputVector );
82 
83  return true;
84 }
85 
87 
89 
90  if( trained ){
91  std::fill(quantizationDistances.begin(),quantizationDistances.end(),0);
92  }
93 
94  return true;
95 }
96 
98 
100 
101  clusters.clear();
102  quantizationDistances.clear();
103  quantizationDistances.clear();
104 
105  return true;
106 }
107 
108 bool KMeansQuantizer::save( std::fstream &file ) const{
109 
110  if( !file.is_open() ){
111  errorLog << "save(fstream &file) - The file is not open!" << std::endl;
112  return false;
113  }
114 
115  //Save the header
116  file << "KMEANS_QUANTIZER_FILE_V1.0" << std::endl;
117 
118  //Save the feature extraction base class settings
120  errorLog << "save(fstream &file) - Failed to save base feature extraction settings to file!" << std::endl;
121  return false;
122  }
123 
124  //Save the KMeansQuantizer settings
125  file << "QuantizerTrained: " << trained << std::endl;
126  file << "NumClusters: " << numClusters << std::endl;
127 
128  if( trained ){
129  file << "Clusters: \n";
130  for(UINT k=0; k<numClusters; k++){
131  for(UINT j=0; j<numInputDimensions; j++){
132  file << clusters[k][j];
133  if( j != numInputDimensions-1 ) file << "\t";
134  else file << std::endl;
135  }
136  }
137  }
138 
139  return true;
140 }
141 
142 bool KMeansQuantizer::load( std::fstream &file ){
143 
144  //Clear any previouly built model and settings
145  clear();
146 
147  if( !file.is_open() ){
148  errorLog << "load(fstream &file) - The file is not open!" << std::endl;
149  return false;
150  }
151 
152  std::string word;
153 
154  //First, you should read and validate the header
155  file >> word;
156  if( word != "KMEANS_QUANTIZER_FILE_V1.0" ){
157  errorLog << "load(fstream &file) - Invalid file format!" << std::endl;
158  return false;
159  }
160 
161  //Second, you should load the base feature extraction settings to the file
163  errorLog << "loadFeatureExtractionSettingsFromFile(fstream &file) - Failed to load base feature extraction settings from file!" << std::endl;
164  return false;
165  }
166 
167  file >> word;
168  if( word != "QuantizerTrained:" ){
169  errorLog << "load(fstream &file) - Failed to load QuantizerTrained!" << std::endl;
170  return false;
171  }
172  file >> trained;
173 
174  file >> word;
175  if( word != "NumClusters:" ){
176  errorLog << "load(fstream &file) - Failed to load NumClusters!" << std::endl;
177  return false;
178  }
179  file >> numClusters;
180 
181  if( trained ){
182  clusters.resize(numClusters, numInputDimensions);
183  file >> word;
184  if( word != "Clusters:" ){
185  errorLog << "load(fstream &file) - Failed to load Clusters!" << std::endl;
186  return false;
187  }
188 
189  for(UINT k=0; k<numClusters; k++){
190  for(UINT j=0; j<numInputDimensions; j++){
191  file >> clusters[k][j];
192  }
193  }
194 
195  initialized = true;
196  featureDataReady = false;
197  quantizationDistances.resize(numClusters,0);
198  }
199 
200  return true;
201 }
202 
204  MatrixFloat data = trainingData.getDataAsMatrixFloat();
205  return train( data );
206 }
207 
209  MatrixFloat data = trainingData.getDataAsMatrixFloat();
210  return train( data );
211 }
212 
214  MatrixFloat data = trainingData.getDataAsMatrixFloat();
215  return train( data );
216 }
217 
219  MatrixFloat data = trainingData.getDataAsMatrixFloat();
220  return train( data );
221 }
222 
224 
225  //Clear any previous model
226  clear();
227 
228  //Train the KMeans model
229  KMeans kmeans;
230  kmeans.setNumClusters(numClusters);
231  kmeans.setComputeTheta( true );
232  kmeans.setMinChange( minChange );
233  kmeans.setMinNumEpochs( minNumEpochs );
234  kmeans.setMaxNumEpochs( maxNumEpochs );
235 
236  if( !kmeans.train_(trainingData) ){
237  errorLog << "train_(MatrixFloat &trainingData) - Failed to train quantizer!" << std::endl;
238  return false;
239  }
240 
241  trained = true;
242  initialized = true;
243  numInputDimensions = trainingData.getNumCols();
244  numOutputDimensions = 1; //This is always 1 for the KMeansQuantizer
245  featureVector.resize(numOutputDimensions,0);
246  clusters = kmeans.getClusters();
247  quantizationDistances.resize(numClusters,0);
248 
249  return true;
250 }
251 
252 UINT KMeansQuantizer::quantize(const Float inputValue){
253  return quantize( VectorFloat(1,inputValue) );
254 }
255 
256 UINT KMeansQuantizer::quantize(const VectorFloat &inputVector){
257 
258  if( !trained ){
259  errorLog << "computeFeatures(const VectorFloat &inputVector) - The quantizer has not been trained!" << std::endl;
260  return 0;
261  }
262 
263  if( inputVector.getSize() != numInputDimensions ){
264  errorLog << "computeFeatures(const VectorFloat &inputVector) - The size of the inputVector (" << inputVector.getSize() << ") does not match that of the filter (" << numInputDimensions << ")!" << std::endl;
265  return 0;
266  }
267 
268  //Find the minimum cluster
269  Float minDist = grt_numeric_limits< Float >::max();
270  UINT quantizedValue = 0;
271 
272  for(UINT k=0; k<numClusters; k++){
273  //Compute the squared Euclidean distance
274  quantizationDistances[k] = 0;
275  for(UINT i=0; i<numInputDimensions; i++){
276  quantizationDistances[k] += grt_sqr( inputVector[i]-clusters[k][i] );
277  }
278  if( quantizationDistances[k] < minDist ){
279  minDist = quantizationDistances[k];
280  quantizedValue = k;
281  }
282  }
283 
284  featureVector[0] = quantizedValue;
285  featureDataReady = true;
286 
287  return quantizedValue;
288 }
289 
291  return numClusters;
292 }
293 
294 bool KMeansQuantizer::setNumClusters(const UINT numClusters){
295  clear();
296  this->numClusters = numClusters;
297  return true;
298 }
299 
300 GRT_END_NAMESPACE
virtual bool train_(ClassificationData &trainingData)
virtual bool computeFeatures(const VectorFloat &inputVector)
std::string getId() const
Definition: GRTBase.cpp:85
UINT quantize(const Float inputValue)
virtual bool reset()
KMeansQuantizer(const UINT numClusters=10)
virtual bool reset()
Definition: MLBase.cpp:147
bool saveFeatureExtractionSettingsToFile(std::fstream &file) const
MatrixFloat getDataAsMatrixFloat() const
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
virtual bool train_(MatrixFloat &data)
Definition: KMeans.cpp:153
virtual bool train(ClassificationData trainingData)
Definition: MLBase.cpp:107
UINT getSize() const
Definition: Vector.h:201
virtual bool deepCopyFrom(const FeatureExtraction *featureExtraction)
bool setMinChange(const Float minChange)
Definition: MLBase.cpp:344
bool clear()
Definition: Matrix.h:553
bool setNumClusters(const UINT numClusters)
The KMeansQuantizer module quantizes the N-dimensional input vector to a 1-dimensional discrete value...
MatrixFloat getDataAsMatrixFloat() const
unsigned int getNumCols() const
Definition: Matrix.h:581
static std::string getId()
bool setMinNumEpochs(const UINT minNumEpochs)
Definition: MLBase.cpp:329
UINT getNumClusters() const
virtual bool clear()
bool loadFeatureExtractionSettingsFromFile(std::fstream &file)
virtual ~KMeansQuantizer()
KMeansQuantizer & operator=(const KMeansQuantizer &rhs)
Definition: KMeans.h:41
MatrixFloat getDataAsMatrixFloat() const
virtual bool resize(const unsigned int r, const unsigned int c)
Definition: Matrix.h:245
bool copyBaseVariables(const FeatureExtraction *featureExtractionModule)
virtual bool save(std::fstream &file) const
virtual bool clear() override
bool setMaxNumEpochs(const UINT maxNumEpochs)
Definition: MLBase.cpp:320
virtual bool load(std::fstream &file)
bool setNumClusters(const UINT numClusters)
Definition: Clusterer.cpp:262