himrep
CaffeFeatExtractor.hpp
1 #ifndef CAFFEFEATEXTRACTOR_H_
2 #define CAFFEFEATEXTRACTOR_H_
3 
4 #include <string>
5 
6 // OpenCV
7 #include <opencv2/opencv.hpp>
8 #include <opencv2/imgproc.hpp>
9 
10 // CUDA-C includes
11 #ifdef HAS_CUDA
12  #include <cuda.h>
13  #include <cuda_runtime.h>
14 #endif
15 
16 // Boost
17 #include "boost/algorithm/string.hpp"
18 #include "boost/make_shared.hpp"
19 
20 // Caffe
21 #include "caffe-version.h"
22 
23 #if (CAFFE_MAJOR >= 1)
24  // new caffe headers
25  #include "caffe/caffe.hpp"
26  #include "caffe/layers/memory_data_layer.hpp"
27 #else
28  // old caffe headers
29  #include "caffe/blob.hpp"
30  #include "caffe/common.hpp"
31  #include "caffe/net.hpp"
32  #include "caffe/proto/caffe.pb.h"
33  #include "caffe/util/io.hpp"
34  #include "caffe/vision_layers.hpp"
35 #endif
36 
37 using namespace std;
38 using namespace caffe;
39 
40 template<class Dtype>
41 class CaffeFeatExtractor {
42 
43  string caffemodel_file;
44  string prototxt_file;
45 
46  caffe::shared_ptr<Net<Dtype> > feature_extraction_net;
47 
48  int mean_width;
49  int mean_height;
50  int mean_channels;
51 
52  vector<string> blob_names;
53 
54  bool gpu_mode;
55  int device_id;
56 
57 public:
58 
59  bool timing;
60 
61  CaffeFeatExtractor(string _caffemodel_file,
62  string _prototxt_file, int _resizeWidth, int _resizeHeight,
63  string _blob_names,
64  string _compute_mode,
65  int _device_id,
66  bool _timing_extraction);
67 
68  bool extractBatch_multipleFeat(vector<cv::Mat> &images, int new_batch_size, vector< Blob<Dtype>* > &features, float (&times)[2]);
69 
70  bool extractBatch_singleFeat(vector<cv::Mat> &images, int new_batch_size, vector< Blob<Dtype>* > &features, float (&times)[2]);
71 
72  bool extractBatch_multipleFeat_1D(vector<cv::Mat> &images, int new_batch_size, vector< vector<Dtype> > &features, float (&times)[2]);
73 
74  bool extractBatch_singleFeat_1D(vector<cv::Mat> &images, int new_batch_size, vector< vector<Dtype> > &features, float (&times)[2]);
75 
76  bool extract_multipleFeat(cv::Mat &image, vector< Blob<Dtype>* > &features, float (&times)[2]);
77 
78  bool extract_singleFeat(cv::Mat &image, Blob<Dtype> *feature, float (&times)[2]);
79 
80  bool extract_multipleFeat_1D(cv::Mat &image, vector< vector<Dtype> > &features, float (&times)[2]);
81 
82  bool extract_singleFeat_1D(cv::Mat &image, vector<Dtype> &features, float (&times)[2]);
83 };
84 
85 template <class Dtype>
86 CaffeFeatExtractor<Dtype>::CaffeFeatExtractor(string _caffemodel_file,
87  string _prototxt_file, int _resizeWidth, int _resizeHeight,
88  string _blob_names,
89  string _compute_mode,
90  int _device_id,
91  bool _timing) {
92 
93  // Setup the GPU or the CPU mode for Caffe
94  if (strcmp(_compute_mode.c_str(), "GPU") == 0 || strcmp(_compute_mode.c_str(), "gpu") == 0) {
95 
96  std::cout << "CaffeFeatExtractor::CaffeFeatExtractor(): using GPU" << std::endl;
97 
98  gpu_mode = true;
99  device_id = _device_id;
100 
101  Caffe::CheckDevice(device_id);
102 
103  std::cout << "CaffeFeatExtractor::CaffeFeatExtractor(): using device_id = " << device_id << std::endl;
104 
105  Caffe::set_mode(Caffe::GPU);
106  Caffe::SetDevice(device_id);
107 
108  // Optional: to check that the GPU is working properly...
109  Caffe::DeviceQuery();
110 
111  } else
112  {
113  std::cout << "CaffeFeatExtractor::CaffeFeatExtractor(): using CPU" << std::endl;
114 
115  gpu_mode = false;
116  device_id = -1;
117 
118  Caffe::set_mode(Caffe::CPU);
119  }
120 
121  // Assign specified .caffemodel and .prototxt files
122  caffemodel_file = _caffemodel_file;
123  prototxt_file = _prototxt_file;
124 
125  // Network creation using the specified .prototxt
126  feature_extraction_net = boost::make_shared<Net<Dtype> > (prototxt_file, caffe::TEST);
127 
128  // Network initialization using the specified .caffemodel
129  feature_extraction_net->CopyTrainedLayersFrom(caffemodel_file);
130 
131  // Mean image initialization
132 
133  mean_width = 0;
134  mean_height = 0;
135  mean_channels = 0;
136 
137  caffe::shared_ptr<MemoryDataLayer<Dtype> > memory_data_layer = boost::dynamic_pointer_cast<caffe::MemoryDataLayer<Dtype> >(feature_extraction_net->layers()[0]);
138 
139  TransformationParameter tp = memory_data_layer->layer_param().transform_param();
140 
141  if (tp.has_mean_file())
142  {
143  const string& mean_file = tp.mean_file();
144  std::cout << "CaffeFeatExtractor::CaffeFeatExtractor(): loading mean file from " << mean_file << std::endl;
145 
146  BlobProto blob_proto;
147  ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);
148 
149  Blob<Dtype> data_mean;
150  data_mean.FromProto(blob_proto);
151 
152  mean_channels = data_mean.channels();
153  mean_width = data_mean.width();
154  mean_height = data_mean.height();
155 
156  } else if (tp.mean_value_size()>0)
157  {
158 
159  const int b = tp.mean_value(0);
160  const int g = tp.mean_value(1);
161  const int r = tp.mean_value(2);
162 
163  mean_channels = tp.mean_value_size();
164  mean_width = _resizeWidth;
165  mean_height = _resizeHeight;
166 
167  std::cout << "CaffeFeatExtractor::CaffeFeatExtractor(): B " << b << " G " << g << " R " << r << std::endl;
168  std::cout << "CaffeFeatExtractor::CaffeFeatExtractor(): resizing anysotropically to " << " W: " << mean_width << " H: " << mean_height << std::endl;
169  }
170  else
171  {
172  std::cout << "CaffeFeatExtractor::CaffeFeatExtractor(): Error: neither mean file nor mean value in prototxt!" << std::endl;
173  }
174 
175  // Check that requested blobs exist
176  boost::split(blob_names, _blob_names, boost::is_any_of(","));
177  for (size_t i = 0; i < blob_names.size(); i++) {
178  if (!feature_extraction_net->has_blob(blob_names[i]))
179  {
180  std::cout << "CaffeFeatExtractor::CaffeFeatExtractor(): unknown feature blob name " << blob_names[i] << " in the network " << prototxt_file << std::endl;
181  }
182  }
183 
184  // Initialize timing flag
185  timing = _timing;
186 
187 }
188 
189 
190 template<class Dtype>
191 bool CaffeFeatExtractor<Dtype>::extractBatch_multipleFeat(vector<cv::Mat> &images, int new_batch_size, vector< Blob<Dtype>* > &features, float (&times)[2]) {
192 
193  times[0] = 0.0f;
194  times[1] = 0.0f;
195 
196  if (images.empty())
197  {
198  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty images!" << std::endl;
199  return false;
200  }
201 
202  #ifdef HAS_CUDA
203 
204  // Start timing
205  cudaEvent_t startPrep, stopPrep, startNet, stopNet;
206 
207  if (timing)
208  {
209  cudaEventCreate(&startPrep);
210  cudaEventCreate(&stopPrep);
211  cudaEventCreate(&startNet);
212  cudaEventCreate(&stopNet);
213 
214  cudaEventRecord(startPrep, NULL);
215  }
216 
217  #else
218 
219  // Start timing
220  double startPrep, stopPrep, startNet, stopNet;
221 
222  if (timing)
223  {
224  startPrep = yarp::os::Time::now();
225  }
226 
227  #endif
228 
229  // Set the GPU/CPU mode for Caffe (here in order to be thread-safe)
230  if (gpu_mode)
231  {
232  Caffe::set_mode(Caffe::GPU);
233  Caffe::SetDevice(device_id);
234  }
235  else
236  {
237  Caffe::set_mode(Caffe::CPU);
238  }
239 
240  // Initialize labels to zero
241  vector<int> labels(images.size(), 0);
242 
243  // Get pointer to data layer to set the input
244  caffe::shared_ptr<MemoryDataLayer<Dtype> > memory_data_layer = boost::dynamic_pointer_cast<caffe::MemoryDataLayer<Dtype> >(feature_extraction_net->layers()[0]);
245 
246  // Set batch size
247 
248  if (memory_data_layer->batch_size()!=new_batch_size)
249  {
250  if (images.size()%new_batch_size==0)
251  {
252  memory_data_layer->set_batch_size(new_batch_size);
253  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
254  }
255  else
256  {
257  if (images.size()%memory_data_layer->batch_size()==0)
258  {
259  cout << "WARNING: image number is not multiple of requested batch size, leaving the old one..." << endl;
260  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
261  } else
262  {
263  cout << "WARNING: image number is not multiple of batch size, setting it to 1 (performance issue)..." << endl;
264  memory_data_layer->set_batch_size(1);
265  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
266  }
267 
268  }
269 
270  } else
271  {
272  if (images.size()%memory_data_layer->batch_size()!=0)
273  {
274  cout << "WARNING: image number is not multiple of batch size, setting it to 1 (performance issue)..." << endl;
275  memory_data_layer->set_batch_size(1);
276  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
277  }
278  }
279 
280  int num_batches = images.size()/new_batch_size;
281 
282  // Input preprocessing
283 
284  // The image passed to AddMatVector must be same size as the mean image
285  // If not, it is resized anisotropically (BILINEAR)
286  // if it is downsampled, LANCZOS4 is used for antialiasing
287 
288  for (int i=0; i<images.size(); i++)
289  {
290 
291  if (images[i].empty())
292  {
293  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty image!" << std::endl;
294  return false;
295  }
296 
297  if (images[i].rows != mean_height || images[i].cols != mean_height)
298  {
299  if (images[i].rows > mean_height || images[i].cols > mean_height)
300  {
301  cv::resize(images[i], images[i], cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LANCZOS4);
302  }
303  else
304  {
305  cv::resize(images[i], images[i], cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LINEAR);
306  }
307  }
308  }
309 
310  memory_data_layer->AddMatVector(images,labels);
311 
312  size_t num_features = blob_names.size();
313 
314  if (timing)
315  {
316  #ifdef HAS_CUDA
317 
318  // Record the stop event
319  cudaEventRecord(stopPrep, NULL);
320 
321  // Wait for the stop event to complete
322  cudaEventSynchronize(stopPrep);
323 
324  cudaEventElapsedTime(times, startPrep, stopPrep);
325  times[0] = times[0]/images.size();
326 
327  // Start the network timer
328  cudaEventRecord(startNet, NULL);
329 
330  #else
331 
332  // Record the stop event
333  stopPrep = yarp::os::Time::now();
334  times[0] = ( stopPrep - startPrep ) / images.size() * 1000;
335 
336  // Start the network timer
337  startNet = yarp::os::Time::now();
338 
339  #endif
340  }
341 
342  // Run network and retrieve features!
343 
344  // depending on your net's architecture, the blobs will hold accuracy and/or labels, etc
345  std::vector<Blob<Dtype>*> results;
346 
347  for (int b=0; b<num_batches; b++)
348  {
349  results = feature_extraction_net->Forward();
350 
351  for (int i = 0; i < num_features; ++i) {
352 
353  const caffe::shared_ptr<Blob<Dtype> > feature_blob = feature_extraction_net->blob_by_name(blob_names[i]);
354 
355  int batch_size = feature_blob->num();
356  int channels = feature_blob->channels();
357  int width = feature_blob->width();
358  int height = feature_blob->height();
359 
360  features.push_back(new Blob<Dtype>(batch_size, channels, height, width));
361 
362  features.back()->CopyFrom(*feature_blob);
363  }
364 
365  }
366 
367  if (timing)
368  {
369  #ifdef HAS_CUDA
370 
371  // Record the stop event
372  cudaEventRecord(stopNet, NULL);
373 
374  // Wait for the stop event to complete
375  cudaEventSynchronize(stopNet);
376 
377  cudaEventElapsedTime(times+1, startNet, stopNet);
378  times[1] = times[1]/images.size();
379 
380  #else
381 
382  stopNet = yarp::os::Time::now();
383  times[1] = ( stopNet - startNet ) / images.size() * 1000;
384 
385  #endif
386  }
387 
388  return true;
389 
390 }
391 
392 template<class Dtype>
393 bool CaffeFeatExtractor<Dtype>::extractBatch_singleFeat(vector<cv::Mat> &images, int new_batch_size, vector< Blob<Dtype>* > &features, float (&times)[2]) {
394 
395  times[0] = 0.0f;
396  times[1] = 0.0f;
397 
398  if (images.empty())
399  {
400  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty images!" << std::endl;
401  return false;
402  }
403 
404  #ifdef HAS_CUDA
405 
406  // Start timing
407  cudaEvent_t startPrep, stopPrep, startNet, stopNet;
408 
409  if (timing)
410  {
411  cudaEventCreate(&startPrep);
412  cudaEventCreate(&stopPrep);
413  cudaEventCreate(&startNet);
414  cudaEventCreate(&stopNet);
415 
416  cudaEventRecord(startPrep, NULL);
417  }
418 
419  #else
420 
421  // Start timing
422  double startPrep, stopPrep, startNet, stopNet;
423 
424  if (timing)
425  {
426  startPrep = yarp::os::Time::now();
427  }
428 
429  #endif
430 
431  // Set the GPU/CPU mode for Caffe (here in order to be thread-safe)
432  if (gpu_mode)
433  {
434  Caffe::set_mode(Caffe::GPU);
435  Caffe::SetDevice(device_id);
436  }
437  else
438  {
439  Caffe::set_mode(Caffe::CPU);
440  }
441 
442  // Initialize the labels to zero
443  vector<int> labels(images.size(), 0);
444 
445  // Get pointer to data layer to set the input
446  caffe::shared_ptr<MemoryDataLayer<Dtype> > memory_data_layer = boost::dynamic_pointer_cast<caffe::MemoryDataLayer<Dtype> >(feature_extraction_net->layers()[0]);
447 
448  // Set batch size
449 
450  if (memory_data_layer->batch_size()!=new_batch_size)
451  {
452  if (images.size()%new_batch_size==0)
453  {
454  memory_data_layer->set_batch_size(new_batch_size);
455  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
456  }
457  else
458  {
459  if (images.size()%memory_data_layer->batch_size()==0)
460  {
461  cout << "WARNING: image number is not multiple of requested batch size, leaving the old one." << endl;
462  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
463  } else
464  {
465  cout << "WARNING: image number is not multiple of batch size, setting it to 1 (performance issue)." << endl;
466  memory_data_layer->set_batch_size(1);
467  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
468  }
469 
470  }
471 
472  } else
473  {
474  if (images.size()%memory_data_layer->batch_size()!=0)
475  {
476  cout << "WARNING: image number is not multiple of batch size, setting it to 1 (performance issue)." << endl;
477  memory_data_layer->set_batch_size(1);
478  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
479  }
480  }
481 
482  int num_batches = images.size()/new_batch_size;
483 
484  // Input preprocessing
485 
486  // The image passed to AddMatVector must be same size as the mean image
487  // If not, it is resized:
488  // if it is downsampled, an anti-aliasing Gaussian Filter is applied
489 
490  for (int i=0; i<images.size(); i++)
491  {
492  if (images[i].rows != mean_height || images[i].cols != mean_height)
493  {
494 
495  if (images[i].empty())
496  {
497  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty image!" << std::endl;
498  return false;
499  }
500 
501  if (images[i].rows > mean_height || images[i].cols > mean_height)
502  {
503  cv::resize(images[i], images[i], cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LANCZOS4);
504  }
505  else
506  {
507  cv::resize(images[i], images[i], cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LINEAR);
508  }
509  }
510  }
511 
512  memory_data_layer->AddMatVector(images,labels);
513 
514  size_t num_features = blob_names.size();
515  if (num_features!=1)
516  {
517  cout<< "Error! The list of features to be extracted has not size one!" << endl;
518  return false;
519  }
520 
521  if (timing)
522  {
523  #ifdef HAS_CUDA
524 
525  // Record the stop event
526  cudaEventRecord(stopPrep, NULL);
527 
528  // Wait for the stop event to complete
529  cudaEventSynchronize(stopPrep);
530 
531  cudaEventElapsedTime(times, startPrep, stopPrep);
532  times[0] = times[0]/images.size();
533 
534  // Start the network timer
535  cudaEventRecord(startNet, NULL);
536 
537  #else
538 
539  // Record the stop event
540  stopPrep = yarp::os::Time::now();
541  times[0] = ( stopPrep - startPrep ) / images.size() * 1000;
542 
543  // Start the network timer
544  startNet = yarp::os::Time::now();
545 
546  #endif
547  }
548 
549  // Run network and retrieve features!
550 
551  // depending on your net's architecture, the blobs will hold accuracy and/or labels, etc
552  std::vector<Blob<Dtype>*> results;
553 
554  for (int b=0; b<num_batches; b++)
555  {
556  results = feature_extraction_net->Forward();
557 
558  const caffe::shared_ptr<Blob<Dtype> > feature_blob = feature_extraction_net->blob_by_name(blob_names[0]);
559 
560  int batch_size = feature_blob->num();
561  int channels = feature_blob->channels();
562  int width = feature_blob->width();
563  int height = feature_blob->height();
564 
565  features.push_back(new Blob<Dtype>(batch_size, channels, height, width));
566 
567  features.back()->CopyFrom(*feature_blob);
568 
569  }
570 
571  if (timing)
572  {
573  #ifdef HAS_CUDA
574 
575  // Record the stop event
576  cudaEventRecord(stopNet, NULL);
577 
578  // Wait for the stop event to complete
579  cudaEventSynchronize(stopNet);
580 
581  cudaEventElapsedTime(times+1, startNet, stopNet);
582  times[1] = times[1]/images.size();
583 
584  #else
585 
586  stopNet = yarp::os::Time::now();
587  times[1] = ( stopNet - startNet ) / images.size() * 1000;
588 
589  #endif
590  }
591 
592  return true;
593 }
594 
595 template<class Dtype>
596 bool CaffeFeatExtractor<Dtype>::extract_multipleFeat(cv::Mat &image, vector< Blob<Dtype>* > &features, float (&times)[2]) {
597 
598 
599  times[0] = 0.0f;
600  times[1] = 0.0f;
601 
602  if (image.empty())
603  {
604  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty image!" << std::endl;
605  return false;
606  }
607 
608  #ifdef HAS_CUDA
609 
610  // Start timing
611  cudaEvent_t startPrep, stopPrep, startNet, stopNet;
612 
613  if (timing)
614  {
615  cudaEventCreate(&startPrep);
616  cudaEventCreate(&stopPrep);
617  cudaEventCreate(&startNet);
618  cudaEventCreate(&stopNet);
619 
620  cudaEventRecord(startPrep, NULL);
621  }
622 
623  #else
624 
625  // Start timing
626  double startPrep, stopPrep, startNet, stopNet;
627 
628  if (timing)
629  {
630  startPrep = yarp::os::Time::now();
631  }
632 
633  #endif
634 
635  // Set the GPU/CPU mode for Caffe (here in order to be thread-safe)
636  if (gpu_mode)
637  {
638  Caffe::set_mode(Caffe::GPU);
639  Caffe::SetDevice(device_id);
640  }
641  else
642  {
643  Caffe::set_mode(Caffe::CPU);
644  }
645 
646  // Initialize the labels to zero
647  int label = 0;
648 
649  // Get pointer to data layer to set the input
650  caffe::shared_ptr<MemoryDataLayer<Dtype> > memory_data_layer = boost::dynamic_pointer_cast<caffe::MemoryDataLayer<Dtype> >(feature_extraction_net->layers()[0]);
651 
652  // Set batch size to 1
653 
654  if (memory_data_layer->batch_size()!=1)
655  {
656  memory_data_layer->set_batch_size(1);
657  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
658  }
659 
660  // Input preprocessing
661 
662  // The image passed to AddMatVector must be same size as the mean image
663  // If not, it is resized:
664  // if it is downsampled, an anti-aliasing Gaussian Filter is applied
665 
666 
667  if (image.rows != mean_height || image.cols != mean_height)
668  {
669  if (image.rows > mean_height || image.cols > mean_height)
670  {
671  cv::resize(image, image, cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LANCZOS4);
672  }
673  else
674  {
675  cv::resize(image, image, cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LINEAR);
676  }
677  }
678 
679  memory_data_layer->AddMatVector(vector<cv::Mat>(1, image),vector<int>(1,label));
680 
681  size_t num_features = blob_names.size();
682 
683  if (timing)
684  {
685  #ifdef HAS_CUDA
686 
687  // Record the stop event
688  cudaEventRecord(stopPrep, NULL);
689 
690  // Wait for the stop event to complete
691  cudaEventSynchronize(stopPrep);
692 
693  cudaEventElapsedTime(times, startPrep, stopPrep);
694 
695  // Start the network timer
696  cudaEventRecord(startNet, NULL);
697 
698  #else
699 
700  // Record the stop event
701  stopPrep = yarp::os::Time::now();
702  times[0] = (stopPrep - startPrep) * 1000;
703 
704  // Start the network timer
705  startNet = yarp::os::Time::now();
706 
707  #endif
708  }
709 
710  // Run network and retrieve features!
711 
712  // depending on your net's architecture, the blobs will hold accuracy and/or labels, etc
713  std::vector<Blob<Dtype>*> results = feature_extraction_net->Forward();
714 
715  for (int f = 0; f < num_features; ++f) {
716 
717  const caffe::shared_ptr<Blob<Dtype> > feature_blob = feature_extraction_net->blob_by_name(blob_names[f]);
718 
719  int batch_size = feature_blob->num(); // should be 1
720  if (batch_size!=1)
721  {
722  cout << "Error! Retrieved more than one feature, exiting..." << endl;
723  return false;
724  }
725 
726  int channels = feature_blob->channels();
727  int width = feature_blob->width();
728  int height = feature_blob->height();
729 
730  features.push_back(new Blob<Dtype>(1, channels, height, width));
731 
732  features.back()->CopyFrom(*feature_blob);
733 
734  }
735 
736  if (timing)
737  {
738  #ifdef HAS_CUDA
739 
740  // Record the stop event
741  cudaEventRecord(stopNet, NULL);
742 
743  // Wait for the stop event to complete
744  cudaEventSynchronize(stopNet);
745 
746  cudaEventElapsedTime(times+1, startNet, stopNet);
747 
748  #else
749 
750  stopNet = yarp::os::Time::now();
751  times[1] = (stopNet - startNet) * 1000;
752 
753  #endif
754  }
755 
756  return true;
757 
758 }
759 
760 template<class Dtype>
761 bool CaffeFeatExtractor<Dtype>::extract_singleFeat(cv::Mat &image, Blob<Dtype> *features, float (&times)[2]) {
762 
763  times[0] = 0.0f;
764  times[1] = 0.0f;
765 
766  if (image.empty())
767  {
768  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty image!" << std::endl;
769  return false;
770  }
771 
772  #ifdef HAS_CUDA
773 
774  // Start timing
775  cudaEvent_t startPrep, stopPrep, startNet, stopNet;
776 
777  if (timing)
778  {
779  cudaEventCreate(&startPrep);
780  cudaEventCreate(&stopPrep);
781  cudaEventCreate(&startNet);
782  cudaEventCreate(&stopNet);
783 
784  cudaEventRecord(startPrep, NULL);
785  }
786 
787  #else
788 
789  // Start timing
790  double startPrep, stopPrep, startNet, stopNet;
791 
792  if (timing)
793  {
794  startPrep = yarp::os::Time::now();
795  }
796 
797  #endif
798 
799  // Set the GPU/CPU mode for Caffe (here in order to be thread-safe)
800  if (gpu_mode)
801  {
802  Caffe::set_mode(Caffe::GPU);
803  Caffe::SetDevice(device_id);
804  }
805  else
806  {
807  Caffe::set_mode(Caffe::CPU);
808  }
809 
810  // Initialize label to zero
811  int label = 0;
812 
813  // Get pointer to data layer to set the input
814  caffe::shared_ptr<MemoryDataLayer<Dtype> > memory_data_layer = boost::dynamic_pointer_cast<caffe::MemoryDataLayer<Dtype> >(feature_extraction_net->layers()[0]);
815 
816  // Set batch size to 1
817 
818  if (memory_data_layer->batch_size()!=1)
819  {
820  memory_data_layer->set_batch_size(1);
821  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
822  }
823 
824  // Input preprocessing
825 
826  // The image passed to AddMatVector must be same size as the mean image
827  // If not, it is resized:
828  // if it is downsampled, an anti-aliasing Gaussian Filter is applied
829 
830  if (image.rows != mean_height || image.cols != mean_height)
831  {
832  if (image.rows > mean_height || image.cols > mean_height)
833  {
834  cv::resize(image, image, cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LANCZOS4);
835  }
836  else
837  {
838  cv::resize(image, image, cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LINEAR);
839  }
840  }
841 
842  memory_data_layer->AddMatVector(vector<cv::Mat>(1, image),vector<int>(1,label));
843 
844  size_t num_features = blob_names.size();
845  if(num_features!=1)
846  {
847  cout<< "Error! The list of features to be extracted has not size one!" << endl;
848  return false;
849  }
850 
851  if (timing)
852  {
853  #ifdef HAS_CUDA
854 
855  // Record the stop event
856  cudaEventRecord(stopPrep, NULL);
857 
858  // Wait for the stop event to complete
859  cudaEventSynchronize(stopPrep);
860 
861  cudaEventElapsedTime(times, startPrep, stopPrep);
862 
863  // Start the network timer
864  cudaEventRecord(startNet, NULL);
865 
866  #else
867 
868  // Record the stop event
869  stopPrep = yarp::os::Time::now();
870  times[0] = (stopPrep - startPrep) * 1000;
871 
872  // Start the network timer
873  startNet = yarp::os::Time::now();
874 
875  #endif
876  }
877 
878  // Run network and retrieve features!
879 
880  // depending on your net's architecture, the blobs will hold accuracy and/or labels, etc
881  std::vector<Blob<Dtype>*> results = feature_extraction_net->Forward();
882 
883  const caffe::shared_ptr<Blob<Dtype> > feature_blob = feature_extraction_net->blob_by_name(blob_names[0]);
884 
885  int batch_size = feature_blob->num(); // should be 1
886  if (batch_size!=1)
887  {
888  cout << "Error! Retrieved more than one feature, exiting..." << endl;
889  return false;
890  }
891 
892  int channels = feature_blob->channels();
893  int width = feature_blob->width();
894  int height = feature_blob->height();
895 
896  if (features==NULL)
897  {
898  features = new Blob<Dtype>(1, channels, height, width);
899  } else
900  {
901  features->Reshape(1, channels, height, width);
902  }
903 
904  features->CopyFrom(*feature_blob);
905 
906  if (timing)
907  {
908  #ifdef HAS_CUDA
909 
910  // Record the stop event
911  cudaEventRecord(stopNet, NULL);
912 
913  // Wait for the stop event to complete
914  cudaEventSynchronize(stopNet);
915 
916  cudaEventElapsedTime(times+1, startNet, stopNet);
917 
918  #else
919 
920  stopNet = yarp::os::Time::now();
921  times[1] = (stopNet - startNet) * 1000;
922 
923  #endif
924  }
925 
926  return true;
927 }
928 
929 template<class Dtype>
930 bool CaffeFeatExtractor<Dtype>::extractBatch_multipleFeat_1D(vector<cv::Mat> &images, int new_batch_size, vector< vector<Dtype> > &features, float (&times)[2]) {
931 
932  times[0] = 0.0f;
933  times[1] = 0.0f;
934 
935  if (images.empty())
936  {
937  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty images!" << std::endl;
938  return false;
939  }
940 
941  #ifdef HAS_CUDA
942 
943  // Start timing
944  cudaEvent_t startPrep, stopPrep, startNet, stopNet;
945 
946  if (timing)
947  {
948  cudaEventCreate(&startPrep);
949  cudaEventCreate(&stopPrep);
950  cudaEventCreate(&startNet);
951  cudaEventCreate(&stopNet);
952 
953  cudaEventRecord(startPrep, NULL);
954  }
955 
956  #else
957 
958  // Start timing
959  double startPrep, stopPrep, startNet, stopNet;
960 
961  if (timing)
962  {
963  startPrep = yarp::os::Time::now();
964  }
965 
966  #endif
967 
968  // Set the GPU/CPU mode for Caffe (here in order to be thread-safe)
969  if (gpu_mode)
970  {
971  Caffe::set_mode(Caffe::GPU);
972  Caffe::SetDevice(device_id);
973  }
974  else
975  {
976  Caffe::set_mode(Caffe::CPU);
977  }
978 
979  // Initialize the labels to zero
980  vector<int> labels(images.size(), 0);
981 
982  // Get pointer to data layer to set the input
983  caffe::shared_ptr<MemoryDataLayer<Dtype> > memory_data_layer = boost::dynamic_pointer_cast<caffe::MemoryDataLayer<Dtype> >(feature_extraction_net->layers()[0]);
984 
985  // Set batch size
986 
987  if (memory_data_layer->batch_size()!=new_batch_size)
988  {
989  if (images.size()%new_batch_size==0)
990  {
991  memory_data_layer->set_batch_size(new_batch_size);
992  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
993  }
994  else
995  {
996  if (images.size()%memory_data_layer->batch_size()==0)
997  {
998  cout << "WARNING: image number is not multiple of requested batch size,leaving the old one." << endl;
999  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
1000  } else
1001  {
1002  cout << "WARNING: image number is not multiple of batch size, setting it to 1 (performance issue)." << endl;
1003  memory_data_layer->set_batch_size(1);
1004  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
1005  }
1006 
1007  }
1008 
1009  } else
1010  {
1011  if (images.size()%memory_data_layer->batch_size()!=0)
1012  {
1013  cout << "WARNING: image number is not multiple of batch size, setting it to 1 (performance issue)." << endl;
1014  memory_data_layer->set_batch_size(1);
1015  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
1016  }
1017  }
1018 
1019  int num_batches = images.size()/new_batch_size;
1020 
1021  // Input preprocessing
1022 
1023  // The image passed to AddMatVector must be same size as the mean image
1024  // If not, it is resized:
1025  // if it is downsampled, an anti-aliasing Gaussian Filter is applied
1026 
1027 
1028  for (int i=0; i<images.size(); i++)
1029  {
1030  if (images[i].rows != mean_height || images[i].cols != mean_height)
1031  {
1032  if (images[i].empty())
1033  {
1034  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty image!" << std::endl;
1035  return false;
1036  }
1037 
1038  if (images[i].rows > mean_height || images[i].cols > mean_height)
1039  {
1040  cv::resize(images[i], images[i], cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LANCZOS4);
1041  }
1042  else
1043  {
1044  cv::resize(images[i], images[i], cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LINEAR);
1045  }
1046  }
1047  }
1048 
1049  memory_data_layer->AddMatVector(images,labels);
1050 
1051  size_t num_features = blob_names.size();
1052 
1053  if (timing)
1054  {
1055  #ifdef HAS_CUDA
1056 
1057  // Record the stop event
1058  cudaEventRecord(stopPrep, NULL);
1059 
1060  // Wait for the stop event to complete
1061  cudaEventSynchronize(stopPrep);
1062 
1063  cudaEventElapsedTime(times, startPrep, stopPrep);
1064  times[0] = times[0]/images.size();
1065 
1066  // Start the network timer
1067  cudaEventRecord(startNet, NULL);
1068 
1069  #else
1070 
1071  // Record the stop event
1072  stopPrep = yarp::os::Time::now();
1073  times[0] = ( stopPrep - startPrep ) / images.size() * 1000;
1074 
1075  // Start the network timer
1076  startNet = yarp::os::Time::now();
1077 
1078  #endif
1079  }
1080 
1081  // Run network and retrieve features!
1082 
1083  // depending on your net's architecture, the blobs will hold accuracy and/or labels, etc
1084  std::vector<Blob<Dtype>*> results;
1085 
1086  for (int b=0; b<num_batches; ++b)
1087  {
1088  results = feature_extraction_net->Forward();
1089 
1090  for (int f = 0; f < num_features; ++f) {
1091 
1092  const caffe::shared_ptr<Blob<Dtype> > feature_blob = feature_extraction_net->blob_by_name(blob_names[f]);
1093 
1094  int batch_size = feature_blob->num();
1095 
1096  int feat_dim = feature_blob->count() / batch_size; // should be equal to channels*width*height
1097 
1098  if (feat_dim!=feature_blob->channels()) // the feature is not 1D i.e. width!=1 or height!=1
1099  {
1100  cout<< "Attention! The feature is not 1D: unrolling according to Caffe's order (i.e. channel, width, height)" << endl;
1101  }
1102 
1103  for (int i=0; i<batch_size; ++i)
1104  {
1105  features.push_back(vector <Dtype>(feature_blob->mutable_cpu_data() + feature_blob->offset(i), feature_blob->mutable_cpu_data() + feature_blob->offset(i) + feat_dim));
1106  }
1107 
1108  }
1109 
1110  }
1111 
1112  if (timing)
1113  {
1114  #ifdef HAS_CUDA
1115 
1116  // Record the stop event
1117  cudaEventRecord(stopNet, NULL);
1118 
1119  // Wait for the stop event to complete
1120  cudaEventSynchronize(stopNet);
1121 
1122  cudaEventElapsedTime(times+1, startNet, stopNet);
1123  times[1] = times[1]/images.size();
1124 
1125  #else
1126 
1127  stopNet = yarp::os::Time::now();
1128  times[1] = ( stopNet - startNet ) / images.size() * 1000;
1129 
1130  #endif
1131  }
1132 
1133  return true;
1134 }
1135 
1136 template<class Dtype>
1137 bool CaffeFeatExtractor<Dtype>::extractBatch_singleFeat_1D(vector<cv::Mat> &images, int new_batch_size, vector< vector<Dtype> > &features, float (&times)[2]) {
1138 
1139  times[0] = 0.0f;
1140  times[1] = 0.0f;
1141 
1142  if (images.empty())
1143  {
1144  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty images!" << std::endl;
1145  return false;
1146  }
1147 
1148  #ifdef HAS_CUDA
1149 
1150  // Start timing
1151  cudaEvent_t startPrep, stopPrep, startNet, stopNet;
1152 
1153  if (timing)
1154  {
1155  cudaEventCreate(&startPrep);
1156  cudaEventCreate(&stopPrep);
1157  cudaEventCreate(&startNet);
1158  cudaEventCreate(&stopNet);
1159 
1160  cudaEventRecord(startPrep, NULL);
1161  }
1162 
1163  #else
1164 
1165  // Start timing
1166  double startPrep, stopPrep, startNet, stopNet;
1167 
1168  if (timing)
1169  {
1170  startPrep = yarp::os::Time::now();
1171  }
1172 
1173  #endif
1174 
1175  // Set the GPU/CPU mode for Caffe (here in order to be thread-safe)
1176  if (gpu_mode)
1177  {
1178  Caffe::set_mode(Caffe::GPU);
1179  Caffe::SetDevice(device_id);
1180  }
1181  else
1182  {
1183  Caffe::set_mode(Caffe::CPU);
1184  }
1185 
1186  // Initialize labels to zero
1187  vector<int> labels(images.size(), 0);
1188 
1189  // Get pointer to data layer to set the input
1190  caffe::shared_ptr<MemoryDataLayer<Dtype> > memory_data_layer = boost::dynamic_pointer_cast<caffe::MemoryDataLayer<Dtype> >(feature_extraction_net->layers()[0]);
1191 
1192  // Set batch size
1193 
1194  if (memory_data_layer->batch_size()!=new_batch_size)
1195  {
1196  if (images.size()%new_batch_size==0)
1197  {
1198  memory_data_layer->set_batch_size(new_batch_size);
1199  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
1200  }
1201  else
1202  {
1203  if (images.size()%memory_data_layer->batch_size()==0)
1204  {
1205  cout << "WARNING: image number is not multiple of requested batch size,leaving the old one." << endl;
1206  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
1207  } else
1208  {
1209  cout << "WARNING: image number is not multiple of batch size, setting it to 1 (performance issue)." << endl;
1210  memory_data_layer->set_batch_size(1);
1211  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
1212  }
1213 
1214  }
1215 
1216  } else
1217  {
1218  if (images.size()%memory_data_layer->batch_size()!=0)
1219  {
1220  cout << "WARNING: image number is not multiple of batch size, setting it to 1 (performance issue)." << endl;
1221  memory_data_layer->set_batch_size(1);
1222  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
1223  }
1224  }
1225 
1226  int num_batches = images.size()/new_batch_size;
1227 
1228  // Input preprocessing
1229 
1230  // The image passed to AddMatVector must be same size as the mean image
1231  // If not, it is resized:
1232  // if it is downsampled, an anti-aliasing Gaussian Filter is applied
1233 
1234  for (int i=0; i<images.size(); i++)
1235  {
1236  if (images[i].rows != mean_height || images[i].cols != mean_height)
1237  {
1238  if (images[i].empty())
1239  {
1240  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty image!" << std::endl;
1241  return false;
1242  }
1243 
1244  if (images[i].rows > mean_height || images[i].cols > mean_height)
1245  {
1246  cv::resize(images[i], images[i], cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LANCZOS4);
1247  }
1248  else
1249  {
1250  cv::resize(images[i], images[i], cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LINEAR);
1251  }
1252  }
1253  }
1254 
1255  memory_data_layer->AddMatVector(images,labels);
1256 
1257  size_t num_features = blob_names.size();
1258  if (num_features!=1)
1259  {
1260  cout<< "Error! The list of features to be extracted has not size one!" << endl;
1261  return false;
1262  }
1263 
1264  if (timing)
1265  {
1266  #ifdef HAS_CUDA
1267 
1268  // Record the stop event
1269  cudaEventRecord(stopPrep, NULL);
1270 
1271  // Wait for the stop event to complete
1272  cudaEventSynchronize(stopPrep);
1273 
1274  cudaEventElapsedTime(times, startPrep, stopPrep);
1275  times[0] = times[0]/images.size();
1276 
1277  // Start the network timer
1278  cudaEventRecord(startNet, NULL);
1279 
1280  #else
1281 
1282  // Record the stop event
1283  stopPrep = yarp::os::Time::now();
1284  times[0] = ( stopPrep - startPrep ) / images.size() * 1000;
1285 
1286  // Start the network timer
1287  startNet = yarp::os::Time::now();
1288 
1289  #endif
1290  }
1291 
1292  // Run network and retrieve features!
1293 
1294  std::vector<Blob<Dtype>*> results;
1295 
1296  for (int b=0; b<num_batches; ++b)
1297  {
1298  results = feature_extraction_net->Forward();
1299 
1300  const caffe::shared_ptr<Blob<Dtype> > feature_blob = feature_extraction_net->blob_by_name(blob_names[0]);
1301 
1302  int batch_size = feature_blob->num();
1303 
1304  int feat_dim = feature_blob->count() / batch_size; // should be equal to: channels*width*height
1305  if (feat_dim!=feature_blob->channels())
1306  {
1307  cout<< "Attention! The feature is not 1D: unrolling according to Caffe's order (i.e. channel, width, height)" << endl;
1308  }
1309 
1310  for (int i=0; i<batch_size; ++i)
1311  {
1312  features.push_back(vector <Dtype>(feature_blob->mutable_cpu_data() + feature_blob->offset(i), feature_blob->mutable_cpu_data() + feature_blob->offset(i) + feat_dim));
1313  }
1314 
1315  }
1316 
1317  if (timing)
1318  {
1319  #ifdef HAS_CUDA
1320 
1321  // Record the stop event
1322  cudaEventRecord(stopNet, NULL);
1323 
1324  // Wait for the stop event to complete
1325  cudaEventSynchronize(stopNet);
1326 
1327  cudaEventElapsedTime(times+1, startNet, stopNet);
1328  times[1] = times[1]/images.size();
1329 
1330  #else
1331 
1332  stopNet = yarp::os::Time::now();
1333  times[1] = ( stopNet - startNet ) / images.size() * 1000;
1334 
1335  #endif
1336  }
1337 
1338  return true;
1339 
1340 }
1341 
1342 template<class Dtype>
1343 bool CaffeFeatExtractor<Dtype>::extract_multipleFeat_1D(cv::Mat &image, vector< vector<Dtype> > &features, float (&times)[2]) {
1344 
1345  times[0] = 0.0f;
1346  times[1] = 0.0f;
1347 
1348  if (image.empty())
1349  {
1350  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty images!" << std::endl;
1351  return false;
1352  }
1353 
1354  #ifdef HAS_CUDA
1355 
1356  // Start timing
1357  cudaEvent_t startPrep, stopPrep, startNet, stopNet;
1358 
1359  if (timing)
1360  {
1361  cudaEventCreate(&startPrep);
1362  cudaEventCreate(&stopPrep);
1363  cudaEventCreate(&startNet);
1364  cudaEventCreate(&stopNet);
1365 
1366  cudaEventRecord(startPrep, NULL);
1367  }
1368 
1369  #else
1370 
1371  // Start timing
1372  double startPrep, stopPrep, startNet, stopNet;
1373 
1374  if (timing)
1375  {
1376  startPrep = yarp::os::Time::now();
1377  }
1378 
1379  #endif
1380 
1381  // Set the GPU/CPU mode for Caffe (here in order to be thread-safe)
1382  if (gpu_mode)
1383  {
1384  Caffe::set_mode(Caffe::GPU);
1385  Caffe::SetDevice(device_id);
1386  }
1387  else
1388  {
1389  Caffe::set_mode(Caffe::CPU);
1390  }
1391 
1392  // Initialize labels to zero
1393  int label = 0;
1394 
1395  // Get pointer to data layer to set the input
1396  caffe::shared_ptr<MemoryDataLayer<Dtype> > memory_data_layer = boost::dynamic_pointer_cast<caffe::MemoryDataLayer<Dtype> >(feature_extraction_net->layers()[0]);
1397 
1398  // Set batch size to 1
1399 
1400  if (memory_data_layer->batch_size()!=1)
1401  {
1402  memory_data_layer->set_batch_size(1);
1403  cout << "BATCH SIZE = " << memory_data_layer->batch_size() << endl;
1404  }
1405 
1406  // Input preprocessing
1407 
1408  // The image passed to AddMatVector must be same size as the mean image
1409  // If not, it is resized:
1410  // if it is downsampled, an anti-aliasing Gaussian Filter is applied
1411 
1412  if (image.rows != mean_height || image.cols != mean_height)
1413  {
1414  if (image.rows > mean_height || image.cols > mean_height)
1415  {
1416  cv::resize(image, image, cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LANCZOS4);
1417  }
1418  else
1419  {
1420  cv::resize(image, image, cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LINEAR);
1421  }
1422  }
1423 
1424  memory_data_layer->AddMatVector(vector<cv::Mat>(1, image),vector<int>(1,label));
1425 
1426  size_t num_features = blob_names.size();
1427 
1428  if (timing)
1429  {
1430  #ifdef HAS_CUDA
1431 
1432  // Record the stop event
1433  cudaEventRecord(stopPrep, NULL);
1434 
1435  // Wait for the stop event to complete
1436  cudaEventSynchronize(stopPrep);
1437 
1438  cudaEventElapsedTime(times, startPrep, stopPrep);
1439 
1440  // Start the network timer
1441  cudaEventRecord(startNet, NULL);
1442 
1443  #else
1444 
1445  // Record the stop event
1446  stopPrep = yarp::os::Time::now();
1447  times[0] = (stopPrep - startPrep) * 1000;
1448 
1449  // Start the network timer
1450  startNet = yarp::os::Time::now();
1451 
1452  #endif
1453  }
1454 
1455  // Run network and retrieve features!
1456 
1457  // depending on your net's architecture, the blobs will hold accuracy and/or labels, etc
1458  std::vector<Blob<Dtype>*> results = feature_extraction_net->Forward();
1459 
1460  for (int f = 0; f < num_features; ++f) {
1461 
1462  const caffe::shared_ptr<Blob<Dtype> > feature_blob = feature_extraction_net->blob_by_name(blob_names[f]);
1463 
1464  int batch_size = feature_blob->num(); // should be 1
1465  if (batch_size!=1)
1466  {
1467  cout << "Error! Retrieved more than one feature, exiting..." << endl;
1468  return false;
1469  }
1470 
1471  int feat_dim = feature_blob->count(); // should be equal to: count/batch_size=channels*width*height
1472  if (feat_dim!=feature_blob->channels())
1473  {
1474  cout<< "Attention! The feature is not 1D: unrolling according to Caffe's order (i.e. channel, width, height)" << endl;
1475  }
1476 
1477  features.push_back(vector <Dtype>(feature_blob->mutable_cpu_data() + feature_blob->offset(0), feature_blob->mutable_cpu_data() + feature_blob->offset(0) + feat_dim));
1478 
1479  }
1480 
1481  if (timing)
1482  {
1483  #ifdef HAS_CUDA
1484 
1485  // Record the stop event
1486  cudaEventRecord(stopNet, NULL);
1487 
1488  // Wait for the stop event to complete
1489  cudaEventSynchronize(stopNet);
1490 
1491  cudaEventElapsedTime(times+1, startNet, stopNet);
1492 
1493  #else
1494 
1495  stopNet = yarp::os::Time::now();
1496  times[1] = (stopNet - startNet) * 1000;
1497 
1498  #endif
1499  }
1500 
1501  return true;
1502 
1503 }
1504 
1505 template<class Dtype>
1506 bool CaffeFeatExtractor<Dtype>::extract_singleFeat_1D(cv::Mat &image, vector<Dtype> &features, float (&times)[2]) {
1507 
1508  times[0] = 0.0f;
1509  times[1] = 0.0f;
1510 
1511  if (image.empty())
1512  {
1513  std::cout << "CaffeFeatExtractor::extractBatch_multipleFeat(): empty images!" << std::endl;
1514  return false;
1515  }
1516 
1517  #ifdef HAS_CUDA
1518 
1519  // Start timing
1520  cudaEvent_t startPrep, stopPrep, startNet, stopNet;
1521 
1522  if (timing)
1523  {
1524  cudaEventCreate(&startPrep);
1525  cudaEventCreate(&stopPrep);
1526  cudaEventCreate(&startNet);
1527  cudaEventCreate(&stopNet);
1528 
1529  cudaEventRecord(startPrep, NULL);
1530  }
1531 
1532  #else
1533 
1534  // Start timing
1535  double startPrep, stopPrep, startNet, stopNet;
1536 
1537  if (timing)
1538  {
1539  startPrep = yarp::os::Time::now();
1540  }
1541 
1542  #endif
1543 
1544  // Set the GPU/CPU mode for Caffe (here in order to be thread-safe)
1545  if (gpu_mode)
1546  {
1547  Caffe::set_mode(Caffe::GPU);
1548  Caffe::SetDevice(device_id);
1549  }
1550  else
1551  {
1552  Caffe::set_mode(Caffe::CPU);
1553  }
1554 
1555  // Initialize labels to zero
1556  int label = 0;
1557 
1558  // Get pointer to data layer to set the input
1559  caffe::shared_ptr<MemoryDataLayer<Dtype> > memory_data_layer = boost::dynamic_pointer_cast<caffe::MemoryDataLayer<Dtype> >(feature_extraction_net->layers()[0]);
1560 
1561  // Set batch size to 1
1562  if (memory_data_layer->batch_size()!=1)
1563  {
1564  memory_data_layer->set_batch_size(1);
1565  std::cout << "CaffeFeatExtractor::extract_singleFeat_1D(): BATCH SIZE = " << memory_data_layer->batch_size() << std::endl;
1566  }
1567 
1568  // Image preprocessing
1569  // The image passed to AddMatVector must be same size as the mean image
1570  // If not, it is resized:
1571  // if it is downsampled, an anti-aliasing Gaussian Filter is applied
1572  if (image.rows != mean_height || image.cols != mean_height)
1573  {
1574  if (image.rows > mean_height || image.cols > mean_height)
1575  {
1576  cv::resize(image, image, cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LANCZOS4);
1577  }
1578  else
1579  {
1580  cv::resize(image, image, cv::Size(mean_height, mean_width), 0, 0, cv::INTER_LINEAR);
1581  }
1582  }
1583 
1584  memory_data_layer->AddMatVector(vector<cv::Mat>(1, image),vector<int>(1,label));
1585 
1586  size_t num_features = blob_names.size();
1587  if(num_features!=1)
1588  {
1589  std::cout << "CaffeFeatExtractor::extract_singleFeat_1D(): Error! The list of features to be extracted has not size one!" << std::endl;
1590  return false;
1591  }
1592 
1593  if (timing)
1594  {
1595  #ifdef HAS_CUDA
1596 
1597  // Record the stop event
1598  cudaEventRecord(stopPrep, NULL);
1599 
1600  // Wait for the stop event to complete
1601  cudaEventSynchronize(stopPrep);
1602 
1603  cudaEventElapsedTime(times, startPrep, stopPrep);
1604 
1605  // Start the network timer
1606  cudaEventRecord(startNet, NULL);
1607 
1608  #else
1609 
1610  // Record the stop event
1611  stopPrep = yarp::os::Time::now();
1612  times[0] = (stopPrep - startPrep) * 1000;
1613 
1614  // Start the network timer
1615  startNet = yarp::os::Time::now();
1616 
1617  #endif
1618  }
1619 
1620  // Run network and retrieve features!
1621 
1622  // depending on your net's architecture, the blobs will hold accuracy and/or labels, etc
1623  std::vector<Blob<Dtype>*> results = feature_extraction_net->Forward();
1624 
1625  const caffe::shared_ptr<Blob<Dtype> > feature_blob = feature_extraction_net->blob_by_name(blob_names[0]);
1626 
1627  int batch_size = feature_blob->num(); // should be 1
1628  if (batch_size!=1)
1629  {
1630  std::cout << "CaffeFeatExtractor::extract_singleFeat_1D(): Error! Retrieved more than one feature, exiting..." << std::endl;
1631  return false;
1632  }
1633 
1634  int feat_dim = feature_blob->count(); // should be equal to: count/num=channels*width*height
1635  if (feat_dim!=feature_blob->channels())
1636  {
1637  std::cout << "CaffeFeatExtractor::extract_singleFeat_1D(): Attention! The feature is not 1D: unrolling according to Caffe's order (i.e. channel, height, width)" << std::endl;
1638  }
1639 
1640  features.insert(features.end(), feature_blob->mutable_cpu_data() + feature_blob->offset(0), feature_blob->mutable_cpu_data() + feature_blob->offset(0) + feat_dim);
1641 
1642  if (timing)
1643  {
1644  #ifdef HAS_CUDA
1645 
1646  // Record the stop event
1647  cudaEventRecord(stopNet, NULL);
1648 
1649  // Wait for the stop event to complete
1650  cudaEventSynchronize(stopNet);
1651 
1652  cudaEventElapsedTime(times+1, startNet, stopNet);
1653 
1654  #else
1655 
1656  stopNet = yarp::os::Time::now();
1657  times[1] = (stopNet - startNet) * 1000;
1658 
1659  #endif
1660  }
1661 
1662  return true;
1663 
1664 }
1665 
1666 #endif /* CAFFEFEATEXTRACTOR_H_ */