ipa_room_segmentation (地图分割,用于房间分区)
客户端 room_segmentation_client.cpp
头文件
#include <ros/ros.h> // 提供了ROS节点的基本功能,如初始化节点、发布和订阅消息等。 #include <ros/package.h> // 提供了与ROS包管理相关的功能,例如获取包路径。 #include <string> #include <vector> // C++标准库的头文件,用于处理字符串和向量数据结构。 #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> // OpenCV库的头文件,用于图像处理和图形用户界面功能。 #include <cv_bridge/cv_bridge.h> // cv_bridge库的一部分,它提供了ROS图像消息和OpenCV图像格式之间转换的功能 #include <actionlib/client/simple_action_client.h> #include <actionlib/client/terminal_state.h> // actionlib库的头文件,用于实现ROS中的动作服务器和客户端 #include <ipa_building_msgs/MapSegmentationAction.h> // 房间分割任务相关的自定义消息类型和服务 #include <ipa_room_segmentation/dynamic_reconfigure_client.h> // 动态重新配置房间分割服务的客户端接口
main
客户端是直接把测试地图名写入一个 vector 变量 map_names 中,然后在 for 循环中在指定地址获取相应的地图地址,把地图转为地图话题数据,再装入 goal 中发送给服务端。
设置Ros环境并创建一个节点,一边程序可以与Ros网络中的其他节点进行交互
ros::init(argc, argv, "room_segmentation_client"); ros::NodeHandle nh;
添加地图表,每一个都是对应文件中的地图图像文件名
// map names std::vector< std::string > map_names; map_names.push_back("lab_ipa"); map_names.push_back("lab_c_scan"); ...
整个函数围绕这个for循环进行
for (size_t image_index = 0; image_index<map_names.size(); ++image_index) { // 在 ipa_room_segmentation 功能包的指定位置搜索地图 std::string image_filename = ros::package::getPath("ipa_room_segmentation") + "/common/files/test_maps/" + map_names[image_index] + ".png"; cv::Mat map = cv::imread(image_filename.c_str(), 0); // cv 读地图 ... cv_image.toImageMsg(labeling); // 数据转换 actionlib::SimpleActionClient<ipa_building_msgs::MapSegmentationAction> ac("room_segmentation_server", true); ... // goal 数据装包 ac.sendGoal(goal); // 目标发送到服务端 bool finished_before_timeout = ac.waitForResult(ros::Duration()); // 等待结果 if (finished_before_timeout) { ... // 数据转换到 cv 格式 cv::imshow("segmentation", colour_segmented_map); // cv 显示地图 cv::waitKey(); // 敲空格测试下一张地图 } }
详细解释for中的代码
这段代码展示了如何在ROS(Robot Operating System)中使用OpenCV库来导入图像文件。具体来说,它是从一个特定的路径加载图像文件到cv::Mat对象中
// import maps std::string image_filename = ros::package::getPath("ipa_room_segmentation") + "/common/files/test_maps/" + map_names[image_index] + ".png"; cv::Mat map = cv::imread(image_filename.c_str(), 0);
二值化,将图像中小于255的全部设置为0,即非白即黑
for (int y = 0; y < map.rows; y++) { for (int x = 0; x < map.cols; x++) { //find not reachable regions and make them black if (map.at<unsigned char>(y, x) < 250) { map.at<unsigned char>(y, x) = 0; } //else make it white else { map.at<unsigned char>(y, x) = 255; } } }
这段代码展示了如何使用cv_bridge库将OpenCV的图像格式转换为ROS的sensor_msgs::Image消息格式
//声明了一个sensor_msgs::Image类型的变量labeling,这是ROS中用于表示图像的标准消息类型。 sensor_msgs::Image labeling; //声明了一个cv_bridge::CvImage类型的变量cv_image。CvImage是cv_bridge中的一个类,用于在ROS消息和OpenCV图像之间进行转换 cv_bridge::CvImage cv_image; //这行代码被注释掉了,但如果取消注释,它会设置cv_image的时间戳为当前时间 //cv_image.header.stamp = ros::Time::now(); //设置cv_image的编码格式为"mono8",这表示图像是以8位单通道(灰度)格式存储的。 cv_image.encoding = "mono8"; //将OpenCV图像map赋值给cv_image的image成员。这里的map是一个cv::Mat类型的变量,包含了要转换的图像数据。 cv_image.image = map; //这个函数调用将cv_image中的OpenCV图像转换为ROS的sensor_msgs::Image消息,并将结果存储在labeling变量中。 cv_image.toImageMsg(labeling);