1. 程式人生 > >ORB-SLAM2 執行 —— ROS + Android 手機攝像頭

ORB-SLAM2 執行 —— ROS + Android 手機攝像頭

轉載請註明出處,謝謝
原創作者: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
./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

(可以關掉 rvis)

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。參考資料

參考資料

  • 在Ubuntu 18.04 LTS安裝ROS Melodic
  • sudo rosdep init出錯的解決方案
  • sudo rosdep init 錯誤
  • ERROR while running ./build_ros.sh #535
  • ubuntu16.04下用筆記本攝像頭和ROS編譯執行ORB_SLAM2的單目AR例程
  • ROS實時採集Android的影象和IMU資料
  • OpenCV 相機引數標定(Camera Calibration
  • 採集Android手機攝像頭執行ORB_SLAM2(ubuntu16.04+ROS kinetic
  • ubuntu下通過命令開啟多個終端並在相應終端執指令
  • gnome-terminal

ORB-SLAM2 系列博文

ORB-SLAM2 系列博