1. 程式人生 > >在ROS中使用OpenCV進行簡單的圖像處理

在ROS中使用OpenCV進行簡單的圖像處理

共享指針 works 文件夾 catch 使用 取圖 hand pack process

實例:從ROS中讀取圖象,轉換後將彩色圖象變成灰度圖象,並返回灰度圖象,轉換後在ROS下輸出。

正文


1. 在ROS下創建工作空間

工作空間(work space)是ROS中非常重要的一個概念,可以把工作空間理解為一個大的工廠,裏面的分成幾個大的生產車間(package),每一個生產車間中會有若幹個具有不同技能的工人(node)。當工廠運轉時,每個車間中的工人(node)同時工作,他們通過話題(topic)進行信息溝通。各個大的車間之間也存在這互相依賴的關系,共同組成一個有機的整體。

因此在每次編寫ROS下的程序時都應該先建立一個獨立的工作空間,然後再不段的豐滿它的功能。

方法如下:新建一個終端輸入:

    mkdir -p cv_ws/src

    cd src

    catkin_init_workspace

    cd ..

    catkin_make


2. 在工作空間下創建程序包

創建好了工作空間,下一步需要創建程序包。在ROS中節點是實現某一個功能的可執行文件(工人),一個或者多個節點可以組成一個程序包。這樣做便於代碼的復用。程序包默認在工作空間中的src文件夾中創建,而node默認在程序包的src文件中創建(cpp文件)。

方法如下:在原來的終端下繼續輸入:

    cd src

    catkin_create_pkg robot_vision roscpp std_msgs cv_bridge image_transport sensor_msgs

    cd ..

    catkin_make


創建程序包的一般格式是catkin_create_pkg <name> <dependencies package>,在本程序中我們要用到除roscpp之外的三個程序包進行圖片的轉換工作。

3. 創建.cpp源文件

在ubuntu系統下,沒有類似vs2010那樣的集成開發平臺,編寫程序只需要在文本中編寫,命名時采用相應的後綴即可。在創建的程序包的src文件中創建一個文本文件,並命名為getImage.cpp。具體代碼和註釋如下:

#include<ros/ros.h> //ros標準庫頭文件
#include<iostream> //C++標準輸入輸出庫
/*
  cv_bridge中包含CvBridge庫
*/
#include<cv_bridge/cv_bridge.h> 
/*
  ROS圖象類型的編碼函數
*/
#include<sensor_msgs/image_encodings.h> 
/*
   image_transport 頭文件用來在ROS系統中的話題上發布和訂閱圖象消息
*/
#include<image_transport/image_transport.h> 

//OpenCV2標準頭文件
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>

static const std::string INPUT = "Input"; //定義輸入窗口名稱
static const std::string OUTPUT = "Output"; //定義輸出窗口名稱

//定義一個轉換的類
class RGB_GRAY
{
private:
    ros::NodeHandle nh_; //定義ROS句柄
    image_transport::ImageTransport it_; //定義一個image_transport實例
    image_transport::Subscriber image_sub_; //定義ROS圖象接收器
    //image_transport::Publisher image_pub_; //定義ROS圖象發布器
public:
    RGB_GRAY()
      :it_(nh_) //構造函數
    {
        image_sub_ = it_.subscribe("camera/rgb/image_raw", 1, &RGB_GRAY::convert_callback, this); //定義圖象接受器,訂閱話題是“camera/rgb/image_raw”
       // image_pub_ = it_.publishe("", 1); //定義圖象發布器
        //初始化輸入輸出窗口
        cv::namedWindow(INPUT);
        cv::namedWindow(OUTPUT);
    }
    ~RGB_GRAY() //析構函數
    {
         cv::destroyWindow(INPUT);
         cv::destroyWindow(OUTPUT);
    }
    /*
      這是一個ROS和OpenCV的格式轉換回調函數,將圖象格式從sensor_msgs/Image  --->  cv::Mat
    */
    void convert_callback(const sensor_msgs::ImageConstPtr& msg) 
    {
        cv_bridge::CvImagePtr cv_ptr; // 聲明一個CvImage指針的實例

        try
        {
            cv_ptr =  cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::RGB8); //將ROS消息中的圖象信息提取,生成新cv類型的圖象,復制給CvImage指針
        }
        catch(cv_bridge::Exception& e)  //異常處理
        {
            ROS_ERROR("cv_bridge exception: %s", e.what());
            return;
        }

        image_process(cv_ptr->image); //得到了cv::Mat類型的圖象,在CvImage指針的image中,將結果傳送給處理函數   
    }
    /*
       這是圖象處理的主要函數,一般會把圖像處理的主要程序寫在這個函數中。這裏的例子只是一個彩色圖象到灰度圖象的轉化
    */
    void image_process(cv::Mat img) 
    {
       cv::Mat img_out;
       cv::cvtColor(img, img_out, CV_RGB2GRAY);  //轉換成灰度圖象
       cv::imshow(INPUT, img);
       cv::imshow(OUTPUT, img_out);
       cv::waitKey(5);
    }
};

//主函數
int main(int argc, char** argv)
{
    ros::init(argc, argv, "RGB");
    RGB_GRAY obj;
    ros::spin();
}

4. 以下是對上面代碼中核心的部分進行解釋

1)頭文件

#include<cv_bridge/cv_bridge.h>
頭文件cv_bridge中包含了CvBridge類,而CvBridge中的API可以將ROS下的sensor_msgs/Image消息類型轉化成cv::Mat。
#include<sensor_msgs/image_encodings.h>
頭文件sensor_msgs/Image是ROS下的圖像的類型,這個頭文件中包含對圖像進行編碼的函數。
#include<image_transport/image_transport.h>
這個頭文件中包含的是ImageTransport類,這個類提供ROS中圖像的訂閱和發布。
剩下的頭文件就是如程序中的註釋所示。

2)核心類的主要API

image_transport類:圖像傳輸類,其功能和ROS中的Publisher和Subscriber差不多,但是不同的是這個類在發布和訂閱圖片消息的同時還附帶這攝像頭的信息。相比較之下, 在ROS中傳送圖片信息,使用image_transport類要高效的多。同時,這個類可以以不同的圖像壓縮形式傳輸圖像例如JPG/PNG等等,也可以添加插件定義傳輸數據的壓縮模式。 API: image_transport::ImageTransport類:這個類成員可以定義某個話題的圖像類型的發布器和訂閱器(類似ros的句柄)。 image_transport::Publisher類:這個類定義了image_transport中的發布器。 image_transport::Subsciber類:這個類定義了image_transport中的訂閱器。 cv_bridge類:這個類中提供的API主要功能是將圖像從sensor_msgs/Image類型轉化成cv::Mat類型。 API: cv_bidge::CvImage類:cv_bridge中提供的數據結構,裏面包括OpenCV中的cv::Mat類型的圖像信息,圖像編碼方式,ROS頭文件等等。要得到cv::Mat類型的 圖像,只需要定義一個對象然後給出對象中的成員object.image即可,或者指針CvImagePtr,ptr->image。 cv_bridge::toCvCopy()方法:參數是ROS下的sensor_msgs/ImageConstPtr,和圖像壓縮類型(例如:sensor_msgs::image_encodings::RGB8)。其功能是實 現復制圖像信息這樣,得到副本,這樣我們可以從副本的CvImage中提取cv::Mat類型的圖像進行處理。核心! cv_bridge::toCvShare()方法:參數同上,但是這個函數只是共享指針地址。ROS是不予許直接對圖像格式的消息進行操作的。

5. 編譯成可執行文件

在編寫程序後,這個文本程序在編譯成可執行文件之前是不能夠運行的。首先在建立的robot_vision的程序包中的CMakeLists.txt文件中加入如下代碼:
add_executable(gratImage src/grayImage.cpp)   //將src中的文件添加成名字為grayImage的可執行文件
target_link_libraries(grayImage ${catkin_LIBRARIES})  //將相關的庫和可執行文件鏈接
add_dependencies(grayImage robot_vision_generate_messages_cpp)  //給可執行文件添加依賴包
返回到工作空間下編譯。catkin_make

6. 總結

以上就是在ROS下使用opencv所要做的所有工作。總體上來看就是因為opencv處理的圖像格式和ROS系統實際提供的格式不匹配,故而有cv_bridge這個包作為溝通的橋梁。二本程序中使用image_transport代替傳統的ROS中的Publisher和Subscriber是另一個突破。同時還要註意的是,ubuntu下的opencv2中的某些函數的形式和window中的不相同,使用的時候要註意。
轉載自:http://blog.csdn.net/robogreen/article/details/50488215

在ROS中使用OpenCV進行簡單的圖像處理