转载请注明出处,谢谢

原创作者:Mingrui

原创链接:https://www.cnblogs.com/MingruiYu/p/12404730.html


本文要点:

  • ROS 配置安装

    • 解决 sudo rosdep init 报错 Website may be down.
  • ORB-SLAM2 ROS 配置安装
    • 解决报错 DSO missing from command line
  • Android 手机摄像头与 PC 进行基于 ROS 的通信
  • 手机摄像头标定
    • 采集标定图像
    • OpenCV samples 相机标定例程
  • 使用 Android 手机摄像头,运行 ORB-SLAM2 ROS Mono
  • 简化启动
    • 使用 gnome-terminal,一个脚本运行多个终端

写在前面

最近研究 ORB-SLAM2,自然是想能自己实时跑一跑。但最近因为疫情只能待在家里,身边能当摄像头的东西好像只有笔记本摄像头和手机摄像头。笔记本摄像头不方便(特别是我的 matebook 14 这个在键盘上的弹出摄像头,如想实现可参考),所以选择使用手机摄像头。ORB-SLAM2 官方提供了 ROS 的支持,再结合网上各路大佬提供的工具,最终实现了以 Android 手机摄像头为输入,基于 ROS 在 PC 上实时运行 ORB-SLAM2 Mono。本文将从零开始,介绍如何实现这一目标。

本文环境为:

  • Ubuntu 18.04
  • ROS Melodic
  • Android 手机(MI 9 SE)

ROS 配置安装

首先是 ROS 的配置安装,参照 ROS 官方安装教程,其中第一步使用国内镜像:

sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu/ $DISTRIB_CODENAME main" > /etc/apt/sources.list.d/ros-latest.list'

sudo rosdep init 出错

安装步骤中 sudo rosdep init 报错:

ERROR: cannot download default sources list from:
https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/sources.list.d/20-default.list
Website may be down.

首先试一试在浏览器中能不能打开,如果打不开的话,说明该网站需要翻。

因为在终端中安装,所以光浏览器能翻不够,还得配置终端翻。如果使用的是 ss 的话,终端还需要额外配置。配置方法可自行 google。

成功配置终端后,如果还报这个错,则需要:

sudo c_rehash /etc/ssl/certs
sudo -E rosdep init

之后再 rosdep update 就可以了。

学习教程

ROS-Tutorials

ORB-SLAM2 ROS 配置安装

编译

ORB-SLAM2 的配置安装可见 raulmur/ORB_SLAM2。之前的博文 ORB-SLAM2 初体验 —— 配置安装 中介绍了不包括 ROS 支持的 ORB-SLAM2 配置安装。包括 ROS 支持的配置安装可见 raulmur/ORB_SLAM2#7-ros-examples

在 ~/.bashrc 中添加 ORB-SLAM2 path 至 ROS_PACKAGE_PATH

# 打开 ~/.bashrc
sudo gedit ~/.bashrc # 添加
export ROS_PACKAGE_PATH=${ROS_PACKAGE_PATH}:PATH/ORB_SLAM2/Examples/ROS
# (注意修改 PATH 为自己 ORB-SLAM2 的目录)

NOTICE:

  • ${ROS_PACKAGE_PATH}:和PATH之间不能有空格。
  • 添加的位置要在之前添加的其它的 source 命令之后。

之后进行编译:

cd PATH/ORB_SLAM2
chmod +x build_ros.sh ./build_ros.sh

会报错:DSO missing from command line

解决方法:ERROR while running ./build_ros.sh #535

运行

例如运行单目 ORB-SLAM2:

rosrun ORB_SLAM2 Mono PATH_TO_VOCABULARY PATH_TO_SETTINGS_FILE

下文会详细介绍如何运行。

Android 手机摄像头与 PC 进行基于 ROS 的通信

该实现基于 GitHub 上的一个项目:hitcm/Android_Camera-IMU,作者实现了将手机的摄像头信息和 IMU 信息传给 PC(可参考作者博文 ROS实时采集Android的图像和IMU数据)。本文中,我们只需使用摄像头信息。

git clone https://github.com/hitcm/Android_Camera-IMU.git

sudo apt-get install ros-melodic-imu-tools  # 修改对应自己的 ROS 版本(本文中其实不需要)

将 clone 下来的文件夹中已经编译好的 apk 拷到 Android 手机上,在手机上安装。并将 PC 和 Android 手机 置于同一局域网下。

运行方式:

PC Terminal 1: roscore

Android: 打开应用,在 在 IP Port 中修改 IP 地址为 PC的 IP地址,port不需要修改(PC 的 IP 可在 PC 终端输入 ifconfig 查看),之后点击 Connect,连接成功则进入相机界面。

PC Terminal 2:

cd Android_Camera-IMU
roslaunch android_cam-imu.launch

之后会弹出一个 Rviz 界面:

  • 如果要实时显示 image,需要 Add - By topic - 添加/camera/image_raw/image。
  • 如果要显示 imu,则需要 Add - By topic - 添加 imu,且在 Fix Frame 中 将 map 改为 imu。

手机摄像头标定

为了 ORB-SLAM2 准确运行,需要对手机摄像头进行标定。标定方式为:对棋盘格标定板进行各个方向的拍照,之后基于 OpenCV 进行标定。注意这里采集的图片需要和 ORB-SLAM2 程序读取到的一致,所以不能直接使用手机自带相机 app 拍照,因为手机会自动通过算法进行校正,而上述通信传输的是 raw images。因此,首先我们需要完成的任务是:采集并保存摄像头图像。

使用下图作为标定板(参考资料),可直接在电脑屏幕上显示,对其拍照即可。

注意:

  • 实验发现,使用长宽格数不一样的棋盘标定板效果更好。
  • 实验发现,标定板周围要是白色的才行,黑色的提取不出角点来(在电脑屏幕上显示标定板时尤其需要注意)。
  • 摄像头需要从不同方向拍摄棋盘格,可参考 OpenCV 安装目录下 samples/data 中的 left0x.jpg 系列标定图片。

采集并保存图片

目前没有找到直接保存的方法,所以我们选择写一个 ROS node 来接收手机传来的图像,再通过 OpenCV 进行显示和保存。

为了方便,我们选择直接在 ORB-SLAM2 的 ros_mono.cc 的代码基础上进行修改,在 ros_mono.cc 同一目录下写了个 ros_camera_capture.cc:

/**
* This file is to capture images from Android phone, for camera calibration
* This file is used with Android_Camera-IMU
*/ #include<iostream>
#include<algorithm>
#include<fstream>
#include<chrono> #include<ros/ros.h>
#include <cv_bridge/cv_bridge.h> #include<opencv2/core/core.hpp> #include"../../../include/System.h" using namespace std; string save_dir = "PATH"; // 修改为自己保存图片的路径
int imgId = 0; void GrabImage(const sensor_msgs::ImageConstPtr& msg); int main(int argc, char **argv)
{ std::cout << "To save the current frame, please press 'Q' or 'q' " << std::endl;
std::cout << "The images will be saved to " << save_dir << std::endl; ros::init(argc, argv, "PClistener");
ros::start(); ros::NodeHandle nodeHandler;
ros::Subscriber sub = nodeHandler.subscribe("/camera/image_raw", 1, GrabImage); ros::spin(); ros::shutdown(); return 0;
} void GrabImage(const sensor_msgs::ImageConstPtr& msg)
{
string imgname;
cv_bridge::CvImageConstPtr cv_ptr;
try
{
cv_ptr = cv_bridge::toCvShare(msg);
cv::Mat img = cv_ptr->image;
cv::imshow("img_name", img); char key = cv::waitKey(1);
// press "q" to save the image
if(key == 'q' || key == 'Q'){
imgId++;
imgname = "img_" + to_string(imgId) + ".jpg";
cv::imwrite(save_dir + imgname, img);
std::cout << "has saved image "<< imgId << " to " << save_dir << std::endl;
}
}
catch (cv_bridge::Exception& e)
{
ROS_ERROR("cv_bridge exception: %s", e.what());
return;
}
}

注意修改其中保存图像的目录。

另外,在 ORB_SLAM2/Examples/ROS/ORB_SLAM2 目录中的 CMakeLists.txt 中添加如下内容(添加在 # Node for monocular camera 上方即可):

# Node for capture images for camera calibration
rosbuild_add_executable(CameraCapture
src/ros_camera_capture.cc
) target_link_libraries(CameraCapture
${LIBS}
)

之后重新编译 ORB_SLAM2 项目。

cd PATH/ORB_SLAM2
./build_ros.sh

使用方法:

Terminal 1:

roscore

手机进入 app 运行

Terminal 2: 在 Android_Camera-IMU 目录

roslaunch android_cam-imu.launch

(可以关掉 Rviz)

Terminal 3:

rosrun ORB_SLAM2 CameraCapture

鼠标选中图像框,按下 q 键保存图像。

进行标定

使用 OpenCV samples 中的代码实现。参考资料

标定例程

新建一个工作目录(文件夹)camera_calibration_opencv,将 OpenCV 安装目录中的 samples/cpp/tutorial_code/calib3d/camera_calibration 文件夹内的内容拷贝至该目录。

修改 VID5.xml

VID5.xml 中存储着标定图像的路径,所以要在 VID.xml 中添加所有标定图像的路径,eg:

<?xml version="1.0"?>
<opencv_storage>
<images>
PATH/img_1.jpg
PATH/img_2.jpg
PATH/img_3.jpg
</images>
</opencv_storage>

修改 in_VID5.xml

<BoardSize_Width> 9</BoardSize_Width>
<BoardSize_Height>6</BoardSize_Height>

表示棋盘格的宽和高,注意,这里的宽度和高度是指内部交叉点的个数,而不是方形格的个数。如上图棋盘的数据就是9和6。

<Square_Size>20</Square_Size>

修改为每格的边长 (mm),拿尺子量。

<Input>"VID5.xml"</Input>

修改 VID5.xml 的路径。

<Calibrate_FixPrincipalPointAtTheCenter> 1 </Calibrate_FixPrincipalPointAtTheCenter>

此处原来是0,需要改为1,表示引入切向畸变参数(因为 ORB-SLAM2 中也引入了切向畸变参数),否则只有径向畸变参数。

其它地方应该不需要改动,想进一步了解可看其中的注释。

编译

在工作目录 camera_calibration_opencv 中新建 CMakeLists.txt:

project(Camera_Calibration)
set(CMAKE_CXX_STANDARD 11) find_package(OpenCV 3.0 QUIET)
if(NOT OpenCV_FOUND)
find_package(OpenCV 2.4.3 QUIET)
if(NOT OpenCV_FOUND)
message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
endif()
endif() include_directories(${OpenCV_INCLUDE_DIR})
add_executable(Camera_Calibration camera_calibration.cpp)
target_link_libraries(Camera_Calibration ${OpenCV_LIBS})

之后编译:

cd camera_calibration_opencv
mkdir build
cd build
cmake ..
make

运行,标定

cd camera_calibration_opencv
./build/Camera_Calibration in_VID5.xml

程序启动后会显示标定图像的角点提取情况,之后会显示校正后图像,一个一个全部关闭后才会保存标定参数至 out_camera_data.xml。

参数填入 ORB-SLAM2 的配置文件

参数输出在 out_camera_data.xml 中:

  • <camera_matrix type_id="opencv-matrix"> 是相机内参矩阵,顺序为 fx, 0, cx; 0, fy, cy; 0, 0, 1。
  • <distortion_coefficients type_id="opencv-matrix"> 是畸变参数,其顺序为 k1, k2, p1, p2, k3。

之后在 ORB_SLAM2 中新建一个配置文件 AndroidPhone.yaml(建哪儿都行,我为了方便就和 TUM1.yaml 放在了一个目录下),将 TUM1.yaml 的内容拷贝过来,并把其中的 Camera 参数进行修改。

注意: 相机参数对 ORB-SLAM2 的运行效果有极大影响(尤其是初始化),所以标定过程须认真完成。

运行 ORB-SLAM2 Mono

Terminal 1:

roscore

手机进入 app 运行

Terminal 2: 在 Android_Camera-IMU 目录

roslaunch android_cam-imu.launch

(可以关掉 Rviz)

Terminal 3:

rosrun ORB_SLAM2 Mono PATH_TO_VOCABULARY PATH_TO_SETTINGS_FILE

运行效果展示:

注意: ORB-SLAM2 Mono 还是比较难以初始化的(其设置的初始化条件相对苛刻),在开始时,选择特征纹理丰富的区域,多上下左右平移相机,有利于初始化。

简化启动

上述启动步骤需要启动3个终端,挺麻烦的,所以可以选择写一个脚本来自动启动这3个终端。参考资料

新建 ORB_SLAM2_with_AndroidPhone.sh,在其中填入:

gnome-terminal --title="roscore" -x bash -c "roscore"
# 暂停 2s,保证几个不同终端的启动顺序
sleep 2s; gnome-terminal --title="AndroidPhone" -x bash -c "cd PATH/Android_Camera-IMU; roslaunch android_cam-imu.launch"
sleep 2s; gnome-terminal --title="ORB-SLAM2" -x bash -c "rosrun ORB_SLAM2 Mono PATH_TO_VOCABULARY PATH_TO_SETTINGS_FILE"

之后赋予权限(仅需一次):

chmod +x ORB_SLAM2_with_AndroidPhone.sh

运行:

./ORB_SLAM2_with_AndroidPhone.sh

即可一次性打开3个终端,并运行相关命令。之后手机再打开 app 就可以了。

注意: 此时终端运行结束后会自动退出,如果不想自动退出,可 在terminal点右键,选择Profiles->Profile Preferences然后找到Title and Command,里面有一项When command exits,后面选择为Hold the terminal open。参考资料

参考资料

ORB-SLAM2 系列博文

ORB-SLAM2 系列博文

ORB-SLAM2 运行 —— ROS + Android 手机摄像头的更多相关文章

  1. DSO 运行 —— dso_ros + Android 手机摄像头

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12425855.html 本文要点: dso 配置安装 dso 离线 ...

  2. Android手机摄像头编程入门

    本讲内容:Android手机摄像头编程入门智能手机中的摄像头和普通手机中的摄像头最大的区别在于,智能机上的摄像头可以由程序员写程序控制, 做一些有趣的应用譬如,画中画,做一些有用的应用譬如二维码识别, ...

  3. 关于降低android手机摄像头预览分辨率

    假设现在有这样一个需求需要一直开着手机摄像头 但是不做任何拍照动作 但是每个手机的相机分辨率都不同 而默认预览的时候参数是最大分辨率 这样有时候就回导致电量损耗的加快 所以我们可以采取降低相机分辨率的 ...

  4. Android 手机上安装并运行 Ubuntu 12.04

    ubuntu.sh脚本的原地址变动了,导致下载不了,现在更新了网盘地址.小技巧:遇到一些下载失效的时候可以试一试p2p下载工具(如 easyMule.迅雷等)试一试,说不定有人分享过~* —————— ...

  5. android 通过wifi 热点实现手机摄像头数据共享(转)

    原文地址:http://blog.csdn.net/sinat_35845281/article/details/52674946 最近想搞一个新奇的玩意儿~~~ 最近一直在在学习通过两个Androi ...

  6. Ubuntu14.04 使用本地摄像头跑ORB SLAM2(暂未完成)

    嗯 这个方法我暂时弄不出来,用了另外一个方法:SLAM14讲 第一次课 使用摄像头或视频运行 ORB-SLAM2 前面的准备: Ubuntu14.04安装 ROS 安装步骤和问题总结 Ubuntu14 ...

  7. win7 cmd终端连接android手机运行adb shell脚本命令

    win7 cmd终端连接android手机运行adb shell脚本命令 (2013-03-22 20:13:57) 转载▼ 标签: android it shell 连接 linux 分类: 嵌入式 ...

  8. [Android相机]通过手机摄像头识别环境亮度(转)

    源: [Android相机]通过手机摄像头识别环境亮度 iOS利用摄像头获取环境光感参数

  9. appium常见问题05_修改Android手机运行环境(adb指令修改hosts)

    自动化测试过程中,手机有时会跳网,怎样保持手机测试的环境稳定性,可以通过adb指令修改android手机hosts,保持手机运行在hosts中配置的环境中: 修改方法如下: 前提条件:已安装andro ...

随机推荐

  1. Opencv笔记(三)——视频的获取及保存

    一.利用摄像头获取视频 我们经常需要使用摄像头捕获实时图像.OpenCV 为这中应用提供了一个非常简单的接口.让我们使用摄像头来捕获一段视频,并把它转换成灰度视频显示出来.了获取视频,你应该创建一个 ...

  2. Sqlite教程(4) Activity

    之前我们已经有了DbHelper.Data Access Object.Configuration. 那麽现在就是由Activity去创建它们,然後就可以存取Sqlite. 架构图表示了它们的关系. ...

  3. spring自定义controller全局异常拦截

    --异常类可以按需要自定义package com.dhht.wechat.exception; import com.alibaba.fastjson.JSONObject;import org.sp ...

  4. fastjon案例

    --json为json串JSONObject obj = JSON.parseObject(json);String x = obj.getString("cropId");JSO ...

  5. mui a链接的点击

    mui里面,使用click点击在有时候是无效的,或者点击的位置错位.在别处点击才有效. mui中对a的点击应该这样写: mui('body').on('tap', "#chart" ...

  6. c# winForm 将窗体状态栏StatusStrip 分成左中右三部分 右边显示当前时间

    实现效果:通过StatusStrip显示窗体状态栏同时将状态栏分成三部分居左边显示相关文字信息中间空白显示居右边显示时间信息 1.创建窗体及添加StatusStrip  默认StatusStrip名称 ...

  7. day42-进程池

    #进程池Pool:apply apply_async-close-join-get map callback #1.进程池Pool:执行下面代码发现任务012先执行,345后执行,因为进程池只有3个进 ...

  8. 前端-jQuery-长期维护

     ###############    jQuery简介     ################ jQuery这是非常重要的,在django项目中大量的前端都是使用jQuery进行操作 为什么要学习 ...

  9. webservice入门程序学习中经验总结

    ***第一步:创建客户端服务 1)创建一个服务接口 2)创建一个实现类实现接口 3)创建一个方法开启服务 这三步注意点:::实现类上必须添加@WebService标签 :::发布服务的时候用到的函数是 ...

  10. MOOC(7)- case依赖、读取json配置文件进行多个接口请求-模拟接口响应数据(18)

    这里是把传入的请求数据作为响应值返回 # -*- coding: utf-8 -*- # @Time : 2020/2/15 9:47 # @File : do_mock_18.py # @Autho ...