ROS關於cv_brige的使用


最近想使用OpenCV 和ROS實現點雲的拼接,實現三維重建,那么在學習了kinect的基本的使用方法以后我們知道,直接使用ROS 的包即可得到點雲,深度圖,rgb圖等信息,

roslaunch openni_launch openni.launch(深度圖彩色圖,還有點雲都獲取了)

rosrun openni_camera openni_node   (深度圖與彩色圖)

那么實現點雲的拼接就需要使用cv_bridge把ROS 的數據格式轉為Opencv可以使用的數據格式。即是一個提供ROS和OpenCV庫提供之間的接口的開發包。

                                                   

(1) 將ROS圖像信息轉換為OpenCV圖像

cvbridge定義了一個opencv圖像cvimage的類型、包含了編碼和ROS的信息頭。cvimage包含准確的信息sensor_msgs /image,因此我們可以將兩種數據類型進行轉換。cvimage類格式:

namespace cv_bridge {

class CvImage
{
public:
  std_msgs::Header header;
  std::string encoding;
  cv::Mat image;
};

typedef boost::shared_ptr<CvImage> CvImagePtr;
typedef boost::shared_ptr<CvImage const> CvImageConstPtr;

}

當要把一個ROS 的sensor_msgs /image 信息轉化為一cvimage,cvbridge有兩個不同的使用情況:

(1)如果要修改某一位的數據。我們必須復制ROS信息數據的作為副本。

(2)不修改數據。可以安全地共享的ROS信息,而不是復制的數據。

cvbridge轉換為CvImage提供了以下功能:

// Case 1: Always copy, returning a mutable CvImage
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr& source,
                    const std::string& encoding = std::string());
CvImagePtr toCvCopy(const sensor_msgs::Image& source,
                    const std::string& encoding = std::string());

// Case 2: Share if possible, returning a const CvImage
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr& source,
                          const std::string& encoding = std::string());
CvImageConstPtr toCvShare(const sensor_msgs::Image& source,
                          const boost::shared_ptr<void const>& tracked_object,
                          const std::string& encoding = std::string());

輸入是圖像消息指針,以及可選的編碼參數。編碼是指cvimage的類型。

tocvcopy復制從ROS消息的圖像數據,可以自由修改返回的cvimage。即使當源和目的編碼匹配。

tocvshare將避免復制,在ROS的消息數據把指針返回的 cv::mat,,如果源和目的編碼匹配。只要你保持一份返回的cvimage,ROS的消息數據將不會釋放。如果編碼不匹配時,它將分配一個新的緩沖區,執行轉換。將不得修改返回的cvimage,因為它可能與ROS的圖像信息共享數據,這反過來又可能與其他回調函數共享。注:對tocvshare二次過載更方便,轉換當一個指針指向其他信息類型(如stereo_msgs / disparityimage)包含一個sensor_msgs /image。

如果沒有編碼(或更確切地說,空字符串),則目標圖像編碼將與圖像消息編碼相同。在這種情況下tocvshare保證不復制圖像數據。圖像編碼可以是以下任何一個opencv圖像編碼:

  • 8UC[1-4]
  • 8SC[1-4]
  • 16UC[1-4]
  • 16SC[1-4]
  • 32SC[1-4]
  • 32FC[1-4]
  • 64FC[1-4]

介紹集中cvbridge 中常見的數據編碼的形式,cv_bridge可以有選擇的對顏色和深度信息進行轉化。為了使用指定的特征編碼,就有下面集中的編碼形式:

mono8CV_8UC1, 灰度圖像

mono16: CV_16UC1,16位灰度圖像

bgr8: CV_8UC3,帶有顏色信息並且顏色的順序是BGR順序

rgb8: CV_8UC3,帶有顏色信息並且顏色的順序是RGB順序

bgra8: CV_8UC4, BGR的彩色圖像,並且帶alpha通道

rgba8: CV_8UC4,CV,RGB彩色圖像,並且帶alpha通道

注:這其中mono8和bgr8兩種圖像編碼格式是大多數OpenCV的編碼格式。

Finally, CvBridge will recognize Bayer pattern encodings as having OpenCV type 8UC1 (8-bit unsigned, one channel). It will not perform conversions to or from Bayer pattern; in a typical ROS system, this is done instead by image_proc. CvBridge recognizes the following Bayer encodings:

  • bayer_rggb8

  • bayer_bggr8

  • bayer_gbrg8

  • bayer_grbg8

1.把Opencv圖像轉換為ROS圖像格式

To convert a CvImage into a ROS image message, use one the toImageMsg() member function:

class CvImage
{
  sensor_msgs::ImagePtr toImageMsg() const;

  // Overload mainly intended for aggregate messages that contain
  // a sensor_msgs::Image as a member.
  void toImageMsg(sensor_msgs::Image& ros_image) const;
};

舉個例子

首先要在創建的包CMakeLists.txt里添加依賴包。分別如下:

sensor_msgs
cv_bridge
roscpp std_msgs image_transport                         

 在src文件下建立一個cv_ros_beginner.cpp文件文件內容如下

#include <ros/ros.h>               //ros 的頭文件
#include <image_transport/image_transport.h>   //image_transport
#include <cv_bridge/cv_bridge.h>              //cv_bridge
#include <sensor_msgs/image_encodings.h>    //圖像編碼格式
#include <opencv2/imgproc/imgproc.hpp>      //圖像處理
#include <opencv2/highgui/highgui.hpp>       //opencv GUI

static const std::string OPENCV_WINDOW = "Image window";   //申明一個GUI 的顯示的字符串

class ImageConverter    //申明一個圖像轉換的類
{
  ros::NodeHandle nh_;        //實例化一個節點
  image_transport::ImageTransport it_;
  image_transport::Subscriber image_sub_;     //訂閱節點
  image_transport::Publisher image_pub_;      //發布節點
  
public:
  ImageConverter()
    : it_(nh_)
  {
    // Subscrive to input video feed and publish output video feed
    image_sub_ = it_.subscribe("/rgb/image_raw", 1, &ImageConverter::imageCb, this);
    image_pub_ = it_.advertise("/image_converter/output_video", 1);

    cv::namedWindow(OPENCV_WINDOW);
  }

  ~ImageConverter()
  {
    cv::destroyWindow(OPENCV_WINDOW);
  }

  void imageCb(const sensor_msgs::ImageConstPtr& msg)   //回調函數
  {
    cv_bridge::CvImagePtr cv_ptr;  //申明一個CvImagePtr
    try
    {
      cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
    }
    catch (cv_bridge::Exception& e)
    {
      ROS_ERROR("cv_bridge exception: %s", e.what());
      return;
    }
//轉化為opencv的格式之后就可以對圖像進行操作了
    // Draw an example circle on the video stream
    if (cv_ptr->image.rows > 60 && cv_ptr->image.cols > 60)
      cv::circle(cv_ptr->image, cv::Point(50, 50), 10, CV_RGB(255,0,0));  //畫圓

    // Update GUI Window
    cv::imshow(OPENCV_WINDOW, cv_ptr->image);
    cv::waitKey(3);
    
    // Output modified video stream
    image_pub_.publish(cv_ptr->toImageMsg());
  }
};

int main(int argc, char** argv)
{
  ros::init(argc, argv, "image_converter");
  ImageConverter ic;
  ros::spin();
  return 0;
}

然后在CMakeLists.txt添加,

  add_executable(cv_ros_beginner src/cv_ros_beginner.cpp)
 target_link_libraries(cv_ros_beginner
   ${catkin_LIBRARIES}
 )

返回catin_ws 下catkin_make即可生成可執行文件

那么我們在查看結果的時候就是要把

image_sub_ = it_.subscribe("/rgb/image_raw", 1, &ImageConverter::imageCb, this);                 

把訂閱的節點換成之前我們需要訂閱的節點即可實現    在訂閱的圖像上畫一個小圓圈,並且可視化出來。

 (小技巧記錄:如果你的工作空間下包很多,每次都使用catkin_make的話效率十分低下,因為這種編譯方法會編譯工作空間下的所有的包,特別是我們在調試程序是會經常修改CMakeLists.txt文件里的內容,這樣每次都會要編譯整個工作空間,那么所以我們可以使用ROS的catkin_Make的功能編譯一個或者多個包,具體的命令是:catkin_make -DCATKIN_WHITELIST_PACKAGES=" 你的包名"),例如:catkin_make -DCATKIN_WHITELIST_PACKAGES="ros_slam"

如果需要編譯兩個或者多個只需要中間加分號即可catkin_make -DCATKIN_WHITELIST_PACKAGES="ros_slam;cv_bridge",

只是搬運以下官網的程序,當然你可以實現更多的處理

那么有關於ROS以及PCL的使用的興趣者掃描二維碼關注一起與我交流分享


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM