himrep
main.cpp
1 /*
2  * Copyright (C) 2013 iCub Facility - Istituto Italiano di Tecnologia
3  * Author: Sean Ryan Fanello, Carlo Ciliberto
4  * email: sean.fanello@iit.it carlo.ciliberto@iit.it
5  * Permission is granted to copy, distribute, and/or modify this program
6  * under the terms of the GNU General Public License, version 2 or any
7  * later version published by the Free Software Foundation.
8  *
9  * A copy of the license can be found at
10  * http://www.robotcub.org/icub/license/gpl.txt
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15  * Public License for more details
16 */
17 
91 #include <yarp/os/Network.h>
92 #include <yarp/os/RFModule.h>
93 #include <yarp/os/Time.h>
94 #include <yarp/os/BufferedPort.h>
95 #include <yarp/os/RpcClient.h>
96 #include <yarp/os/PortReport.h>
97 
98 #include <yarp/sig/Vector.h>
99 #include <yarp/sig/Image.h>
100 
101 #include <yarp/cv/Cv.h>
102 
103 #include <yarp/math/Math.h>
104 #include <yarp/math/Rand.h>
105 
106 #include <opencv2/opencv.hpp>
107 
108 #include <cstdio>
109 #include <string>
110 #include <deque>
111 #include <algorithm>
112 #include <vector>
113 #include <iostream>
114 #include <fstream>
115 #include <algorithm>
116 #include <utility>
117 #include <mutex>
118 
119 #include "SiftGPU_Extractor.h"
120 #include "DictionaryLearning.h"
121 
122 using namespace std;
123 using namespace yarp;
124 using namespace yarp::os;
125 using namespace yarp::sig;
126 using namespace yarp::cv;
127 using namespace yarp::math;
128 
129 #define CMD_HELP yarp::os::createVocab32('h','e','l','p')
130 #define DUMP_SIFT yarp::os::createVocab32('d','u','m','p')
131 #define DUMP_STOP yarp::os::createVocab32('s','t','o','p')
132 #define LEARN_DICT yarp::os::createVocab32('l','e','a','r')
133 
134 #define CODE_MODE_SC 0
135 #define CODE_MODE_BOW 1
136 #define CODE_MODE_BCE 2
137 
138 
139 class SparseCoderPort: public BufferedPort<Image>
140 {
141 private:
142  ResourceFinder &rf;
143 
144  bool verbose;
145  bool help;
146 
147  vector<SiftGPU::SiftKeypoint> keypoints;
148  vector<float> descriptors;
149 
150  Port port_out_code;
151  Port port_out_img;
152 
153  SiftGPU_Extractor siftGPU_extractor;
154 
155  int grid_step;
156  int grid_scale;
157 
158  DictionaryLearning *sparse_coder;
159  IplImage *ipl;
160 
161  mutex mtx;
162 
163  bool no_code;
164  int dense;
165  bool dump_sift;
166  FILE *fout_sift;
167 
168  double rate;
169  double last_read;
170 
171  int code_mode;
172  int pyramidLevels;
173 
174  string contextPath;
175 
176 
177  virtual void onRead(Image &img)
178  {
179  //read at specified rate
180  if(Time::now()-last_read<rate)
181  return;
182 
183  lock_guard<mutex> lg(mtx);
184  if(ipl==NULL || ipl->width!=img.width() || ipl->height!=img.height())
185  {
186  if(ipl!=NULL)
187  {
188  cvReleaseImage(&ipl);
189  }
190  ipl=cvCreateImage(cvSize(img.width(),img.height()),IPL_DEPTH_8U,1);
191  siftGPU_extractor.setDenseGrid(ipl,grid_step,grid_scale);
192  }
193 
194  cv::cvtColor(toCvMat(img),cv::cvarrToMat(ipl),CV_RGB2GRAY);
195 
196  //cvSmooth(ipl,ipl);
197  if(dense)
198  siftGPU_extractor.extractDenseSift(ipl,&keypoints,&descriptors);
199  else
200  siftGPU_extractor.extractSift(ipl,&keypoints,&descriptors);
201 
202  if(dump_sift)
203  {
204  for(int i=0; i<keypoints.size(); i++)
205  {
206  for(int j=0; j<128; j++)
207  fprintf(fout_sift,"%f ",descriptors[i*128+j]);
208  fprintf(fout_sift,"\n");
209  }
210  }
211  //code the input vector
212  if(!no_code)
213  {
214  vector<Vector> features(keypoints.size());
215  Vector coding;
216  for(unsigned int i=0; i<keypoints.size(); i++)
217  {
218  features[i].resize(128);
219  for(unsigned int j=0; j<128; j++)
220  features[i][j]=descriptors[i*128+j];
221  }
222 
223  switch(code_mode)
224  {
225  case CODE_MODE_SC:
226  {
227  sparse_coder->maxPooling(features,coding,keypoints,pyramidLevels,ipl->width, ipl->height);
228  break;
229  }
230  case CODE_MODE_BCE:
231  {
232  sparse_coder->maxPooling(features,coding,keypoints,pyramidLevels,ipl->width, ipl->height);
233  break;
234  }
235  case CODE_MODE_BOW:
236  {
237  sparse_coder->avgPooling(features,coding,keypoints,pyramidLevels,ipl->width, ipl->height);
238  break;
239  }
240  }
241 
242 
243  if(port_out_code.getOutputCount())
244  {
245  port_out_code.write(coding);
246  }
247  if(port_out_img.getOutputCount())
248  {
249  for(unsigned int i=0; i<keypoints.size(); i++)
250  {
251  int x = cvRound(keypoints[i].x);
252  int y = cvRound(keypoints[i].y);
253  cv::Mat imgMat=toCvMat(img);
254  cv::circle(imgMat,cvPoint(x,y),3,cvScalar(0,0,255),-1);
255  }
256  port_out_img.write(img);
257  }
258  }
259  }
260 
261 
262 public:
263  SparseCoderPort(ResourceFinder &_rf)
264  :BufferedPort<Image>(),rf(_rf)
265  {
266  ipl=NULL;
267  help=false;
268  verbose=rf.check("verbose");
269 
270  grid_step=rf.check("grid_step",Value(8)).asInt32();
271  grid_scale=rf.check("grid_scale",Value(1)).asInt32();
272 
273  contextPath=rf.getHomeContextPath().c_str();
274  string dictionary_name=rf.check("dictionary_file",Value("dictionary_bow.ini")).asString().c_str();
275 
276  string dictionary_path=rf.findFile(dictionary_name);
277  if(dictionary_path=="")
278  dictionary_path=contextPath+"/"+dictionary_name;
279  string dictionary_group=rf.check("dictionary_group",Value("DICTIONARY")).asString().c_str();
280 
281  no_code=rf.check("no_code");
282  dump_sift=rf.check("dump_sift");
283 
284  if(dump_sift)
285  {
286  string sift_path=rf.check("dump_sift",Value("sift.txt")).asString().c_str();
287  sift_path=contextPath+"/"+sift_path;
288  string sift_write_mode=rf.check("append")?"a":"w";
289 
290  fout_sift=fopen(sift_path.c_str(),sift_write_mode.c_str());
291  }
292 
293  rate=rf.check("rate",Value(0.0)).asFloat64();
294  dense=rf.check("useDense",Value(1)).asInt32();
295  int knn=rf.check("KNN",Value(5)).asInt32();
296  last_read=0.0;
297 
298  pyramidLevels=rf.check("PyramidLevels",Value(3)).asInt32();
299 
300  if(dense)
301  fprintf(stdout,"Step: %d Scale: %d Pyramid: %d Using Dense SIFT Grid\n",grid_step, grid_scale, pyramidLevels);
302  else
303  fprintf(stdout,"Step: %d Scale: %d Pyramid: %d Using Sparse SIFTs \n",grid_step, grid_scale, pyramidLevels);
304 
305  string code_mode_string=rf.check("code_mode",Value("SC")).asString().c_str();
306 
307  sparse_coder=NULL;
308  sparse_coder=new DictionaryLearning(dictionary_path,dictionary_group,code_mode_string,knn);
309 
310 
311 
312  //set all chars to lower case
313  for(int i=0; i<code_mode_string.size(); i++)
314  code_mode_string[i] = std::toupper((unsigned char)code_mode_string[i]);
315 
316  fprintf(stdout,"%s\n",code_mode_string.c_str());
317 
318  if(code_mode_string=="SC")
319  code_mode=CODE_MODE_SC;
320  if(code_mode_string=="BCE")
321  code_mode=CODE_MODE_BCE;
322  if(code_mode_string=="BOW")
323  code_mode=CODE_MODE_BOW;
324 
325  string name=rf.find("name").asString().c_str();
326 
327  port_out_img.open(("/"+name+"/img:o").c_str());
328  port_out_code.open(("/"+name+"/code:o").c_str());
329  BufferedPort<Image>::useCallback();
330  }
331 
332  virtual void interrupt()
333  {
334  lock_guard<mutex> lg(mtx);
335  port_out_code.interrupt();
336  port_out_img.interrupt();
337  BufferedPort<Image>::interrupt();
338  }
339 
340  virtual void resume()
341  {
342  lock_guard<mutex> lg(mtx);
343  port_out_code.resume();
344  port_out_img.resume();
345  BufferedPort<Image>::resume();
346  }
347 
348  virtual void close()
349  {
350  lock_guard<mutex> lg(mtx);
351  if(ipl!=NULL)
352  cvReleaseImage(&ipl);
353 
354  if(dump_sift)
355  fclose(fout_sift);
356 
357  //some closure :P
358  if(sparse_coder!=NULL)
359  delete sparse_coder;
360 
361  port_out_code.close();
362  port_out_img.close();
363  BufferedPort<Image>::close();
364  }
365 
366 
367  bool execReq(const Bottle &command, Bottle &reply)
368  {
369  switch(command.get(0).asVocab32())
370  {
371  case(CMD_HELP):
372  {
373  reply.clear();
374  if(!help)
375  {
376  reply.addString("There's no help in this life. You oughta do everything on your own");
377  help=true;
378  } else
379  {
380  reply.add(Value::makeVocab32("many"));
381  reply.addString("Ok joking.. here the help!");
382  reply.addString("[dump] [a] for starting the SIFT dumping in the context directory.. use 'a' for appending");
383  reply.addString("[stop] for stopping the SIFT dumping in the context directory.. ");
384  reply.addString("[learn] [dictionarySize] [usePCA] [dimPCA] for learning the dictionary from a SIFT file previously dumped..");
385  }
386 
387  return true;
388  }
389  case(DUMP_SIFT):
390  {
391  lock_guard<mutex> lg(mtx);
392  dump_sift=true;
393  string sift_path="sift.txt";
394  sift_path=contextPath+"/"+sift_path;
395 
396  string sift_write_mode;
397  if(command.size()==1)
398  sift_write_mode="w";
399  else
400  sift_write_mode=command.get(1).asString().c_str();
401 
402  fout_sift=fopen(sift_path.c_str(),sift_write_mode.c_str());
403  reply.addString("Starting to dump SIFTs...");
404  return true;
405 
406  }
407  case(DUMP_STOP):
408  {
409  lock_guard<mutex> lg(mtx);
410  dump_sift=false;
411  fclose(fout_sift);
412  reply.addString("Stopped SIFT Dump.");
413  return true;
414  }
415  case(LEARN_DICT):
416  {
417  lock_guard<mutex> lg(mtx);
418  //string sift_path="sift.txt";
419  //sift_path=contextPath+"/"+sift_path;
420  string sift_path=rf.findFile("sift.txt").c_str();
421  string dictionary_path="newDictionary.ini";
422  dictionary_path=contextPath+"/"+dictionary_path;
423  reply.addString("Dictionary Learned.");
424  int dictSize;
425  if(command.size()==1)
426  dictSize=512;
427  else
428  dictSize=command.get(1).asInt32();
429 
430  bool usePCA=command.size()>2;
431 
432  int dimPCA;
433  if(command.size()>3)
434  {
435  dimPCA=command.get(3).asInt32();
436  }else
437  {
438  if(usePCA)
439  dimPCA=80;
440  }
441  sparse_coder->learnDictionary(sift_path, dictSize,usePCA,dimPCA);
442  sparse_coder->saveDictionary(dictionary_path);
443  return true;
444  }
445  default:
446  return false;
447  }
448  }
449 
450 
451 };
452 
453 
454 class SparseCoderModule: public RFModule
455 {
456 protected:
457  SparseCoderPort *scPort;
458  Port rpcPort;
459 
460 public:
461  SparseCoderModule()
462  {
463  scPort=NULL;
464  }
465 
466  virtual bool configure(ResourceFinder &rf)
467  {
468  string name=rf.find("name").asString().c_str();
469 
470  scPort=new SparseCoderPort(rf);
471  scPort->open(("/"+name+"/img:i").c_str());
472  rpcPort.open(("/"+name+"/rpc").c_str());
473  attach(rpcPort);
474 
475  return true;
476  }
477 
478  virtual bool close()
479  {
480  if(scPort!=NULL)
481  {
482  scPort->interrupt();
483  scPort->close();
484  delete scPort;
485  }
486 
487  rpcPort.interrupt();
488  rpcPort.close();
489 
490  return true;
491  }
492 
493  virtual bool respond(const Bottle &command, Bottle &reply)
494  {
495  if(scPort->execReq(command,reply))
496  return true;
497  else
498  return RFModule::respond(command,reply);
499  }
500 
501  virtual double getPeriod() { return 1.0; }
502  virtual bool updateModule()
503  {
504  //scPort->update();
505 
506  return true;
507  }
508 
509 };
510 
511 
512 
513 
514 int main(int argc, char *argv[])
515 {
516  Network yarp;
517 
518  if (!yarp.checkNetwork())
519  return 1;
520 
521  ResourceFinder rf;
522  rf.setDefaultContext("himrep");
523  rf.setDefaultConfigFile("sparseCoder.ini");
524  rf.configure(argc,argv);
525  rf.setDefault("name","sparseCoder");
526  SparseCoderModule mod;
527 
528  return mod.runModule(rf);
529 }
530