Robotics-Ros1-cv_bridge功能包使用示例
我们用一个最简单、完整的例子来理解 cv_bridge:ROS 订阅摄像头图像 → 转换为 OpenCV 图像 → 将彩色图像转换成灰度图 → 再通过 ROS 发布出去。
下面使用你之前学习的环境:ROS1 Noetic + Ubuntu 20.04 + C++。
一、先理解程序的工作流程
摄像头节点
│
│ 发布 /camera/image_raw
▼
我们的图像处理节点
│
├── ① 接收 sensor_msgs/Image
│
├── ② cv_bridge 转换为 cv::Mat
│
├── ③ OpenCV 转换为灰度图
│
├── ④ cv_bridge 转换回 ROS 图像消息
│
└── ⑤ 发布 /camera/image_gray
│
▼
其他 ROS 节点
这里有三个不同的角色:
- ROS:负责图像消息的传输。
- cv_bridge:负责 ROS 图像消息和 OpenCV 图像数据之间的转换。
- OpenCV:负责真正的图像处理。
二、编写 C++ 程序
创建一个 ROS 功能包,名称为 cv_bridge_demo。
1. 编写图像处理节点
新建文件 src/image_processor.cpp:
#include <ros/ros.h> #include <sensor_msgs/Image.h> #include <cv_bridge/cv_bridge.h> #include <opencv2/imgproc/imgproc.hpp> class ImageProcessor { public: ImageProcessor() { // 订阅摄像头图像 image_sub_ = nh_.subscribe( "/camera/image_raw", 1, &ImageProcessor::imageCallback, this ); // 发布灰度图像 image_pub_ = nh_.advertise<sensor_msgs::Image>( "/camera/image_gray", 1 ); ROS_INFO("ImageProcessor started."); } private: ros::NodeHandle nh_; ros::Subscriber image_sub_; ros::Publisher image_pub_; void imageCallback( const sensor_msgs::ImageConstPtr& msg) { try { // 1. ROS 图像消息转换为 OpenCV 图像 cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(msg, "bgr8"); // 2. 获取 OpenCV 图像 cv::Mat color_image = cv_ptr->image; // 3. 使用 OpenCV 转换为灰度图 cv::Mat gray_image; cv::cvtColor( color_image, gray_image, cv::COLOR_BGR2GRAY ); // 4. OpenCV 图像转换为 ROS 图像消息 sensor_msgs::ImagePtr output_msg = cv_bridge::CvImage( msg->header, "mono8", gray_image ).toImageMsg(); // 5. 发布处理结果 image_pub_.publish(output_msg); ROS_INFO_THROTTLE( 5.0, "Image processed successfully." ); } catch (const cv_bridge::Exception& e) { ROS_ERROR( "cv_bridge exception: %s", e.what() ); } } }; int main(int argc, char** argv) { ros::init(argc, argv, "image_processor"); ImageProcessor processor; ros::spin(); return 0; }
2. 重点看这三行代码
第一步:ROS 消息转换为 OpenCV 图像。
cv_bridge::CvImagePtr cv_ptr =
cv_bridge::toCvCopy(msg, "bgr8");
输入:
sensor_msgs::Image
输出:
cv_bridge::CvImagePtr
通过:
cv::Mat color_image = cv_ptr->image;
获取 OpenCV 图像。
注意,toCvCopy() 会创建图像数据副本,必要时还会进行编码转换。
第二步:OpenCV 处理图像。
cv::cvtColor(
color_image,
gray_image,
cv::COLOR_BGR2GRAY
);
这一步完全由 OpenCV 完成,与 cv_bridge 无关。
输入是 BGR 彩色图像,输出是单通道灰度图像。
第三步:OpenCV 图像转换为 ROS 消息。
sensor_msgs::ImagePtr output_msg =
cv_bridge::CvImage(
msg->header,
"mono8",
gray_image
).toImageMsg();
这一步重新使用 cv_bridge,把 OpenCV 处理后的图像封装为 ROS 消息。
最后:
image_pub_.publish(output_msg);
由 ROS 将图像发送给其他节点。
三、配置编译文件
在功能包的 CMakeLists.txt 中添加以下配置:
cmake_minimum_required(VERSION 3.0.2) project(cv_bridge_demo) find_package(catkin REQUIRED COMPONENTS roscpp sensor_msgs cv_bridge ) find_package(OpenCV REQUIRED) catkin_package() include_directories( ${catkin_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ) add_executable(image_processor src/image_processor.cpp ) target_link_libraries(image_processor ${catkin_LIBRARIES} ${OpenCV_LIBRARIES} ) 在 package.xml 中声明依赖: <buildtool_depend>catkin</buildtool_depend> <depend>roscpp</depend> <depend>sensor_msgs</depend> <depend>cv_bridge</depend>
如果你使用 Ubuntu 20.04 的 ROS Noetic,通常可以直接安装相关依赖:
sudo apt update
sudo apt install \
ros-noetic-cv-bridge \
ros-noetic-sensor-msgs \
libopencv-dev
四、编译运行
假设你的 ROS 工作空间为 ~/catkin_ws。
1. 编译
将功能包放在:
~/catkin_ws/src/cv_bridge_demo/
执行:
cd ~/catkin_ws
catkin_make
source devel/setup.bash
2. 启动 ROS
首先启动 ROS Master:
roscore
然后在另一个终端启动图像处理节点:
source ~/catkin_ws/devel/setup.bash
rosrun cv_bridge_demo image_processor
注意:此时还需要有摄像头节点或其他图像发布节点,向 /camera/image_raw 发布图像,否则程序不会收到图像。
3. 查看图像话题
查看系统中的图像话题:
rostopic list
查看处理后的灰度图像:
rostopic echo /camera/image_gray
这里会输出消息的元数据和图像数据,图像数据本身通常较长。
如果安装了 rqt_image_view,可以用它直接查看图像:
sudo apt install ros-noetic-rqt-image-view
rosrun rqt_image_view rqt_image_view
在界面中选择:
/camera/image_gray
就可以看到灰度图像。
五、没有摄像头怎么办?
你可以先使用电脑上的图片进行测试。
例如,准备一张 test.jpg,然后使用 ROS 自带的 image_publisher 发布图片:
rosrun image_publisher image_publisher \
/绝对路径/test.jpg
安装命令:
sudo apt install ros-noetic-image-publisher
注意,不同版本的 image_publisher 参数形式可能有所区别,可以先执行:
rosrun image_publisher image_publisher --help
确认参数格式。
然后启动前面的 image_processor 节点。
如果发布的图像话题名称不是 /camera/image_raw,需要将代码中的订阅话题修改为实际名称。
六、通过这个例子,你应该理解什么?
| 操作 | 使用的技术 | 作用 |
|---|---|---|
| 接收图像 | ROS Subscriber | 获取 ROS 图像消息 |
toCvCopy() |
cv_bridge | 将 ROS 图像转换为 OpenCV 图像 |
cv::cvtColor() |
OpenCV | 完成灰度化处理 |
toImageMsg() |
cv_bridge | 将 OpenCV 图像封装为 ROS 消息 |
publish() |
ROS Publisher | 发布处理后的图像 |
你可以把整个程序理解为三个模块协作:
ROS 负责通信,cv_bridge 负责适配,OpenCV 负责处理。
对于你后续学习机器人视觉,这种设计很重要:你可以更换摄像头、替换图像处理算法,或者把图像处理模块部署到其他节点,而不必将所有功能耦合在一起。
另外,这个示例是 ROS1 Noetic 版本。如果以后使用 ROS2,整体思路不变,但节点接口、构建系统和消息发布订阅 API 都会有所不同。

浙公网安备 33010602011771号