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

时间:2013-02-16 15:14:51

标签: c++ opencv sift feature-descriptor

我对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 paper中声明:

  

因此,我们减少了影响力   大的梯度幅度   对单元中的值进行阈值处理   每个特征向量都不大   超过0.2,然后重新归一化为   单位长度。这意味着匹配   大梯度的大小是   再也不那么重要了   方向分布有   更加重视。 0.2的值是   通过实验确定使用图像   包含不同的照明   相同的3D对象。

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

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

1 个答案:

答案 0 :(得分:7)

  

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

没有。该论文称SIFT描述符是:

  1. 归一化(使用L2规范)
  2. 使用0.2作为阈值进行截断(即循环超过规范化值并在适当时截断)
  3. 再次标准化
  4. 因此理论上任何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);
    }
    

    使用:

    static const float SIFT_INT_DESCR_FCTR = 512.f;
    

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