camera_info_manager.cpp
Go to the documentation of this file.
1 /* $Id$ */
2 
3 /*********************************************************************
4 * Software License Agreement (BSD License)
5 *
6 * Copyright (c) 2010-2012 Jack O'Quin
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
19 * * Neither the name of the author nor other contributors may be
20 * used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *********************************************************************/
36 
37 #include <string>
38 #include <locale>
39 #include <stdlib.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #ifdef _WIN32
43  #ifndef S_ISDIR
44  #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
45  #endif
46 #else
47  #include <unistd.h>
48 #endif
49 
50 #include <ros/ros.h>
51 #include <ros/package.h>
52 #include <boost/algorithm/string.hpp>
54 
56 
67 namespace camera_info_manager
68 {
69 
70 using namespace camera_calibration_parsers;
71 
73 const std::string
74  default_camera_info_url = "file://${ROS_HOME}/camera_info/${NAME}.yaml";
75 
77 
88  const std::string &cname,
89  const std::string &url):
90  nh_(nh),
91  camera_name_(cname),
92  url_(url),
93  loaded_cam_info_(false)
94 {
95  // register callback for camera calibration service request
96  info_service_ = nh_.advertiseService("set_camera_info",
98 }
99 
115 sensor_msgs::CameraInfo CameraInfoManager::getCameraInfo(void)
116 {
117  while (ros::ok())
118  {
119  std::string cname;
120  std::string url;
121  {
122  boost::mutex::scoped_lock lock_(mutex_);
123  if (loaded_cam_info_)
124  {
125  return cam_info_; // all done
126  }
127 
128  // load being attempted now
129  loaded_cam_info_ = true;
130 
131  // copy the name and URL strings
132  url = url_;
133  cname = camera_name_;
134 
135  } // release the lock
136 
137  // attempt load without the lock, it is not recursive
138  loadCalibration(url, cname);
139  }
140 
141  return sensor_msgs::CameraInfo();
142 }
143 
149 std::string CameraInfoManager::getPackageFileName(const std::string &url)
150 {
151  ROS_DEBUG_STREAM("camera calibration URL: " << url);
152 
153  // Scan URL from after "package://" until next '/' and extract
154  // package name. The parseURL() already checked that it's present.
155  size_t prefix_len = std::string("package://").length();
156  size_t rest = url.find('/', prefix_len);
157  std::string package(url.substr(prefix_len, rest - prefix_len));
158 
159  // Look up the ROS package path name.
160  std::string pkgPath(ros::package::getPath(package));
161  if (pkgPath.empty()) // package not found?
162  {
163  ROS_WARN_STREAM("unknown package: " << package << " (ignored)");
164  return pkgPath;
165  }
166  else
167  {
168  // Construct file name from package location and remainder of URL.
169  return pkgPath + url.substr(rest);
170  }
171 }
172 
183 {
184  while (true)
185  {
186  std::string cname;
187  std::string url;
188  {
189  boost::mutex::scoped_lock lock_(mutex_);
190  if (loaded_cam_info_)
191  {
192  return (cam_info_.K[0] != 0.0);
193  }
194 
195  // load being attempted now
196  loaded_cam_info_ = true;
197 
198  // copy the name and URL strings
199  url = url_;
200  cname = camera_name_;
201 
202  } // release the lock
203 
204  // attempt load without the lock, it is not recursive
205  loadCalibration(url, cname);
206  }
207 }
208 
219 bool CameraInfoManager::loadCalibration(const std::string &url,
220  const std::string &cname)
221 {
222  bool success = false; // return value
223 
224  const std::string resURL(resolveURL(url, cname));
225  url_type_t url_type = parseURL(resURL);
226 
227  if (url_type != URL_empty)
228  {
229  ROS_INFO_STREAM("camera calibration URL: " << resURL);
230  }
231 
232  switch (url_type)
233  {
234  case URL_empty:
235  {
236  ROS_INFO("using default calibration URL");
237  success = loadCalibration(default_camera_info_url, cname);
238  break;
239  }
240  case URL_file:
241  {
242  success = loadCalibrationFile(resURL.substr(7), cname);
243  break;
244  }
245  case URL_flash:
246  {
247  success = loadCalibrationFlash(resURL.substr(8), cname);
248  break;
249  }
250  case URL_package:
251  {
252  std::string filename(getPackageFileName(resURL));
253  if (!filename.empty())
254  success = loadCalibrationFile(filename, cname);
255  break;
256  }
257  default:
258  {
259  ROS_ERROR_STREAM("Invalid camera calibration URL: " << resURL);
260  break;
261  }
262  }
263 
264  return success;
265 }
266 
277 bool CameraInfoManager::loadCalibrationFile(const std::string &filename,
278  const std::string &cname)
279 {
280  bool success = false;
281 
282  ROS_DEBUG_STREAM("reading camera calibration from " << filename);
283  std::string cam_name;
284  sensor_msgs::CameraInfo cam_info;
285 
286  if (readCalibration(filename, cam_name, cam_info))
287  {
288  if (cname != cam_name)
289  {
290  ROS_WARN_STREAM("[" << cname << "] does not match name "
291  << cam_name << " in file " << filename);
292  }
293  success = true;
294  {
295  // lock only while updating cam_info_
296  boost::mutex::scoped_lock lock(mutex_);
297  cam_info_ = cam_info;
298  }
299  }
300  else
301  {
302  ROS_WARN_STREAM("Camera calibration file " << filename << " not found.");
303  }
304 
305  return success;
306 }
307 
308 bool CameraInfoManager::loadCalibrationFlash(const std::string &flashURL,
309  const std::string &cname) {
310  ROS_WARN("[CameraInfoManager] reading from flash not implemented for this CameraInfoManager");
311  return false;
312 }
313 
325 bool CameraInfoManager::loadCameraInfo(const std::string &url)
326 {
327  std::string cname;
328  {
329  boost::mutex::scoped_lock lock(mutex_);
330  url_ = url;
331  cname = camera_name_;
332  loaded_cam_info_ = true;
333  }
334 
335  // load using copies of the parameters, no need to hold the lock
336  return loadCalibration(url, cname);
337 }
338 
339 
348 std::string CameraInfoManager::resolveURL(const std::string &url,
349  const std::string &cname)
350 {
351  std::string resolved;
352  size_t rest = 0;
353 
354  while (true)
355  {
356  // find the next '$' in the URL string
357  size_t dollar = url.find('$', rest);
358 
359  if (dollar >= url.length())
360  {
361  // no more variables left in the URL
362  resolved += url.substr(rest);
363  break;
364  }
365 
366  // copy characters up to the next '$'
367  resolved += url.substr(rest, dollar-rest);
368 
369  if (url.substr(dollar+1, 1) != "{")
370  {
371  // no '{' follows, so keep the '$'
372  resolved += "$";
373  }
374  else if (url.substr(dollar+1, 6) == "{NAME}")
375  {
376  // substitute camera name
377  resolved += cname;
378  dollar += 6;
379  }
380  else if (url.substr(dollar+1, 10) == "{ROS_HOME}")
381  {
382  // substitute $ROS_HOME
383  std::string ros_home;
384  char *ros_home_env;
385  if ((ros_home_env = getenv("ROS_HOME")))
386  {
387  // use environment variable
388  ros_home = ros_home_env;
389  }
390  else if ((ros_home_env = getenv("HOME")))
391  {
392  // use "$HOME/.ros"
393  ros_home = ros_home_env;
394  ros_home += "/.ros";
395  }
396  resolved += ros_home;
397  dollar += 10;
398  }
399  else
400  {
401  // not a valid substitution variable
402  ROS_ERROR_STREAM("[CameraInfoManager]"
403  " invalid URL substitution (not resolved): "
404  << url);
405  resolved += "$"; // keep the bogus '$'
406  }
407 
408  // look for next '$'
409  rest = dollar + 1;
410  }
411 
412  return resolved;
413 }
414 
423 {
424  if (url == "")
425  {
426  return URL_empty;
427  }
428  if (boost::iequals(url.substr(0, 8), "file:///"))
429  {
430  return URL_file;
431  }
432  if (boost::iequals(url.substr(0, 9), "flash:///"))
433  {
434  return URL_flash;
435  }
436  if (boost::iequals(url.substr(0, 10), "package://"))
437  {
438  // look for a '/' following the package name, make sure it is
439  // there, the name is not empty, and something follows it
440  size_t rest = url.find('/', 10);
441  if (rest < url.length()-1 && rest > 10)
442  return URL_package;
443  }
444  return URL_invalid;
445 }
446 
457 bool
458 CameraInfoManager::saveCalibration(const sensor_msgs::CameraInfo &new_info,
459  const std::string &url,
460  const std::string &cname)
461 {
462  bool success = false;
463 
464  const std::string resURL(resolveURL(url, cname));
465 
466  switch (parseURL(resURL))
467  {
468  case URL_empty:
469  {
470  // store using default file name
471  success = saveCalibration(new_info, default_camera_info_url, cname);
472  break;
473  }
474  case URL_file:
475  {
476  success = saveCalibrationFile(new_info, resURL.substr(7), cname);
477  break;
478  }
479  case URL_package:
480  {
481  std::string filename(getPackageFileName(resURL));
482  if (!filename.empty())
483  success = saveCalibrationFile(new_info, filename, cname);
484  break;
485  }
486  case URL_flash:
487  {
488  success = saveCalibrationFlash(new_info, resURL.substr(8), cname);
489  break;
490  }
491  default:
492  {
493  // invalid URL, save to default location
494  ROS_ERROR_STREAM("invalid url: " << resURL << " (ignored)");
495  success = saveCalibration(new_info, default_camera_info_url, cname);
496  break;
497  }
498  }
499 
500  return success;
501 }
502 
512 bool
513 CameraInfoManager::saveCalibrationFile(const sensor_msgs::CameraInfo &new_info,
514  const std::string &filename,
515  const std::string &cname)
516 {
517  ROS_INFO_STREAM("writing calibration data to " << filename);
518 
519  // isolate the name of the containing directory
520  size_t last_slash = filename.rfind('/');
521  if (last_slash >= filename.length())
522  {
523  // No slash in the name. This should never happen, the URL
524  // parser ensures there is at least one '/' at the beginning.
525  ROS_ERROR_STREAM("filename [" << filename << "] has no '/'");
526  return false; // not a valid URL
527  }
528 
529  // make sure the directory exists and is writable
530  std::string dirname(filename.substr(0, last_slash+1));
531  struct stat stat_data;
532  int rc = stat(dirname.c_str(), &stat_data);
533  if (rc != 0)
534  {
535  if (errno == ENOENT)
536  {
537  // directory does not exist, try to create it and its parents
538  std::string command("mkdir -p " + dirname);
539  rc = system(command.c_str());
540  if (rc != 0)
541  {
542  // mkdir failed
543  ROS_ERROR_STREAM("unable to create path to directory ["
544  << dirname << "]");
545  return false;
546  }
547  }
548  else
549  {
550  // not accessible, or something screwy
551  ROS_ERROR_STREAM("directory [" << dirname << "] not accessible");
552  return false;
553  }
554  }
555  else if (!S_ISDIR(stat_data.st_mode))
556  {
557  // dirname exists but is not a directory
558  ROS_ERROR_STREAM("[" << dirname << "] is not a directory");
559  return false;
560  }
561 
562  // Directory exists and is accessible. Permissions might still be bad.
563 
564  // Currently, writeCalibration() always returns true no matter what
565  // (ros-pkg ticket #5010).
566  return writeCalibration(filename, cname, new_info);
567 }
568 
569 bool CameraInfoManager::saveCalibrationFlash(const sensor_msgs::CameraInfo &new_info,
570  const std::string &flashURL,
571  const std::string &cname) {
572  ROS_ERROR_STREAM("flash url: " << flashURL << " (ignored)");
573  return saveCalibration(new_info, default_camera_info_url, cname);
574 }
575 
584 bool
585 CameraInfoManager::setCameraInfoService(sensor_msgs::SetCameraInfo::Request &req,
586  sensor_msgs::SetCameraInfo::Response &rsp)
587 {
588  // copies of class variables needed for saving calibration
589  std::string url_copy;
590  std::string cname;
591  {
592  boost::mutex::scoped_lock lock(mutex_);
593  cam_info_ = req.camera_info;
594  url_copy = url_;
595  cname = camera_name_;
596  loaded_cam_info_ = true;
597  }
598 
599  if (!nh_.ok())
600  {
601  ROS_ERROR("set_camera_info service called, but driver not running.");
602  rsp.status_message = "Camera driver not running.";
603  rsp.success = false;
604  return false;
605  }
606 
607  rsp.success = saveCalibration(req.camera_info, url_copy, cname);
608  if (!rsp.success)
609  rsp.status_message = "Error storing camera calibration.";
610 
611  return true;
612 }
613 
624 bool CameraInfoManager::setCameraName(const std::string &cname)
625 {
626  // the camera name may not be empty
627  if (cname.empty())
628  return false;
629 
630  // validate the camera name characters
631  for (unsigned i = 0; i < cname.size(); ++i)
632  {
633  if (!isalnum(cname[i]) && cname[i] != '_')
634  return false;
635  }
636 
637  // The name is valid, so update our private copy. Since the new
638  // name might cause the existing URL to resolve somewhere else,
639  // force @c cam_info_ to be reloaded before being used again.
640  {
641  boost::mutex::scoped_lock lock(mutex_);
642  camera_name_ = cname;
643  loaded_cam_info_ = false;
644  }
645 
646  return true;
647 }
648 
657 bool CameraInfoManager::setCameraInfo(const sensor_msgs::CameraInfo &camera_info)
658 {
659  boost::mutex::scoped_lock lock(mutex_);
660 
661  cam_info_ = camera_info;
662  loaded_cam_info_ = true;
663 
664  return true;
665 }
666 
674 bool CameraInfoManager::validateURL(const std::string &url)
675 {
676  std::string cname; // copy of camera name
677  {
678  boost::mutex::scoped_lock lock(mutex_);
679  cname = camera_name_;
680  } // release the lock
681 
682  url_type_t url_type = parseURL(resolveURL(url, cname));
683  return (url_type < URL_invalid);
684 }
685 
686 } // namespace camera_info_manager
camera_info_manager::CameraInfoManager::getCameraInfo
virtual sensor_msgs::CameraInfo getCameraInfo(void)
Definition: camera_info_manager.cpp:115
camera_info_manager::CameraInfoManager::info_service_
ros::ServiceServer info_service_
set_camera_info service
Definition: camera_info_manager.h:253
ros::package::getPath
ROSLIB_DECL std::string getPath(const std::string &package_name)
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(args)
camera_info_manager::CameraInfoManager::camera_name_
std::string camera_name_
camera name
Definition: camera_info_manager.h:254
camera_info_manager::CameraInfoManager::CameraInfoManager
CameraInfoManager(ros::NodeHandle nh, const std::string &cname="camera", const std::string &url="")
Definition: camera_info_manager.cpp:87
ros.h
command
ROSLIB_DECL std::string command(const std::string &cmd)
camera_info_manager::CameraInfoManager::URL_file
@ URL_file
Definition: camera_info_manager.h:213
camera_info_manager::CameraInfoManager::URL_invalid
@ URL_invalid
Definition: camera_info_manager.h:216
camera_info_manager::CameraInfoManager::loadCameraInfo
virtual bool loadCameraInfo(const std::string &url)
Definition: camera_info_manager.cpp:325
ros::NodeHandle::advertiseService
ServiceServer advertiseService(AdvertiseServiceOptions &ops)
camera_info_manager::CameraInfoManager::loadCalibrationFlash
virtual bool loadCalibrationFlash(const std::string &flashURL, const std::string &cname)
Definition: camera_info_manager.cpp:308
ROS_DEBUG_STREAM
#define ROS_DEBUG_STREAM(args)
camera_calibration_parsers
ros::ok
ROSCPP_DECL bool ok()
writeCalibration
bool writeCalibration(const std::string &file_name, const std::string &camera_name, const sensor_msgs::CameraInfo &cam_info)
package
string package
ROS_WARN_STREAM
#define ROS_WARN_STREAM(args)
camera_info_manager::CameraInfoManager::loadCalibration
virtual bool loadCalibration(const std::string &url, const std::string &cname)
Definition: camera_info_manager.cpp:219
camera_info_manager::CameraInfoManager::URL_empty
@ URL_empty
Definition: camera_info_manager.h:212
camera_info_manager::CameraInfoManager::URL_package
@ URL_package
Definition: camera_info_manager.h:214
camera_info_manager::CameraInfoManager::getPackageFileName
std::string getPackageFileName(const std::string &url)
Definition: camera_info_manager.cpp:149
camera_info_manager::CameraInfoManager::loadCalibrationFile
virtual bool loadCalibrationFile(const std::string &filename, const std::string &cname)
Definition: camera_info_manager.cpp:277
camera_info_manager::CameraInfoManager::isCalibrated
virtual bool isCalibrated(void)
Definition: camera_info_manager.cpp:182
ROS_WARN
#define ROS_WARN(...)
camera_info_manager::CameraInfoManager::saveCalibrationFlash
virtual bool saveCalibrationFlash(const sensor_msgs::CameraInfo &new_info, const std::string &flashURL, const std::string &cname)
Definition: camera_info_manager.cpp:569
ROS_INFO_STREAM
#define ROS_INFO_STREAM(args)
camera_info_manager
Definition: camera_info_manager.h:67
camera_info_manager::CameraInfoManager::setCameraInfoService
virtual bool setCameraInfoService(sensor_msgs::SetCameraInfo::Request &req, sensor_msgs::SetCameraInfo::Response &rsp)
Definition: camera_info_manager.cpp:585
package.h
readCalibration
def readCalibration(file_name)
camera_info_manager::CameraInfoManager::setCameraInfo
virtual bool setCameraInfo(const sensor_msgs::CameraInfo &camera_info)
Definition: camera_info_manager.cpp:657
camera_info_manager::CameraInfoManager::validateURL
virtual bool validateURL(const std::string &url)
Definition: camera_info_manager.cpp:674
camera_info_manager::CameraInfoManager::mutex_
boost::mutex mutex_
mutual exclusion lock for private data
Definition: camera_info_manager.h:249
camera_info_manager::CameraInfoManager::url_type_t
url_type_t
Definition: camera_info_manager.h:209
camera_info_manager::CameraInfoManager::cam_info_
sensor_msgs::CameraInfo cam_info_
current CameraInfo
Definition: camera_info_manager.h:256
ros::NodeHandle::ok
bool ok() const
camera_info_manager::CameraInfoManager::parseURL
url_type_t parseURL(const std::string &url)
Definition: camera_info_manager.cpp:422
camera_info_manager::CameraInfoManager::loaded_cam_info_
bool loaded_cam_info_
cam_info_ load attempted
Definition: camera_info_manager.h:257
camera_info_manager::CameraInfoManager::~CameraInfoManager
virtual ~CameraInfoManager()
Definition: camera_info_manager.cpp:76
camera_info_manager.h
CameraInfo Manager interface.
camera_info_manager::CameraInfoManager::setCameraName
virtual bool setCameraName(const std::string &cname)
Definition: camera_info_manager.cpp:624
ROS_ERROR
#define ROS_ERROR(...)
parse.h
camera_info_manager::default_camera_info_url
const std::string default_camera_info_url
Definition: camera_info_manager.cpp:74
camera_info_manager::CameraInfoManager::URL_flash
@ URL_flash
Definition: camera_info_manager.h:217
camera_info_manager::CameraInfoManager::saveCalibrationFile
virtual bool saveCalibrationFile(const sensor_msgs::CameraInfo &new_info, const std::string &filename, const std::string &cname)
Definition: camera_info_manager.cpp:513
ROS_INFO
#define ROS_INFO(...)
camera_info_manager::CameraInfoManager::resolveURL
virtual std::string resolveURL(const std::string &url, const std::string &cname)
Definition: camera_info_manager.cpp:348
camera_info_manager::CameraInfoManager::saveCalibration
virtual bool saveCalibration(const sensor_msgs::CameraInfo &new_info, const std::string &url, const std::string &cname)
Definition: camera_info_manager.cpp:458
ros::NodeHandle
camera_info_manager::CameraInfoManager::url_
std::string url_
URL for calibration data.
Definition: camera_info_manager.h:255
camera_info_manager::CameraInfoManager::nh_
ros::NodeHandle nh_
node handle for service
Definition: camera_info_manager.h:252


camera_info_manager
Author(s): Jack O'Quin
autogenerated on Sat Jan 20 2024 03:14:54