我不明白前 3 行
事实上这个 SIFT 实现encodes内的几个值KeyPoint
octave
属性。如果您参考line 439 https://github.com/Itseez/opencv/blob/173442bb2ecd527f1884d96d7327bff293f0c65a/modules/nonfree/src/sift.cpp#L439你可以看到:
kpt.octave = octv + (layer << 8) + (cvRound((xi + 0.5)*255) << 16);
这意味着八度音程存储在第一个字节块中,层存储在第二个字节块中,等等。
So kpt.octave & 255
(可以在unpackOctave
方法)只是屏蔽关键点八度音程以检索有效八度音程值。
另外:此 SIFT 实现使用负的第一个八度音程(int firstOctave = -1
)以处理更高分辨率的图像。由于八度音阶索引从 0 开始,因此计算映射:
octave index = 0 => 255
octave index = 1 => 0
octave index = 2 => 1
...
该映射是在以下位置计算的line 790 https://github.com/Itseez/opencv/blob/173442bb2ecd527f1884d96d7327bff293f0c65a/modules/nonfree/src/sift.cpp#L790:
kpt.octave = (kpt.octave & ~255) | ((kpt.octave + firstOctave) & 255);
因此上面的第二行只是映射回这些值的一种方法:
octave = 255 => -1
octave = 0 => 0
octave = 1 => 1
..
第三行只是计算音阶的一种方法,考虑到负八度给出的音阶 > 1,例如1 << -octave
给出 2 为octave = -1
这意味着它的大小增加了一倍。
[我不明白]最后一行。
基本上它对应于包裹尺寸平方块的圆的半径D
,因此sqrt(2)
并除以 2。D
通过乘法计算:
- 关键点尺度,
- 放大倍数 = 3,
- 描述符直方图的宽度 = 4,向上舍入到下一个整数(因此为 +1)
事实上,您可以在其中找到详细的描述vlfeat 的 SIFT 实现 https://github.com/vlfeat/vlfeat/blob/38a03e12daf50ee98633de06120834d0d1d87e23/vl/sift.c#L1948:
每个空间仓的支持度扩展为SBP = 3sigma
像素,其中 sigma 是关键点的比例。因此所有的
bin 一起具有支持 SBP x NBP 像素宽。自从
使用像素加权和插值,支持扩展
另一个半箱。因此,支撑体是一个方形窗口
SBP x (NBP + 1) 像素。最后,由于补丁可以
任意旋转,我们需要考虑一个窗口 2W += sqrt(2) x
SBP x (NBP + 1) 像素宽。
最后强烈推荐大家参考一下这个vlfeat SIFT 文档 http://www.vlfeat.org/api/sift.html.