我对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对象中转换的?
答案 0 :(得分:7)
因此特征向量中的数字不应大于0.2 值。
没有。该论文称SIFT描述符是:
0.2
作为阈值进行截断(即循环超过规范化值并在适当时截断)因此理论上任何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]
范围。