video_stream.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (Modified BSD License)
00003  *
00004  *  Copyright (c) 2016, PAL Robotics, S.L.
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 PAL Robotics, S.L. 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  * @author Sammy Pfeiffer
00035  */
00036 
00037 #include <ros/ros.h>
00038 #include <image_transport/image_transport.h>
00039 #include <camera_info_manager/camera_info_manager.h>
00040 #include <opencv2/highgui/highgui.hpp>
00041 #include <opencv2/imgproc/imgproc.hpp>
00042 #include <cv_bridge/cv_bridge.h>
00043 #include <sstream>
00044 #include <boost/assign/list_of.hpp>
00045 
00046 // Based on the ros tutorial on transforming opencv images to Image messages
00047 
00048 sensor_msgs::CameraInfo get_default_camera_info_from_image(sensor_msgs::ImagePtr img){
00049     sensor_msgs::CameraInfo cam_info_msg;
00050     cam_info_msg.header.frame_id = img->header.frame_id;
00051     // Fill image size
00052     cam_info_msg.height = img->height;
00053     cam_info_msg.width = img->width;
00054     ROS_INFO_STREAM("The image width is: " << img->width);
00055     ROS_INFO_STREAM("The image height is: " << img->height);
00056     // Add the most common distortion model as sensor_msgs/CameraInfo says
00057     cam_info_msg.distortion_model = "plumb_bob";
00058     // Don't let distorsion matrix be empty
00059     cam_info_msg.D.resize(5, 0.0);
00060     // Give a reasonable default intrinsic camera matrix
00061     cam_info_msg.K = boost::assign::list_of(1.0) (0.0) (img->width/2.0)
00062                                            (0.0) (1.0) (img->height/2.0)
00063                                            (0.0) (0.0) (1.0);
00064     // Give a reasonable default rectification matrix
00065     cam_info_msg.R = boost::assign::list_of (1.0) (0.0) (0.0)
00066                                             (0.0) (1.0) (0.0)
00067                                             (0.0) (0.0) (1.0);
00068     // Give a reasonable default projection matrix
00069     cam_info_msg.P = boost::assign::list_of (1.0) (0.0) (img->width/2.0) (0.0)
00070                                             (0.0) (1.0) (img->height/2.0) (0.0)
00071                                             (0.0) (0.0) (1.0) (0.0);
00072     return cam_info_msg;
00073 }
00074 
00075 
00076 
00077 int main(int argc, char** argv)
00078 {
00079     ros::init(argc, argv, "image_publisher");
00080     ros::NodeHandle nh;
00081     ros::NodeHandle _nh("~"); // to get the private params
00082     image_transport::ImageTransport it(nh);
00083     image_transport::CameraPublisher pub = it.advertiseCamera("camera", 1);
00084 
00085     // provider can be an url (e.g.: rtsp://10.0.0.1:554) or a number of device, (e.g.: 0 would be /dev/video0)
00086     std::string video_stream_provider;
00087     cv::VideoCapture cap;
00088     if (_nh.getParam("video_stream_provider", video_stream_provider)){
00089         ROS_INFO_STREAM("Resource video_stream_provider: " << video_stream_provider);
00090         // If we are given a string of 4 chars or less (I don't think we'll have more than 100 video devices connected)
00091         // treat is as a number and act accordingly so we open up the videoNUMBER device
00092         if (video_stream_provider.size() < 4){
00093             ROS_INFO_STREAM("Getting video from provider: /dev/video" << video_stream_provider);
00094             cap.open(atoi(video_stream_provider.c_str()));
00095         }
00096         else{
00097             ROS_INFO_STREAM("Getting video from provider: " << video_stream_provider);
00098             cap.open(video_stream_provider);
00099         }
00100     }
00101     else{
00102         ROS_ERROR("Failed to get param 'video_stream_provider'");
00103         return -1;
00104     }
00105 
00106     std::string camera_name;
00107     _nh.param("camera_name", camera_name, std::string("camera"));
00108     ROS_INFO_STREAM("Camera name: " << camera_name);
00109 
00110     int fps;
00111     _nh.param("fps", fps, 240);
00112     ROS_INFO_STREAM("Throttling to fps: " << fps);
00113 
00114     std::string frame_id;
00115     _nh.param("frame_id", frame_id, std::string("camera"));
00116     ROS_INFO_STREAM("Publishing with frame_id: " << frame_id);
00117 
00118     std::string camera_info_url;
00119     _nh.param("camera_info_url", camera_info_url, std::string(""));
00120     ROS_INFO_STREAM("Provided camera_info_url: '" << camera_info_url << "'");
00121 
00122     bool flip_horizontal;
00123     _nh.param("flip_horizontal", flip_horizontal, false);
00124     ROS_INFO_STREAM("Flip horizontal image is: " << ((flip_horizontal)?"true":"false"));
00125 
00126     bool flip_vertical;
00127     _nh.param("flip_vertical", flip_vertical, false);
00128     ROS_INFO_STREAM("Flip vertical image is: " << ((flip_vertical)?"true":"false"));
00129 
00130     int width_target;
00131     int height_target;
00132     _nh.param("width", width_target, 0);
00133     _nh.param("height", height_target, 0);
00134     if (width_target != 0 && height_target != 0){
00135         ROS_INFO_STREAM("Forced image width is: " << width_target);
00136         ROS_INFO_STREAM("Forced image height is: " << height_target);
00137     }
00138 
00139     // From http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#void flip(InputArray src, OutputArray dst, int flipCode)
00140     // FLIP_HORIZONTAL == 1, FLIP_VERTICAL == 0 or FLIP_BOTH == -1
00141     bool flip_image = true;
00142     int flip_value;
00143     if (flip_horizontal && flip_vertical)
00144         flip_value = 0; // flip both, horizontal and vertical
00145     else if (flip_horizontal)
00146         flip_value = 1;
00147     else if (flip_vertical)
00148         flip_value = -1;
00149     else
00150         flip_image = false;
00151 
00152     if(!cap.isOpened()){
00153         ROS_ERROR_STREAM("Could not open the stream.");
00154         return -1;
00155     }
00156     if (width_target != 0 && height_target != 0){
00157         cap.set(CV_CAP_PROP_FRAME_WIDTH, width_target);
00158         cap.set(CV_CAP_PROP_FRAME_HEIGHT, height_target);
00159     }
00160 
00161 
00162     ROS_INFO_STREAM("Opened the stream, starting to publish.");
00163 
00164     cv::Mat frame;
00165     sensor_msgs::ImagePtr msg;
00166     sensor_msgs::CameraInfo cam_info_msg;
00167     std_msgs::Header header;
00168     header.frame_id = frame_id;
00169     camera_info_manager::CameraInfoManager cam_info_manager(nh, camera_name, camera_info_url);
00170     // Get the saved camera info if any
00171     cam_info_msg = cam_info_manager.getCameraInfo();
00172 
00173     ros::Rate r(fps);
00174     while (nh.ok()) {
00175         cap >> frame;
00176         if (pub.getNumSubscribers() > 0){
00177             // Check if grabbed frame is actually full with some content
00178             if(!frame.empty()) {
00179                 // Flip the image if necessary
00180                 if (flip_image)
00181                     cv::flip(frame, frame, flip_value);
00182                 msg = cv_bridge::CvImage(header, "bgr8", frame).toImageMsg();
00183                 // Create a default camera info if we didn't get a stored one on initialization
00184                 if (cam_info_msg.distortion_model == ""){
00185                     ROS_WARN_STREAM("No calibration file given, publishing a reasonable default camera info.");
00186                     cam_info_msg = get_default_camera_info_from_image(msg);
00187                     cam_info_manager.setCameraInfo(cam_info_msg);
00188                 }
00189                 // The timestamps are in sync thanks to this publisher
00190                 pub.publish(*msg, cam_info_msg, ros::Time::now());
00191             }
00192 
00193             ros::spinOnce();
00194         }
00195         r.sleep();
00196     }
00197 }


video_stream_opencv
Author(s): Sammy Pfeiffer
autogenerated on Tue Nov 15 2016 07:17:35