天天看點

使用ros中的image_transport API将自己的資料集做成rosbag

因為很多的slam代碼是有ROS版的,ROS版的一般資料的輸入都是rosbag的形式,是以為了使用,測試新的資料集,需要将沒有rosbag的資料集轉為rosbag的形式,其實這裡涉及的就是将普通的照片轉為ros的圖檔,使用一個節點釋出這寫圖檔流,然後使用rosbag進行記錄,然後生成一個rosbag的包.整體就是這樣的思路.ROS的官網上也有相關的Tutorials.Tutorials 裡面指令有一些小錯誤,但是不會影響很大.接下來将分兩個部分來記錄一下自己轉換的過程.第一部分是學習ROS WIKI上的tutorials的内容,第二部分是使用自己的資料集進行實驗.

一. Tutorials的學習

在ROS的image_transport的tutorial上,根據它的教程進行如下的指令操作,這些操作的前提是你已經在你的系統上安裝了ROS的系統,哇是跟着官方教程 安裝的,這裡因為設定軟體源的問題,折騰了好久,最後先删除出問題的軟體源,最後再安裝官方的教程就可以成功了.然後按照image_transport的教程走通如下的指令:

$ mkdir -p ~/image_transport_ws/src
$ cd ~/image_transport_ws/src
$ source /opt/ros/kinetic/setup.bash  #notice 看你安裝的是什麼版本的ros,我的是kinetic
$ catkin_create_pkg learning_image_transport image_transport cv_bridge #生成一個包
$ cd ~/image_transport_ws  #或者 cd ..
$ rosdep install --from-paths src -i -y --rosdistro kinetic #這裡也需要改成自己的安裝
$ catkin_make
$ source devel/setup.bash
$ git clone https://github.com/ros-perception/image_common.git
$ ln -s `pwd`/image_common/image_transport/tutorial/ ./src/image_transport_tutorial
$catkin_make #編譯源檔案
           

以上操作完成之後,你就可以使用如下步驟你就可以釋出一張圖檔到ROS的節點中去了.

  1. 在你編譯的指令行視窗新開一個視窗,保證其是在 /image_transport_ws 這個路徑下的,然後運作:
  1. 在你編譯的指令行視窗新開一個視窗,保證其是在 /image_transport_ws 這個路徑下的,然後運作:
$ source /opt/ros/kinetic/setup.bash
$ source devel/setup.bash
$ rosrun image_transport_tutorial my_publisher path/to/some/image.jpg
           

以上source是為了保證某些路徑,沒有寫進bash裡面的話每次新開指令行都需要運作source一下.以上指令是釋出了一個圖檔消息.想要看你啟動的節點以及釋出的圖像資料.緊接着做第3步.

  1. 檢視節點

輸出如下内容:(根據有些插件的不同可能輸出不同,但是隻要具有查不多的就好)

Published topics:

* /rosout [roslib/Log] 1 publisher

* /camera/image [sensor_msgs/Image] 1 publisher

* /rosout_agg [roslib/Log] 1 publisher

Subscribed topics:

* /rosout [roslib/Log] 1 subscriber

  1. 訂閱節點
$rosrun image_transport_tutorial my_subscriber
           

如果有view的話,運作上訴指令之後就會出現你釋出的image圖檔.

二. 使用自己的資料集做rosbag包

方法一:使用ros進行資料釋出

目前我找到了兩種方法實作ros-bag的生成,第一種就是接下來要詳細介紹的直接使用ros的publisher節點進行資料的釋出,然後使用rosbag進行錄制.

這個部分主要是根據第一部分的tutorial進行改進的,主要是針對自己的資料集對publisher.cpp檔案進行了改進.改進的代碼我直接貼在下面:

#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
#include <iostream>
#include <vector>
#include <glob.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
using namespace std;

vector<string> getFiles(string dirc){
    vector<string> files;
    struct dirent *ptr;
    char base[];
    DIR *dir;
    dir = opendir(dirc.c_str());
    /*
    if(dir == NULL){
        perror("open dir error ...");
        exit(1);
    }*/
    while((ptr = readdir(dir)) != NULL){
        if(ptr->d_type == )//it;s file
        {
            files.push_back(dirc+'/'+ptr->d_name);
        }

        else if(ptr->d_type == )//link file
            continue;
        else if(ptr->d_type == ){
            files.push_back(ptr->d_name);
        }
    }
    closedir(dir);
    sort(files.begin(),files.end());
    for(size_t i = ; i < files.size();++i){
        cout << files[i] << endl;
    }
    return files;
}

void origin(int argc,char** argv){
  /*
  **這個函數和官網提供的一張照片的tutorial很類似,隻用于測試一張照片的情況.
  **前面部分是基本的ros釋出資料的操作,在這裡不多說.
  */
    ros::init(argc, argv, "image_publisher");
    ros::NodeHandle nh;
    image_transport::ImageTransport it(nh);
    image_transport::Publisher pub = it.advertise("camera/image", );
    cv::Mat image = cv::imread(argv[], CV_LOAD_IMAGE_COLOR);
    cout << argv[] << endl;
    cv::waitKey();
    sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", image).toImageMsg();
    ros::Rate loop_rate();
    while (nh.ok()) {
        pub.publish(msg);
        ros::spinOnce();
        loop_rate.sleep();
        }
}


void directory(int argc,char** argv){
/*
**這個函數針對的是大量資料的
*/
    ros::init(argc, argv, "image_publisher");
    ros::NodeHandle nh;
    image_transport::ImageTransport it(nh);
    image_transport::Publisher pub = it.advertise("camera/image", );
    vector<string> result = getFiles(argv[]);// /home/***/***/dataset/Mars/*.pgm

    //the argv is the url of the image,may we can use that for all images
    ros::Rate loop_rate();
    for(size_t i = ; i < result.size();++i){
        if(!nh.ok())
            break;
        ostringstream stringStream;
        stringStream << result[i];
        cv::Mat image = cv::imread(stringStream.str(),CV_LOAD_IMAGE_COLOR);
        sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", image).toImageMsg();
        msg->header.stamp = ros::Time();//這裡的時間戳換成你自己的,需要自己再寫一個讀取時間戳的函數,注意和image進行對應.一般時間戳檔案也包含在圖檔的檔案夾中.

        pub.publish(msg);
        ros::spinOnce();
        loop_rate.sleep();
    }
}

int main(int argc, char** argv)
{
  DIR *dir;
  dir = opendir(argv[]);
  if(dir == NULL)
      origin(argc,argv);
  else
      directory(argc,argv);

}
           

以上是publisher的部分,然後到subscriber部分還是之前tutorial的代碼,然後按照之前的操作進行,最後使用rosbag record -a(-a表示錄制全部釋出的話題,其它參數參考官方文檔).

以上就是使用ros生成自己資料集的rosbag的方法.

方法二.使用rosbag的包,直接寫入

這個部分是參考大神的代碼

我隻是當了以下搬運工,将其應用到自己的資料集上了.

以下是我的代碼,因為我需要整合IMU資料和image的資料,而且兩者都是有時間戳timestamp的.

以下是我的代碼:

import cv2
import time, sys, os
from ros import rosbag
import roslib
import rospy
roslib.load_manifest('sensor_msgs')
from sensor_msgs.msg import Image,Imu
from geometry_msgs.msg import Vector3

# import ImageFile
from PIL import ImageFile
from PIL import Image as ImagePIL

def CompSortFileNamesNr(f):
    g = os.path.splitext(os.path.split(f)[])[] #get the file of the
    numbertext = ''.join(c for c in g if c.isdigit())
    return int(numbertext)

def ReadImages(filename):
    '''Generates a list of files from the directory'''
    print("Searching directory %s" % dir)
    all = []
    left_files = []
    right_files = []
    files = os.listdir(filename)
    for f in sorted(files):
        if os.path.splitext(f)[] in ['.bmp', '.png', '.jpg', '.pgm']:
            '''
            if 'left' in f or 'left' in path:
                left_files.append(os.path.join(path, f))
            elif 'right' in f or 'right' in path:
                right_files.append(os.path.join(path, f))
            '''
            all.append(os.path.join(filename, f))
    return all

def ReadIMU(filename):
    '''return IMU data and timestamp of IMU'''
    file = open(filename,'r')
    all = file.readlines()
    timestamp = []
    imu_data = []
    for f in all:
        line = f.rstrip('\n').split(' ')
        timestamp.append(line[])
        imu_data.append(line[:])
    return timestamp,imu_data


def CreateBag(args):#img,imu, bagname, timestamps
    '''read time stamps'''
    imgs = ReadImages(args[])
    imagetimestamps=[]
    imutimesteps,imudata = ReadIMU(args[]) #the url of  IMU data
    file = open(args[], 'r')
    all = file.readlines()
    for f in all:
        imagetimestamps.append(f.rstrip('\n').split(' ')[])
    file.close()
    '''Creates a bag file with camera images'''
    if not os.path.exists(args[]):
    os.system(r'touch %s' % args[])
    bag = rosbag.Bag(args[], 'w')

    try:
        for i in range(len(imudata)):
            imu = Imu()
            angular_v = Vector3()
            linear_a = Vector3()
            angular_v.x = float(imudata[i][])
            angular_v.y = float(imudata[i][])
            angular_v.z = float(imudata[i][])
            linear_a.x = float(imudata[i][])
            linear_a.y = float(imudata[i][])
            linear_a.z = float(imudata[i][])
            imuStamp = rospy.rostime.Time.from_sec(float(imutimesteps[i]))
            imu.header.stamp=imuStamp
            imu.angular_velocity = angular_v
            imu.linear_acceleration = linear_a

            bag.write("IMU/imu_raw",imu,imuStamp)

        for i in range(len(imgs)):
            print("Adding %s" % imgs[i])
            fp = open(imgs[i], "r")
            p = ImageFile.Parser()

            '''read image size'''
            imgpil = ImagePIL.open(imgs[])
            width, height = imgpil.size
            # print "size:",width,height

            while :
                s = fp.read()
                if not s:
                    break
                p.feed(s)

            im = p.close()

            Stamp = rospy.rostime.Time.from_sec(float(imagetimestamps[i]))

            '''set image information '''
            Img = Image()

            Img.header.stamp = Stamp
            Img.height = height
            Img.width = width
            Img.header.frame_id = "camera"

            '''for mono8'''
            Img.encoding = "mono8"
            Img_data = [pix for pixdata in [im.getdata()] for pix in pixdata]
            Img.step = Img.width


            Img.data = Img_data
            bag.write('camera/image_raw', Img, Stamp)
    finally:
        bag.close()

if __name__ == "__main__":
      print(sys.argv)
      CreateBag(sys.argv[:])
           

這個直接使用python運作就可以了,不需要ros的幫助,但是前提是你已經裝了ros,而且将ros的環境變量類的寫進了bash檔案.

運作指令:

python img2bag_Mars_imu.py /home/***/***/dataset/Mars/Regular_1/img_data/left /home/***/***/dataset/Mars/Regular_1/imu_data.txt /home/***/***/test.bag /home/***/***/dataset/Mars/Regular_1/img_data/timestamps.txt
           

第一個參數是image的檔案夾名稱,第二個參數是IMU的資料,第三個參數是你要生成的rosbag的名稱,第四個是image的時間戳.

這種方法最先在這裡看到.

以上,就是自己折騰了将近兩天的結果了,雖然最後測試的效果不是很好,至少資料進行了處理.希望對大家有用.

轉載請著名出處.

繼續閱讀