动态环境下的ORB-SLAM2_实现鲁棒的定位

参考论文:DS-SLAM: A Semantic Visual SLAM towards Dynamic Environments (github网址

注:直接使用请引用。
github:ORBSLAM2_Dynamic

实现原理

将ORB-SLAM2的特征点提取进行了改进,分为动态区域和静态区域,只提取静态区域的ORB特征点。

getDynamicObjectBbox实现

  • 目标检测:使用darknet框架实现的YOLOv4
  • 动态特征点检测:使用LK光流跟踪特征点,然后根据特征点到极线的距离判断是否为动态特征点(注意:此处提取的特征点用作判断是否为动态目标框的条件,与ORB-SLAM2中提取的ORB特征点不同)。
  • 动态区域判断:动态区域为目标检测的矩形区域,通过矩形区域中动态特征点的数量和所占比例进行筛选。

getSpecifiedObjectBbox实现

  • 目标检测:使用darknet框架实现的YOLOv4。
  • 动态区域判断:动态区域为目标检测的矩形区域,通过先验的动态信息直接选择特征物体种类的矩形区域。

操作指南

UBuntu18.04系统(GPU RTX2080ti)

编译

安装ORB-SLAM2相关依赖
编译darknet,生成动态库libdarknet.so
(如果使用GPU需要安装CUDA和CUDNN)

执行

  • 先设置.yaml文件参数。下面是新增的参数:
    yaml_set
  • darknet/weight目录下载yolov4.weights或者yolov4-tiny.weights。(下载地址
  • darknet/下默认的libdarknet.so是在CPU上运行的,在GPU上运行将libdarknet_GPU.so重命名为libdarknet.so
  • 具体运行命令与ORB-SLAM2一样。

自动化工具

运行脚本evaluate/run.sh,所有数据集运行5次(次数可以自己修改),然后计算绝对轨迹误差的平均值,画绝对轨迹误差图。

# 运行举例
sh run.sh ~/Github/ORB_SLAM2_dynamic /media/sata3/TUM_Dynamic/dataset TS_SLAM
#!/bin/bash

workspace=$1  # 工作空间根目录
datasetPath=$2 # 数据集根目录
resultFileName=$3 # 保存结果的文本文件

workspace=${workspace%*/}"/"
datasetPath=${datasetPath%*/}"/"
resultFile=$workspace"evaluate/"$resultFileName
tempFile=$workspace"evaluate/temp.txt" # 保存执行evaluate_ate.py输出数据
tempFile2=$workspace"evaluate/temp2.txt" # 保存执行Examples/RGB-D/rgbd_tum输出数据

folders="$(ls "$datasetPath")"
cd "$workspace" || return #进入工作空间的目录
for foldername in $folders
do
	# >> 追加,> 覆盖
	echo "$foldername" >> "$resultFile"
	resultFloder=evaluate/$foldername
	mkdir "$resultFloder" 
	allFrames=$(awk 'END{print NR}' "$datasetPath$foldername""/associations.txt")
	
	# 每个数据集执行5次,计算均值
	for (( i=1; i<=5; i++ ))
	do
		command="Examples/RGB-D/rgbd_tum Vocabulary/ORBvoc.txt config/TUM3.yaml ""$datasetPath$foldername"" ""$datasetPath$foldername""/associations.txt"
		info=$(eval "$command") # 执行字符串指令
		echo "$info" >> "$tempFile2"
		timeLine=$(sed -n '/^mean tracking time/p' "$tempFile2")
		time=${timeLine##* }
		mv -i CameraTrajectory.txt "$resultFloder""/CameraTrajectory""$i"".txt"
		mv -i KeyFrameTrajectory.txt "$resultFloder""/KeyFrameTrajectory""$i"".txt"
		command="python2 ./evaluate/evaluate_ate.py ""$datasetPath$foldername""/groundtruth.txt ./evaluate/""$foldername""/CameraTrajectory""$i"".txt --plot ""$resultFloder""/""$foldername""_""$i"".png"
		eval "$command"
		command="python2 ./evaluate/evaluate_ate.py ""$datasetPath$foldername""/groundtruth.txt ./evaluate/""$foldername""/""CameraTrajectory""$i"".txt --verbose"
		error=$(eval "$command")
		trackOkFrame=$(awk 'END{print NR}' ./evaluate/"$foldername"/CameraTrajectory"$i".txt)
		echo "$error"" ""$trackOkFrame"" ""$allFrames"" ""$time" >> "$resultFile"
		echo "$error"" ""$trackOkFrame"" ""$allFrames"" ""$time" >> "$tempFile"
		rm "$tempFile2"
	done
	command="python ./evaluate/tool.py"
	error=$(eval "$command")
	echo "$error" >> "$resultFile"
	rm "$tempFile"
done

源码分析

CMakeLists

增加darknet相关部分动态库。

ADD_DEFINITIONS(-DOPENCV)
ADD_DEFINITIONS(-DGPU)

include_directories(
${PROJECT_SOURCE_DIR}/darknet-master/include  # darknet
)

add_library(${PROJECT_NAME} SHARED
src/DynamicObjectDetecting.cc
)

find_library(darknet libdarknet_yolov4.so ${PROJECT_SOURCE_DIR}/darknet-master/)

target_link_libraries(${PROJECT_NAME}
${darknet}
)

Tracking::Tracking

读取.yaml文件参数,初始化目标检测器。

Tracking::Tracking(System *pSys, ORBVocabulary* pVoc, FrameDrawer *pFrameDrawer, MapDrawer *pMapDrawer, Map *pMap, KeyFrameDatabase* pKFDB, const string &strSettingPath, const int sensor, DynamicObjectDetecting& dynamicObjectDetector):
	......
    double BBoxZoomSize = 1;
    fSettings["Detect.BBoxZoomSize"] >> BBoxZoomSize;
    mBBoxSingleSideZoomSize = (BBoxZoomSize-1)/2;
    fSettings["Detect.SelectMethod"] >>  mSelectMethod;
    fSettings["Detect.SaveDynaImD"] >> mbSaveDynaImD; 
    fSettings["Detect.SaveDynaImDPath"] >>  mSaveDynaImDPath;

    std::cout << endl << "Parameters for Dynamic SLAM:" << std::endl;
    switch (mSelectMethod) {
        case 1:
            std::cout << "ORB-SLAM2 in dynamic environment and detect the specified object." << std::endl;
            break;
        case 2:
            std::cout << "ORB-SLAM2 in dynamic environment and detect the dynamic object." << std::endl;
            break;
        default :
            mbSaveDynaImD = false;
            std::cout << "Please Select 'Detect.SelectMethod' 1(Specified), 2(Dynamic)." << std::endl;
            std::cout << "Now, it runs just as ORB-SLAM2." << std::endl;
    }

    string strThings;
    fSettings["Detect.SpecifiedThings"] >> strThings;
    fSettings["Detect.Network.CfgFile"] >> mCfgFile; 
    fSettings["Detect.Network.WeightFile"] >> mWeightFile;
    fSettings["Detect.LabelPath"] >> mLabelPath;
    fSettings["Detect.Threshold"] >> mDetectTh;

    string name = "";
    for (int i = 0; i < strThings.size(); i++) {
        if (strThings[i]==' ' || strThings[i]==','){
            if (name.size() > 0) {
                mSpecifiedThings.push_back(name);
                name = "";
            }
            continue;
        }
        name += strThings[i];
    }
    if (name.size() > 0) {
        mSpecifiedThings.push_back(name);
    }
    
    dynamicObjectDetector.init(mSpecifiedThings, mCfgFile, mWeightFile, mLabelPath, mDetectTh);
}

Tracking::GrabImageRGBD

筛选出包含动态物体的目标框。

cv::Mat Tracking::GrabImageRGBD(const cv::Mat &imRGB,const cv::Mat &imD, const double &timestamp, const double &timestampD, DynamicObjectDetecting& dynamicObjectDetector)
{
	......
	// 不同的目标框筛选方式,dynamic保存了筛选后的bbox
    std::vector<bbox_t>  dynaObjs;
    switch (mSelectMethod) {
        case 1:
            dynaObjs = dynamicObjectDetector.getSpecifiedObjectBbox(mImGray);
            break;
        case 2:
            dynaObjs = dynamicObjectDetector.getDynamicObjectBbox(mImGray);
            break;
    }
    // 每一帧初始化的时候会进行ORB特征点的提取,故在此去除动态区域的特征点
    mCurrentFrame = Frame(mImGray,imDepth,timestamp,mpORBextractorLeft,mpORBVocabulary,mK,mDistCoef,mbf,mThDepth, dynaObjs, mBBoxSingleSideZoomSize);
    // 原图画上bbox,会影响关键点提取,应该放在关键点提取之后
    mpFrameDrawer->draw_boxes(mImGray, dynaObjs, dynamicObjectDetector.id2name)
    Track();
    // track后的帧设置为上一帧
    dynamicObjectDetector.setImGrayPre(mImGray);
    return mCurrentFrame.mTcw.clone();
}

ORBextractor::ComputeStaticKeyPointsOctTree

去除动态区域的特征点。

void ORBextractor::ComputeStaticKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoints, const std::vector<bbox_t>& dynaObjs, const double bboxSingleSideZoomSize)
{
        ......   
        // *************************************************************
        vector<vector<bool>> g(maxBorderY+1,vector<bool>(maxBorderX+1,true));
        // 去除动态特征点
        for (bbox_t bbox: dynaObjs) {
            // bbox扩大0.1倍
            int x1 = round((float)(bbox.x-bboxSingleSideZoomSize*bbox.w)*scale);
            int y1 = round((float)(bbox.y-bboxSingleSideZoomSize*bbox.h)*scale);
            int x2 = round((float)(bbox.x+(1+bboxSingleSideZoomSize)*bbox.w)*scale);
            int y2 = round((float)(bbox.y+(1+bboxSingleSideZoomSize)*bbox.h)*scale);
            y1 = y1 < minBorderY ? minBorderY : y1;
            y2 = y2 >= maxBorderY ? maxBorderY : y2;
            x1 = x1 < minBorderX ? minBorderX : x1;
            x2 = x2 >= maxBorderX ? maxBorderX : x2;
            for (size_t i = y1; i <= y2; i++) {
                for (size_t j = x1; j <= x2; j++) {
                    g[i][j] = false;
                }
            }
        }
        // *************************************************************

        for(int i=0; i<nRows; i++)
        {
			......
            for(int j=0; j<nCols; j++)
            {
            	......
                // *************************************************************
                vector<cv::KeyPoint> vKeysCellStatic;
                for (cv::KeyPoint kp: vKeysCell) {
                    if (g[kp.pt.y+i*hCell+minBorderY][kp.pt.x+j*wCell+minBorderX]) { // 选择非目标框范围内的特征点
                        vKeysCellStatic.push_back(kp);
                    }else {
                        // std::cout << "gg" << std::endl;
                    }
                }

                if(!vKeysCellStatic.empty())
                {
                    for(vector<cv::KeyPoint>::iterator vit=vKeysCellStatic.begin(); vit!=vKeysCellStatic.end();vit++)
                    {
                        (*vit).pt.x+=j*wCell;
                        (*vit).pt.y+=i*hCell;
                        vToDistributeKeys.push_back(*vit);
                    }
                }
                // *************************************************************
            }
        }
        ......
}

DynamicObjectDetecting.cc

新增加的类,主要用于实现getDynamicObjectBboxgetSpecifiedObjectBbox两个功能。

  • 6
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
### 回答1: ORB-SLAM2_with_semantic_label是一种基于ORB-SLAM2的视觉SLAM系统,它使用语义标签信息来增强场景理解和地图构建。该系统通过将每个地图点与语义标签相对应,从而为地图中的每个区域提供更多的上下文信息。这有助于提高系统的鲁棒性和场景理解能力,并可以在机器人导航、自动驾驶等领域得到广泛应用。 ### 回答2: ORB-SLAM2是一种视觉SLAM算法,可以实现从单个或多个摄像头的图像序列中实时重建3D地图,同时在该地图中定位相机。它广泛应用于机器人导航、增强现实、自动驾驶等领域。然而,在某些现实场景中,例如室内场景、城市环境等,只有3D地图是不够的,需要利用语义信息来更好地理解环境。 因此,ORB-SLAM2的研究人员进行了扩展,开发了一种ORB-SLAM2_with_semantic_label算法,以结合视觉SLAM和语义信息。该算法的目标是在ORB-SLAM2中增加对语义信息的支持,从而允许机器理解其所在环境中的物体及其特征。该算法的一个重要应用是在机器人导航中,机器人可以利用语义标签对其周围环境进行更准确、更可靠的理解,从而更好地规划路径。 该算法的关键步骤包括以下几个方面。首先,需要将语义分割模型与ORB-SLAM2进行集成,产生语义标记的地图,这可以在ORB-SLAM2映射初始化期间完成。其次,需要利用深度学习技术提取图像的语义特征,用于在传统视觉SLAM系统中增加语义信息。接着,需要将ORB-SLAM2中的回环检测模块改进,以考虑语义信息来消除误报。最后,需要使用机器学习算法,通过对特定环境中所遇到的物体的历史观测进行学习,从而使机器人能够在不同环境中尽可能准确地识别物体。 该算法的优点是可以在不增加太多计算量的情况下增加语义信息,从而使机器能够自然地与人类进行交互。但是,该算法的缺点是需要对语义标注数据进行精确的手动标注,这是一项非常耗时的任务。此外,该算法对光照和尺度变化非常敏感,因此在实际应用中需要特别注意。 ### 回答3: ORB-SLAM2是一种基于视觉SLAM技术的实时多目标跟踪和定位系统,它结合了ORB特征提取器和BoW词袋模型,使得系统具有高效的实时位姿估计能力。而ORB-SLAM2 with Semantic Label则是在ORB-SLAM2的基础上,加入了语义标签的支持。 语义标签是指对环境元素的分类标注,例如标注图像中的建筑、人、车等。加入语义标签的目的是提高系统对环境信息的理解和描述能力。在ORB-SLAM2 with Semantic Label中,可以通过在输入图像中标记语义标签信息,并将其存储到地图数据中,从而实现地图的语义化描述。同时,语义标签可以通过深度学习等技术来实现自动分类。 与传统的视觉SLAM系统相比,ORB-SLAM2 with Semantic Label可以更好地应对复杂的环境场景。在城市街道和室内场所等环境中,ORB-SLAM2 with Semantic Label可以对人、车辆和建筑等复杂元素进行识别,并在建立地图时,将这些语义信息一同存储在地图中。这样可以提供更为精确的地图信息,使得系统的位置估计更加准确、稳定。 总之,ORB-SLAM2 with Semantic Label是一种具有语义理解能力的SLAM系统,可以为机器人的自主导航和环境理解等方面的应用提供更为准确、可靠的基础支撑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值