CARLA
 
载入中...
搜索中...
未找到
CarlaOpticalFlowCameraPublisher.cpp
浏览该文件的文档.
1#define _GLIBCXX_USE_CXX11_ABI 0
2
3#include "CarlaOpticalFlowCameraPublisher.h"// 引入Carla光流相机发布者的头文件
4
5#include <string>// 引入字符串处理的标准库
6#include <cmath>// 引入数学计算的标准库(可能用于图像处理或数据转换)
7// 引入Carla ROS 2类型定义的头文件,用于序列化/反序列化图像和相机信息数据
8#include "carla/ros2/types/ImagePubSubTypes.h"// 引入图像消息类型的定义
9#include "carla/ros2/types/CameraInfoPubSubTypes.h"// 引入相机信息消息类型的定义
10#include "carla/ros2/listeners/CarlaListener.h"// 引入Carla监听器的头文件
11// 引入FastDDS相关的头文件,用于实现DDS(Data Distribution Service)通信
12#include <fastdds/dds/domain/DomainParticipant.hpp> // 引入域参与者的类定义
13#include <fastdds/dds/publisher/Publisher.hpp>// 引入发布者的类定义
14#include <fastdds/dds/topic/Topic.hpp>// 引入主题的类定义
15#include <fastdds/dds/publisher/DataWriter.hpp> // 引入数据写入器的类定义
16#include <fastdds/dds/topic/TypeSupport.hpp>// 引入类型支持的类定义(用于序列化/反序列化)
17// 引入FastDDS的QoS(Quality of Service)相关的头文件
18#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>// 引入域参与者QoS配置的类定义
19#include <fastdds/dds/domain/DomainParticipantFactory.hpp>// 引入域参与者工厂的类定义
20#include <fastdds/dds/publisher/qos/PublisherQos.hpp> // 引入发布者QoS配置的类定义
21#include <fastdds/dds/topic/qos/TopicQos.hpp>// 引入主题QoS配置的类定义
22// 引入FastRTPS(FastDDS的底层实现)相关的头文件,用于配置参与者属性和QoS策略
23#include <fastrtps/attributes/ParticipantAttributes.h>// 引入参与者属性的类定义
24#include <fastrtps/qos/QosPolicies.h> // 引入QoS策略的类定义
25#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>// 引入数据写入器QoS配置的类定义
26#include <fastdds/dds/publisher/DataWriterListener.hpp>// 引入数据写入器监听器的类定义(用于处理写入事件)
27/**
28 * @brief 通用CLAMP函数,用于将值限制在指定范围内。
29 *
30 * @param value 要限制的值。
31 * @param low 范围的下限。
32 * @param high 范围的上限。
33 * @return 限制后的值。
34 * @template T 值的类型,需要支持比较操作。
35 */
36template <typename T> T CLAMP(const T& value, const T& low, const T& high)
37{
38 return value < low ? low : (value > high ? high : value);
39}
40/**
41 * @namespace carla
42 * @brief Carla项目的命名空间。
43 */
44 /**
45 * @namespace carla::ros2
46 * @brief Carla项目中与ROS 2相关的功能的命名空间。
47 */
48namespace carla {
49namespace ros2 {
50 /**
51 * @brief FastDDS DDS命名空间的别名,用于简化代码。
52 */
53 namespace efd = eprosima::fastdds::dds;
54 /**
55 * @brief FastRTPS返回码类型的别名,用于简化代码。
56 */
57 using erc = eprosima::fastrtps::types::ReturnCode_t;
58 /**
59 * @brief Carla光流相机发布者内部实现的结构体。
60 *
61 * 包含了发布图像数据所需的FastDDS组件和辅助数据。
62 */
64 efd::DomainParticipant* _participant { nullptr };///< 域参与者,用于创建其他DDS实体。
65 efd::Publisher* _publisher { nullptr };///< 发布者,用于发送数据。
66 efd::Topic* _topic { nullptr };///< 主题,定义了发布的数据类型。
67 efd::DataWriter* _datawriter { nullptr };///< 数据写入器,用于将数据写入主题。
68 efd::TypeSupport _type { new sensor_msgs::msg::ImagePubSubType() };///< 类型支持,用于序列化和反序列化图像数据。
69 CarlaListener _listener {}; ///< Carla监听器,可能用于接收相关事件或数据。
70 sensor_msgs::msg::Image _image {};///< 存储待发布的图像数据。
71 };
72 /**
73 * @brief Carla相机信息发布者内部实现的结构体。
74 *
75 * 包含了发布相机信息数据所需的FastDDS组件和辅助数据。
76 */
77 struct CarlaCameraInfoPublisherImpl {
78 efd::DomainParticipant* _participant { nullptr };///< 域参与者。
79 efd::Publisher* _publisher { nullptr };///< 发布者。
80 efd::Topic* _topic { nullptr }; ///< 主题。
81 efd::DataWriter* _datawriter { nullptr };///< 数据写入器。
82 efd::TypeSupport _type { new sensor_msgs::msg::CameraInfoPubSubType() };///< 类型支持,用于序列化和反序列化相机信息数据。
83 CarlaListener _listener {};///< Carla监听器。
84 bool _init { false};///< 初始化标志。
85 sensor_msgs::msg::CameraInfo _info {};///< 存储待发布的相机信息数据。
86 };
87 /**
88 * @brief 检查类是否已经被初始化。
89 *
90 * @return 如果类已经被初始化,则返回true;否则返回false。
91 */
95 /**
96 * @brief 初始化摄像头信息数据。
97 *
98 * @param x_offset X轴偏移量
99 * @param y_offset Y轴偏移量
100 * @param height 图像高度
101 * @param width 图像宽度
102 * @param fov 视场角
103 * @param do_rectify 是否进行校正
104 */
105 void CarlaOpticalFlowCameraPublisher::InitInfoData(uint32_t x_offset, uint32_t y_offset, uint32_t height, uint32_t width, float fov, bool do_rectify) {
106 _impl_info->_info = std::move(sensor_msgs::msg::CameraInfo(height, width, fov));
107 SetInfoRegionOfInterest(x_offset, y_offset, height, width, do_rectify);
108 _impl_info->_init = true;
109 }
110 /**
111 * @brief 初始化类。
112 *
113 * 调用InitImage()和InitInfo()进行初始化,并返回两者的逻辑与结果。
114 *
115 * @return 如果初始化成功,则返回true;否则返回false。
116 */
120 /**
121 * @brief 初始化图像相关的资源。
122 *
123 * 创建一个DomainParticipant、Publisher、Topic和DataWriter用于发布图像数据。
124 *
125 * @return 如果初始化成功,则返回true;否则返回false。
126 */
128 if (_impl->_type == nullptr) {
129 std::cerr << "Invalid TypeSupport" << std::endl;
130 return false;
131 }
132 /// 设置DomainParticipant的QoS策略为默认值,并设置名称。
133 efd::DomainParticipantQos pqos = efd::PARTICIPANT_QOS_DEFAULT;
134 pqos.name(_name);
135 /// 获取DomainParticipantFactory的实例。
136 auto factory = efd::DomainParticipantFactory::get_instance();
137 /// 创建DomainParticipant。
138 _impl->_participant = factory->create_participant(0, pqos);
139 if (_impl->_participant == nullptr) {
140 /// 如果创建DomainParticipant失败,输出错误信息并返回false。
141 std::cerr << "Failed to create DomainParticipant" << std::endl;
142 return false;
143 }
144 /// 在DomainParticipant中注册数据类型。
145 _impl->_type.register_type(_impl->_participant);
146 /// 设置Publisher的QoS策略为默认值。
147 efd::PublisherQos pubqos = efd::PUBLISHER_QOS_DEFAULT;
148 /// 创建Publisher。
149 _impl->_publisher = _impl->_participant->create_publisher(pubqos, nullptr);
150 if (_impl->_publisher == nullptr) {
151 /// 如果创建Publisher失败,输出错误信息并返回false。
152 std::cerr << "Failed to create Publisher" << std::endl;
153 return false;
154 }
155 /// 设置Topic的QoS策略为默认值。
156 efd::TopicQos tqos = efd::TOPIC_QOS_DEFAULT;
157 /// 构建Topic的名称。
158 const std::string publisher_type {"/image"};
159 const std::string base { "rt/carla/" };
160 std::string topic_name = base;
161 if (!_parent.empty())
162 topic_name += _parent + "/";
163 topic_name += _name;
164 topic_name += publisher_type;
165 /// 创建Topic。
166 _impl->_topic = _impl->_participant->create_topic(topic_name, _impl->_type->getName(), tqos);
167 if (_impl->_topic == nullptr) {
168 /// 如果创建Topic失败,输出错误信息并返回false。
169 std::cerr << "Failed to create Topic" << std::endl;
170 return false;
171 }
172 /// 设置DataWriter的QoS策略为默认值,并修改历史内存策略。
173 efd::DataWriterQos wqos = efd::DATAWRITER_QOS_DEFAULT;
174 wqos.endpoint().history_memory_policy = eprosima::fastrtps::rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
175 /// 获取DataWriter的监听器。
176 efd::DataWriterListener* listener = (efd::DataWriterListener*)_impl->_listener._impl.get();
177 /// 创建DataWriter。
178 _impl->_datawriter = _impl->_publisher->create_datawriter(_impl->_topic, wqos, listener);
179 if (_impl->_datawriter == nullptr) {
180 /// 如果创建DataWriter失败,输出错误信息并返回false。
181 std::cerr << "Failed to create DataWriter" << std::endl;
182 return false;
183 }
184 /// 设置帧ID为名称。
186 /// 所有对象都成功创建,返回true。
187 return true;
188 }
189 /**
190 * @brief 初始化信息并设置CarlaOpticalFlowCameraPublisher的相关参数。
191 *
192 * 此函数负责初始化域参与者(DomainParticipant)、发布者(Publisher)、主题(Topic)和数据写入器(DataWriter),
193 * 并确保它们被正确创建。如果任何一步失败,函数将输出错误信息并返回false。
194 *
195 * @return 如果初始化成功,返回true;否则返回false。
196 */
198 /**
199 * 检查类型支持是否有效。如果_impl_info->_type为空,则输出错误信息并返回false。
200 */
201 if (_impl_info->_type == nullptr) {
202 std::cerr << "Invalid TypeSupport" << std::endl;
203 return false;
204 }
205 /**
206 * 设置域参与者的QoS策略,并将其命名为_name。
207 */
208 efd::DomainParticipantQos pqos = efd::PARTICIPANT_QOS_DEFAULT;
209 pqos.name(_name);
210 auto factory = efd::DomainParticipantFactory::get_instance();
211 _impl_info->_participant = factory->create_participant(0, pqos);
212 /**
213 * 如果域参与者创建失败,输出错误信息并返回false。
214 */
215 if (_impl_info->_participant == nullptr) {
216 std::cerr << "Failed to create DomainParticipant" << std::endl;
217 return false;
218 }
219 /**
220 * 在域参与者中注册类型。
221 */
222 _impl_info->_type.register_type(_impl_info->_participant);
223 /**
224 * 设置发布者的QoS策略,并创建一个发布者。
225 */
226 efd::PublisherQos pubqos = efd::PUBLISHER_QOS_DEFAULT;
227 _impl_info->_publisher = _impl_info->_participant->create_publisher(pubqos, nullptr);
228 /**
229 * 如果发布者创建失败,输出错误信息并返回false。
230 */
231 if (_impl_info->_publisher == nullptr) {
232 std::cerr << "Failed to create Publisher" << std::endl;
233 return false;
234 }
235 /**
236 * 设置主题的QoS策略,并创建一个主题。主题名称由基础名称、父级名称(如果存在)、自身名称和类型名称组成。
237 */
238 efd::TopicQos tqos = efd::TOPIC_QOS_DEFAULT;
239 const std::string publisher_type {"/camera_info"};
240 const std::string base { "rt/carla/" };
241 std::string topic_name = base;
242 if (!_parent.empty())
243 topic_name += _parent + "/";
244 topic_name += _name;
245 topic_name += publisher_type;
246 _impl_info->_topic = _impl_info->_participant->create_topic(topic_name, _impl_info->_type->getName(), tqos);
247 /**
248 * 如果主题创建失败,输出错误信息并返回false。
249 */
250 if (_impl_info->_topic == nullptr) {
251 std::cerr << "Failed to create Topic" << std::endl;
252 return false;
253 }
254 /**
255 * 设置数据写入器的QoS策略,并创建一个数据写入器。
256 */
257 efd::DataWriterQos wqos = efd::DATAWRITER_QOS_DEFAULT;
258 efd::DataWriterListener* listener = (efd::DataWriterListener*)_impl_info->_listener._impl.get();
259 _impl_info->_datawriter = _impl_info->_publisher->create_datawriter(_impl_info->_topic, wqos, listener);
260 /**
261 * 如果数据写入器创建失败,输出错误信息并返回false。
262 */
263 if (_impl_info->_datawriter == nullptr) {
264 std::cerr << "Failed to create DataWriter" << std::endl;
265 return false;
266 }
267 /// 设置帧ID为名称。
269 /// 所有对象都成功创建,返回true。
270 return true;
271 }
272 /**
273 * @brief 发布图像和相关信息。
274 *
275 * 此函数负责调用PublishImage()和PublishInfo()函数来发布图像和相关信息。
276 * 如果两者都成功发布,则返回true;否则返回false。
277 *
278 * @return 如果图像和相关信息都成功发布,返回true;否则返回false。
279 */
283 /**
284 * @brief 发布图像数据。
285 *
286 * 此函数尝试使用DataWriter发布图像数据。根据返回的ReturnCode值,函数会输出相应的错误信息(如果有的话)
287 * 并返回发布是否成功的布尔值。
288 *
289 * @return 如果图像数据成功发布,返回true;否则返回false。
290 */
292 eprosima::fastrtps::rtps::InstanceHandle_t instance_handle;
293 /**
294 * 尝试写入图像数据到DataWriter。
295 */
296 eprosima::fastrtps::types::ReturnCode_t rcode = _impl->_datawriter->write(&_impl->_image, instance_handle);
297 /**
298 * 根据返回的ReturnCode值处理发布结果。
299 */
300 if (rcode == erc::ReturnCodeValue::RETCODE_OK) {
301 /// @retval true 表示发布信息成功。
302 return true;
303 }
304 if (rcode == erc::ReturnCodeValue::RETCODE_ERROR) {
305 /// @retval false 表示通用错误。
306 std::cerr << "RETCODE_ERROR" << std::endl;
307 return false;
308 }
309 if (rcode == erc::ReturnCodeValue::RETCODE_UNSUPPORTED) {
310 /// @retval false 表示操作不支持。
311 std::cerr << "RETCODE_UNSUPPORTED" << std::endl;
312 return false;
313 }
314 if (rcode == erc::ReturnCodeValue::RETCODE_BAD_PARAMETER) {
315 /// @retval false 表示参数错误。
316 std::cerr << "RETCODE_BAD_PARAMETER" << std::endl;
317 return false;
318 }
319 if (rcode == erc::ReturnCodeValue::RETCODE_PRECONDITION_NOT_MET) {
320 /// @retval false 表示前提条件未满足。
321 std::cerr << "RETCODE_PRECONDITION_NOT_MET" << std::endl;
322 return false;
323 }
324 if (rcode == erc::ReturnCodeValue::RETCODE_OUT_OF_RESOURCES) {
325 /// @retval false 表示资源不足。
326 std::cerr << "RETCODE_OUT_OF_RESOURCES" << std::endl;
327 return false;
328 }
329 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ENABLED) {
330 /// @retval false 表示功能未启用。
331 std::cerr << "RETCODE_NOT_ENABLED" << std::endl;
332 return false;
333 }
334 if (rcode == erc::ReturnCodeValue::RETCODE_IMMUTABLE_POLICY) {
335 /// @retval false 表示策略不可变。
336 std::cerr << "RETCODE_IMMUTABLE_POLICY" << std::endl;
337 return false;
338 }
339 if (rcode == erc::ReturnCodeValue::RETCODE_INCONSISTENT_POLICY) {
340 /// @retval false 表示策略不一致。
341 std::cerr << "RETCODE_INCONSISTENT_POLICY" << std::endl;
342 return false;
343 }
344 if (rcode == erc::ReturnCodeValue::RETCODE_ALREADY_DELETED) {
345 /// @retval false 表示实体已被删除。
346 std::cerr << "RETCODE_ALREADY_DELETED" << std::endl;
347 return false;
348 }
349 if (rcode == erc::ReturnCodeValue::RETCODE_TIMEOUT) {
350 /// @retval false 表示操作超时。
351 std::cerr << "RETCODE_TIMEOUT" << std::endl;
352 return false;
353 }
354 if (rcode == erc::ReturnCodeValue::RETCODE_NO_DATA) {
355 /// @retval false 表示无数据。
356 std::cerr << "RETCODE_NO_DATA" << std::endl;
357 return false;
358 }
359 if (rcode == erc::ReturnCodeValue::RETCODE_ILLEGAL_OPERATION) {
360 /// @retval false 表示非法操作。
361 std::cerr << "RETCODE_ILLEGAL_OPERATION" << std::endl;
362 return false;
363 }
364 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ALLOWED_BY_SECURITY) {
365 /// @retval false 表示安全策略不允许。
366 std::cerr << "RETCODE_NOT_ALLOWED_BY_SECURITY" << std::endl;
367 return false;
368 }
369 /// @retval false 表示未知错误,发布失败。
370 std::cerr << "UNKNOWN" << std::endl;
371 return false;
372 }
373 /**
374 * @brief 发布信息函数
375 *
376 * 此函数尝试通过数据写入器发布信息。根据返回码(ReturnCode_t)的不同,函数会返回不同的结果,
377 * 并在控制台输出相应的错误信息。
378 *
379 * @return 如果发布信息成功,则返回true;否则返回false。
380 */
382 /// @var instance_handle
383 /// 用于存储数据写入操作后的实例句柄。
384 eprosima::fastrtps::rtps::InstanceHandle_t instance_handle;
385 /// @var rcode
386 /// 存储数据写入操作的返回码。
387 eprosima::fastrtps::types::ReturnCode_t rcode = _impl_info->_datawriter->write(&_impl_info->_info, instance_handle);
388 // 检查返回码,并根据不同的返回码执行相应的操作
389 if (rcode == erc::ReturnCodeValue::RETCODE_OK) {
390 /// @retval true 表示发布信息成功。
391 return true;
392 }
393 if (rcode == erc::ReturnCodeValue::RETCODE_ERROR) {
394 /// @retval false 表示发生错误。
395 std::cerr << "RETCODE_ERROR" << std::endl;
396 return false;
397 }
398 if (rcode == erc::ReturnCodeValue::RETCODE_UNSUPPORTED) {
399 /// @retval false 表示操作不支持。
400 std::cerr << "RETCODE_UNSUPPORTED" << std::endl;
401 return false;
402 }
403 if (rcode == erc::ReturnCodeValue::RETCODE_BAD_PARAMETER) {
404 /// @retval false 表示参数错误。
405 std::cerr << "RETCODE_BAD_PARAMETER" << std::endl;
406 return false;
407 }
408 if (rcode == erc::ReturnCodeValue::RETCODE_PRECONDITION_NOT_MET) {
409 /// @retval false 表示前提条件未满足。
410 std::cerr << "RETCODE_PRECONDITION_NOT_MET" << std::endl;
411 return false;
412 }
413 if (rcode == erc::ReturnCodeValue::RETCODE_OUT_OF_RESOURCES) {
414 /// @retval false 表示资源不足。
415 std::cerr << "RETCODE_OUT_OF_RESOURCES" << std::endl;
416 return false;
417 }
418 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ENABLED) {
419 /// @retval false 表示未启用。
420 std::cerr << "RETCODE_NOT_ENABLED" << std::endl;
421 return false;
422 }
423 if (rcode == erc::ReturnCodeValue::RETCODE_IMMUTABLE_POLICY) {
424 /// @retval false 表示策略不可变。
425 std::cerr << "RETCODE_IMMUTABLE_POLICY" << std::endl;
426 return false;
427 }
428 if (rcode == erc::ReturnCodeValue::RETCODE_INCONSISTENT_POLICY) {
429 /// @retval false 表示策略不一致。
430 std::cerr << "RETCODE_INCONSISTENT_POLICY" << std::endl;
431 return false;
432 }
433 if (rcode == erc::ReturnCodeValue::RETCODE_ALREADY_DELETED) {
434 /// @retval false 表示已删除。
435 std::cerr << "RETCODE_ALREADY_DELETED" << std::endl;
436 return false;
437 }
438 if (rcode == erc::ReturnCodeValue::RETCODE_TIMEOUT) {
439 /// @retval false 表示超时。
440 std::cerr << "RETCODE_TIMEOUT" << std::endl;
441 return false;
442 }
443 if (rcode == erc::ReturnCodeValue::RETCODE_NO_DATA) {
444 /// @retval false 表示无数据。
445 std::cerr << "RETCODE_NO_DATA" << std::endl;
446 return false;
447 }
448 if (rcode == erc::ReturnCodeValue::RETCODE_ILLEGAL_OPERATION) {
449 /// @retval false 表示非法操作。
450 std::cerr << "RETCODE_ILLEGAL_OPERATION" << std::endl;
451 return false;
452 }
453 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ALLOWED_BY_SECURITY) {
454 /// @retval false 表示安全策略不允许。
455 std::cerr << "RETCODE_NOT_ALLOWED_BY_SECURITY" << std::endl;
456 return false;
457 }/// @retval false 表示未知错误。
458 std::cerr << "UNKNOWN" << std::endl;
459 return false;
460 }
461 /**
462 * @brief 设置图像数据,将光学流数据转换为RGBA图像数据
463 *
464 * 该函数将输入的光学流数据(速度向量场)转换为RGBA格式的图像数据。
465 * 每个速度向量(vx, vy)被转换为一个HSV颜色值,然后转换为RGB格式,并附加一个透明度通道(Alpha)。
466 *
467 * @param seconds 时间戳的秒部分
468 * @param nanoseconds 时间戳的纳秒部分
469 * @param height 图像的高度
470 * @param width 图像的宽度
471 * @param data 指向包含光学流数据的浮点数组的指针,每个元素对(vx, vy)表示一个速度向量
472 */
473 void CarlaOpticalFlowCameraPublisher::SetImageData(int32_t seconds, uint32_t nanoseconds, size_t height, size_t width, const float* data) {
474 // 常量定义:圆周率π和弧度转角度的转换系数
475 constexpr float pi = 3.1415f;
476 constexpr float rad2ang = 360.0f/(2.0f*pi);
477 // 计算最大索引值,即数据数组中的元素总数的一半(因为每个速度向量有两个分量)
478 const size_t max_index = width * height * 2;
479 // 创建一个uint8_t类型的向量,用于存储最终的RGBA图像数据
480 std::vector<uint8_t> vector_data;
481 // 调整向量大小以匹配图像数据的总大小(每个像素4个字节,对应RGBA)
482 vector_data.resize(height * width * 4);
483 // 索引变量,用于遍历输入数据数组
484 size_t data_index = 0;
485 // 遍历每个速度向量
486 for (size_t index = 0; index < max_index; index += 2) {
487 // 获取当前速度向量的x和y分量
488 const float vx = data[index];
489 const float vy = data[index + 1];
490 // 计算角度(从-180到180度,然后调整到0到360度)
491 float angle = 180.0f + std::atan2(vy, vx) * rad2ang;
492 if (angle < 0)
493 {
494 angle = 360.0f + angle;
495 }
496 angle = std::fmod(angle, 360.0f);
497 // 计算速度向量的模(即速度的大小)
498 const float norm = std::sqrt(vx * vx + vy * vy);
499 // 计算HSV颜色空间中的值
500 const float shift = 0.999f;
501 const float a = 1.0f / std::log(0.1f + shift);
502 const float intensity = CLAMP<float>(a * std::log(norm + shift), 0.0f, 1.0f);
503 // 将角度赋值给H(色调),设置S(饱和度)为1.0,V(亮度)为计算得到的intensity
504 const float& H = angle;
505 const float S = 1.0f;
506 const float V = intensity;
507 // 将色调H转换为0到5之间的整数,用于后续的颜色计算
508 const float H_60 = H * (1.0f / 60.0f);
509 // 计算C(色度)和m(最小亮度值)
510 const float C = V * S;
511 const float X = C * (1.0f - std::abs(std::fmod(H_60, 2.0f) - 1.0f));
512 const float m = V - C;
513 // 根据色调H的值,计算RGB颜色分量
514 float r = 0;
515 float g = 0;
516 float b = 0;
517 const unsigned int angle_case = static_cast<const unsigned int>(H_60);
518 switch (angle_case) {
519 case 0:
520 r = C;
521 g = X;
522 b = 0;
523 break;
524 case 1:
525 r = X;
526 g = C;
527 b = 0;
528 break;
529 case 2:
530 r = 0;
531 g = C;
532 b = X;
533 break;
534 case 3:
535 r = 0;
536 g = X;
537 b = C;
538 break;
539 case 4:
540 r = X;
541 g = 0;
542 b = C;
543 break;
544 case 5:
545 r = C;
546 g = 0;
547 b = X;
548 break;
549 default:
550 r = 1;
551 g = 1;
552 b = 1;
553 break;
554 }
555 // 将RGB颜色分量转换为uint8_t类型,并附加透明度通道(Alpha设为0,表示不透明)
556 const uint8_t R = static_cast<uint8_t>((r + m) * 255.0f);
557 const uint8_t G = static_cast<uint8_t>((g + m) * 255.0f);
558 const uint8_t B = static_cast<uint8_t>((b + m) * 255.0f);
559
560 // 将RGBA值依次存储到vector_data中
561 vector_data[data_index++] = B;
562 vector_data[data_index++] = G;
563 vector_data[data_index++] = R;
564 vector_data[data_index++] = 0;
565 }
566 // 调用SetData函数,将转换后的图像数据、时间戳和尺寸信息传递给其他处理部分
567 SetData(seconds, nanoseconds, height, width, std::move(vector_data));
568 }
569 /**
570 * @brief 设置感兴趣区域(ROI)信息
571 *
572 * 该函数用于设置相机的感兴趣区域(Region Of Interest, ROI)信息,
573 * 包括ROI的起始点偏移(x_offset, y_offset)、高度(height)、宽度(width)
574 * 以及是否进行校正(do_rectify)。
575 *
576 * @param x_offset ROI起始点的x轴偏移量
577 * @param y_offset ROI起始点的y轴偏移量
578 * @param height ROI的高度
579 * @param width ROI的宽度
580 * @param do_rectify 是否对ROI进行校正
581 */
582 void CarlaOpticalFlowCameraPublisher::SetInfoRegionOfInterest( uint32_t x_offset, uint32_t y_offset, uint32_t height, uint32_t width, bool do_rectify) {
584 roi.x_offset(x_offset);
585 roi.y_offset(y_offset);
586 roi.height(height);
587 roi.width(width);
588 roi.do_rectify(do_rectify);
589 _impl_info->_info.roi(roi);
590 }
591 /**
592 * @brief 设置图像数据
593 *
594 * 该函数用于设置图像的时间戳、高度、宽度以及图像数据。
595 *
596 * @param seconds 时间戳的秒部分
597 * @param nanoseconds 时间戳的纳秒部分
598 * @param height 图像的高度
599 * @param width 图像的宽度
600 * @param data 图像数据,使用右值引用和移动语义来避免不必要的拷贝
601 */
602 void CarlaOpticalFlowCameraPublisher::SetData(int32_t seconds, uint32_t nanoseconds, size_t height, size_t width, std::vector<uint8_t>&& data) {
604 time.sec(seconds);
605 time.nanosec(nanoseconds);
606
607 std_msgs::msg::Header header;
608 header.stamp(std::move(time));
609 header.frame_id(_frame_id);
610
611 _impl->_image.header(std::move(header));
612 _impl->_image.width(width);
613 _impl->_image.height(height);
614 _impl->_image.encoding("bgra8");
615 _impl->_image.is_bigendian(0);
616 _impl->_image.step(_impl->_image.width() * sizeof(uint8_t) * 4);
617 _impl->_image.data(std::move(data)); //https://github.com/eProsima/Fast-DDS/issues/2330
618 }
619 /**
620 * @brief 设置相机信息数据的时间戳
621 *
622 * 该函数用于设置相机信息消息的时间戳和帧ID。
623 *
624 * @param seconds 时间戳的秒部分
625 * @param nanoseconds 时间戳的纳秒部分
626 */
627 void CarlaOpticalFlowCameraPublisher::SetCameraInfoData(int32_t seconds, uint32_t nanoseconds) {
629 time.sec(seconds);
630 time.nanosec(nanoseconds);
631
632 std_msgs::msg::Header header;
633 header.stamp(std::move(time));
634 header.frame_id(_frame_id);
635 _impl_info->_info.header(header);
636 }
637 /**
638 * @brief CarlaOpticalFlowCameraPublisher类的构造函数
639 *
640 * 初始化CarlaOpticalFlowCameraPublisher对象,创建内部实现对象和相机信息发布者对象。
641 *
642 * @param ros_name ROS节点名称
643 * @param parent 父节点或相关标识符
644 */
646 _impl(std::make_shared<CarlaOpticalFlowCameraPublisherImpl>()),
647 _impl_info(std::make_shared<CarlaCameraInfoPublisherImpl>()) {
648 _name = ros_name;
649 _parent = parent;
650 }
651 /**
652 * @brief CarlaOpticalFlowCameraPublisher类的析构函数
653 *
654 * 清理CarlaOpticalFlowCameraPublisher对象,释放与DDS(数据分发服务)相关的资源。
655 */
657 if (!_impl)
658 return;
659 // 清理_impl相关的DDS资源
660 if (_impl->_datawriter)
661 _impl->_publisher->delete_datawriter(_impl->_datawriter);
662
663 if (_impl->_publisher)
664 _impl->_participant->delete_publisher(_impl->_publisher);
665
666 if (_impl->_topic)
667 _impl->_participant->delete_topic(_impl->_topic);
668
669 if (_impl->_participant)
670 efd::DomainParticipantFactory::get_instance()->delete_participant(_impl->_participant);
671
672 if (!_impl_info)
673 return;
674 // 清理_impl_info相关的DDS资源
675 if (_impl_info->_datawriter)
676 _impl_info->_publisher->delete_datawriter(_impl_info->_datawriter);
677
678 if (_impl_info->_publisher)
679 _impl_info->_participant->delete_publisher(_impl_info->_publisher);
680
681 if (_impl_info->_topic)
682 _impl_info->_participant->delete_topic(_impl_info->_topic);
683
684 if (_impl_info->_participant)
685 efd::DomainParticipantFactory::get_instance()->delete_participant(_impl_info->_participant);
686 }
687 /**
688 * @brief CarlaOpticalFlowCameraPublisher类的拷贝构造函数
689 *
690 * 创建CarlaOpticalFlowCameraPublisher对象的深拷贝。
691 *
692 * @param other 要拷贝的CarlaOpticalFlowCameraPublisher对象
693 */
701 /**
702 * @brief 赋值运算符重载
703 *
704 * 将另一个CarlaOpticalFlowCameraPublisher对象赋值给当前对象。
705 * @param other 要赋值的CarlaOpticalFlowCameraPublisher对象
706 * @return 引用当前对象
707 */
709 _frame_id = other._frame_id;
710 _name = other._name;
711 _parent = other._parent;
712 _impl = other._impl;
713 _impl_info = other._impl_info;
714
715 return *this;
716 }
717 /**
718 * @brief CarlaOpticalFlowCameraPublisher类的移动构造函数
719 *
720 * 创建CarlaOpticalFlowCameraPublisher对象的移动拷贝,避免不必要的拷贝操作。
721 *
722 * @param other 要移动的CarlaOpticalFlowCameraPublisher对象
723 */
725 _frame_id = std::move(other._frame_id);
726 _name = std::move(other._name);
727 _parent = std::move(other._parent);
728 _impl = std::move(other._impl);
729 _impl_info = std::move(other._impl_info);
730
731 }
732 /**
733 * @brief 移动赋值运算符重载
734 *
735 * 将另一个CarlaOpticalFlowCameraPublisher对象移动赋值给当前对象,避免不必要的拷贝操作。
736 *
737 * @param other 要移动赋值的CarlaOpticalFlowCameraPublisher对象
738 * @return 引用当前对象
739 */
741 _frame_id = std::move(other._frame_id);
742 _name = std::move(other._name);
743 _parent = std::move(other._parent);
744 _impl = std::move(other._impl);
745 _impl_info = std::move(other._impl_info);
746
747 return *this;
748 }
749}
750}
T CLAMP(const T &value, const T &low, const T &high)
通用CLAMP函数,用于将值限制在指定范围内。
carla::rpc::Response< T > R
此类表示用户在IDL文件中定义的Time结构。
eProsima_user_DllExport void nanosec(uint32_t _nanosec)
此函数设置成员nanosec的值。
Definition Time.cpp:183
eProsima_user_DllExport void sec(int32_t _sec)
此函数设置成员sec的值。
Definition Time.cpp:152
void InitInfoData(uint32_t x_offset, uint32_t y_offset, uint32_t height, uint32_t width, float fov, bool do_rectify)
初始化摄像头信息数据。
CarlaOpticalFlowCameraPublisher & operator=(const CarlaOpticalFlowCameraPublisher &)
赋值运算符重载
void SetImageData(int32_t seconds, uint32_t nanoseconds, size_t height, size_t width, const float *data)
设置图像数据,将光学流数据转换为RGBA图像数据
void SetInfoRegionOfInterest(uint32_t x_offset, uint32_t y_offset, uint32_t height, uint32_t width, bool do_rectify)
设置感兴趣区域(ROI)信息
bool HasBeenInitialized() const
检查类是否已经被初始化。
void SetCameraInfoData(int32_t seconds, uint32_t nanoseconds)
设置相机信息数据的时间戳
bool InitInfo()
初始化信息并设置CarlaOpticalFlowCameraPublisher的相关参数。
CarlaOpticalFlowCameraPublisher(const char *ros_name="", const char *parent="")
CarlaOpticalFlowCameraPublisher类的构造函数
void SetData(int32_t seconds, uint32_t nanoseconds, size_t height, size_t width, std::vector< uint8_t > &&data)
设置图像数据
std::shared_ptr< CarlaOpticalFlowCameraPublisherImpl > _impl
~CarlaOpticalFlowCameraPublisher()
CarlaOpticalFlowCameraPublisher类的析构函数
std::shared_ptr< CarlaCameraInfoPublisherImpl > _impl_info
const std::string & parent() const
此类表示用户在 IDL 文件中定义的 CameraInfo 类型的 TopicDataType。 <>
This class represents the structure CameraInfo defined by the user in the IDL file....
Definition CameraInfo.h:75
此类表示用户在IDL文件中定义的Image类型的主题数据类型。
This class represents the structure Image defined by the user in the IDL file.这个类表示在 IDL(接口定义语言)文件中由用...
This class represents the structure RegionOfInterest defined by the user in the IDL file.
eProsima_user_DllExport void y_offset(uint32_t _y_offset)
This function sets a value in member y_offset
eProsima_user_DllExport void width(uint32_t _width)
This function sets a value in member width
eProsima_user_DllExport void height(uint32_t _height)
This function sets a value in member height
eProsima_user_DllExport void x_offset(uint32_t _x_offset)
This function sets a value in member x_offset
eProsima_user_DllExport void do_rectify(bool _do_rectify)
This function sets a value in member do_rectify
eprosima::fastrtps::types::ReturnCode_t erc
@using erc
CARLA模拟器的主命名空间。
Definition Carla.cpp:139
Carla相机信息发布者内部实现的结构体。
sensor_msgs::msg::CameraInfo _info
相机信息消息实例。
efd::DomainParticipant * _participant
DDS域参与者指针。
efd::TypeSupport _type
DDS类型支持,用于相机信息消息。
efd::DataWriter * _datawriter
DDS数据写入器指针。
efd::Publisher * _publisher
DDS发布者指针。
CarlaListener _listener
CARLA监听器实例。
Carla光流相机发布者内部实现的结构体。
sensor_msgs::msg::Image _image
存储待发布的图像数据。
efd::DomainParticipant * _participant
域参与者,用于创建其他DDS实体。
efd::Publisher * _publisher
发布者,用于发送数据。
efd::TypeSupport _type
类型支持,用于序列化和反序列化图像数据。
efd::Topic * _topic
主题,定义了发布的数据类型。
efd::DataWriter * _datawriter
数据写入器,用于将数据写入主题。
CarlaListener _listener
Carla监听器,可能用于接收相关事件或数据。