opencv3 orb源码解析

orb的原理已经有很多博主已经解释过了,但是感觉大家都讲的很理论,有些具体的实现还是没有讲清楚,因此自己翻出了opencv的源码出来看。

源码的位置如图:

看了好几天之后,才大概弄清楚了orb算法的具体实现是怎样的,画个流程图给你们看。

至于orb描述子的生成呢,它是有2点对比较,3点对和4点对比较三种生成方式,就是说每次可以在特征点的邻域内随机选取两个,三个或者四个点作为一组进行比较。对于最常用的两点对,比较的结果就是0或1,即1个比特,而描述子作为矩阵,存储的数据类型为8位无符号整数,因此是在一次循环中取16个点,按顺序为8组点对,得到八个比特即一个字节的比较结果,源码如下:

        if( wta_k == 2 )
        {
            for (i = 0; i < dsize; ++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;
            }
        }

而对于三点对和四点对,则是找出点对中最大的点的编号(1,2或3)/(1,2,3或4),因此结果为2个比特,故一次循环中取12或者16个点比较,从而得到8比特即一字节的描述子,源码中表述如下(3点对的就不贴了,反正是一个意思):

        else if( wta_k == 4 )
        {
            for (i = 0; i < dsize; ++i, pattern += 16)
            {
                int t0, t1, t2, t3, u, v, k, val;
                t0 = GET_VALUE(0); t1 = GET_VALUE(1);
                t2 = GET_VALUE(2); t3 = GET_VALUE(3);
                u = 0, v = 2;
                if( t1 > t0 ) t0 = t1, u = 1;
                if( t3 > t2 ) t2 = t3, v = 3;
                k = t0 > t2 ? u : v;
                val = k;

                t0 = GET_VALUE(4); t1 = GET_VALUE(5);
                t2 = GET_VALUE(6); t3 = GET_VALUE(7);
                u = 0, v = 2;
                if( t1 > t0 ) t0 = t1, u = 1;
                if( t3 > t2 ) t2 = t3, v = 3;
                k = t0 > t2 ? u : v;
                val |= k << 2;

                t0 = GET_VALUE(8); t1 = GET_VALUE(9);
                t2 = GET_VALUE(10); t3 = GET_VALUE(11);
                u = 0, v = 2;
                if( t1 > t0 ) t0 = t1, u = 1;
                if( t3 > t2 ) t2 = t3, v = 3;
                k = t0 > t2 ? u : v;
                val |= k << 4;

                t0 = GET_VALUE(12); t1 = GET_VALUE(13);
                t2 = GET_VALUE(14); t3 = GET_VALUE(15);
                u = 0, v = 2;
                if( t1 > t0 ) t0 = t1, u = 1;
                if( t3 > t2 ) t2 = t3, v = 3;
                k = t0 > t2 ? u : v;
                val |= k << 6;

                desc[i] = (uchar)val;
            }
        }
那么就要问了,点对的选取方式是怎样的呢?对于两点对的orb描述子,通过神经网络的训练,已经发现了一种效果很好的点对pattern,适合的应用场景是31X31的特征点所在邻域,一共是256行,每行4个值,代表两个点的横纵坐标,通常orb描述子是32个字节的,即256比特,因此这个pattern对于2点对来说,是刚好的。而对于3/4点对生成方式,则是由这个已有的pattern来随机生成所需要的pattern。但是对于其他大小的邻域,这个pattern就不能使用了,因此就是随机生成的pattern。pattern在源码中的定义如下:

static int bit_pattern_31_[256*4]
最后提一句,在生成金字塔的时候,为了节省存储空间,各层图片都是放在一个大矩阵里面的,然而各层图片不是紧密连接挨着的,而是每一层图片外围都加上了一个固定宽度的边框,这是因为在之后的描述子计算前,要提取所在层的图像,然后对这一层的图像做了高斯模糊,这是为了提高对噪声的鲁棒性,因此加上边框便于模糊处理。而边框的添加方式,则是以边界为对称轴,镜像复制图像边缘的像素值到边框里面。源码中的体现如下:

copyMakeBorder(currImg, extImg, border, border, border, border,
                           BORDER_REFLECT_101+BORDER_ISOLATED);
大概想说的就这么多了,看了好几天的源码真的挺心累的。。。如果有什么不对的,欢迎各位指正!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值