当前位置: 首页 > article >正文

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());
    }

结束语

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


http://www.kler.cn/a/396178.html

相关文章:

  • [JAVA]有关MyBatis环境配置介绍
  • 前端搭建低代码平台,微前端如何选型?
  • sql专题 之 where和join on
  • 有了Makefile, CMake存在的意义是什么?如何借助Makefile构建ObjC语言编译环境?如何获取编译器的版本号?
  • 【项目组件】第三方库——websocketpp
  • `node-gyp` 无法找到版本为 `10.0.19041.0` 的 Windows SDK
  • 开源AI大模型工作流神器Flowise本地部署与远程访问
  • VMware高危漏洞VMSA-2024-0019修复堆溢出和权限提升漏洞
  • 最后一个单词的长度---每日小题
  • 【免越狱】iOS砸壳 可下载AppStore任意版本 旧版本IPA下载
  • Spring Boot框架:电商系统的技术革新
  • CSS Grid 布局实战:从入门到精通
  • 推理计算:GPT-o1 和 AI 治理
  • 一文说清C++类型转换操作符(cast operator)
  • datawhale11月组队学习 模型压缩技术2:PyTorch模型剪枝教程
  • 多路转接之poll
  • SpringBoot整合Minio
  • 第二十章 TCP 客户端 服务器通信 - 立即发送模式(Q 模式)
  • react的import 导入语句中的特殊符号
  • Cpolar 内网穿透使用
  • 人群计数制作私有数据集教程-----自用
  • 动力商城-03 Idea集成apifox Mybatis-Plus字段策略
  • 前端开发中的CSS框架:昔日辉煌与新兴潮流
  • 电脑不显示wifi列表怎么办?电脑不显示WiF列表的解决办法
  • sychronized锁
  • QT_CONFIG宏使用