我正在深入研究OpenCV的SIFT描述符提取实现.我发现了一些令人费解的代码来获得兴趣点邻域的半径.下面是带注释的代码,变量名称更改为更具描述性:
// keep octave below 256 (255 is 1111 1111)
int octave = kpt.octave & 255;
// if octave is >= 128, ...????
octave = octave < 128 ? octave : (-128 | octave);
// 1/2^absval(octave)
float scale = octave >= 0 ? 1.0f/(1 << octave) : (float)(1 << -octave);
// multiply the point's radius by the calculated scale
float scl = kpt.size * 0.5f * scale;
// the constant sclFactor is 3 and has the following comment:
// determines the size of a single descriptor orientation histogram
float histWidth = sclFactor * scl;
// descWidth is the number of histograms on one side of the descriptor
// the long float is sqrt(2)
int radius = (int)(histWidth * 1.4142135623730951f * (descWidth + 1) * 0.5f);
Run Code Online (Sandbox Code Playgroud)
我知道这与转换到兴趣点的比例有关(我读过Lowe的论文),但我无法将这些点连接到代码上.具体来说,我不明白前3行和最后一行.
我需要理解这一点,为运动创建一个类似的本地点描述符.
我不明白前3行
实际上,这个SIFT实现在属性中编码了几个值KeyPoint
octave
.如果您参考第439行,您可以看到:
kpt.octave = octv + (layer << 8) + (cvRound((xi + 0.5)*255) << 16);
Run Code Online (Sandbox Code Playgroud)
这意味着八度音程存储在第一个字节块内,第二个字节块内的层等等.
所以kpt.octave & 255
(可以在unpackOctave
方法中找到)只是屏蔽关键点八度音以检索有效的八度音程值.
另外:此SIFT实现使用负的第一个八度(int firstOctave = -1
)来处理更高分辨率的图像.由于八度音程索引从0开始,因此计算映射:
octave index = 0 => 255
octave index = 1 => 0
octave index = 2 => 1
...
Run Code Online (Sandbox Code Playgroud)
此映射在第790行计算:
kpt.octave = (kpt.octave & ~255) | ((kpt.octave + firstOctave) & 255);
Run Code Online (Sandbox Code Playgroud)
因此,上面的第二行只是一种映射这些值的方法:
octave = 255 => -1
octave = 0 => 0
octave = 1 => 1
..
Run Code Online (Sandbox Code Playgroud)
第三行只是一种计算尺度的方法,考虑到负八度音阶给出的音阶> 1,例如1 << -octave
给出2,octave = -1
这意味着它的大小加倍.
[我不明白]最后一行.
基本上它对应于包裹方形平面补丁的圆的半径D
,因此sqrt(2)
除以2. D
通过乘以计算:
实际上,您可以在vlfeat的SIFT实现中找到详细说明:
每个空间仓的支持具有SBP = 3西格玛像素的扩展,其中西格玛是关键点的尺度.因此,所有箱一起具有支撑SBP x NBP像素宽.由于使用了像素的加权和内插,因此支撑由另一个半箱延伸.因此,支撑是SBP x(NBP + 1)像素的方形窗口.最后,由于补丁可以任意转动,我们需要考虑的窗口2W + = SQRT(2)X SBP X(NBP + 1)个像素宽.
最后我强烈建议您参考这个vlfeat SIFT文档.
归档时间: |
|
查看次数: |
4436 次 |
最近记录: |