因為很多的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的節點中去了.
- 在你編譯的指令行視窗新開一個視窗,保證其是在 /image_transport_ws 這個路徑下的,然後運作:
- 在你編譯的指令行視窗新開一個視窗,保證其是在 /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步.
- 檢視節點
輸出如下内容:(根據有些插件的不同可能輸出不同,但是隻要具有查不多的就好)
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
- 訂閱節點
$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的時間戳.
這種方法最先在這裡看到.
以上,就是自己折騰了将近兩天的結果了,雖然最後測試的效果不是很好,至少資料進行了處理.希望對大家有用.
轉載請著名出處.