事件相机(Event-based camera)模拟器ESIM配置及使用指南

144
0
2020年12月16日 09时13分

事件相机的原理和特性在此处不解释,本文只讲解如何配置和使用事件相机模拟器。模拟器是用线性插值和高斯噪声扰动的方式,模拟出事件流来。因此需要帧率尽可能的高一些。亲自测了以后,和DAVIS事件相机实际对着电脑屏幕拍摄的已经记录的视频没什么差别。

 

模拟器在github网址为:点击这里

 

目录

一、模拟器的配置

可能出错以及解决方案:

继续配置:

二、模拟器的使用

(一)跑通demo:

(二)用自己的视频模拟事件流

(三)从bag中解析数据至txt文件中

 


一、模拟器的配置

首先,安装事件相机模拟器,最基本的要求有两点:

1.(必要)必须安装ROS (这个教程网上已经足够多,本文不再介绍)

2.(可能必要,看情况)挂代理

 


刚开始的步骤,和github安装上的步骤一样,而且一般不会出问题:

 

mkdir -p ~/sim_ws/src && cd ~/sim_ws
catkin init
catkin config --extend /opt/ros/kinetic --cmake-args -DCMAKE_BUILD_TYPE=Release

 

之后安装vcstools:

 

sudo apt-get install python-vcstool

 

之后的三步:

 

cd src/
git clone git@github.com:uzh-rpg/rpg_esim.git
vcs-import < rpg_esim/dependencies.yaml

 

其中,第二步可能会报错:Permission denied (publickey). fatal: Could not read from remote repository.

解决方法为:git push(clone)失败报错:Permission denied (publickey). fatal: Could not read from remote repository.

在解决这个问题之后,安装pcl-ros:

 

sudo apt-get install ros-kinetic-pcl-ros

 

安装glfw:

 

sudo apt-get install libglfw3 libglfw3-dev

 

安装glm:

 

sudo apt-get install libglm-dev

 

继续安装:

 

sudo apt-get install ros-kinetic-hector-trajectory-server

 

执行以下操作:

 

cd ze_oss
touch imp_3rdparty_cuda_toolkit/CATKIN_IGNORE \
      imp_app_pangolin_example/CATKIN_IGNORE \
      imp_benchmark_aligned_allocator/CATKIN_IGNORE \
      imp_bridge_pangolin/CATKIN_IGNORE \
      imp_cu_core/CATKIN_IGNORE \
      imp_cu_correspondence/CATKIN_IGNORE \
      imp_cu_imgproc/CATKIN_IGNORE \
      imp_ros_rof_denoising/CATKIN_IGNORE \
      imp_tools_cmd/CATKIN_IGNORE \
      ze_data_provider/CATKIN_IGNORE \
      ze_geometry/CATKIN_IGNORE \
      ze_imu/CATKIN_IGNORE \
      ze_trajectory_analysis/CATKIN_IGNORE

 

之后,执行关键的一步:

 

catkin build esim_ros

 

这一步非常重要。最后一定要提示所有的都安装了,0个跳过,0个failed,0个abandon。否则使用功能的时候会出错。

 

如果直接就成功了,那么恭喜,跳过我下面这部分的分割线继续看。

 


可能出错以及解决方案:

 

如果有类似如下错误:

 

[ 16%] Performing download step (download, verify and extract) for 'luacov'
-- downloading...
 src='https://github.com/keplerproject/luacov/archive/v0.7.tar.gz'
 dst='/home/build/my_build/external_projects/downloads/v0.7.tar.gz'
 timeout='none'
CMake Error at /home/build/my_build/luacov-prefix/src/luacov-stamp/download-luacov.cmake:21 (message):
 error: downloading
'https://github.com/keplerproject/luacov/archive/v0.7.tar.gz' failed
status_code: 1
status_string: "Unsupported protocol"
log: Protocol "https" not supported or disabled in libcurl
Closing connection -1
make[3]: *** [luacov-prefix/src/luacov-stamp/luacov-download] Error 1
make[2]: *** [CMakeFiles/luacov.dir/all] Error 2
make[1]: *** [CMakeFiles/luacov.dir/rule] Error 2
make: *** [luacov] Error 2

 

那么可以进行如下操作:先进入cmake的目录下,

 

然后:

 

./bootstrap --system-curl
make
sudo make install

 

注意boostrap这个文件夹是在cmake目录下。

 

(实验室有朋友表示,找不到这个cmake的目录。如果你遇到这种情况,你应该去回忆一下,你到底有没有到官网用源码装过Cmake。因为ROS也自带一个Cmake,如果把ROS卸载掉,就不能使用cmake了,那说明你没有装过。应该去官网安装一个Cmake。我随便找个教程:Ubuntu 下cmake的安装(以ubuntu16.04,cmake-3.14.0为例,其他版本也可进行参考)

 

执行完上面的操作后,在刚刚的sim_ws文件夹下重新:

 

catkin build esim_ros

 

检查是否是否所有的都被安装了。如果仍然有错误(一般就是那个assimp有问题),那么参见:

ubuntu下配置ss教程

 

要按我教程中的去做。(这个链接已经打不开了,相关内容不让发,总之是想挂上out网,所以各位自己想办法吧,国内的网配这个可能有点问题)

 

做完以后,之后重新执行该指令:(proxychains是一个指令,在终端里访问那什么的。把网的事情搞定了,这个指令不用也行,直接catkin build esim_ros即可)

 

proxychains catkin build esim_ros

 

可以看到所有的都被安装了,0个fail,0个abondan。

 


继续配置:

 

在执行完catkin build指令后,

 

echo "source ~/sim_ws/devel/setup.bash" >> ~/setupeventsim.sh
chmod +x ~/setupeventsim.sh

 

然后打开bashrc文件:

 

sudo gedit ~/.bashrc

 

在bashrc文件最末尾,加上这句话:

 

alias ssim='source ~/setupeventsim.sh'

 

二、模拟器的使用

 

这里只讲解,如何根据video,模拟生成对应的模拟事件流rosbag。(即:Simulating events from a video)

模拟器其余功能的介绍见 事件相机(Event-based camera)模拟器功能介绍

 

(一)跑通demo:

 

mkdir -p /tmp/cheetah_example
cd /tmp/cheetah_example

 

这里保存在根目录的tmp文件下,重启后会自动删除。之所以样例中会这样,可能是因为这样路径长度比较短。

然后,下载安装这个:

 

pip install youtube-dl

 

这个不挂代理也能成功的装上。

 

youtube-dl https://youtu.be/THA_5cqAfCQ -o cheetah

 

上面这步相当于是下载视频,然后保存名字为cheeetah。要想这步执行成功,必须按照上面配置的ss方法中,把终端也挂上代理。实测发现proxychains这个指令在这不顶用了,还是应该开启代理,然后在当前终端里输入

 

export http_proxy=socks5://127.0.0.1:1080

 

(这个是按照你自己的代理设置配的)

 

然后重新执行上面的下载视频指令。

 

切割视频:

 

ffmpeg -i cheetah.mkv -ss 00:02:07 -t 00:00:40 -async 1 -strict -2 cheetah_cut.mkv

 

resize视频:

 

ffmpeg -i cheetah_cut.mkv -vf scale=640:-1 -crf 0 cheetah_sd.mkv

 

然后预处理:

 

mkdir frames
ffmpeg -i cheetah_sd.mkv frames/frames_%010d.png

 

之后决定启动模拟器(一定要打开,在当前终端有效,否则之后会报错):

 

ssim

重新开启一个终端,把roscore也打开:

 

roscore

 

然后回到之前的终端,执行:

 

roscd esim_ros
python scripts/generate_stamps_file.py -i /tmp/cheetah_example/frames -r 1200.0

 

然后执行:

 

rosrun esim_ros esim_node \
 --data_source=2 \
 --path_to_output_bag=/tmp/out.bag \
 --path_to_data_folder=/tmp/cheetah_example/frames \
 --ros_publisher_frame_rate=60 \
 --exposure_time_ms=10.0 \
 --use_log_image=1 \
 --log_eps=0.1 \
 --contrast_threshold_pos=0.15 \
 --contrast_threshold_neg=0.15

 

(如果这一步提示,没有找到esim_node,首先要判断,在当前终端里有没有执行ssim这个指令启动模拟器,有没有在外面打开roscore。如果还是找不到,说明最之前的catkin build就没有成功,回到上面重新弄吧!)

 

重新开启终端:

 

rosrun dvs_renderer dvs_renderer events:=/cam0/events

 

重新开启终端:

 

rosbag play /tmp/out.bag -l -r 0.1.

 

然后重新开启终端:

 

rqt_image_view /dvs_rendering

 

可以看到一个豹子在上面跑。这样样例的demo就跑通了。

 


(二)用自己的视频模拟事件流

 

这个如果需要切割,或者resize,就可以模仿样例中的ffmpeg使用方式来。这个不属于模拟器的范畴。

 

反正,首先,把你要用的视频,(未必是样例中的mkv格式,mp4什么的都可以),拷贝到home下面的文件夹下。(因为样例中的tmp文件夹重启后会清空。

 

例如,拷贝到/home/zhaokai/sim_ws/MOT/下:

 

这样sim_ws下面有一个名为MOT的文件夹,里面放着一个视频,例如:MOT16-04.mp4

 

然后:

 

cd /home/zhaokai/sim_ws/
mkdir frames
ffmpeg -i MOT16-04.mp4 frames/frames_%010d.png

 

然后发现ffmpeg把视频拆成了帧,放到了frames文件夹下。

 

ssim
roscd esim_ros
python scripts/generate_stamps_file.py -i /home/zhaokai/sim_ws/MOT/frames -r 1200.0

 

注意:

1.这里路径是不认“~”这种符号的。如果写成了 ~/sim_ws会报错的,要从根目录下面开始写。

 

2.1200表示的是输入视频的帧率。如果你不知道输入视频的帧率,那就可以打开那个视频,看看时长。然后看看frames文件夹下拆成了多少帧,二者一除就知道了。

 

之后,执行模拟器指令(要确保另一个终端里开着roscore)

 

rosrun esim_ros esim_node \
 --data_source=2 \
 --path_to_output_bag=/home/zhaokai/sim_ws/MOT/out.bag \
 --path_to_data_folder=/home/zhaokai/sim_ws/MOT/frames \
 --ros_publisher_frame_rate=60 \
 --exposure_time_ms=10.0 \
 --use_log_image=1 \
 --log_eps=0.1 \
 --contrast_threshold_pos=0.15 \
 --contrast_threshold_neg=0.15

 

指令的介绍见github上的解释。

这样执行完,就生成了一个out.bag文件。

然后还是和之前跑样例一样,开一个新的终端:

 

rosrun dvs_renderer dvs_renderer events:=/cam0/events

 

这里 -l 表示是循环播放。-r表示是慢速播放。如果你想跟原视频同步,那么把 指令中的-r 0.1给去掉。

 

开一个新的终端:

 

rqt_image_view /dvs_rendering

 

可以看到你的视频模拟成了事件流。

 

最后的输出保存在bag文件中。如果想把其中的事件,读成txt文本的形式,读出其中模拟的的x,y,p,t,需要解析bag包。


(三)从bag中解析数据至txt文件中

 

记录为bag后,不太熟悉ros的或者只专注于图像的同学可能对于如何把这个bag解析为txt文件有些疑惑。我刚刚接触的时候也比较疑惑,一个月前我对ros就懂一些皮毛。在这个上面走了一些弯路,特意把过程记录在这里,一个目的是能帮助到大家,第二个目的是方便我回头再看。(因为不写下来的话很快就会忘记)

 

先分析一下,播放这个bag文件:

 

ssim
rosbag play out.bag -l -r 0.1

 

然后再开启一个终端:

 

rostopic list

 

可以看到,输出为:

 

/cam0/camera_info
/cam0/events
/cam0/image_corrupted
/cam0/image_raw
/clock
/rosout
/rosout_agg

 

很明显,播放的话题就是这个/cam0/events

 

我们需要看一下这个话题的格式:

 

rostopic type /cam0/events

 

可以看到输出为:

 

dvs_msgs/EventArray

 

或者用info语句来看:

 

rostopic info /cam0/events

 

可以看到输出为:

 

Type: dvs_msgs/EventArray

Publishers:
* /play_1579125764739259831 (http://zhaokai-System:33439/)

Subscribers: None

 

这时,两种方式都显示话题/cam0/events的发布类型为:dvs_msgs/EventArray

 

因此,再用rosmsg查看一下这个类型的具体内容:

 

rosmsg show dvs_msgs/EventArray

 

或者也可以直接用roscd指令,到具体文件夹下拿vi指令去查看这个类型的定义:

 

roscd dvs_msgs
ls
cd msg
vi EventArray.msg

 

可以看到输出为:

 

std_msgs/Header header
uint32 seq
time stamp
string frame_id
uint32 height
uint32 width
dvs_msgs/Event[] events
uint16 x
uint16 y
time ts
bool polarity

 

现在我们要做的就是把里面的events给保存到txt当中。

 

弯路:

 

刚开始我打算写一个监听程序,把顺便把内容给记录下来。由于CPP版本的程序还需要再编译,所以随手写了一个脚本,想在callback里面把它记录在txt当中。先随便试了一下,随便打印点什么东西:

 

#!/usr/bin/env python
import rospy
from std_msgs.msg import String
from dvs_msgs.msg import EventArray
 
EVENT=[]
 
def callback(data):
    #events=data.events
    #global EVENT
    #EVENT.append(events)
    global flag
    a=data.header.stamp
    if(flag):
        print("first msg")
        first=a
        flag=False
    else:
        print(a)
    
 
def listener():
 
    # In ROS, nodes are uniquely named. If two nodes with the same
    # node are launched, the previous one is kicked off. The
    # anonymous=True flag means that rospy will choose a unique
    # name for our 'listener' node so that multiple listeners can
    # run simultaneously.
    rospy.init_node('listener', anonymous=True)
 
    rospy.Subscriber("/cam0/events", EventArray, callback)
 
    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()
 
if __name__ == '__main__':
    flag=True
    listener()

 

结果发现打印频率和监听频率对不上,每次输出的都不太一样(有的给漏掉了),说明不能用这这种方法。后来听别人的,又在rospy.Subscriber(“/cam0/events”, EventArray, callback)中加了一堆消息队列和缓冲序列,还是有问题。

 

通过这种方式在终端中运行python脚本,首先是需在终端中启用ssim,其次,如果安装了anaconda的话,需要在~/.bashrc下面把anaconda的环境变量注释掉。python3是不能用rospy的,会报错,找不到rospkg。因此在命令行里的python应该是python2才行,所以需要去掉环境变量中的anaconda去掉,让默认启动的python是2而不是3。

 

之后又想通过matlab解析这个bag包,结果用github上的开源版本,bug一堆,关键这个消息还是自己定义的,可谓浪费时间。(还花了段时间在ubuntu下面装matlab,感觉自己简直像弱智)

 

最后,发现python本来就有方法读取,rosbag就可以了。至于里面的数据结构怎么定义的,可以拿关键字“dir”写在脚本里看一下。试了好一会,最后写完的代码如下:

 

#!/usr/bin/env python
import rosbag
from tqdm import tqdm
bag=rosbag.Bag('out.bag')
with open("out.txt",'w') as f: 
    for i,(topic,msgs,t) in enumerate(bag.read_messages(topics=['/cam0/events'])):
        for single_event in tqdm(msgs.events):  
            f.write(str(single_event.ts.secs+single_event.ts.nsecs*1.0/1000000000)+' ')         
            f.write(str(single_event.x)+' ')
	    f.write(str(single_event.y)+' ')
            if(single_event.polarity==True):        
	        f.write("1")
            else:
                f.write("0")
	    f.write('\n')  
        print("Writing events between two pic, now is "+ str(i)+'!')
print("Writing is over!")
bag.close()

 

把这个文件命名为reader.py,放置在生成的out.bag同一路径下。

 

注意,为了可视化进度,我安装了tqdm。安装指令:

 

pip install tqdm

 

之后通过如下指令,解析bag,记录到txt中:

 

ssim
python reader.py

 

发表评论

后才能评论