5

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

我正在执行以下操作:

    SiftDescriptorExtractor extractor;
    Mat descriptors_object;
    extractor.compute( img_object, keypoints_object, descriptors_object );

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

std::cout<< descriptors_object.row(1) << std::endl;

输出看起来像:

[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]

但在Lowe 论文中指出:

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

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

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

4

1 回答 1

10

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

不,论文说 SIFT 描述符是:

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

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

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

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

这是 OpenCVmodules/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);
}

和:

static const float SIFT_INT_DESCR_FCTR = 512.f;

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

于 2013-02-16T22:58:52.833 回答