CameraNode.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 * Software License Agreement (BSD License)
00003 *
00004 *  Copyright (c) 2012, Kevin Hallenbeck
00005 *  All rights reserved.
00006 *
00007 *  Redistribution and use in source and binary forms, with or without
00008 *  modification, are permitted provided that the following conditions
00009 *  are met:
00010 *
00011 *   * Redistributions of source code must retain the above copyright
00012 *     notice, this list of conditions and the following disclaimer.
00013 *   * Redistributions in binary form must reproduce the above
00014 *     copyright notice, this list of conditions and the following
00015 *     disclaimer in the documentation and/or other materials provided
00016 *     with the distribution.
00017 *   * Neither the name of Kevin Hallenbeck nor the names of its
00018 *     contributors may be used to endorse or promote products derived
00019 *     from this software without specific prior written permission.
00020 *
00021 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 *  POSSIBILITY OF SUCH DAMAGE.
00033 *********************************************************************/
00034 
00035 #include <ueye/CameraNode.h>
00036 
00037 namespace ueye {
00038 
00039 const std::string configFileName(Camera &cam){
00040         stringstream ss;
00041         ss << "Cal-" << cam.getCameraName() << "-" << cam.getZoom() << "-" << cam.getCameraSerialNo() << ".txt";
00042         return ss.str();
00043 }
00044 
00045 CameraNode::CameraNode(ros::NodeHandle node, ros::NodeHandle priv_nh)
00046 : it_(node)
00047 {
00048         running_ = false;
00049         configured_ = false;
00050         force_streaming_ = false;
00051         auto_exposure_ = false;
00052         auto_gain_ = false;
00053         trigger_mode_ = zoom_ = -1;
00054 
00055         // Check for a valid uEye installation and supported version
00056         char *Version;
00057         int Major, Minor, Build;
00058         if(cam_.checkVersion(Major, Minor, Build, Version)){
00059                 ROS_INFO("Loaded uEye SDK %s.", Version);
00060         }else{
00061                 ROS_WARN("Loaded uEye SDK %d.%d.%d. Expecting %s.", Major, Minor, Build, Version);
00062         }
00063 
00064         // Make sure there is at least one camera available
00065         int NumberOfCameras = cam_.getNumberOfCameras();
00066         if(NumberOfCameras > 0){
00067                 if(NumberOfCameras == 1){
00068                         ROS_INFO("Found 1 uEye camera.");
00069                 }else{
00070                         ROS_INFO("Found %d uEye cameras.", NumberOfCameras);
00071                 }
00072         }else{
00073                 ROS_ERROR("Found 0 uEye cameras.");
00074                 ros::shutdown();
00075                 return;
00076         }
00077 
00078         // Open camera with either serialNo, deviceId, or cameraId
00079         int id = 0;
00080         if(priv_nh.getParam("serialNo", id)){
00081                 if(!cam_.openCameraSerNo(id)){
00082                         ROS_ERROR("Failed to open uEye camera with serialNo: %u.", id);
00083                         ros::shutdown();
00084                         return;
00085                 }
00086         }else if(priv_nh.getParam("deviceId", id)){
00087                 if(!cam_.openCameraDevId(id)){
00088                         ROS_ERROR("Failed to open uEye camera with deviceId: %u.", id);
00089                         ros::shutdown();
00090                         return;
00091                 }
00092         }else{
00093                 priv_nh.getParam("cameraId", id);
00094                 if(!cam_.openCameraCamId(id)){
00095                         ROS_ERROR("Failed to open uEye camera with cameraId: %u.", id);
00096                         ros::shutdown();
00097                         return;
00098                 }
00099         }
00100         ROS_INFO("Opened camera %s %u", cam_.getCameraName(), cam_.getCameraSerialNo());
00101 
00102         // Setup Dynamic Reconfigure
00103         dynamic_reconfigure::Server<monoConfig>::CallbackType f = boost::bind(&CameraNode::reconfig, this, _1, _2);
00104         srv_.setCallback(f);    //start dynamic reconfigure
00105 
00106         // Service call for setting calibration.
00107         srv_cam_info_ = node.advertiseService("set_camera_info", &CameraNode::setCameraInfo, this);
00108 
00109         // Special publisher for images to support compression
00110         pub_stream_ = it_.advertiseCamera("image_raw", 0);
00111 
00112         // Set up Timer
00113         timer_ = node.createTimer(ros::Duration(1/5.0), &CameraNode::timerCallback, this);
00114 }
00115 
00116 CameraNode::~CameraNode()
00117 {
00118         closeCamera();
00119 }
00120 
00121 void CameraNode::handlePath(std::string &path)
00122 {
00123         // Set default path if not present
00124         if(path.length() == 0){
00125                 path = ros::package::getPath("ueye");
00126         }
00127 
00128         // Remove trailing "/" from folder path
00129         unsigned int length = path.length();
00130         if(length > 0){
00131                 if(path.c_str()[length-1] == '/'){
00132                         path = path.substr(0, length-1);
00133                 }
00134         }
00135         config_path_ = path;
00136 }
00137 void CameraNode::reconfig(monoConfig &config, uint32_t level)
00138 {
00139         force_streaming_ = config.force_streaming;
00140         handlePath(config.config_path);
00141 
00142         // Trigger
00143         if (trigger_mode_ != config.trigger){
00144                 stopCamera();
00145                 TriggerMode mode;
00146                 switch(config.trigger){
00147                 case mono_TGR_HARDWARE_RISING:
00148                         mode = TRIGGER_LO_HI;
00149                         break;
00150                 case mono_TGR_HARDWARE_FALLING:
00151                         mode = TRIGGER_HI_LO;
00152                         break;
00153                 case mono_TGR_AUTO:
00154                 default:
00155                         mode = TRIGGER_OFF;
00156                         break;
00157                 }
00158                 if(!cam_.setTriggerMode(mode)){
00159                         cam_.setTriggerMode(TRIGGER_OFF);
00160                         config.trigger = mono_TGR_AUTO;
00161                 }
00162         }
00163         trigger_mode_ = config.trigger;
00164 
00165         // Latch Auto Parameters
00166         if(auto_gain_ && !config.auto_gain){
00167                 config.gain = cam_.getHardwareGain();
00168         }
00169         auto_gain_ = config.auto_gain;
00170         if(auto_exposure_ && !config.auto_exposure){
00171                 config.exposure_time = cam_.getExposure();
00172         }
00173         auto_exposure_ = config.auto_exposure;
00174 
00175         // Hardware Gamma Correction
00176         if (cam_.getHardwareGamma() != config.hardware_gamma){
00177                 cam_.setHardwareGamma(&config.hardware_gamma);
00178         }
00179 
00180         // Gain Boost
00181         if (cam_.getGainBoost() != config.gain_boost){
00182                 cam_.setGainBoost(&config.gain_boost);
00183         }
00184 
00185         // Hardware Gain
00186         if (cam_.getAutoGain() != config.auto_gain){
00187                 cam_.setAutoGain(&config.auto_gain);
00188         }
00189         if (!config.auto_gain){
00190                 cam_.setHardwareGain(&config.gain);
00191         }
00192 
00193         // Zoom
00194         if (cam_.getZoom() != config.zoom){
00195                 cam_.setZoom(&config.zoom);
00196         }
00197 
00198         // Pixel Clock
00199         if (cam_.getPixelClock() != config.pixel_clock){
00200                 cam_.setPixelClock(&config.pixel_clock);
00201         }
00202 
00203         // Frame Rate
00204         cam_.setFrameRate(&config.frame_rate);
00205 
00206         // Exposure
00207         if (cam_.getAutoExposure() != config.auto_exposure){
00208                 cam_.setAutoExposure(&config.auto_exposure);
00209         }
00210         if (!config.auto_exposure){
00211                 cam_.setExposure(&config.exposure_time);
00212         }
00213 
00214         // Zoom
00215         if(zoom_ != config.zoom){
00216                 zoom_ = config.zoom;
00217                 loadIntrinsics();
00218         }
00219 
00220         msg_camera_info_.header.frame_id = config.frame_id;
00221         configured_ = true;
00222 }
00223 
00224 void CameraNode::timerCallback(const ros::TimerEvent& event)
00225 {
00226         if((pub_stream_.getNumSubscribers() > 0) || force_streaming_){
00227                 startCamera();
00228         }else{
00229                 stopCamera();
00230         }
00231 }
00232 
00233 // Support camera calibration requests
00234 // http://www.ros.org/wiki/camera_calibration/Tutorials/MonocularCalibration
00235 bool CameraNode::setCameraInfo(sensor_msgs::SetCameraInfo::Request& req, sensor_msgs::SetCameraInfo::Response& rsp)
00236 {
00237         ROS_INFO("New camera info received");
00238         sensor_msgs::CameraInfo &info = req.camera_info;
00239         info.header.frame_id = msg_camera_info_.header.frame_id;
00240 
00241         // Sanity check: the image dimensions should match the resolution of the sensor.
00242         unsigned int height = cam_.getHeight();
00243         unsigned int width = cam_.getWidth();
00244 
00245         if (info.width != width || info.height != height) {
00246                 rsp.success = false;
00247                 rsp.status_message = (boost::format("Camera_info resolution %ix%i does not match current video "
00248                 "setting, camera running at resolution %ix%i.")
00249                 % info.width % info.height % width % height).str();
00250                 ROS_ERROR("%s", rsp.status_message.c_str());
00251                 return true;
00252         }
00253 
00254         std::string camname = cam_.getCameraName();
00255         std::stringstream ini_stream;
00256         if (!camera_calibration_parsers::writeCalibrationIni(ini_stream, camname, info)) {
00257                 rsp.status_message = "Error formatting camera_info for storage.";
00258                 rsp.success = false;
00259         }else{
00260                 std::string ini = ini_stream.str();
00261                 fstream param_file;
00262                 std::string filename = config_path_ + "/" + configFileName(cam_);
00263                 param_file.open(filename.c_str(), ios::in | ios::out | ios::trunc);
00264 
00265                 if (param_file.is_open()) {
00266                         param_file<< ini.c_str();
00267                         param_file.close();
00268 
00269                         msg_camera_info_ = info;
00270                         rsp.success = true;
00271                 }else{
00272                         rsp.success = false;
00273                         rsp.status_message = "file write failed";
00274                 }
00275         }
00276         if (!rsp.success){
00277                 ROS_ERROR("%s", rsp.status_message.c_str());
00278         }
00279         return true;
00280 }
00281 
00282 // Try to load previously saved camera calibration from a file.
00283 void CameraNode::loadIntrinsics()
00284 {
00285         char buffer[12800];
00286 
00287         std::string MyPath = config_path_ + "/" + configFileName(cam_);
00288         fstream param_file;
00289         param_file.open(MyPath.c_str(), ios::out | ios::in);
00290 
00291         if (param_file.is_open()) {
00292                 param_file.read(buffer, 12800);
00293                 param_file.close();
00294         }
00295 
00296         // Parse calibration file
00297         std::string camera_name;
00298         if (camera_calibration_parsers::parseCalibrationIni(buffer, camera_name, msg_camera_info_)){
00299                 ROS_INFO("Loaded calibration for camera '%s'", camera_name.c_str());
00300         }else{
00301                 ROS_WARN("Failed to load intrinsics for camera from file");
00302         }
00303 }
00304 
00305 // Add properties to image message
00306 sensor_msgs::ImagePtr CameraNode::processFrame(IplImage* frame, sensor_msgs::CameraInfoPtr &info)
00307 {
00308         msg_camera_info_.header.stamp = ros::Time::now();
00309         msg_camera_info_.header.seq++;
00310         msg_camera_info_.roi.x_offset = 0;
00311         msg_camera_info_.roi.y_offset = 0;
00312         msg_camera_info_.height = cam_.getHeight();
00313         msg_camera_info_.width = cam_.getWidth();
00314         msg_camera_info_.roi.width = 0;
00315         msg_camera_info_.roi.height = 0;
00316         sensor_msgs::CameraInfoPtr msg(new sensor_msgs::CameraInfo(msg_camera_info_));
00317         info = msg;
00318 
00319         converter_.header = msg_camera_info_.header;
00320         converter_.encoding = "bgr8";
00321         converter_.image = frame;
00322         return converter_.toImageMsg();
00323 }
00324 
00325 // Timestamp and publish the image. Called by the streaming thread.
00326 void CameraNode::publishImage(IplImage * frame)
00327 {
00328         sensor_msgs::CameraInfoPtr info;
00329         sensor_msgs::ImagePtr img = processFrame(frame, info);
00330         pub_stream_.publish(img, info);
00331 }
00332 
00333 void CameraNode::startCamera()
00334 {
00335         if(running_ || !configured_)
00336                 return;
00337         cam_.startVideoCapture(boost::bind(&CameraNode::publishImage, this, _1));
00338         ROS_INFO("Started video stream.");
00339         running_ = true;
00340 }
00341 
00342 void CameraNode::stopCamera()
00343 {
00344         if(!running_)
00345                 return;
00346         cam_.stopVideoCapture();
00347         ROS_INFO("Stopped video stream.");
00348         running_ = false;
00349 }
00350 
00351 void CameraNode::closeCamera(){
00352         stopCamera();
00353         cam_.closeCamera();
00354 }
00355 
00356 } // namespace ueye


ueye
Author(s): Kevin Hallenbeck
autogenerated on Tue Jan 7 2014 11:40:31