diff --git a/image_transport/tutorial/CMakeLists.txt b/image_transport/tutorial/CMakeLists.txt new file mode 100644 index 00000000..ed5f28fe --- /dev/null +++ b/image_transport/tutorial/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 2.8) +project(image_transport_tutorial) + +find_package(catkin REQUIRED COMPONENTS cv_bridge image_transport message_generation sensor_msgs) + +# add the resized image message +add_message_files(DIRECTORY msg + FILES ResizedImage.msg +) +generate_messages(DEPENDENCIES sensor_msgs) + +catkin_package(CATKIN_DEPENDS cv_bridge image_transport message_runtime sensor_msgs) + +find_package(OpenCV) + +include_directories(include ${catkin_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS}) + +# add the publisher example +add_executable(my_publisher src/my_publisher.cpp) +add_dependencies(my_publisher ${catkin_EXPORTED_TARGETS} ${${PROJECT_NAME}_EXPORTED_TARGETS}) +target_link_libraries(my_publisher ${catkin_LIBRARIES} ${OpenCV_LIBRARIES}) + +# add the subscriber example +add_executable(my_subscriber src/my_subscriber.cpp) +add_dependencies(my_subscriber ${catkin_EXPORTED_TARGETS} ${${PROJECT_NAME}_EXPORTED_TARGETS}) +target_link_libraries(my_subscriber ${catkin_LIBRARIES} ${OpenCV_LIBRARIES}) + +# add the plugin example +add_library(resized_publisher src/manifest.cpp src/resized_publisher.cpp src/resized_subscriber.cpp) +add_dependencies(resized_publisher ${catkin_EXPORTED_TARGETS} ${${PROJECT_NAME}_EXPORTED_TARGETS}) +target_link_libraries(resized_publisher ${catkin_LIBRARIES} ${OpenCV_LIBRARIES}) + + +# Mark executables and/or libraries for installation +install(TARGETS my_publisher my_subscriber resized_publisher + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + +install(FILES resized_plugins.xml + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) diff --git a/image_transport/tutorial/include/image_transport_tutorial/resized_publisher.hpp b/image_transport/tutorial/include/image_transport_tutorial/resized_publisher.hpp new file mode 100644 index 00000000..9a37de54 --- /dev/null +++ b/image_transport/tutorial/include/image_transport_tutorial/resized_publisher.hpp @@ -0,0 +1,15 @@ +#include +#include + +class ResizedPublisher : public image_transport::SimplePublisherPlugin +{ +public: + virtual std::string getTransportName() const + { + return "resized"; + } + +protected: + virtual void publish(const sensor_msgs::Image& message, + const PublishFn& publish_fn) const; +}; diff --git a/image_transport/tutorial/include/image_transport_tutorial/resized_subscriber.hpp b/image_transport/tutorial/include/image_transport_tutorial/resized_subscriber.hpp new file mode 100644 index 00000000..3e7ded74 --- /dev/null +++ b/image_transport/tutorial/include/image_transport_tutorial/resized_subscriber.hpp @@ -0,0 +1,26 @@ +#include +#include + +class ResizedSubscriber : public image_transport::SimpleSubscriberPlugin +{ +public: + virtual ~ResizedSubscriber() {} + + virtual std::string getTransportName() const + { + return "resized"; + } + + void subscribeImpl( + rclcpp::Node * node, + const std::string & base_topic, + const Callback & callback, + rmw_qos_profile_t custom_qos, + rclcpp::SubscriptionOptions options) override + { + this->subscribeImplWithOptions(node, base_topic, callback, custom_qos, options); + } +protected: + virtual void internalCallback(const typename image_transport_tutorial::ResizedImage::ConstPtr& message, + const Callback& user_cb); +}; diff --git a/image_transport_tutorial/msg/ResizedImage.msg b/image_transport/tutorial/msg/ResizedImage.msg similarity index 100% rename from image_transport_tutorial/msg/ResizedImage.msg rename to image_transport/tutorial/msg/ResizedImage.msg diff --git a/image_transport/tutorial/package.xml b/image_transport/tutorial/package.xml new file mode 100644 index 00000000..668cd0ac --- /dev/null +++ b/image_transport/tutorial/package.xml @@ -0,0 +1,26 @@ + + image_transport_tutorial + 0.0.0 + Tutorial for image_transport. This is useful for the tutorials at http://wiki.ros.org/image_transport/Tutorials/ + Vincent Rabaud + Vincent Rabaud + Apache 2.0 + + cv_bridge + image_transport + message_generation + opencv2 + sensor_msgs + + cv_bridge + image_transport + message_runtime + opencv2 + sensor_msgs + + catkin + + + + + diff --git a/image_transport_tutorial/resized_plugins.xml b/image_transport/tutorial/resized_plugins.xml similarity index 100% rename from image_transport_tutorial/resized_plugins.xml rename to image_transport/tutorial/resized_plugins.xml diff --git a/image_transport/tutorial/src/manifest.cpp b/image_transport/tutorial/src/manifest.cpp new file mode 100644 index 00000000..ab208194 --- /dev/null +++ b/image_transport/tutorial/src/manifest.cpp @@ -0,0 +1,7 @@ +#include +#include +#include + +PLUGINLIB_EXPORT_CLASS(ResizedPublisher, image_transport::PublisherPlugin) + +PLUGINLIB_EXPORT_CLASS(ResizedSubscriber, image_transport::SubscriberPlugin) diff --git a/image_transport/tutorial/src/my_publisher.cpp b/image_transport/tutorial/src/my_publisher.cpp new file mode 100644 index 00000000..458a5893 --- /dev/null +++ b/image_transport/tutorial/src/my_publisher.cpp @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + ros::init(argc, argv, "image_publisher"); + ros::NodeHandle nh; + image_transport::ImageTransport it(nh); + image_transport::Publisher pub = it.advertise("camera/image", 1); + + cv::Mat image = cv::imread(argv[1], CV_LOAD_IMAGE_COLOR); + sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", image).toImageMsg(); + + ros::Rate loop_rate(5); + while (nh.ok()) { + pub.publish(msg); + ros::spinOnce(); + loop_rate.sleep(); + } +} + diff --git a/image_transport/tutorial/src/my_subscriber.cpp b/image_transport/tutorial/src/my_subscriber.cpp new file mode 100644 index 00000000..63544a36 --- /dev/null +++ b/image_transport/tutorial/src/my_subscriber.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +void imageCallback(const sensor_msgs::ImageConstPtr& msg) +{ + try + { + cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image); + cv::waitKey(10); + } + catch (cv_bridge::Exception& e) + { + ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str()); + } +} + +int main(int argc, char **argv) +{ + ros::init(argc, argv, "image_listener"); + ros::NodeHandle nh; + cv::namedWindow("view"); + cv::startWindowThread(); + image_transport::ImageTransport it(nh); + image_transport::Subscriber sub = it.subscribe("camera/image", 1, imageCallback); + ros::spin(); + cv::destroyWindow("view"); +} diff --git a/image_transport/tutorial/src/resized_publisher.cpp b/image_transport/tutorial/src/resized_publisher.cpp new file mode 100644 index 00000000..178f4821 --- /dev/null +++ b/image_transport/tutorial/src/resized_publisher.cpp @@ -0,0 +1,37 @@ +#include +#include +#include + +void ResizedPublisher::publish(const sensor_msgs::Image& message, + const PublishFn& publish_fn) const +{ + cv::Mat cv_image; + boost::shared_ptr tracked_object; + try + { + cv_image = cv_bridge::toCvShare(message, tracked_object, message.encoding)->image; + } + catch (cv::Exception &e) + { + ROS_ERROR("Could not convert from '%s' to '%s'.", message.encoding.c_str(), message.encoding.c_str()); + return; + } + + // Retrieve subsampling factor from the parameter server + double subsampling_factor; + std::string param_name; + nh().param("resized_image_transport_subsampling_factor", subsampling_factor, 2.0); + + // Rescale image + int new_width = cv_image.cols / subsampling_factor + 0.5; + int new_height = cv_image.rows / subsampling_factor + 0.5; + cv::Mat buffer; + cv::resize(cv_image, buffer, cv::Size(new_width, new_height)); + + // Set up ResizedImage and publish + image_transport_tutorial::ResizedImage resized_image; + resized_image.original_height = cv_image.rows; + resized_image.original_width = cv_image.cols; + resized_image.image = *(cv_bridge::CvImage(message.header, "bgr8", cv_image).toImageMsg()); + publish_fn(resized_image); +} diff --git a/image_transport/tutorial/src/resized_subscriber.cpp b/image_transport/tutorial/src/resized_subscriber.cpp new file mode 100644 index 00000000..299dc83d --- /dev/null +++ b/image_transport/tutorial/src/resized_subscriber.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +void ResizedSubscriber::internalCallback(const image_transport_tutorial::ResizedImage::ConstPtr& msg, + const Callback& user_cb) +{ + // This is only for optimization, not to copy the image + boost::shared_ptr tracked_object_tmp; + cv::Mat img_rsz = cv_bridge::toCvShare(msg->image, tracked_object_tmp)->image; + // Resize the image to its original size + cv::Mat img_restored; + cv::resize(img_rsz, img_restored, cv::Size(msg->original_width, msg->original_height)); + + // Call the user callback with the restored image + cv_bridge::CvImage cv_img(msg->image.header, msg->image.encoding, img_restored); + user_cb(cv_img.toImageMsg()); +}; diff --git a/image_transport_tutorial/CMakeLists.txt b/image_transport_tutorial/CMakeLists.txt deleted file mode 100644 index c88520a2..00000000 --- a/image_transport_tutorial/CMakeLists.txt +++ /dev/null @@ -1,90 +0,0 @@ -cmake_minimum_required(VERSION 3.8) -project(image_transport_tutorial) - -# Default to C++17 -if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 17) -endif() - -if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") - add_compile_options(-Wall -Wextra -Wpedantic) -endif() - -find_package(ament_cmake REQUIRED) -find_package(cv_bridge REQUIRED) -find_package(image_transport REQUIRED) -find_package(OpenCV REQUIRED) -find_package(pluginlib REQUIRED) -find_package(rclcpp REQUIRED) -find_package(rosidl_default_generators REQUIRED) -find_package(sensor_msgs REQUIRED) - -include_directories(include) - -# add the resized image message -set(msg_files - "msg/ResizedImage.msg" -) -rosidl_generate_interfaces(${PROJECT_NAME} - ${msg_files} - DEPENDENCIES sensor_msgs -) - -# add the publisher example -add_executable(my_publisher src/my_publisher.cpp) -ament_target_dependencies(my_publisher - "cv_bridge" - "image_transport" - "OpenCV" - "rclcpp") - -# add the subscriber example -add_executable(my_subscriber src/my_subscriber.cpp) -ament_target_dependencies(my_subscriber - "cv_bridge" - "image_transport" - "OpenCV" - "rclcpp") - -# add the plugin example -add_library(resized_plugins src/manifest.cpp src/resized_publisher.cpp src/resized_subscriber.cpp) -ament_target_dependencies(resized_plugins - "image_transport" - "OpenCV") - -# add the publisher from video example -add_executable(publisher_from_video src/publisher_from_video.cpp) -ament_target_dependencies(publisher_from_video - "cv_bridge" - "image_transport" - "OpenCV" - "rclcpp") - -# Install plugin descriptions -pluginlib_export_plugin_description_file(${PROJECT_NAME} resized_plugins.xml) - -# Link interface -rosidl_target_interfaces(resized_plugins - ${PROJECT_NAME} "rosidl_typesupport_cpp") - -# Install executables -install( - TARGETS my_publisher my_subscriber resized_plugins publisher_from_video - RUNTIME DESTINATION lib/${PROJECT_NAME} -) - -# Install include directories -install( - DIRECTORY include/ - DESTINATION include -) - -ament_export_include_directories(include) -ament_export_dependencies(cv_bridge image_transport pluginlib rosidl_default_runtime rclcpp sensor_msgs) - -if(BUILD_TESTING) - find_package(ament_lint_auto REQUIRED) - ament_lint_auto_find_test_dependencies() -endif() - -ament_package() diff --git a/image_transport_tutorial/README.md b/image_transport_tutorial/README.md deleted file mode 100644 index 43538720..00000000 --- a/image_transport_tutorial/README.md +++ /dev/null @@ -1,292 +0,0 @@ -# image_transport_tutorial - -Before starting any of the tutorials below, create a workspace and clone the `image_common` repository so you can inspect and manipulate the code: - -``` -$ mkdir -p ~/image_transport_ws/src -$ cd ~/image_transport_ws/src -$ git clone --branch ros2 https://github.com/ros-perception/image_common.git -``` - -Install needed dependencies: - -``` -$ cd ~/image_transport_ws/ -$ source /opt/ros/galactic/setup.bash -$ rosdep install -i --from-path src --rosdistro galactic -y -$ colcon build -``` - -Make sure to include the correct setup file (in the above example it is for Galactic on Ubuntu and for bash). - -## Writing a Simple Image Publisher (C++) -Description: This tutorial shows how to create a publisher node that will continually publish an image. - -Tutorial Level: Beginner - -Take a look at [my_publisher.cpp](src/my_publisher.cpp). - -### The code explained -Now, let's break down the code piece by piece. -For lines not explained here, review [Writing a Simple Publisher and Subscriber (C++)](https://docs.ros.org/en/galactic/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html). - -``` -#include -#include -#include -#include -``` - -These headers will allow us to load an image using OpenCV, convert it to the ROS message format, and publish it. - -``` -rclcpp::Node::SharedPtr node = rclcpp::Node::make_shared("image_publisher", options); -image_transport::ImageTransport it(node); -``` - -We create an `ImageTransport` instance, initializing it with our node. -We use methods of `ImageTransport` to create image publishers and subscribers, much as we use methods of `Node` to create generic ROS publishers and subscribers. - -``` -image_transport::Publisher pub = it.advertise("camera/image", 1); -``` - -Advertise that we are going to be publishing images on the base topic `camera/image`. -Depending on whether more plugins are built, additional (per-plugin) topics derived from the base topic may also be advertised. -The second argument is the size of our publishing queue. - -`advertise()` returns an `image_transport::Publisher` object, which serves two purposes: -1. It contains a `publish()` method that lets you publish images onto the base topic it was created with -2. When it goes out of scope, it will automatically unadvertise - -``` -cv::Mat image = cv::imread(argv[1], cv::IMREAD_COLOR); -std_msgs::msg::Header hdr; -sensor_msgs::msg::Image::SharedPtr msg; -msg = cv_bridge::CvImage(hdr, "bgr8", image).toImageMsg(); -``` - -We load a user-specified (on the command line) color image from disk using OpenCV, then convert it to the ROS type `sensor_msgs/msg/Image`. - -``` -rclcpp::WallRate loop_rate(5); -while (rclcpp::ok()) { - pub.publish(msg); - rclcpp::spin_some(node); - loop_rate.sleep(); -} -``` - -We broadcast the image to anyone connected to one of our topics, exactly as we would have using an `rclcpp::Publisher`. - -### Adding video stream from a webcam -The example above requires a path to an image file to be added as a command line parameter. -This image will be converted and sent as a message to an image subscriber. -In most cases, however, this is not a very practical example as you are often required to handle streaming data. -(For example: multiple webcams mounted on a robot record the scene around it and you have to pass the image data to some other node for further analysis). - -The publisher example can be modified quite easily to make it work with a video device supported by `cv::VideoCapture` (in case it is not, you have to handle it accordingly). -Take a look at [publisher_from_video.cpp](src/publisher_from_video.cpp) to see how a video device can be passed in as a command line argument and used as the image source. - -If you have a single device, you do not need to do the whole routine with passing a command line argument. -In this case, you can hard-code the index/address of the device and directly pass it to the video capturing structure in OpenCV (example: `cv::VideoCapture(0)` if `/dev/video0` is used). -Multiple checks are also included here to make sure that the publisher does not break if the camera is shut down. -If the retrieved frame from the video device is not empty, it will then be converted to a ROS message which will be published by the publisher. - -## Writing a Simple Image Subscriber (C++) -Description: This tutorial shows how to create a subscriber node that will display an image on the screen. -By using the `image_transport` subscriber to subscribe to images, any image transport can be used at runtime. -To learn how to actually use a specific image transport, see the next tutorial. - -Tutorial Level: Beginner - -Take a look at [my_subscriber.cpp](src/my_subscriber.cpp). - -### The code explained -Now, let's break down the code piece by piece. - -``` -#include -#include -#include -#include - -#include "rclcpp/logging.hpp" -``` - -These headers will allow us to subscribe to image messages, display images using OpenCV's simple GUI capabilities, and log errors. - -``` -void imageCallback(const sensor_msgs::msg::Image::ConstSharedPtr & msg) -``` - -This is the callback function that will be called when a new image has arrived on the `camera/image` topic. -Although the image may have been sent in some arbitrary transport-specific message type, notice that the callback need only handle the normal `sensor_msgs/msg/Image` type. -All image encoding/decoding is handled automatically for you. - -``` -try { - cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image); - cv::waitKey(10); -} catch (cv_bridge::Exception & e) { - auto logger = rclcpp::get_logger("my_subscriber"); - RCLCPP_ERROR(logger, "Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str()); -``` - -The body of the callback. -We convert the ROS image message into an OpenCV image with BGR pixel encoding, then show it in a display window. - - -``` -rclcpp::Node::SharedPtr node = rclcpp::Node::make_shared("image_listener", options); -image_transport::ImageTransport it(node); -``` - -We create an `ImageTransport` instance, initializing it with our node. - -``` -image_transport::Subscriber sub = it.subscribe("camera/image", 1, imageCallback); -``` - -Subscribe to the `camera/image` base topic. -The actual ROS topic subscribed to depends on which transport is used. -In the default case, "raw" transport, the topic is `camera/image` with type `sensor_msgs/msg/Image`. -ROS will call the `imageCallback` function whenever a new image arrives. -The 2nd argument is the queue size. - -`subscribe()` returns an `image_transport::Subscriber` object that you must hold on to until you want to unsubscribe. -When the Subscriber object is destructed, it will automatically unsubscribe from the `camera/image` base topic. - -In just a few lines of code, we have written a ROS image viewer that can handle images in both raw and a variety of compressed forms. - -## Running the Simple Image Publisher and Subscriber with Different Transports -Description: This tutorial discusses running the simple image publisher and subscriber using multiple transports. - -Tutorial Level: Beginner - -### Running the publisher -In a previous tutorial we made a publisher node called `my_publisher`. -Now run the node with an image file as the command-line argument: - -``` -$ ros2 run image_transport_tutorial my_publisher path/to/some/image.jpg -``` - -To check that your node is running properly, list the topics being published: - -``` -$ ros2 topic list -``` - -You should see `/camera/image` in the output. -You can also get more information about the topic: - -``` -$ ros2 topic info /camera/image -``` - -The output should be: - -``` -Type: sensor_msgs/msg/Image -Publisher count: 1 -Subscription count: 0 -``` - -### Running the subscriber -In the last tutorial, we made a subscriber node called `my_subscriber`. Now run it: - -``` -$ ros2 run image_transport_tutorial my_subscriber -``` - -You should see a window pop up with the image you gave to the publisher. - -### Finding available transports -`image_transport` searches your ROS installation for transport plugins at runtime and dynamically loads all that are built. -This affords you great flexibility in adding additional transports, but makes it unclear which are available on your system. -`image_transport` provides a `list_transports` executable for this purpose: - -``` -$ ros2 run image_transport list_transports -``` - -Which should show: - -``` -Declared transports: -image_transport/raw - -Details: ----------- -"image_transport/raw" - - Provided by package: image_transport - - Publisher: - This is the default publisher. It publishes the Image as-is on the base topic. - - - Subscriber: - This is the default pass-through subscriber for topics of type sensor_msgs/Image. -``` - -This the expected output for an otherwise new ROS installation after completing the previous tutorials. -Depending on your setup, you may already have "theora" or other transports available. - -### Adding new transports -Our nodes are currently communicating raw `sensor_msgs/msg/Image` messages, so we are not gaining anything over using `rclcpp::Publisher` and `rclcpp::Subscriber`. -Let's change that by introducing a new transport. - -The `compressed_image_transport` package provides plugins for the "compressed" transport, which sends images over the wire in either JPEG- or PNG-compressed form. -Notice that `compressed_image_transport` is not a dependency of your package; `image_transport` will automatically discover all transport plugins built in your ROS system. - -The easiest way to add the "compressed" transport is to install the package: - -``` -$ sudo apt-get install ros-galactic-compressed-image-transport -``` - -Or install all the transport plugins at once: - -``` -$ sudo apt-get install ros-galactic-image-transport-plugins -``` - -But you can also build from source. - -### Changing the transport used -Now let's start up a new subscriber, this one using compressed transport. -The key is that `image_transport` subscribers check the parameter `_image_transport` for the name of a transport to use in place of "raw". -Let's set this parameter and start a subscriber node with name "compressed_listener": - -``` -$ ros2 run image_transport_tutorial my_subscriber --ros-args --remap __name:=compressed_listener -p _image_transport:=compressed -``` - -You should see an identical image window pop up. - -`compressed_listener` is listening to a separate topic carrying JPEG-compressed versions of the same images published on `/camera/image`. - -### Changing transport-specific behavior -For a particular transport, we may want to tweak settings such as compression level, bit rate, etc. -Transport plugins can expose such settings through ROS parameters. -For example, `/camera/image/compressed` allows you to change the compression format and quality on the fly; see the package documentation for full details. - -For now let's adjust the JPEG quality. -By default, the "compressed" transport uses JPEG compression at 80% quality. -Let's change it to 15%. -We can use the GUI, `rqt_reconfigure`, to change the quality: - -``` -$ ros2 run rqt_reconfigure rqt_reconfigure -``` - -Now pick `/image_publisher` in the drop-down menu and move the `jpeg_quality` slider down to 15%. -Do you see the compression artifacts in your second view window? - -The `rqt_reconfigure` GUI has updated the ROS parameter `/image_publisher/jpeg_quality`. -You can verify this by running: - -``` -$ ros2 param get /image_publisher jpeg_quality -``` - -This should display 15. diff --git a/image_transport_tutorial/include/image_transport_tutorial/resized_publisher.hpp b/image_transport_tutorial/include/image_transport_tutorial/resized_publisher.hpp deleted file mode 100644 index 39c3ef10..00000000 --- a/image_transport_tutorial/include/image_transport_tutorial/resized_publisher.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2021, Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IMAGE_TRANSPORT_TUTORIAL__RESIZED_PUBLISHER_HPP_ -#define IMAGE_TRANSPORT_TUTORIAL__RESIZED_PUBLISHER_HPP_ - -#include -#include - -#include - -class ResizedPublisher : public image_transport::SimplePublisherPlugin - -{ -public: - virtual std::string getTransportName() const - { - return "resized"; - } - -protected: - virtual void publish( - const sensor_msgs::msg::Image & message, - const PublishFn & publish_fn) const; -}; - -#endif // IMAGE_TRANSPORT_TUTORIAL__RESIZED_PUBLISHER_HPP_ diff --git a/image_transport_tutorial/include/image_transport_tutorial/resized_subscriber.hpp b/image_transport_tutorial/include/image_transport_tutorial/resized_subscriber.hpp deleted file mode 100644 index c8a8babd..00000000 --- a/image_transport_tutorial/include/image_transport_tutorial/resized_subscriber.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2021, Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef IMAGE_TRANSPORT_TUTORIAL__RESIZED_SUBSCRIBER_HPP_ -#define IMAGE_TRANSPORT_TUTORIAL__RESIZED_SUBSCRIBER_HPP_ - -#include -#include - -#include - -class ResizedSubscriber : public image_transport::SimpleSubscriberPlugin - -{ -public: - virtual ~ResizedSubscriber() {} - - virtual std::string getTransportName() const - { - return "resized"; - } - -protected: - void subscribeImpl( - rclcpp::Node * node, - const std::string & base_topic, - const Callback & callback, - rmw_qos_profile_t custom_qos, - rclcpp::SubscriptionOptions options) override - { - this->subscribeImplWithOptions(node, base_topic, callback, custom_qos, options); - } - - virtual void internalCallback( - const typename image_transport_tutorial::msg::ResizedImage::ConstSharedPtr & message, - const Callback & user_cb); -}; - -#endif // IMAGE_TRANSPORT_TUTORIAL__RESIZED_SUBSCRIBER_HPP_ diff --git a/image_transport_tutorial/package.xml b/image_transport_tutorial/package.xml deleted file mode 100644 index c75e7003..00000000 --- a/image_transport_tutorial/package.xml +++ /dev/null @@ -1,32 +0,0 @@ - - image_transport_tutorial - 3.1.0 - Tutorial for image_transport. - Vincent Rabaud - Michael Carroll - Apache 2.0 - - ament_cmake_ros - rosidl_default_generators - - cv_bridge - image_transport - libopencv-dev - sensor_msgs - - rosidl_default_runtime - cv_bridge - image_transport - libopencv-dev - sensor_msgs - - ament_lint_auto - ament_lint_common - - rosidl_interface_packages - - - ament_cmake - - - diff --git a/image_transport_tutorial/src/manifest.cpp b/image_transport_tutorial/src/manifest.cpp deleted file mode 100644 index 0fa48fc1..00000000 --- a/image_transport_tutorial/src/manifest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2021, Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "image_transport_tutorial/resized_publisher.hpp" -#include "image_transport_tutorial/resized_subscriber.hpp" - -PLUGINLIB_EXPORT_CLASS(ResizedPublisher, image_transport::PublisherPlugin) -PLUGINLIB_EXPORT_CLASS(ResizedSubscriber, image_transport::SubscriberPlugin) diff --git a/image_transport_tutorial/src/my_publisher.cpp b/image_transport_tutorial/src/my_publisher.cpp deleted file mode 100644 index 8e2a30bb..00000000 --- a/image_transport_tutorial/src/my_publisher.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2021, Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include - -int main(int argc, char ** argv) -{ - rclcpp::init(argc, argv); - rclcpp::NodeOptions options; - rclcpp::Node::SharedPtr node = rclcpp::Node::make_shared("image_publisher", options); - image_transport::ImageTransport it(node); - image_transport::Publisher pub = it.advertise("camera/image", 1); - - cv::Mat image = cv::imread(argv[1], cv::IMREAD_COLOR); - std_msgs::msg::Header hdr; - sensor_msgs::msg::Image::SharedPtr msg; - msg = cv_bridge::CvImage(hdr, "bgr8", image).toImageMsg(); - - rclcpp::WallRate loop_rate(5); - while (rclcpp::ok()) { - pub.publish(msg); - rclcpp::spin_some(node); - loop_rate.sleep(); - } -} diff --git a/image_transport_tutorial/src/my_subscriber.cpp b/image_transport_tutorial/src/my_subscriber.cpp deleted file mode 100644 index 6f79e698..00000000 --- a/image_transport_tutorial/src/my_subscriber.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2021, Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include - -#include "rclcpp/logging.hpp" - -void imageCallback(const sensor_msgs::msg::Image::ConstSharedPtr & msg) -{ - try { - cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image); - cv::waitKey(10); - } catch (cv_bridge::Exception & e) { - auto logger = rclcpp::get_logger("my_subscriber"); - RCLCPP_ERROR(logger, "Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str()); - } -} - -int main(int argc, char ** argv) -{ - rclcpp::init(argc, argv); - rclcpp::NodeOptions options; - rclcpp::Node::SharedPtr node = rclcpp::Node::make_shared("image_listener", options); - cv::namedWindow("view"); - cv::startWindowThread(); - image_transport::ImageTransport it(node); - image_transport::Subscriber sub = it.subscribe("camera/image", 1, imageCallback); - rclcpp::spin(node); - cv::destroyWindow("view"); -} diff --git a/image_transport_tutorial/src/publisher_from_video.cpp b/image_transport_tutorial/src/publisher_from_video.cpp deleted file mode 100644 index 58c15061..00000000 --- a/image_transport_tutorial/src/publisher_from_video.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2021, Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include - -int main(int argc, char ** argv) -{ - // Check if video source has been passed as a parameter - if (argv[1] == NULL) {return 1;} - - rclcpp::init(argc, argv); - rclcpp::NodeOptions options; - rclcpp::Node::SharedPtr node = rclcpp::Node::make_shared("image_publisher", options); - image_transport::ImageTransport it(node); - image_transport::Publisher pub = it.advertise("camera/image", 1); - - // Convert the command line parameter index for the video device to an integer - std::istringstream video_sourceCmd(argv[1]); - int video_source; - - // Check if it is indeed a number - if (!(video_sourceCmd >> video_source)) {return 1;} - - cv::VideoCapture cap(video_source); - // Check if video device can be opened with the given index - if (!cap.isOpened()) {return 1;} - cv::Mat frame; - std_msgs::msg::Header hdr; - sensor_msgs::msg::Image::SharedPtr msg; - - rclcpp::WallRate loop_rate(5); - while (rclcpp::ok()) { - cap >> frame; - // Check if grabbed frame is actually full with some content - if (!frame.empty()) { - msg = cv_bridge::CvImage(hdr, "bgr8", frame).toImageMsg(); - pub.publish(msg); - cv::waitKey(1); - } - - rclcpp::spin_some(node); - loop_rate.sleep(); - } -} diff --git a/image_transport_tutorial/src/resized_publisher.cpp b/image_transport_tutorial/src/resized_publisher.cpp deleted file mode 100644 index 4b61c82e..00000000 --- a/image_transport_tutorial/src/resized_publisher.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2021, Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include - -#include "image_transport_tutorial/resized_publisher.hpp" -#include "rclcpp/logging.hpp" - -void ResizedPublisher::publish( - const sensor_msgs::msg::Image & message, - const PublishFn & publish_fn) const -{ - cv::Mat cv_image; - std::shared_ptr tracked_object; - try { - cv_image = cv_bridge::toCvShare(message, tracked_object, message.encoding)->image; - } catch (cv::Exception & e) { - auto logger = rclcpp::get_logger("resized_publisher"); - RCLCPP_ERROR( - logger, "Could not convert from '%s' to '%s'.", - message.encoding.c_str(), message.encoding.c_str()); - return; - } - - // Rescale image - double subsampling_factor = 2.0; - int new_width = cv_image.cols / subsampling_factor + 0.5; - int new_height = cv_image.rows / subsampling_factor + 0.5; - cv::Mat buffer; - cv::resize(cv_image, buffer, cv::Size(new_width, new_height)); - - // Set up ResizedImage and publish - image_transport_tutorial::msg::ResizedImage resized_image; - resized_image.original_height = cv_image.rows; - resized_image.original_width = cv_image.cols; - resized_image.image = *(cv_bridge::CvImage(message.header, "bgr8", cv_image).toImageMsg()); - publish_fn(resized_image); -} diff --git a/image_transport_tutorial/src/resized_subscriber.cpp b/image_transport_tutorial/src/resized_subscriber.cpp deleted file mode 100644 index a073ad01..00000000 --- a/image_transport_tutorial/src/resized_subscriber.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2021, Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include - -#include "image_transport_tutorial/resized_subscriber.hpp" - -void ResizedSubscriber::internalCallback( - const image_transport_tutorial::msg::ResizedImage::ConstSharedPtr & msg, - const Callback & user_cb) -{ - // This is only for optimization, not to copy the image - std::shared_ptr tracked_object_tmp; - cv::Mat img_rsz = cv_bridge::toCvShare(msg->image, tracked_object_tmp)->image; - // Resize the image to its original size - cv::Mat img_restored; - cv::resize(img_rsz, img_restored, cv::Size(msg->original_width, msg->original_height)); - - // Call the user callback with the restored image - cv_bridge::CvImage cv_img(msg->image.header, msg->image.encoding, img_restored); - user_cb(cv_img.toImageMsg()); -}