1. 程式人生 > >“一起做RGB_D SLAM”學習筆記(123)

“一起做RGB_D SLAM”學習筆記(123)

一直在蒙著頭跑程式,之前只會複製貼上,真正從頭開始才發現之前根本沒理解,現將學習記錄如下:

PS:此篇僅為高博一起做RGB_D SLAM的學習記錄,感謝高博~

1.1寫CMakeLists.txt時:

  • 我們前面建立的這幾個分立的資料夾,本身其實是沒有任何聯絡的,要想產生聯絡(變成有關係分工的一個工程),就是通過CMakeLists.txt建立聯絡的。
CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) #設定版本
PROJECT( slam ) #設定工程名
SET( CMAKE_CXX_COMPILER "g++") #設定編譯器
	
#設定可執行二進位制檔案的目錄
SET( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 
	
#設定存放編譯出來的庫檔案的目錄
SET( LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) 
#並且把該目錄設為連線目錄
LINK_DIRECTORIES( ${PROJECT_SOURCE_DIR}/lib)
	
#設定標頭檔案目錄
INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/include)
	
#增加子資料夾,也就是進入原始碼資料夾繼續構建;lib bin資料夾中無
ADD_SUBDIRECTORY( ${PROJECT_SOURCE_DIR}/src)
  • 二進位制就是可以直接執行的程式啦,庫檔案呢,就是為這些二進位制提供函式的啦。有main函式的程式碼可以編譯成二進位制,其他的則編譯成庫檔案。連結時,把庫檔案鏈到二進位制上,就可以執行啦。
  • 上文中提到的,跳至src子資料夾中繼續構建,所以在src中還需要有一個CMakeLists.txt(Cmake實踐中說,需要為任何子目錄建立一個 CMakeLists.txt。這裡的子目錄也就是在上層CMakeLists.txt中新增的子目錄,而不是指工程中任何一個子目錄,比如承接庫檔案和可執行檔案的bin和lib資料夾中就沒有)。  
  • 每級資料夾中的CMakeLists.txt主要負責對所在資料夾中的檔案或資料夾進行操作,比如專案根目錄RGBD-SLAM中的,串聯各個目錄,設定輸出位置和標頭檔案引用目錄等工作。src中的CMakeLists.txt就只操作src中的main.cpp,用其新增一個可執行檔案。 參考:
    RGBD-SLAM學習1
  • 上級CMakeLists.txt新增的子目錄,子目錄中必須要有CMakeLists.txt!

1.2 make編譯main函式時報錯

/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o:在函式‘_start’中:
(.text+0x20):對‘main’未定義的引用
collect2: error: ld returned 1 exit status
make[2]: *** [../bin/main] 錯誤 1
make[1]: *** [src/CMakeFiles/main.dir/all] 錯誤 2
make: *** [all] 錯誤 2

解決:重新打了一遍main.cpp中的int main


2.1  Kinect(或其他rgb-d相機)裡直接採到的RGB圖和深度圖存在的問題:

  • 有一些時差(約幾到十幾個毫秒)。這個時差的存在,會產生“RGB圖已經向右轉了,怎麼深度圖還沒轉”的感覺。
  • 光圈中心未對齊。因為深度畢竟是靠另一個相機獲取的,所以深度感測器和彩色感測器引數可能不一致。
  • 深度圖裡有很多“洞”。因為RGB-D相機不是萬能的,它有一個探測距離的限制啦!太遠或太近的東西都是看不見的。關於這些“洞”,我們暫時睜一隻眼閉一隻眼,不去理它。以後我們也可以靠雙邊bayes濾波器去填這些洞。但是!這是RGB-D相機本身的侷限性。軟體演算法頂多給它修修補補,並不能完全彌補它的缺陷。

2.2 data資料夾放置位置

//這樣的話,date資料夾應在build資料夾下(或專案資料夾)
rgb=cv::imread("./data/rgb.png");
depth=cv::imread("./data/depth.png",-1);
//生成的.pcd檔案也在build資料夾下
pcl::io::savePCDFile( "./pointcloud.pcd", *cloud );

可改為

//重新編譯執行,則在專案資料夾中
rgb=cv::imread("../data/rgb.png");
depth=cv::imread("../data/depth.png",-1);
pcl::io::savePCDFile( "../pointcloud.pcd", *cloud );

2.3遍歷深度圖--先列後行!!!

 for(int m=0;m<depth.rows;m++)
	for(int n=0;n<depth.cols;n++)
  • 我們使用OpenCV的imread函式讀取圖片。在OpenCV2裡,影象是以矩陣(cv::MAt)作為基本的資料結構。Mat結構既可以幫你管理記憶體、畫素資訊,還支援一些常見的矩陣運算,是非常方便的結構。
  • 彩色影象含有R,G,B三個通道,每個通道佔8個bit(也就是unsigned char),故稱為8UC3(8位unsigend char, 3通道)結構。而深度圖則是單通道的影象,每個畫素由16個bit組成(也就是C++裡的unsigned short),畫素的值代表該點離感測器的距離。通常1000的值代表1米,所以我們把camera_factor設定成1000. 這樣,深度圖裡每個畫素點的讀數除以1000,就是它離你的真實距離了。

注意:換行符為endl而非end1 !!!

######執行#######

cd ./slam
cd ./build
cmake ..
make

cd ..
./bin/generate_pointcloud
pcl_viewer pointcloud.pcd


3.1 CMakeLists.txt新增書寫

##在lib中生成了一個名為libslambase.a的靜態庫檔案,注意,這個庫的名稱叫slambase(add_library中定義的名字),所以後面使用時,連結此庫的時候,就是用它的庫名slambase
ADD_LIBRARY( slambase slamBase.cpp )
TARGET_LINK_LIBRARIES( slambase
    ${OpenCV_LIBS} 
    ${PCL_LIBRARIES} )

# 增加特徵點匹配的可執行檔案
ADD_EXECUTABLE(detectfeatures detectFeatures.cpp )
# 連結上我們自己寫的庫
target_link_libraries(detectfeatures slambase )

  • 一個程式編譯連結之後,並不一定都生成可執行程式,有的是生成了庫,以備其他程式呼叫。所以這兩個有點並行的意味。首先,一個庫要有標頭檔案和庫檔案.
  • CMakelist中,命令名字是不區分大小寫的,而引數和變數是大小寫相關的。在 src/CMakeLists.txt 中加入以下幾行,將 slamBase.cpp 編譯成一個庫,供將來呼叫.

3.2 OpenCV未安裝nonfree模組以至於SIFT演算法不能正常使用引發的錯誤(變為ORB匹配演算法可跳過)

fatal error: opencv2/nonfree/nonfree.hpp: 沒有那個檔案或目錄
 #include <opencv2/nonfree/nonfree.hpp>

安裝&使用opencv的nonfree模組

3.3 由SIFT演算法到ORB演算法的一些改動(參考:RGBD-SLAM學習3

// 宣告特徵提取器與描述子提取器
// 如果使用 sift, surf ,之前要初始化nonfree模組
// cv::initModule_nonfree();
// _detector = cv::FeatureDetector::create( "SIFT" );
// _descriptor = cv::DescriptorExtractor::create( "SIFT" );
detector = cv::FeatureDetector::create("ORB");
descriptor = cv::DescriptorExtractor::create("ORB");

cv::FlannBasedMatcher matcher;  //這是高博的
//auto matcher = cv::DescriptorMatcher::create ( "BruteForce-Hamming" );//匹配器matcher的建立要隨動ORB,改成Brute Force match(編譯未通過)

//求解PnP時,solvePnPRansac函式增加了confidence引數:演算法產生有用結果的置信係數。具體改動就是增加一個引數值(這裡就用函式預設值0.99好了):
cv::solvePnPRansac( pts_obj, pts_img, cameraMatrix, cv::Mat(), rvec, tvec, false, 100, 1.0, 0.99, inliers );

######執行#######

cd ..
./bin/detectfeatures

顯示:keypoints<任意鍵>matches<任意鍵>good matches<任意鍵>inlier matches<任意鍵>關閉所有視窗

輸出:

Key points of two images: 500, 500

Find total 500 matches.

min dis = 16.1555
good matches=70
inliers: 31
R=[-0.02381573964575079; 0.03008252220205883; 0.02061441187646476]
t=[0.02775634088144215; 0.008762443617165343; 0.01745294408849403]