39 #include <dynamic_reconfigure/server.h> 42 #include <opencv2/highgui/highgui.hpp> 43 #include <opencv2/imgproc/imgproc.hpp> 47 #include <boost/filesystem.hpp> 48 #include <boost/assign/list_of.hpp> 49 #include <boost/thread/thread.hpp> 52 #include <video_stream_opencv/VideoStreamConfig.h> 54 namespace fs = boost::filesystem;
91 cam_info_msg.header.frame_id = img->header.frame_id;
93 cam_info_msg.height = img->height;
94 cam_info_msg.width = img->width;
98 cam_info_msg.distortion_model =
"plumb_bob";
100 cam_info_msg.D.resize(5, 0.0);
102 cam_info_msg.K = boost::assign::list_of(1.0) (0.0) (img->width/2.0)
103 (0.0) (1.0) (img->height/2.0)
106 cam_info_msg.R = boost::assign::list_of (1.0) (0.0) (0.0)
110 cam_info_msg.P = boost::assign::list_of (1.0) (0.0) (img->width/2.0) (0.0)
111 (0.0) (1.0) (img->height/2.0) (0.0)
112 (0.0) (0.0) (1.0) (0.0);
120 ros::Rate camera_fps_rate(set_camera_fps);
122 int frame_counter = 0;
124 capture_thread_running =
true;
125 while (nh->ok() && capture_thread_running && subscriber_num > 0) {
126 if (!cap->isOpened()) {
131 if (!cap->read(frame)) {
133 if (reopen_on_read_failure) {
141 if (video_stream_provider_type ==
"videofile")
143 camera_fps_rate.
sleep();
145 if (video_stream_provider_type ==
"videofile" &&
146 frame_counter == cap->get(CV_CAP_PROP_FRAME_COUNT))
150 cap->open(video_stream_provider);
160 std::lock_guard<std::mutex> g(q_mutex);
163 framesQueue.push(frame.clone());
168 framesQueue.push(frame.clone());
176 bool is_new_image =
false;
177 sensor_msgs::ImagePtr msg;
181 std::lock_guard<std::mutex> g(q_mutex);
182 if (!framesQueue.empty()){
183 frame = framesQueue.front();
195 if (flip_horizontal && flip_vertical)
196 cv::flip(frame, frame, -1);
197 else if (flip_horizontal)
198 cv::flip(frame, frame, 1);
199 else if (flip_vertical)
200 cv::flip(frame, frame, 0);
204 if (cam_info_msg.distortion_model ==
""){
205 NODELET_WARN_STREAM(
"No calibration file given, publishing a reasonable default camera info.");
216 cap.reset(
new cv::VideoCapture);
218 int device_num = std::stoi(video_stream_provider);
220 cap->open(device_num);
221 }
catch (std::invalid_argument &ex) {
223 cap->open(video_stream_provider);
224 if (!cap->isOpened()) {
229 NODELET_INFO_STREAM(
"Video stream provider type detected: " << video_stream_provider_type);
231 double reported_camera_fps;
234 reported_camera_fps = cap->get(CV_CAP_PROP_FPS);
235 if (reported_camera_fps > 0.0)
240 cap->set(CV_CAP_PROP_FPS, set_camera_fps);
241 if(!cap->isOpened()){
245 if (width_target != 0 && height_target != 0){
246 cap->set(CV_CAP_PROP_FRAME_WIDTH, width_target);
247 cap->set(CV_CAP_PROP_FRAME_HEIGHT, height_target);
251 capture_thread = boost::thread(
253 publish_timer = nh->createTimer(
255 }
catch (std::exception& e) {
262 publish_timer.
stop();
263 capture_thread_running =
false;
264 capture_thread.join();
269 std::lock_guard<std::mutex> lock(s_mutex);
270 if (subscriber_num == 0) {
277 std::lock_guard<std::mutex> lock(s_mutex);
278 bool always_subscribe =
false;
279 pnh->getParamCached(
"always_subscribe", always_subscribe);
280 if (video_stream_provider ==
"videofile" || always_subscribe) {
285 if (subscriber_num == 0) {
308 bool need_resubscribe =
false;
310 if (camera_name != config.camera_name ||
311 camera_info_url != config.camera_info_url ||
312 frame_id != config.frame_id) {
313 camera_name = config.camera_name;
314 camera_info_url = config.camera_info_url;
315 frame_id = config.frame_id;
322 cam_info_msg.header.frame_id =
frame_id;
325 if (set_camera_fps != config.set_camera_fps ||
327 if (config.fps > config.set_camera_fps) {
329 <<
") which is higher than the 'set_camera_fps' (" << config.set_camera_fps <<
330 "), we can't publish faster than the camera provides images.");
331 config.fps = config.set_camera_fps;
333 set_camera_fps = config.set_camera_fps;
337 need_resubscribe =
true;
340 if (max_queue_size != config.buffer_queue_size) {
341 max_queue_size = config.buffer_queue_size;
345 if (flip_horizontal != config.flip_horizontal ||
346 flip_vertical != config.flip_vertical) {
347 flip_horizontal = config.flip_horizontal;
348 flip_vertical = config.flip_vertical;
353 if (width_target != config.width ||
354 height_target != config.height) {
355 width_target = config.width;
356 height_target = config.height;
357 if (width_target != 0 && height_target != 0) {
361 need_resubscribe =
true;
364 if (cap && cap->isOpened()) {
365 cap->set(CV_CAP_PROP_BRIGHTNESS, config.brightness);
366 cap->set(CV_CAP_PROP_CONTRAST, config.contrast);
367 cap->set(CV_CAP_PROP_HUE, config.hue);
368 cap->set(CV_CAP_PROP_SATURATION, config.saturation);
369 if (config.auto_exposure) {
370 cap->set(CV_CAP_PROP_AUTO_EXPOSURE, 0.75);
371 config.exposure = 0.5;
373 cap->set(CV_CAP_PROP_AUTO_EXPOSURE, 0.25);
374 cap->set(CV_CAP_PROP_EXPOSURE, config.exposure);
378 loop_videofile = config.loop_videofile;
379 reopen_on_read_failure = config.reopen_on_read_failure;
381 if (subscriber_num > 0 && need_resubscribe) {
396 int device_num = std::stoi(video_stream_provider);
397 video_stream_provider_type =
"videodevice";
398 }
catch (std::invalid_argument &ex) {
399 if (video_stream_provider.find(
"http://") != std::string::npos ||
400 video_stream_provider.find(
"https://") != std::string::npos){
401 video_stream_provider_type =
"http_stream";
403 else if(video_stream_provider.find(
"rtsp://") != std::string::npos){
404 video_stream_provider_type =
"rtsp_stream";
407 fs::file_type file_type = fs::status(fs::path(video_stream_provider)).type();
409 case fs::file_type::character_file:
410 case fs::file_type::block_file:
411 video_stream_provider_type =
"videodevice";
413 case fs::file_type::regular_file:
414 video_stream_provider_type =
"videofile";
417 video_stream_provider_type =
"unknown";
423 dyn_srv = boost::make_shared<dynamic_reconfigure::Server<VideoStreamConfig> >(*pnh);
425 dyn_srv->setCallback(
f);
438 connect_cb, connect_cb,
439 info_connect_cb, info_connect_cb,
444 if (subscriber_num > 0)
#define NODELET_INFO_STREAM(...)
virtual void disconnectionCallback(const image_transport::SingleSubscriberPublisher &)
void publish(const sensor_msgs::Image &image, const sensor_msgs::CameraInfo &info) const
boost::function< void(const SingleSubscriberPublisher &)> SubscriberStatusCallback
#define NODELET_ERROR(...)
sensor_msgs::CameraInfo getCameraInfo(void)
#define NODELET_WARN(...)
virtual ~VideoStreamNodelet()
boost::thread capture_thread
boost::function< void(const SingleSubscriberPublisher &)> SubscriberStatusCallback
#define NODELET_WARN_STREAM(...)
image_transport::CameraPublisher pub
virtual void do_capture()
virtual void unsubscribe()
ros::NodeHandle & getPrivateNodeHandle() const
std::string video_stream_provider_type
#define NODELET_ERROR_STREAM(...)
boost::shared_ptr< ros::NodeHandle > nh
CameraPublisher advertiseCamera(const std::string &base_topic, uint32_t queue_size, bool latch=false)
virtual void connectionCallbackImpl()
virtual void disconnectionCallbackImpl()
virtual void configCallback(VideoStreamConfig &config, uint32_t level)
boost::shared_ptr< dynamic_reconfigure::Server< VideoStreamConfig > > dyn_srv
virtual sensor_msgs::CameraInfo get_default_camera_info_from_image(sensor_msgs::ImagePtr img)
boost::shared_ptr< cv::VideoCapture > cap
ros::NodeHandle & getNodeHandle() const
virtual void do_publish(const ros::TimerEvent &event)
virtual void infoDisconnectionCallback(const ros::SingleSubscriberPublisher &)
std::string video_stream_provider
virtual void connectionCallback(const image_transport::SingleSubscriberPublisher &)
std::string camera_info_url
#define NODELET_INFO(...)
std::queue< cv::Mat > framesQueue
sensor_msgs::CameraInfo cam_info_msg
#define NODELET_FATAL_STREAM(...)
bool reopen_on_read_failure
bool capture_thread_running
boost::shared_ptr< ros::NodeHandle > pnh
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
virtual void infoConnectionCallback(const ros::SingleSubscriberPublisher &)
#define NODELET_DEBUG(...)
sensor_msgs::ImagePtr toImageMsg() const