ORB-SLAM2-Brief描述子方向计算

ORB-SLAM2-Brief描述子方向计算


代码

在计算完特征点的方向后,开始计算描述子

Mat descriptors;//首先定义了描述子

    int nkeypoints = 0;//统计金字塔中所有特征点
    for (int level = 0; level < nlevels; ++level)//开始遍历每一层图像金字塔,然后将每一层金字塔上特征点进行总和
        nkeypoints += (int)allKeypoints[level].size();
    if( nkeypoints == 0 )//如果没有特征点那么就删除描述子
        _descriptors.release();
    else
    {
        _descriptors.create(nkeypoints, 32, CV_8U);//如果有就创建描述子
        descriptors = _descriptors.getMat();
    }

    _keypoints.clear();//关键点清空,预分配内存
    _keypoints.reserve(nkeypoints);


   int offset = 0;
    for (int level = 0; level < nlevels; ++level)//开始遍历每一层
    {
        vector<KeyPoint>& keypoints = allKeypoints[level];//将当前层的描述子传入keypoints
        int nkeypointsLevel = (int)keypoints.size();//本层特征点数目

        if(nkeypointsLevel==0)//没有特征点
            continue;

        // preprocess the resized image计算描述子进行了高斯模糊,防止噪声的影响
        Mat workingMat = mvImagePyramid[level].clone();//存储当前层的图像
        GaussianBlur(workingMat, workingMat, Size(7, 7), 2, 2, BORDER_REFLECT_101);//进行高斯模糊

        // Compute the descriptors
        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]; //getScale(level, firstLevel, scaleFactor);
            for (vector<KeyPoint>::iterator keypoint = keypoints.begin(),
                 keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
                keypoint->pt *= scale;
        }
        // And add the keypoints to the output
        _keypoints.insert(_keypoints.end(), keypoints.begin(), keypoints.end());
    }
}

进入computeDescriptors函数,计算描述子

static void computeDescriptors(const Mat& image,//高斯后的图
                               vector<KeyPoint>& keypoints,//当前图像中的特征点
                                Mat& descriptors,//存储计算后的描述子
                               const vector<Point>& pattern)//随机采样点
{
    descriptors = Mat::zeros((int)keypoints.size(), 32, CV_8UC1);//清空保存特征点描述子容器

    for (size_t i = 0; i < keypoints.size(); i++)
        computeOrbDescriptor(keypoints[i],//要计算的特征点
         image,//以及它的图像
          &pattern[0],//随机点的首地址
          descriptors.ptr((int)i)//提取出的描述子的保存位置 
          );
}

进入computeOrbDescriptor函数

const float factorPI = (float)(CV_PI/180.f);//转弧度。
static void computeOrbDescriptor(const KeyPoint& kpt,
                                 const Mat& img, const Point* pattern,
                                 uchar* desc)
{
    float angle = (float)kpt.angle*factorPI;//得到特征点的角度,并且将其转换为弧度
    float a = (float)cos(angle), b = (float)sin(angle);//计算余弦值与正弦值,这部分原理看图一

    const uchar* center = &img.at<uchar>(cvRound(kpt.pt.y), cvRound(kpt.pt.x));//获取中心指针
    const int step = (int)img.step;//获取每行字节数

    #define GET_VALUE(idx) \  //将随机点点集的x轴方向,旋转到特征点方向
        center[cvRound(pattern[idx].x*b + pattern[idx].y*a)*step + \   //y'*step
               cvRound(pattern[idx].x*a - pattern[idx].y*b)]   //x'


    for (int i = 0; i < 32; ++i, pattern += 16)
    {
        int t0, t1, val;
        t0 = GET_VALUE(0); t1 = GET_VALUE(1);
        val = t0 < t1;
        t0 = GET_VALUE(2); t1 = GET_VALUE(3);
        val |= (t0 < t1) << 1;
        t0 = GET_VALUE(4); t1 = GET_VALUE(5);
        val |= (t0 < t1) << 2;
        t0 = GET_VALUE(6); t1 = GET_VALUE(7);
        val |= (t0 < t1) << 3;
        t0 = GET_VALUE(8); t1 = GET_VALUE(9);
        val |= (t0 < t1) << 4;
        t0 = GET_VALUE(10); t1 = GET_VALUE(11);
        val |= (t0 < t1) << 5;
        t0 = GET_VALUE(12); t1 = GET_VALUE(13);
        val |= (t0 < t1) << 6;
        t0 = GET_VALUE(14); t1 = GET_VALUE(15);
        val |= (t0 < t1) << 7;

        desc[i] = (uchar)val;
    }

    #undef GET_VALUE
}

在这里插入图片描述
图 1

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值