ORBSLAM2-灰度质心法求旋转不变性

ORBSLAM2-灰度质心法求旋转不变性


代码

当使用四叉树的策略,将ORB特征点均匀的分布在在图像中后,接下来就需要进行计算方向,因为FAST角点与Brief描述子是不具备旋转不变性的,因此用灰度质心法计算旋转不变性。

const int scaledPatchSize = PATCH_SIZE*mvScaleFactor[level];//定义每层patch_size的缩放,,这边就是在前面系统构造函数中所画的圆的直径,因为在图像金字塔中,每层的图像大小是不一样的,因此计算的圆的大小也是不一样的,需要进行比例缩放

        // Add border to coordinates and scale information
        const int nkps = keypoints.size();//获取保留下来的特征点的数目
        for(int i=0; i<nkps ; i++)
        { 
        //遍历每个特征点,恢复到扩充图层的坐标
            keypoints[i].pt.x+=minBorderX;
            keypoints[i].pt.y+=minBorderY;
            keypoints[i].octave=level;//获取图像在金字塔的哪层
            keypoints[i].size = scaledPatchSize;//每层对应patchsize的大小
        }
    }

    // compute orientations开始计算方向
    for (int level = 0; level < nlevels; ++level)
        computeOrientation(mvImagePyramid[level], //对应的图层图像
        allKeypoints[level],//这个图层中提取并且保留下来的特征电容器
         umax);//patch的坐标边界
}

进入computeOrientation函数

static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints, const vector<int>& umax)
{
    for (vector<KeyPoint>::iterator keypoint = keypoints.begin(),
         keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)//这边开始遍历每一个特征点
    {//调用IC——Angle来计算
        keypoint->angle = IC_Angle(image, keypoint->pt, umax);
    }
}

进入到IC_Angle函数
关于灰度质心法如下:
图1
图1
如图1所示,p是特征点,以p为圆心PATCH_SIZE为直径画圆,那么P就是这个圆的几何中心,然后计算圆内的灰度,算出灰度质心Q,具体公式如14讲上面:
遍历[-HALF_PATCH_SIZE,HALF_PATCH_SIZE]上的像素点,算出整个圆的灰度值m00.

在这里插入图片描述
然后计算出x轴与y轴方向上的灰度,主要通过权重来算出:
在这里插入图片描述
例如m10中x表示的是x轴方向上的像素坐标,I(x,y)表示的是每个点灰度值。
算出x轴与y轴上的灰度值,将其与整体灰度相除,就能算出图像在x轴与y轴的灰度质心点,即整个图像的灰度质心点Q。
在这里插入图片描述
然后,利用arctan算出角度,就可以表示该特征点的方向。
在这里插入图片描述

IC_Angle函数加速

在这里插入图片描述
参考连接 图2
对于遍历整个圆中的坐标点是有点慢的,可以对其进行加速。
先算出中间红线这一行的m10,然后在平行于x轴算出m10和m01,一次计算相当于图像中的同个颜色的两个line

static float IC_Angle(const Mat& image, Point2f pt,  const vector<int> & u_max)
{

    int m_01 = 0, m_10 = 0;//表示灰度质心里面的x与y轴上的灰度

    const uchar* center = &image.at<uchar> (cvRound(pt.y), cvRound(pt.x));//特征点所在的灰度值的指针  

    // Treat the center line differently, v=0//开始计算,原理可以看图2,首先计算第0行的,也就是红色线条那行,比较特殊
    
    for (int u = -HALF_PATCH_SIZE; u <= HALF_PATCH_SIZE; ++u)//这边遍历【-u,u】,也就是平行于x轴
        m_10 += u * center[u];//x*I(x,y)

    // Go line by line in the circuI853lar patch
    int step = (int)image.step1();//图像一行中包含的字节总数 ,方便取对称的行数
    for (int v = 1; v <= HALF_PATCH_SIZE; ++v)//v是正的,也就是只遍历上半部分圆,
    {
        // Proceed over the two lines
        int v_sum = 0;
        int d = u_max[v];//横坐标的最大范围
        // 假设每次处理的两个点坐标,中心线上方为(x,y),中心线下方为(x,-y) 
        // 对于某次待处理的两个点:m_10 = Σ x*I(x,y) =  x*I(x,y) + x*I(x,-y) = x*(I(x,y) + I(x,-y))
        // 对于某次待处理的两个点:m_01 = Σ y*I(x,y) =  y*I(x,y) - y*I(x,-y) = y*(I(x,y) - I(x,-y))
        for (int u = -d; u <= d; ++u)//但是u却取了整个,即【-u,u】,遍历两行
        {
            int val_plus = center[u + v*step], val_minus = center[u - v*step];//v相对于center的位移,也就是y与-y
            v_sum += (val_plus - val_minus);
            m_10 += u * (val_plus + val_minus);
        }
        m_01 += v * v_sum;
    }

    return fastAtan2((float)m_01, (float)m_10);//返回角度
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值