OpenCV的SiftDescriptorExtractor如何转换描述符值?

fen*_*sss 4 c++ opencv sift feature-descriptor

我对SiftDescriptorExtractor工作的最后一部分有疑问,

我正在做以下事情:

    SiftDescriptorExtractor extractor;
    Mat descriptors_object;
    extractor.compute( img_object, keypoints_object, descriptors_object );
Run Code Online (Sandbox Code Playgroud)

现在我想检查一下descriptors_object Mat对象的元素:

std::cout<< descriptors_object.row(1) << std::endl;
Run Code Online (Sandbox Code Playgroud)

输出看起来像:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 32, 15, 0, 0, 0, 0, 0, 0, 73, 33, 11, 0, 0, 0, 0, 0, 0, 5, 114, 1, 0, 0, 0, 0, 51, 154, 20, 0, 0, 0, 0, 0, 154, 154, 1, 2, 1, 0, 0, 0, 154, 148, 18, 1, 0, 0, 0, 0, 0, 2, 154, 61, 0, 0, 0, 0, 5, 60, 154, 30, 0, 0, 0, 0, 34, 70, 6, 15, 3, 2, 1, 0, 14, 16, 2, 0, 0, 0, 0, 0, 0, 0, 154, 84, 0, 0, 0, 0, 0, 0, 154, 64, 0, 0, 0, 0, 0, 0, 6, 6, 1, 0, 1, 0, 0, 0]
Run Code Online (Sandbox Code Playgroud)

但在Lowe论文中指出:

因此,我们通过对单位特征向量中的值进行阈值处理来减小大梯度量值的影响,每个值不大于0.2,然后重新归一化为单位长度.这意味着匹配大梯度的大小不再那么重要,并且方向的分布具有更大的重点.使用包含针对相同3D对象的不同照明的图像,通过实验确定0.2的值.

因此,特征向量中的数字不应大于0.2.

问题是,这些值是如何在Mat对象中转换的?

del*_*eil 8

因此,特征向量中的数字不应大于0.2.

没有.论文说SIFT描述符是:

  1. 归一化(L2范数)
  2. 截断使用0.2阈值(即在规范化值上循环并在适当时截断)
  3. 再次归一化

因此理论上任何SIFT描述符组件都介于其间[0, 1],即使在实践中观察到的有效范围较小(见下文).

问题是,这些值是如何在Mat对象中转换的?

它们从浮点值转换为unsigned char-s.

这是OpenCV modules/nonfree/src/sift.cpp calcSIFTDescriptor方法的相关部分:

float nrm2 = 0;
len = d*d*n;
for( k = 0; k < len; k++ )
    nrm2 += dst[k]*dst[k];
float thr = std::sqrt(nrm2)*SIFT_DESCR_MAG_THR;
for( i = 0, nrm2 = 0; i < k; i++ )
{
    float val = std::min(dst[i], thr);
    dst[i] = val;
    nrm2 += val*val;
}
nrm2 = SIFT_INT_DESCR_FCTR/std::max(std::sqrt(nrm2), FLT_EPSILON);
for( k = 0; k < len; k++ )
{
    dst[k] = saturate_cast<uchar>(dst[k]*nrm2);
}
Run Code Online (Sandbox Code Playgroud)

附:

static const float SIFT_INT_DESCR_FCTR = 512.f;
Run Code Online (Sandbox Code Playgroud)

这是因为经典的SIFT实现unsigned char通过512乘法因子将归一化的浮点值量化为整数,这相当于考虑任何SIFT分量在其间变化[0, 1/2],从而避免在尝试编码整个[0, 1]范围时的松散精度.