CvBridge は ROS イメージと OpenCV イメージの間で変換します

目次

1.コンセプト

2. ROS イメージを OpenCV イメージに変換する

3. OpenCV イメージを ROS イメージ メッセージに変換する

4. 例

1.コンセプト

        ROS の sensor_msgs/Imageメッセージ形式自体は画像を送信するためのものですが、Opencv に直接渡すことができないため、ROS は CvBridge を提供します。間の変換。

         この記事では、ノードを作成する方法、CvBridge を使用して ROS を OpenCV 形式に変換する方法、および公開するために Opencv イメージを ROS 形式に変換する方法について説明します。

2. ROS イメージを OpenCV イメージに変換する

         CvBridge は、Opencv イメージを含む特殊な CvImage タイプを定義します。 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 に変換する 2 つの方法があります。

1. データを変更したい場合は、メッセージをコピーする必要があります。

2. データを変更したくないので、ROS メッセージ データをコピーする代わりに安全に共有できます。

ROS は、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());

 両方の関数の入力がメッセージ ポインター (サブスクライバーのコールバック関数のパラメーター) であり、もう 1 つのパラメーターがオプションのエンコード パラメーターであることがわかります。

1. toCvCopy は、ROS メッセージによって作成された画像データのコピーを返します。これは、CvImagePtr を自由に変更できます。

2. toCvShare は変更不可能な CvImageConstPtr を返します

画像のエンコード方法には次のようなものがあります。

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

 一般的に使用されるエンコード方法の例をいくつか示します。

   

  • mono8: CV_8UC1、グレースケール画像

  • mono16: CV_16UC1、16 ビット グレースケール画像

  • bgr8: CV_8UC3、青、緑、赤の連続カラー画像

  • rgb8: CV_8UC3、赤、緑、青の連続カラー画像

  • bgra8: CV_8UC4、アルファ チャネル BGR カラー イメージ

  • rgba8: CV_8UC4、アルファ チャネル付きの RGB カラー イメージ

注: mono8 と bgr8 は、OpenCV で最も期待され、一般的に使用される画像エンコーディングです。

3. OpenCV イメージを ROS イメージ メッセージに変換する

         CvImage を ROS イメージ メッセージに変換するには、 toImageMsg() メンバー関数を使用します。

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

  //重载的函数
  void toImageMsg(sensor_msgs::Image& ros_image) const;
};

ROS には 2 つのオーバーロードが用意されており、 オブジェクトを使用して を直接呼び出すことができます。

4. 例

この例の最初の例は公式 Web サイトの例で、もう 1 つは私自身のカメラを使用した例です。時間があるので追加します。

公式サイトに記載されている例では、画像を cv::Mat 型に変換し、画像上に円を描画し、OpenCV に画像を表示し、ros に再公開しています。関数パッケージの依存関係を作成するときは、(catkin_create_pkg) を追加して依存関係を追加する必要があります。

センサーメッセージ
cv_ブリッジ
ロスクップ
std_msgs
画像_トランスポート

ヘッド ファイル:

#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

 image_transport を使用すると、圧縮された画像ストリームをサブスクライブできます。 imgproc と hihgui は、画像処理と gui に直接使用することもできます。#include <opencv/opencv.hpp> には、すべての opencv ヘッダー ファイルが含まれます。cv_bridge为本章的主题需要包含。接下来看定义的类和主函数。

static const std::string OPENCV_WINDOW = "Image window";

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("/camera/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;//接受到ros图像的对象
    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;
    }

    // Draw an example circle on the video stream
    //cv_ptr->image就是传递一个Mat类当opencv使用就可以了
    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;
}

5 独自の Mat クラスを ros イメージに変換する

        ここでの公式の cvImage は msg を通じて初期化されているため、最初から Mat クラスのイメージを操作する方法しかわかりません。作者は cvImage を定義して cv_ptr->image=Mat を使用したいと考えていますが、それは不可能でしょうか?

v_bridge::CvImagePtr ptr;
ptr.image=image.clone();

残念ながら、このオブジェクトは初期コンストラクターを呼び出すため、これは機能しません。公式のソース コードを読むと、cvImage がどのように構築されているかがわかります。

CvImage() {}

  /**
   * \brief Constructor.
   */
  CvImage(
    const std_msgs::msg::Header & header, const std::string & encoding,
    const cv::Mat & image = cv::Mat())
  : header(header), encoding(encoding), image(image)
  {
  }

cvImage オブジェクトを作成しただけで初期化が正しく完了しないと、このオブジェクトを正常に使用できなくなります。正しい方法:

sensor_msgs::ImagePtr  msg = cv_bridge::CvImage(std_msgs::Header(), "mono8", Right_raw).toImageMsg();

OK、これで画像を通常通り公開できます。​ 

おすすめ

転載: blog.csdn.net/HHB791829200/article/details/128395768