• R3LIVE源码解析(10) — R3LIVE中r3live_vio.cpp文件


    目录

    1 r3live_vio.cpp简介

    2 r3live_vio.cpp源码解析


    1 r3live_vio.cpp简介

    R3LIVE主要的公式推导在VIO上,所以我们来细细的分析这部分的功能。R3LIVE将VIO分成了两步,一是直接通过帧间的光流来追踪地图点,并且通过最小化追踪到的地图点的PNP投影误差来获取系统状态;二是通过这些地图点的出现的帧到地图的光度误差来优化状态。

    2 r3live_vio.cpp源码解析

    首先r3live_vio.cpp中,我们会先通过一个线程来获取图像的信息

    1. void R3LIVE::image_comp_callback( const sensor_msgs::CompressedImageConstPtr &msg )
    2. {
    3. std::unique_lock< std::mutex > lock2( mutex_image_callback );
    4. if ( sub_image_typed == 1 )
    5. {
    6. return; // Avoid subscribe the same image twice.
    7. }
    8. sub_image_typed = 2;
    9. g_received_compressed_img_msg.push_back( msg );
    10. // 如果是第一次收到图片,则启动一个线程
    11. if ( g_flag_if_first_rec_img )
    12. {
    13. g_flag_if_first_rec_img = 0;
    14. // 通过线程池k方法调用service_process_img_buffer函数来处理图像
    15. // 内部其实在循环调用process_image()函数
    16. m_thread_pool_ptr->commit_task( &R3LIVE::service_process_img_buffer, this );
    17. }
    18. return;
    19. }
    20. // ANCHOR - image_callback
    21. void R3LIVE::image_callback( const sensor_msgs::ImageConstPtr &msg )
    22. {
    23. std::unique_lock< std::mutex > lock( mutex_image_callback );
    24. if ( sub_image_typed == 2 )
    25. {
    26. return; // Avoid subscribe the same image twice.
    27. }
    28. sub_image_typed = 1;
    29. // 与上面的函数相同
    30. if ( g_flag_if_first_rec_img )
    31. {
    32. g_flag_if_first_rec_img = 0;
    33. m_thread_pool_ptr->commit_task( &R3LIVE::service_process_img_buffer, this );
    34. }
    35. // 将图像消息转opencv格式
    36. cv::Mat temp_img = cv_bridge::toCvCopy( msg, sensor_msgs::image_encodings::BGR8 )->image.clone();
    37. // 图像预处理,然后保存到m_queue_image_with_pose队列
    38. process_image( temp_img, msg->header.stamp.toSec() );
    39. }

     这里面通过 m_thread_pool_ptr->commit_task线程池的方式完成了图像buffer的压入与处理。在这个函数的末尾,会调用process_image函数

    1. void R3LIVE::service_process_img_buffer()
    2. {
    3. while ( 1 )
    4. {
    5. // To avoid uncompress so much image buffer, reducing the use of memory.
    6. // 如果m_queue_image_with_pose队列内的数据>4,表示这些数据还没被处理,暂时挂起预处理线程(丢一些数据)
    7. if ( m_queue_image_with_pose.size() > 4 )
    8. {
    9. while ( m_queue_image_with_pose.size() > 4 )
    10. {
    11. ros::spinOnce();
    12. std::this_thread::sleep_for( std::chrono::milliseconds( 2 ) );
    13. std::this_thread::yield();
    14. }
    15. }
    16. cv::Mat image_get;
    17. double img_rec_time;
    18. // sub_image_typed == 2,表示接收的是压缩图像格式
    19. if ( sub_image_typed == 2 )
    20. {
    21. // 如果队列中没有数据,暂停当前线程1s,以减少CPU的使用
    22. while ( g_received_compressed_img_msg.size() == 0 )
    23. {
    24. ros::spinOnce();
    25. std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );
    26. std::this_thread::yield();
    27. }
    28. // 从队列的前端获取一个压缩图像消息msg
    29. sensor_msgs::CompressedImageConstPtr msg = g_received_compressed_img_msg.front();
    30. try
    31. {
    32. // 将压缩图像消息转换为cv::Mat类型的图像数据
    33. cv_bridge::CvImagePtr cv_ptr_compressed = cv_bridge::toCvCopy( msg, sensor_msgs::image_encodings::BGR8 );
    34. // 存储获取的时间和图像
    35. img_rec_time = msg->header.stamp.toSec();
    36. image_get = cv_ptr_compressed->image;
    37. // 释放内存
    38. cv_ptr_compressed->image.release();
    39. }
    40. catch ( cv_bridge::Exception &e )
    41. {
    42. printf( "Could not convert from '%s' to 'bgr8' !!! ", msg->format.c_str() );
    43. }
    44. mutex_image_callback.lock();
    45. g_received_compressed_img_msg.pop_front();
    46. mutex_image_callback.unlock();
    47. }
    48. else
    49. {
    50. // 如果队列中没有数据,暂停当前线程1s,以减少CPU的使用
    51. while ( g_received_img_msg.size() == 0 )
    52. {
    53. ros::spinOnce();
    54. std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );
    55. std::this_thread::yield();
    56. }
    57. // 与前面的流程类似,区别在于需要将接受的最前的图像pop
    58. sensor_msgs::ImageConstPtr msg = g_received_img_msg.front();
    59. image_get = cv_bridge::toCvCopy( msg, sensor_msgs::image_encodings::BGR8 )->image.clone();
    60. img_rec_time = msg->header.stamp.toSec();
    61. mutex_image_callback.lock();
    62. g_received_img_msg.pop_front();
    63. mutex_image_callback.unlock();
    64. }
    65. process_image( image_get, img_rec_time );
    66. }
    67. }

    process_image函数主要做了三件事情,分别是检测时间戳,初始化参数,并启动service_pub_rgb_mapsservice_VIO_update线程,以及去畸变与图像处理。

    void R3LIVE::process_image( cv::Mat &tem
  • 相关阅读:
    JavaScript 设计模式之发布订阅者模式
    No ‘Access-Control-Allow-Origin‘ header前端浏览器跨域用LiveServer处理
    TensorFlow的transformer类模型文件转换为pytorch
    数据结构--第八章--图
    C语言从入门到精通- CLion安装配置Gitee
    软考 - 软件工程
    shiro
    北京优秀律师事务所排名(前十名权威推荐)
    2022.10.1
    Jquery自定义多级导航菜单完整代码带搜索查询功能附注释
  • 原文地址:https://blog.csdn.net/qq_41921826/article/details/132724505