很多人对GCNv2比较感兴趣,但是因为这是比较久之前做的测试,具体细节已经遗忘。。。问题无法一一解答,鉴于目前也在orbslam3基础上改东西,最近会再测试一下
=========================================================================
文章写于2021.9.29
由于在实时跑ORB_SLAM3的时候,相机转动过快会LOST,因此采用其他特征点提取方法进行尝试,首先是GCNv2_SLAM。
系统:Ubuntu 18.04
g++:5.x
CUDA:10.2
参考文章:Ubuntu系统pangolin与libtorch所引发的连接错误_feiyang_luo的博客-CSDN博客
GCNv2编译过程中出现的问题_CAFE-BABE的博客-CSDN博客
Pytorch1.4下运行 GCNv2slam 需要修改的地方_马马虎虎半吊子的博客-CSDN博客 (主要参考)
1、首先下载:https://github.com/jiexiong2016/GCNv2_SLAM https://github.com/jiexiong2016/GCNv2_SLAM
(因为版本问题,github提供的pytorch 源码编译方法在编译的时候会报错(ubuntu版本过高或者g++版本低))
2、官网下载libtorch,和CUDA适配,X11 ABI的版本的(pre-X11版本 后续会报错),下载后解压即可,无需构建 (当时下载的1.9.1版本)
3、代码改动:
GCNextractor.h :
//99行
//原
std::shared_ptr<torch::jit::script::Module> module;
//改为
torch::jit::script::Module module;
//270行
//原
auto output = module->forward(inputs).toTuple();
//改为
auto output = module.forward(inputs).toTuple();
CMakeLists.txt
//更改c++编译标准
set(CMAKE_CXX_STANDARD 14)
//在if( TORCH_PATH ) 前加 给一个刚刚下载的路径
set(TORCH_PATH "/home/***/libtorch/share/cmake/Torch")
//最后项目链接 从11改成14
set_property(TARGET rgbd_gcn PROPERTY CXX_STANDARD 14)
4、数据改动
双击打开gcn2_320x240.pt (其他pt文件同理)(无需解压)/gcn/code/'下找到 ‘gcn.py’
#原 这是因为1.3以前默认true 1.3以后默认false
_32 = torch.squeeze(torch.grid_sampler(input, grid, 0, 0))
#改为
_32 = torch.squeeze(torch.grid_sampler(input, grid, 0, 0, True))
#原
_14 = torch.unsqueeze(torch.index(det, [_12, _13]), 1)
#改为
det_flatten = torch.flatten(det, start_dim=0, end_dim=-1)
_12_13 = _12*320+_13
_14 = torch.unsqueeze(torch.index_select(det_flatten, 0, _12_13),1)
我猜测 _14是根据待选特征点的横纵坐标_12 _13,在分数矩阵det中提取待选特征点的分数。 index在这个地方因为版本更迭导致作用失效(我就没找到index的说明文档在哪里。。)。所以直接将dat展平,利用index_select提取0维度上的点的值。
5、编译GCNv2_SLAM
6、执行程序
GCN_PATH=/home/***/GCNv2_SLAM-master/GCN2/gcn2_320x240.pt ./rgbd_gcn /home/***/GCNv2_SLAM-master/Vocabulary/voc/ORBvoc.bin /home/***/GCNv2_SLAM-master/GCN2/TUM3.yaml /home/***/datasets/tum/rgbd_dataset_freiburg2_xyz /home/***/datasets/tum/rgbd_dataset_freiburg2_xyz/associate.txt
=========================================================================
然后我把这部分代码摘了出来,想要单独验证下其性能,另外评估一下我模型地方改的对不对 (删掉了GCNextractor的namespace)
代码解释:读取了euroc的图片,参数从ORBSLAM3文件中找的,直接填了进去。
检测器方面:由于 在双目初始化过程中是针对金字塔一层层采集的,GCN是没有金字塔的..关键帧track是比对的BOW,BOW是由特征点生成的,所以直接比对特征点就好了。所以这里直接用的opencv的DMach(因为给的双目图像, 所以参数给的比较苛刻。)。
test1.cpp
#include "GCNextractor.h"
#include <vector>
#include <opencv2/opencv.hpp>
void Frame(const cv::Mat &imLeft, const cv::Mat &imRight)
{
GCNextractor* mpleftGCNextractor = new GCNextractor(1000,1.2,8,20,7);
GCNextractor* mprightGCNextractor = new GCNextractor(1000,1.2,8,20,7);
std::vector<cv::KeyPoint> mvLeftKeys,mvRightKeys;
cv::Mat mleftDescriptors,mRightDescriptors;
(*mpleftGCNextractor)(imLeft,cv::Mat(),mvLeftKeys,mleftDescriptors);
(*mprightGCNextractor)(imRight,cv::Mat(),mvRightKeys,mRightDescriptors);
if(mvLeftKeys.empty()||mvRightKeys.empty())
std::cout<<"特征点提取出现问题"<<std::endl;
std::cout<<"imtrack"<<std::endl;
std::vector<cv::DMatch> matches;
cv::BFMatcher bfmatcher(cv::NORM_HAMMING);
bfmatcher.match(mleftDescriptors, mRightDescriptors, matches);
double min_dist = 1000, max_dist = 0;
for (int i = 0; i < mleftDescriptors.rows; i++)
{
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
std::vector<cv::DMatch> good_matches;
for (int i = 0; i < mleftDescriptors.rows; i++)
{
if (matches[i].distance <= std::max(1.2 * min_dist, 30.0))
good_matches.push_back(matches[i]);
}
cv::Mat img_match,img_match2;
drawMatches(imLeft, mvLeftKeys, imRight, mvRightKeys, good_matches, img_match);
cv::namedWindow("img_match", CV_WINDOW_NORMAL);
cv::namedWindow("img_match2", CV_WINDOW_NORMAL);
imshow("img_match",img_match);
cv::hconcat(imLeft,imRight,img_match2);
cv::cvtColor(img_match2,img_match2,CV_GRAY2RGB);
std::cout << "1"<<std::endl;
for(int i = 0; i < mvLeftKeys.size(); i++)
{
cv::circle(img_match2,cv::Point2f(mvLeftKeys[i].pt.x,mvLeftKeys[i].pt.y),2,cv::Scalar(255,0,0),1);
}
for(int i = 0; i < mvRightKeys.size(); i++)
{
cv::circle(img_match2,cv::Point2f(mvRightKeys[i].pt.x + imLeft.cols,mvRightKeys[i].pt.y),2,cv::Scalar(255,0,0),1);
}
for(int i = 0; i < good_matches.size(); i++)
{
cv::circle(img_match2,cv::Point2f(mvLeftKeys[good_matches[i].queryIdx].pt.x,mvLeftKeys[good_matches[i].queryIdx].pt.y),2,cv::Scalar(0,255,0),1);
}
for(int i = 0; i < good_matches.size(); i++)
{
cv::circle(img_match2,cv::Point2f(mvRightKeys[good_matches[i].trainIdx].pt.x + imLeft.cols,mvRightKeys[good_matches[i].trainIdx].pt.y),2,cv::Scalar(0,255,0),1);
}
imshow("img_match2",img_match2);
// cv::waitKey(0);
}
int main(int argc,char** argv)
{
cv::Mat imleft = cv::imread("/home/***/euroc/MH_01/mav0/cam0/data/1403636579813555456.png");
cv::Mat imright = cv::imread("/home/***/euroc/MH_01/mav0/cam1/data/1403636579813555456.png");
if(imleft.channels()==3)
{
cvtColor(imleft,imleft,CV_RGB2GRAY);
}
if(imright.channels()==3)
{
cvtColor(imright,imright,CV_RGB2GRAY);
}
cv::Mat leftmap1,leftmap2,rightmap1,rightmap2;
cv::Mat leftintrinsics = (cv::Mat_<double>(3,3) << 458.654,0., 367.215,0., 457.296, 248.375,0.,0.,1);
cv::Mat leftdistortion = (cv::Mat_<double>(4,1) << -0.28340811, 0.07395907, 0.00019359, 1.76187114e-05);
cv::Mat rightintrinsics = (cv::Mat_<double>(3,3) << 457.587,0., 379.999,0.,456.134, 255.238,0.,0.,1);
cv::Mat rightdistortion = (cv::Mat_<double>(4,1) << -0.28368365, 0.07451284, -0.00010473, -3.55590700e-05);
cv::Mat leftR = (cv::Mat_<double>(3,3) << 0.999966347530033, -0.001422739138722922, 0.008079580483432283, 0.001365741834644127, 0.9999741760894847, 0.007055629199258132, -0.008089410156878961, -0.007044357138835809, 0.9999424675829176);
cv::Mat rightR = (cv::Mat_<double>(3,3) << 0.9999633526194376, -0.003625811871560086, 0.007755443660172947, 0.003680398547259526, 0.9999684752771629, -0.007035845251224894, -0.007729688520722713, 0.007064130529506649, 0.999945173484644);
cv::Size imageSize(752, 480);
cv::Size unimageSize(320, 240);
cv::Mat newintrinsics = (cv::Mat_<double>(3,3) << 194.7179,0., 159.5,0., 228.0670, 119.5 ,0.,0.,1); // vfov 与 hfov 保持不变,按左图
initUndistortRectifyMap(leftintrinsics,leftdistortion,leftR,newintrinsics,imageSize,CV_32FC1,leftmap1,leftmap2);
cv::Mat unimleft,unimright;
cv::remap(imleft, unimleft, leftmap1, leftmap2, 1, 0);
unimleft = unimleft(cv::Rect(0, 0, 320,240)).clone();
initUndistortRectifyMap(rightintrinsics,rightdistortion,rightR,newintrinsics,imageSize,CV_32FC1,rightmap1,rightmap2);
cv::remap(imright, unimright, rightmap1, rightmap2, 1, 0);
unimright = unimright(cv::Rect(0, 0, 320,240)).clone();
cv::imshow("unimleft",unimleft);
cv::imshow("unimright",unimright);
Frame(unimleft, unimright);
cv::waitKey(0);
return 0;
}
img_match
img_match2
从图上看还是可用的,接下来将其运用到双目匹配中。