face_recognition_nodelet.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2017, Yuki Furuta.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the Kei Okada nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 
35 #include <algorithm>
36 #include <boost/filesystem.hpp>
37 #include <boost/shared_ptr.hpp>
38 #include <boost/thread.hpp>
39 #include <boost/version.hpp>
40 #include <iomanip>
41 #include <map>
42 #include <stdexcept>
43 #include <string>
44 #include <opencv2/opencv.hpp>
45 #include <pwd.h>
46 #include <vector>
47 
48 #include <cv_bridge/cv_bridge.h>
49 #include <dynamic_reconfigure/server.h>
57 
58 #include <opencv_apps/nodelet.h>
59 #include <opencv_apps/FaceArrayStamped.h>
60 #include <opencv_apps/FaceRecognitionTrain.h>
61 #include <opencv_apps/FaceRecognitionConfig.h>
62 
64 #if BOOST_VERSION < 105000
65 namespace fs = boost::filesystem3; // for hydro
66 #else
67 namespace fs = boost::filesystem;
68 #endif
69 
70 #if CV_MAJOR_VERSION >= 3
71 #include <opencv2/face.hpp>
72 namespace face = cv::face;
73 #else
74 namespace face = cv;
75 #endif
76 
77 #if CV_MAJOR_VERSION >= 4
78 #include <opencv2/imgcodecs/legacy/constants_c.h> // include CV_LOAD_IMAGE_COLOR
79 #include <opencv2/imgproc/imgproc_c.h> // include CV_AA
80 #endif
81 
82 // utility for resolving path
83 namespace boost
84 {
85 #if BOOST_VERSION < 105000
86 namespace filesystem3
87 { // for hydro
88 #else
89 namespace filesystem
90 {
91 #endif
92 #if BOOST_VERSION < 108300
93 template <>
94 path& path::append<typename path::iterator>(typename path::iterator lhs, typename path::iterator rhs,
95  const codecvt_type& cvt)
96 {
97  for (; lhs != rhs; ++lhs)
98  *this /= *lhs;
99  return *this;
100 }
101 #endif
102 path user_expanded_path(const path& p)
103 {
104 #if BOOST_VERSION < 108300
105  path::const_iterator it(p.begin());
106 #else
107  if (p.size() < 2)
108  return p;
109 
110  auto it = p.begin();
111  // Replace the tilda with the home directory
112 #endif
113  std::string user_dir = (*it).string();
114  if (user_dir.length() == 0 || user_dir[0] != '~')
115  return p;
116  path ret;
117  char* homedir;
118  if (user_dir.length() == 1)
119  {
120  homedir = getenv("HOME");
121  if (homedir == nullptr)
122  {
123  homedir = getpwuid(getuid())->pw_dir;
124  }
125  }
126  else
127  {
128  std::string uname = user_dir.substr(1, user_dir.length());
129  passwd* pw = getpwnam(uname.c_str());
130  if (pw == nullptr)
131  return p;
132  homedir = pw->pw_dir;
133  }
134 
135  // Append the rest of path
136  ret = path(std::string(homedir));
137 #if BOOST_VERSION < 108300
138  return ret.append(++it, p.end(), path::codecvt());
139 #else
140  ++it;
141  for (; it != p.end(); ++it)
142  {
143  ret /= *it;
144  }
145  return ret;
146 #endif
147 }
148 } // namespace filesystem
149 } // namespace boost
150 
151 namespace opencv_apps
152 {
154 {
155  std::map<std::string, int> m_;
156 
157 public:
158  void add(std::vector<std::string>& l)
159  {
160  int id = 0;
161  for (std::map<std::string, int>::const_iterator it = m_.begin(); it != m_.end(); ++it)
162  {
163  if (id < it->second)
164  id = it->second + 1;
165  }
166  for (const std::string& i : l)
167  {
168  if (m_.find(i) == m_.end())
169  {
170  m_[i] = id;
171  id++;
172  }
173  }
174  }
175  std::vector<int> get(std::vector<std::string>& v)
176  {
177  std::vector<int> ret(v.size());
178  for (size_t i = 0; i < v.size(); ++i)
179  {
180  ret[i] = m_[v[i]];
181  }
182  return ret;
183  }
184  std::string lookup(int id)
185  {
186  for (std::map<std::string, int>::const_iterator it = m_.begin(); it != m_.end(); ++it)
187  {
188  if (it->second == id)
189  return it->first;
190  }
191  return "nan";
192  }
193  const std::map<std::string, int>& getMap() const
194  {
195  return m_;
196  }
197 
198  void debugPrint()
199  {
200  ROS_WARN_STREAM("label mapper: debug print:");
201  for (std::map<std::string, int>::const_iterator it = m_.begin(); it != m_.end(); ++it)
202  {
203  ROS_WARN_STREAM("\t" << it->first << ": " << it->second);
204  }
205  ROS_WARN_STREAM("label mapper: debug print end");
206  }
207 };
208 
209 class Storage
210 {
211  fs::path base_dir_;
212 
213 public:
214  Storage(const fs::path& base_dir)
215  {
216  base_dir_ = fs::user_expanded_path(base_dir);
217  if (!fs::exists(base_dir_))
218  {
219  init();
220  }
221  if (!fs::is_directory(base_dir_))
222  {
223  std::stringstream ss;
224  ss << base_dir_ << " is not a directory";
225  throw std::runtime_error(ss.str());
226  }
227  };
228  void init()
229  {
230  if (!fs::create_directories(base_dir_))
231  {
232  std::stringstream ss;
233  ss << "failed to initialize directory: " << base_dir_;
234  throw std::runtime_error(ss.str());
235  }
236  }
237 
238  void load(std::vector<cv::Mat>& images, std::vector<std::string>& labels, bool append = true)
239  {
240  if (!append)
241  {
242  images.clear();
243  labels.clear();
244  }
245  fs::directory_iterator end;
246  for (fs::directory_iterator it(base_dir_); it != end; ++it)
247  {
248  if (fs::is_directory(*it))
249  {
250  std::string label = it->path().stem().string();
251  for (fs::directory_iterator cit(it->path()); cit != end; ++cit)
252  {
253  if (fs::is_directory(*cit))
254  continue;
255  fs::path file_path = cit->path();
256  try
257  {
258  cv::Mat img = cv::imread(file_path.string(), CV_LOAD_IMAGE_COLOR);
259  labels.push_back(label);
260  images.push_back(img);
261  }
262  catch (cv::Exception& e)
263  {
264  ROS_ERROR_STREAM("Error: load image from " << file_path << ": " << e.what());
265  }
266  }
267  }
268  }
269  }
270 
271  void save(const std::vector<cv::Mat>& images, const std::vector<std::string>& labels)
272  {
273  if (images.size() != labels.size())
274  {
275  throw std::length_error("images.size() != labels.size()");
276  }
277  for (size_t i = 0; i < images.size(); ++i)
278  {
279  save(images[i], labels[i]);
280  }
281  }
282 
283  void save(const cv::Mat& image, const std::string& label)
284  {
285  fs::path img_dir = base_dir_ / fs::path(label);
286  if (!fs::exists(img_dir) && !fs::create_directories(img_dir))
287  {
288  std::stringstream ss;
289  ss << "failed to initialize directory: " << img_dir;
290  throw std::runtime_error(ss.str());
291  }
292  fs::directory_iterator end;
293  int file_count = 0;
294  for (fs::directory_iterator it(img_dir); it != end; ++it)
295  {
296  if (!fs::is_directory(*it))
297  file_count++;
298  }
299 
300  std::stringstream ss;
301  // data_dir/person_label/person_label_123456.jpg
302  ss << label << "_" << std::setw(6) << std::setfill('0') << file_count << ".jpg";
303  fs::path file_path = img_dir / ss.str();
304  ROS_INFO_STREAM("saving image to :" << file_path);
305  try
306  {
307  cv::imwrite(file_path.string(), image);
308  }
309  catch (cv::Exception& e)
310  {
311  ROS_ERROR_STREAM("Error: save image to " << file_path << ": " << e.what());
312  }
313  }
314 };
315 
317 {
318  typedef opencv_apps::FaceRecognitionConfig Config;
319  typedef dynamic_reconfigure::Server<Config> Server;
323 
334 
340  std::string data_dir_;
341  boost::mutex mutex_;
342 
346  cv::Ptr<face::FaceRecognizer> model_;
347 
348  void drawFace(cv::Mat& img, const opencv_apps::Face& face)
349  {
350  cv::Rect r(int(face.face.x - face.face.width / 2.0 - face.face.width * face_padding_ / 2.0),
351  int(face.face.y - face.face.height / 2.0 - face.face.height * face_padding_ / 2.0),
352  int(face.face.width + face.face.width * face_padding_),
353  int(face.face.height + face.face.height * face_padding_));
354  cv::Scalar color(0.0, 0.0, 255.0);
355  int boldness = 2;
356  cv::rectangle(img, r.tl(), r.br(), color, boldness, CV_AA);
357 
358  double font_scale = 1.5;
359  int text_height = 20;
360  cv::Point text_bl;
361  if (r.br().y + text_height > img.rows)
362  text_bl = r.tl() + cv::Point(0, -text_height);
363  else
364  text_bl = r.br() + cv::Point(-r.width, text_height);
365  std::stringstream ss;
366  ss << face.label << " (" << std::fixed << std::setprecision(2) << face.confidence << ")";
367  cv::putText(img, ss.str(), text_bl, cv::FONT_HERSHEY_PLAIN, font_scale, color, boldness, CV_AA);
368  }
369 
370  void extractImage(const cv::Mat& img, const opencv_apps::Rect& rect, cv::Mat& ret, double padding = 0.0)
371  {
372  int x = std::max(0, int(rect.x - rect.width / 2.0 - rect.width * padding / 2.0));
373  int y = std::max(0, int(rect.y - rect.height / 2.0 - rect.height * padding / 2.0));
374  cv::Rect r(x, y, std::min(img.cols - x, int(rect.width + rect.width * padding)),
375  std::min(img.rows - y, int(rect.height + rect.height * padding)));
376  ret = img(r);
377  }
378 
379  void extractImage(const cv::Mat& img, const opencv_apps::Face& face, cv::Mat& ret, double padding = 0.0)
380  {
381  extractImage(img, face.face, ret, padding);
382  }
383 
384  void retrain()
385  {
386  NODELET_DEBUG("retrain");
387  std::vector<cv::Mat> images;
388  std::vector<std::string> labels;
389  train(images, labels);
390  }
391 
392  void train(std::vector<cv::Mat>& images, std::vector<std::string>& labels)
393  {
394  size_t new_image_size = images.size();
395 
396  if (use_saved_data_)
397  {
398  storage_->load(images, labels);
399  }
400 
401  if (images.empty())
402  return;
403 
404  std::vector<cv::Mat> resized_images(images.size());
405  for (int i = 0; i < images.size(); ++i)
406  {
407  cv::resize(images[i], resized_images[i], face_model_size_, 0, 0, cv::INTER_CUBIC);
408  cv::cvtColor(resized_images[i], resized_images[i], CV_BGR2GRAY);
409  }
410 
411  label_mapper_->add(labels);
412  std::vector<int> ids = label_mapper_->get(labels);
413  NODELET_INFO_STREAM("training with " << images.size() << " images");
414  // label_mapper_->debugPrint();
415  model_->train(resized_images, ids);
416 
417  if (save_train_data_ && new_image_size > 0)
418  {
419  std::vector<cv::Mat> new_images(images.begin(), images.begin() + new_image_size);
420  std::vector<std::string> new_labels(labels.begin(), labels.begin() + new_image_size);
421  storage_->save(new_images, new_labels);
422  }
423  }
424 
425  void predict(const cv::Mat& img, int& label, double& confidence)
426  {
427  cv::Mat resized_img;
428  cv::resize(img, resized_img, face_model_size_, 0, 0, cv::INTER_CUBIC);
429  cv::cvtColor(resized_img, resized_img, CV_BGR2GRAY);
430  model_->predict(resized_img, label, confidence);
431  }
432 
433  void faceImageCallback(const sensor_msgs::Image::ConstPtr& image, const opencv_apps::FaceArrayStamped::ConstPtr& faces)
434  {
435  NODELET_DEBUG("faceImageCallback");
436  boost::mutex::scoped_lock lock(mutex_);
437 
438  // check if the face data is being trained
439  if (label_mapper_->getMap().empty())
440  {
441  NODELET_WARN_THROTTLE(1.0, "Face data is not trained. Please train first.");
442  return;
443  }
444 
445  // check if need to draw and publish debug image
446  bool publish_debug_image = debug_img_pub_.getNumSubscribers() > 0;
447 
448  try
449  {
450  cv::Mat cv_img = cv_bridge::toCvShare(image, enc::BGR8)->image;
451  opencv_apps::FaceArrayStamped ret_msg = *faces;
452  for (size_t i = 0; i < faces->faces.size(); ++i)
453  {
454  cv::Mat face_img, resized_image;
455  extractImage(cv_img, faces->faces[i], face_img, face_padding_);
456 
457  int label_id = -1;
458  double confidence = 0.0;
459  predict(face_img, label_id, confidence);
460  if (label_id == -1)
461  continue;
462  ret_msg.faces[i].label = label_mapper_->lookup(label_id);
463  ret_msg.faces[i].confidence = confidence;
464 
465  // draw debug image
466  if (publish_debug_image)
467  drawFace(cv_img, ret_msg.faces[i]);
468  }
469  face_pub_.publish(ret_msg);
470  if (publish_debug_image)
471  {
472  sensor_msgs::Image::Ptr debug_img = cv_bridge::CvImage(image->header, enc::BGR8, cv_img).toImageMsg();
473  debug_img_pub_.publish(debug_img);
474  NODELET_DEBUG("Published debug image");
475  }
476  }
477  catch (cv::Exception& e)
478  {
479  NODELET_ERROR_STREAM("error at image processing: " << e.err << " " << e.func << " " << e.file << " " << e.line);
480  }
481  }
482 
483  bool trainCallback(opencv_apps::FaceRecognitionTrain::Request& req, opencv_apps::FaceRecognitionTrain::Response& res)
484  {
485  boost::mutex::scoped_lock lock(mutex_);
486  try
487  {
488  std::vector<cv::Mat> images(req.images.size());
489  bool use_roi = !req.rects.empty();
490 
491  if (use_roi && req.images.size() != req.rects.size())
492  {
493  throw std::length_error("req.images.size() != req.rects.size()");
494  }
495 
496  for (size_t i = 0; i < req.images.size(); ++i)
497  {
498  sensor_msgs::Image img = req.images[i];
499  images[i] = cv_bridge::toCvCopy(img, enc::BGR8)->image;
500  if (use_roi)
501  {
502  cv::Mat face_img;
503  extractImage(images[i], req.rects[i], face_img);
504  images[i] = face_img;
505  }
506  }
507  std::vector<std::string> labels(req.labels.begin(), req.labels.end());
508  train(images, labels);
509  res.ok = true;
510  return true;
511  }
512  catch (cv::Exception& e)
513  {
514  std::stringstream ss;
515  ss << "error at training: " << e.err << " " << e.func << " " << e.file << " " << e.line;
516  res.ok = false;
517  res.error = ss.str();
518  }
519  return false;
520  }
521 
522  void configCallback(Config& config, uint32_t level)
523  {
524  boost::mutex::scoped_lock lock(mutex_);
525 
526  bool need_recreate_model = false;
527  bool need_retrain = false;
528 
529  use_saved_data_ = config.use_saved_data;
530  save_train_data_ = config.save_train_data;
531  face_padding_ = config.face_padding;
532 
533  if (face_model_size_.width != config.face_model_width)
534  {
535  face_model_size_.width = config.face_model_width;
536  need_retrain = true;
537  }
538  if (face_model_size_.height != config.face_model_height)
539  {
540  face_model_size_.height = config.face_model_height;
541  need_retrain = true;
542  }
543 
544  if (data_dir_ != config.data_dir)
545  {
546  data_dir_ = config.data_dir;
547  need_retrain = true;
548  label_mapper_.reset(new LabelMapper());
549  storage_.reset(new Storage(fs::path(data_dir_)));
550  }
551 
552  if (config_.model_method != config.model_method)
553  {
554  need_recreate_model = true;
555  }
556 
557  if (config_.model_num_components != config.model_num_components)
558  {
559  need_recreate_model = true;
560  }
561 
562  if (config.model_method == "LBPH" &&
563  (config_.lbph_radius != config.lbph_radius || config_.lbph_neighbors != config.lbph_neighbors ||
564  config_.lbph_grid_x != config.lbph_grid_x || config_.lbph_grid_y != config.lbph_grid_y))
565  {
566  need_recreate_model = true;
567  }
568 
569  if (need_recreate_model)
570  {
571  try
572  {
573  if (config.model_method == "eigen")
574  {
575 // https://docs.opencv.org/3.3.1/da/d60/tutorial_face_main.html
576 #if (CV_MAJOR_VERSION >= 4) || (CV_MAJOR_VERSION >= 3 && CV_MINOR_VERSION >= 3)
577  model_ = face::EigenFaceRecognizer::create(config.model_num_components, config.model_threshold);
578 #else
579  model_ = face::createEigenFaceRecognizer(config.model_num_components, config.model_threshold);
580 #endif
581  }
582  else if (config.model_method == "fisher")
583  {
584 #if (CV_MAJOR_VERSION >= 4) || (CV_MAJOR_VERSION >= 3 && CV_MINOR_VERSION >= 3)
585  model_ = face::FisherFaceRecognizer::create(config.model_num_components, config.model_threshold);
586 #else
587  model_ = face::createFisherFaceRecognizer(config.model_num_components, config.model_threshold);
588 #endif
589  }
590  else if (config.model_method == "LBPH")
591  {
592 #if (CV_MAJOR_VERSION >= 4) || (CV_MAJOR_VERSION >= 3 && CV_MINOR_VERSION >= 3)
593  model_ = face::LBPHFaceRecognizer::create(config.lbph_radius, config.lbph_neighbors, config.lbph_grid_x,
594  config.lbph_grid_y);
595 #else
596  model_ = face::createLBPHFaceRecognizer(config.lbph_radius, config.lbph_neighbors, config.lbph_grid_x,
597  config.lbph_grid_y);
598 #endif
599  }
600  need_retrain = true;
601  }
602  catch (cv::Exception& e)
603  {
604  NODELET_ERROR_STREAM("Error: create face recognizer: " << e.what());
605  }
606  }
607 
608  if (need_retrain)
609  {
610  try
611  {
612  retrain();
613  }
614  catch (cv::Exception& e)
615  {
616  NODELET_ERROR_STREAM("Error: train: " << e.what());
617  }
618  }
619 
620  if (config_.model_threshold != config.model_threshold)
621  {
622  try
623  {
624 #if CV_MAJOR_VERSION >= 3
625  if (face::BasicFaceRecognizer* model = dynamic_cast<face::BasicFaceRecognizer*>(model_.get()))
626  {
627  model->setThreshold(config.model_threshold);
628  }
629  else if (face::LBPHFaceRecognizer* model = dynamic_cast<face::LBPHFaceRecognizer*>(model_.get()))
630  {
631  model->setThreshold(config.model_threshold);
632  }
633 #else
634  model_->set("threshold", config.model_threshold);
635 #endif
636  }
637  catch (cv::Exception& e)
638  {
639  NODELET_ERROR_STREAM("Error: set threshold: " << e.what());
640  }
641  }
642  config_ = config;
643  }
644 
645  void subscribe() // NOLINT(modernize-use-override)
646  {
647  NODELET_DEBUG("subscribe");
648  img_sub_.subscribe(*it_, "image", 1);
649  face_sub_.subscribe(*nh_, "faces", 1);
650  if (use_async_)
651  {
652  async_ = boost::make_shared<message_filters::Synchronizer<ApproximateSyncPolicy> >(queue_size_);
653  async_->connectInput(img_sub_, face_sub_);
654  async_->registerCallback(boost::bind(&FaceRecognitionNodelet::faceImageCallback, this, boost::placeholders::_1,
656  }
657  else
658  {
659  sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(queue_size_);
660  sync_->connectInput(img_sub_, face_sub_);
661  sync_->registerCallback(boost::bind(&FaceRecognitionNodelet::faceImageCallback, this, boost::placeholders::_1,
663  }
664  }
665 
666  void unsubscribe() // NOLINT(modernize-use-override)
667  {
668  NODELET_DEBUG("unsubscribe");
669  img_sub_.unsubscribe();
670  face_sub_.unsubscribe();
671  }
672 
673 public:
674  ~FaceRecognitionNodelet() // NOLINT(modernize-use-override)
675  {
676  sync_.reset();
677  async_.reset();
678  }
679 
680  virtual void onInit() // NOLINT(modernize-use-override)
681  {
682  Nodelet::onInit();
683 
684  // variables
685  face_model_size_ = cv::Size(190, 90);
686 
687  // dynamic reconfigures
688  cfg_srv_ = boost::make_shared<Server>(*pnh_);
689  Server::CallbackType f =
690  boost::bind(&FaceRecognitionNodelet::configCallback, this, boost::placeholders::_1, boost::placeholders::_2);
691  cfg_srv_->setCallback(f);
692 
693  // parameters
694  pnh_->param("approximate_sync", use_async_, false);
695  pnh_->param("queue_size", queue_size_, 100);
696 
697  // advertise
698  debug_img_pub_ = advertise<sensor_msgs::Image>(*pnh_, "debug_image", 1);
699  face_pub_ = advertise<opencv_apps::FaceArrayStamped>(*pnh_, "output", 1);
700  train_srv_ = pnh_->advertiseService("train", &FaceRecognitionNodelet::trainCallback, this);
702 
703  onInitPostProcess();
704  }
705 };
706 } // namespace opencv_apps
707 
709 {
711 {
712 public:
713  virtual void onInit() // NOLINT(modernize-use-override)
714  {
715  ROS_WARN("DeprecationWarning: Nodelet face_recognition/face_recognition is deprecated, "
716  "and renamed to opencv_apps/face_recognition.");
718  }
719 };
720 } // namespace face_recognition
721 
722 #ifdef USE_PLUGINLIB_CLASS_LIST_MACROS_H
724 #else
726 #endif
opencv_apps::FaceRecognitionNodelet::img_sub_
image_transport::SubscriberFilter img_sub_
Definition: face_recognition_nodelet.cpp:329
opencv_apps::Storage
Definition: face_recognition_nodelet.cpp:209
image_transport::SubscriberFilter
sensor_msgs::image_encodings
nodelet.h
ros::Publisher
image_encodings.h
opencv_apps::FaceRecognitionNodelet::face_sub_
message_filters::Subscriber< opencv_apps::FaceArrayStamped > face_sub_
Definition: face_recognition_nodelet.cpp:330
opencv_apps::LabelMapper
Definition: face_recognition_nodelet.cpp:153
image_transport::ImageTransport
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(args)
boost::shared_ptr< Server >
cv_bridge::CvImage::toImageMsg
sensor_msgs::ImagePtr toImageMsg() const
opencv_apps::FaceRecognitionNodelet::train
void train(std::vector< cv::Mat > &images, std::vector< std::string > &labels)
Definition: face_recognition_nodelet.cpp:392
opencv_apps::LabelMapper::m_
std::map< std::string, int > m_
Definition: face_recognition_nodelet.cpp:155
face_recognition
Definition: face_recognition_nodelet.cpp:708
opencv_apps::FaceRecognitionNodelet::it_
boost::shared_ptr< image_transport::ImageTransport > it_
Definition: face_recognition_nodelet.cpp:326
boost::placeholders::_1
boost::arg< 1 > _1
Definition: nodelet.cpp:44
opencv_apps::FaceRecognitionNodelet::face_pub_
ros::Publisher face_pub_
Definition: face_recognition_nodelet.cpp:332
opencv_apps::Nodelet
Nodelet to automatically subscribe/unsubscribe topics according to subscription of advertised topics.
Definition: nodelet.h:90
opencv_apps::FaceRecognitionNodelet::cfg_srv_
boost::shared_ptr< Server > cfg_srv_
Definition: face_recognition_nodelet.cpp:325
opencv_apps::FaceRecognitionNodelet::data_dir_
std::string data_dir_
Definition: face_recognition_nodelet.cpp:340
opencv_apps::FaceRecognitionNodelet::save_train_data_
bool save_train_data_
Definition: face_recognition_nodelet.cpp:335
opencv_apps::FaceRecognitionNodelet::label_mapper_
boost::shared_ptr< LabelMapper > label_mapper_
Definition: face_recognition_nodelet.cpp:343
opencv_apps::FaceRecognitionNodelet::extractImage
void extractImage(const cv::Mat &img, const opencv_apps::Rect &rect, cv::Mat &ret, double padding=0.0)
Definition: face_recognition_nodelet.cpp:370
opencv_apps::FaceRecognitionNodelet::Config
opencv_apps::FaceRecognitionConfig Config
Definition: face_recognition_nodelet.cpp:318
opencv_apps::LabelMapper::get
std::vector< int > get(std::vector< std::string > &v)
Definition: face_recognition_nodelet.cpp:175
image_transport::SubscriberFilter::subscribe
void subscribe(ImageTransport &it, const std::string &base_topic, uint32_t queue_size, const TransportHints &transport_hints=TransportHints())
boost
opencv_apps::LabelMapper::getMap
const std::map< std::string, int > & getMap() const
Definition: face_recognition_nodelet.cpp:193
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
message_filters::Subscriber::unsubscribe
void unsubscribe()
f
f
NODELET_WARN_THROTTLE
#define NODELET_WARN_THROTTLE(rate,...)
message_filters::Subscriber< opencv_apps::FaceArrayStamped >
ros::ServiceServer
opencv_apps::FaceRecognitionNodelet::queue_size_
int queue_size_
Definition: face_recognition_nodelet.cpp:339
class_list_macros.h
opencv_apps::FaceRecognitionNodelet
Definition: face_recognition_nodelet.cpp:316
opencv_apps::Storage::load
void load(std::vector< cv::Mat > &images, std::vector< std::string > &labels, bool append=true)
Definition: face_recognition_nodelet.cpp:238
opencv_apps::FaceRecognitionNodelet::SyncPolicy
message_filters::sync_policies::ExactTime< sensor_msgs::Image, opencv_apps::FaceArrayStamped > SyncPolicy
Definition: face_recognition_nodelet.cpp:320
ROS_WARN_STREAM
#define ROS_WARN_STREAM(args)
opencv_apps::Storage::base_dir_
fs::path base_dir_
Definition: face_recognition_nodelet.cpp:211
message_filters::sync_policies::ApproximateTime
face_recognition::FaceRecognitionNodelet::onInit
virtual void onInit()
Initialize nodehandles nh_ and pnh_. Subclass should call this method in its onInit method.
Definition: face_recognition_nodelet.cpp:713
opencv_apps::FaceRecognitionNodelet::use_async_
bool use_async_
Definition: face_recognition_nodelet.cpp:336
subscriber_filter.h
opencv_apps::Storage::Storage
Storage(const fs::path &base_dir)
Definition: face_recognition_nodelet.cpp:214
cv_bridge::toCvCopy
CvImagePtr toCvCopy(const sensor_msgs::CompressedImage &source, const std::string &encoding=std::string())
NODELET_ERROR_STREAM
#define NODELET_ERROR_STREAM(...)
opencv_apps::FaceRecognitionNodelet::unsubscribe
void unsubscribe()
This method is called when publisher is unsubscribed by other nodes. Shut down subscribers in this me...
Definition: face_recognition_nodelet.cpp:666
opencv_apps::FaceRecognitionNodelet::config_
Config config_
Definition: face_recognition_nodelet.cpp:324
subscriber.h
opencv_apps::FaceRecognitionNodelet::ApproximateSyncPolicy
message_filters::sync_policies::ApproximateTime< sensor_msgs::Image, opencv_apps::FaceArrayStamped > ApproximateSyncPolicy
Definition: face_recognition_nodelet.cpp:322
boost::filesystem3
Definition: face_recognition_nodelet.cpp:118
opencv_apps::FaceRecognitionNodelet::face_padding_
double face_padding_
Definition: face_recognition_nodelet.cpp:338
opencv_apps::Storage::save
void save(const cv::Mat &image, const std::string &label)
Definition: face_recognition_nodelet.cpp:283
opencv_apps::FaceRecognitionNodelet::model_
cv::Ptr< face::FaceRecognizer > model_
Definition: face_recognition_nodelet.cpp:346
boost::placeholders::_2
boost::arg< 2 > _2
Definition: nodelet.cpp:45
ROS_WARN
#define ROS_WARN(...)
opencv_apps::FaceRecognitionNodelet::subscribe
void subscribe()
This method is called when publisher is subscribed by other nodes. Set up subscribers in this method.
Definition: face_recognition_nodelet.cpp:645
opencv_apps::FaceRecognitionNodelet::predict
void predict(const cv::Mat &img, int &label, double &confidence)
Definition: face_recognition_nodelet.cpp:425
opencv_apps::FaceRecognitionNodelet::storage_
boost::shared_ptr< Storage > storage_
Definition: face_recognition_nodelet.cpp:344
ROS_INFO_STREAM
#define ROS_INFO_STREAM(args)
opencv_apps::FaceRecognitionNodelet::async_
boost::shared_ptr< message_filters::Synchronizer< ApproximateSyncPolicy > > async_
Definition: face_recognition_nodelet.cpp:328
opencv_apps
Demo code to calculate moments.
Definition: nodelet.h:68
opencv_apps::FaceRecognitionNodelet::face_model_size_
cv::Size face_model_size_
Definition: face_recognition_nodelet.cpp:345
image_transport.h
opencv_apps::FaceRecognitionNodelet::~FaceRecognitionNodelet
~FaceRecognitionNodelet()
Definition: face_recognition_nodelet.cpp:674
opencv_apps::FaceRecognitionNodelet::faceImageCallback
void faceImageCallback(const sensor_msgs::Image::ConstPtr &image, const opencv_apps::FaceArrayStamped::ConstPtr &faces)
Definition: face_recognition_nodelet.cpp:433
exact_time.h
opencv_apps::FaceRecognitionNodelet::retrain
void retrain()
Definition: face_recognition_nodelet.cpp:384
opencv_apps::FaceRecognitionNodelet::debug_img_pub_
ros::Publisher debug_img_pub_
Definition: face_recognition_nodelet.cpp:331
opencv_apps::FaceRecognitionNodelet::sync_
boost::shared_ptr< message_filters::Synchronizer< SyncPolicy > > sync_
Definition: face_recognition_nodelet.cpp:327
opencv_apps::FaceRecognitionNodelet::train_srv_
ros::ServiceServer train_srv_
Definition: face_recognition_nodelet.cpp:333
message_filters::Subscriber::subscribe
void subscribe()
opencv_apps::FaceRecognitionNodelet::mutex_
boost::mutex mutex_
Definition: face_recognition_nodelet.cpp:341
nodelet::Nodelet
append
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
opencv_apps::LabelMapper::debugPrint
void debugPrint()
Definition: face_recognition_nodelet.cpp:198
opencv_apps::FaceRecognitionNodelet::drawFace
void drawFace(cv::Mat &img, const opencv_apps::Face &face)
Definition: face_recognition_nodelet.cpp:348
opencv_apps::FaceRecognitionNodelet::onInit
virtual void onInit()
Initialize nodehandles nh_ and pnh_. Subclass should call this method in its onInit method.
Definition: face_recognition_nodelet.cpp:680
cv_bridge.h
opencv_apps::FaceRecognitionNodelet::use_saved_data_
bool use_saved_data_
Definition: face_recognition_nodelet.cpp:337
cv_bridge::CvImage
class_list_macros.hpp
opencv_apps::FaceRecognitionNodelet::trainCallback
bool trainCallback(opencv_apps::FaceRecognitionTrain::Request &req, opencv_apps::FaceRecognitionTrain::Response &res)
Definition: face_recognition_nodelet.cpp:483
synchronizer.h
init
void init(const M_string &remappings)
face_recognition::FaceRecognitionNodelet
Definition: face_recognition_nodelet.cpp:710
approximate_time.h
boost::filesystem3::user_expanded_path
path user_expanded_path(const path &p)
Definition: face_recognition_nodelet.cpp:166
cv
Demo code for equalizeHist function.
Definition: equalize_histogram_nodelet.cpp:58
ros::Publisher::getNumSubscribers
uint32_t getNumSubscribers() const
opencv_apps::LabelMapper::lookup
std::string lookup(int id)
Definition: face_recognition_nodelet.cpp:184
cv_bridge::toCvShare
CvImageConstPtr toCvShare(const sensor_msgs::Image &source, const boost::shared_ptr< void const > &tracked_object, const std::string &encoding=std::string())
opencv_apps::Storage::init
void init()
Definition: face_recognition_nodelet.cpp:228
NODELET_INFO_STREAM
#define NODELET_INFO_STREAM(...)
message_filters::sync_policies::ExactTime
opencv_apps::FaceRecognitionNodelet::configCallback
void configCallback(Config &config, uint32_t level)
Definition: face_recognition_nodelet.cpp:522
opencv_apps::Storage::save
void save(const std::vector< cv::Mat > &images, const std::vector< std::string > &labels)
Definition: face_recognition_nodelet.cpp:271
opencv_apps::FaceRecognitionNodelet::Server
dynamic_reconfigure::Server< Config > Server
Definition: face_recognition_nodelet.cpp:319
opencv_apps::FaceRecognitionNodelet::extractImage
void extractImage(const cv::Mat &img, const opencv_apps::Face &face, cv::Mat &ret, double padding=0.0)
Definition: face_recognition_nodelet.cpp:379
image_transport::SubscriberFilter::unsubscribe
void unsubscribe()
PLUGINLIB_EXPORT_CLASS
PLUGINLIB_EXPORT_CLASS(opencv_apps::FaceRecognitionNodelet, nodelet::Nodelet)
NODELET_DEBUG
#define NODELET_DEBUG(...)


opencv_apps
Author(s): Kei Okada
autogenerated on Fri May 23 2025 02:49:49