ORB-SLAM2源码学习:ORBextractor.cc:ORBextractor::operator()主入口函数

前言

主入口函数直接调用了ComputePyramid()、ComputeKeyPointsOctTree()、computeDescriptors()三大核心函数,间接调用了这三大核心函数所调用的函数,可以说是覆盖了所有的函数。

1.函数声明

/*
 用仿函数(重载括号运算符)方法来计算图像特征点
 * 
 _image                    输入原始图的图像
 _mask                     掩膜mask
 _keypoints                存储特征点关键点的向量
 _descriptors              存储特征点描述子的矩阵
 */
void ORBextractor::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _keypoints,
                      OutputArray _descriptors)
{ 
    ....
}

2.函数定义

步骤:

1.接收输入图像(_image)(另一个输入图像矩阵暂时用不到)提取图像的矩阵数据并检查是否是单通道。

if(_image.empty())
        return;

	//获取图像的大小
    Mat image = _image.getMat();// 获取图像的矩阵数据。
	//判断图像的格式是否正确,要求是单通道灰度值
    assert(image.type() == CV_8UC1 );//每个像素值是一个8位无符号整数,三通道。
    // assert是一种断言语句,用于在程序中进行条件检查。

2.调用ComputePyramid() 函数生成图像金字塔。

ORB-SLAM2源码学习:ORBextractor.cc:ComputePyramid构建图像金字塔①

  // Pre-compute the scale pyramid
    ComputePyramid(image);

3.调用ComputeKeyPointsOctTree()函数(传统的方法采用ComputeKeyPointsOld(),这里并未采用)来计算关键(Keypoints)点并存储在 allKeypoints 中。

ORB-SLAM2源码学习:ORBextractor.cc :ComputeKeyPointsOctTree计算并分配特征点②

// 存储所有的特征点,注意此处为二维的vector,第一维存储的是金字塔的层数,第二维存储的是那一层金字塔图像里提取的所有特征点
    vector < vector<KeyPoint> > allKeypoints; 
    //使用四叉树的方式计算每层图像的特征点并进行分配
    ComputeKeyPointsOctTree(allKeypoints);

4.根据每层的特征点数量计算总特征点数量,并为描述子(Descriptors)分配内存。

5. 遍历金字塔的每一层。

   a.对当前层图像应用高斯模糊GaussianBlur(),得到workingMat。

   b.调用 computeDescriptors() 函数计算当前层的描述子(Descriptors)。

ORB-SLAM2源码学习:ORBextractor.cc:computeOrbDescriptor 计算描述子

   c.根据层级缩放特征点坐标,并将其添加到输出的 _keypoints 向量中。   

//因为遍历是一层一层进行的,但是描述子那个矩阵是存储整个图像金字塔中特征点的描述子,所以在这里设置了Offset变量来保存“寻址”时的偏移量,
	//辅助进行在总描述子mat中的定位
    int offset = 0;
	//开始遍历每一层图像
    for (int level = 0; level < nlevels; ++level)
    {
		//获取在allKeypoints中当前层特征点容器的句柄
        vector<KeyPoint>& keypoints = allKeypoints[level];
		//本层的特征点数
        int nkeypointsLevel = (int)keypoints.size();

		//如果特征点数目为0,跳出本次循环,继续下一层金字塔
        if(nkeypointsLevel==0)
            continue;

        // preprocess the resized image
		// 深拷贝当前金字塔所在层级的图像
        Mat workingMat = mvImagePyramid[level].clone();

		// 注意:提取特征点的时候,使用的是清晰的原图像;这里计算描述子的时候,为了避免图像噪声的影响,使用了高斯模糊
        GaussianBlur(workingMat, 		//源图像
					 workingMat, 		//输出图像
					 Size(7, 7), 		//高斯滤波器kernel大小,必须为正的奇数
					 2, 				//高斯滤波在x方向的标准差
					 2, 				//高斯滤波在y方向的标准差
					 BORDER_REFLECT_101);//边缘拓展点插值类型

        // Compute the descriptors 计算描述子
		// desc存储当前图层的描述子
        Mat desc = descriptors.rowRange(offset, offset + nkeypointsLevel);
        computeDescriptors(workingMat, 	//高斯模糊之后的图层图像
						   keypoints, 	//当前图层中的特征点集合
						   desc, 		//存储计算之后的描述子
						   pattern);	//随机采样模板

		// 更新偏移量的值 
        offset += nkeypointsLevel;

        // Scale keypoint coordinates
		// 对于第0层的图像特征点,他们的坐标就不需要再进行恢复了
        if (level != 0)
        {
			// 获取当前图层上的缩放系数
            float scale = mvScaleFactor[level];
            // 遍历本层所有的特征点
            for (vector<KeyPoint>::iterator keypoint = keypoints.begin(),
                 keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
				// 特征点本身直接乘缩放倍数就可以了
                keypoint->pt *= scale;
        }
        
        // And add the keypoints to the output
        // 将keypoints中内容插入到_keypoints 的末尾
        // keypoint其实是对allkeypoints中每层图像中特征点的引用,这样allkeypoints中的所有特征点在这里被转存到输出的_keypoints
        _keypoints.insert(_keypoints.end(), keypoints.begin(), keypoints.end());
    }

结束语

以上就是我学习到的内容,如果对您有帮助请多多支持我,如果哪里有问题欢迎大家在评论区积极讨论,我看到会及时回复。

<think>我们正在处理C++17中bool类型的operator++编译错误,特别是在ORB-SLAM2的LoopClosing.cc文件中。在C++17之前,bool类型支持operator++(递增操作),但C++17移除了这个操作。因此,ORB-SLAM2的代码需要修改以适应这一变化。在LoopClosing.cc中,有一处使用了bool类型的递增:`vbReset[i]=false`,然后有一个循环会对vbReset数组中的每个元素执行`++vbReset[i]`。由于vbReset是一个`vector<bool>`,因此`vbReset[i]`返回的是一个bool的代理对象,而对这个代理对象执行++操作在C++17中是非法的。解决方案:通常有两种修改方法:1.将`++vbReset[i]`改为`vbReset[i]=true`,因为原来的意图是重置标志,而递增操作在bool类型上实际上就是设置为true。具体到ORB-SLAM2的代码中,在LoopClosing.cc中,有一段代码:for(inti=0;i<mnKFs;i++){if(KeyFrame::spReducedKF.count(mpKeyFrameDB->mvpKeyFrame[i]))mpKeyFrameDB->mvpKeyFrame[i]->SetNotErase();mpKeyFrameDB->mvpKeyFrame[i]->SetBadFlag();}...for(vector<bool>::iteratorvit=resetIs.begin(),vend=resetIs.end();vit!=vend;vit++){*vit=true;}或者原来的代码可能是使用递增操作:`(*vit)++`;或者`++(*vit)`;但是根据ORB-SLAM2的上下文,实际上是想要重置所有的标志位。因此,将其直接赋值为true即可。2.另一种方法是使用整数类型代替bool类型。但考虑到ORB-SLAM2的代码结构,直接修改为赋值操作更为合适。具体在ORB-SLAM2的LoopClosing.cc文件中,查找以下代码段:vector<bool>vbReset(mpMap->KeyFramesInMap()%4,false);//...然后在一个循环中有类似:++vbReset[i];或for(auto&reset:vbReset){++reset;}将其改为:for(auto&reset:vbReset){reset=true;//因为原意是将其置为true}或者如果是在一个循环中针对特定索引,则使用:vbReset[i]=true;注意:在ORB-SLAM2的LoopClosing.cc中,可能存在如下代码://Loopclosing.DetectLoopcandidatesandcorrectSim3mpTracker->SetTracking(false);//SendastopsignaltoLocalMapping//AvoidnewkeyframesareinsertedwhilecorrectingtheloopmpLocalMapper->RequestStop();//IfaGlobalBundleAdjustmentisrunning,abortitif(isRunningGBA()){unique_lock<mutex>lock(mMutexGBA);mbStopGBA=true;mnFullBAIdx++;if(mpThreadGBA){mpThreadGBA->detach();deletempThreadGBA;}}//WaituntilLocalMappinghaseffectivelystoppedwhile(!mpLocalMapper->isStopped()){usleep(1000);}//EnsurecurrentkeyframeisupdatedmpCurrentKF->UpdateConnections();//Retrieveneighborsofcurrentkeyframe(incovisibilitygraph)mvpConnectedKFs=mpCurrentKF->GetVectorCovisibleKeyFrames();mvpConnectedKFs.push_back(mpCurrentKF);//StartLoopClosing//DetectloopcandidatesandcheckSim3transformation//...省略//下面找到关键点:在ORB-SLAM2的LoopClosing中,有一个名为vbReset的vector<bool>,其每个元素对应一个关键帧,需要重置。vector<bool>vbReset(mpMap->KeyFramesInMap(),false);set<KeyFrame*>sKFsByBIAS=mpMap->GetKeyFramesByBIAS();//...然后在一个循环中,会递增某些元素:KeyFrame*pKFi=*sit;while(pKFi&&pKFi->GetBIAS()>=minKFid){if(pKFi->GetBIAS()==minKFid)vbReset[pKFi->GetIndexInMap()]=true;//这里直接赋值为truepKFi=pKFi->GetParent();}//或者另一个循环可能是:for(inti=0;i<vbReset.size();i++){if(vbReset[i])//这里原来可能是++vbReset[i];但根据上下文,应该是标记需要重置的关键帧,所以直接赋值即可。//实际上,上面已经直接赋值true了,所以后面应该没有递增操作。}然而,在ORB-SLAM2的GitHub仓库中,实际的LoopClosing.cc中可能并没有直接对vbReset[i]进行递增的代码,但是存在一个常见的错误模式,即使用:for(vector<bool>::iteratorvit=resetIs.begin(),vend=resetIs.end();vit!=vend;vit++){*vit=true;}这是没有问题的,因为使用的是赋值。但如果你确实遇到了使用递增操作的地方,比如:for(vector<bool>::iteratorvit=resetIs.begin(),vend=resetIs.end();vit!=vend;vit++){(*vit)++;}或者for(auto&reset:resetIs){reset++;}那么修改为赋值true即可。因此,请检查你的LoopClosing.cc文件中是否存在对vector<bool>的元素进行递增操作的部分,将其改为赋值true。总结:在C++17中,bool类型不再支持operator++,因此将递增操作改为直接赋值true。</think> ### 解决C++17中bool类型的operator++编译错误(ORB-SLAM2 LoopClosing.cc) 在C++17标准中,**bool类型的前缀递增运算符(`++bool`)** 被明令禁止([cppreference标准文档](https://en.cppreference.com/w/cpp/language/operator_incdec#Built-in_prefix_operators))。这会导致ORB-SLAM2的`LoopClosing.cc`中出现类似错误: ```bash error: cannot increment value of type 'std::vector<bool>::reference' ``` #### 错误原因分析 在ORB-SLAM2的原始代码中(如`LoopClosing.cc: 105行`附近),存在如下操作: ```cpp std::vector<bool> vbReset; for (auto& reset : vbReset) { ++reset; // C++17禁止bool递增 } ``` 在C++17前,编译器隐式将`++reset`转换为`reset=true`(非规范行为),但C++17强制规范后此操作非法[^2]。 --- ### 解决方案 修改`LoopClosing.cc`中的递增操作为显式赋值: #### 1. 定位代码位置 在`LoopClosing::Run()`函数中查找类似代码: ```cpp // 原始错误代码 (约在LoopClosing.cc的第105行附近) for (vector<bool>::iterator vit = vbReset.begin(); vit != vbReset.end(); vit++) { ++(*vit); // 或 *vit++ } ``` #### 2. 修改为显式赋值 ```cpp // 修改后的正确代码 for (auto& reset : vbReset) { reset = true; // 显式赋值替代递增 } ``` 或 ```cpp for (vector<bool>::iterator vit = vbReset.begin(); vit != vbReset.end(); vit++) { *vit = true; // 直接设置bool值 } ``` #### 3. 完整代码示例 ```diff // 修改前 void LoopClosing::Run() { ... vector<bool> vbReset(mpMap->KeyFramesInMap(), false); for (auto& reset : vbReset) { - ++reset; + reset = true; } ... } ``` #### 4. 重新编译 ```bash cd ORB_SLAM2 ./build.sh ``` --- ### 注意事项 1. **业务逻辑验证** ORB-SLAM2使用`vbReset`标记关键帧重置状态,原始递增操作等价于`reset=true`(因bool不支持数值递增)。修改后不影响功能[^3]。 2. **C++标准兼容** ```CMake set(CMAKE_CXX_STANDARD 14) # 如非必须C++17,可降级标准 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值