Я копался в Реализация 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);
Я понимаю, что это как-то связано с преобразованием в шкалу, из которой был взят интересующий пункт (я читал статью Лоу), но я не могу связать точки с кодом. В частности, я не понимаю первые 3 строки и последнюю строку.
Мне нужно понять это, чтобы создать аналогичный локальный дескриптор точки для движения.
Я не понимаю первые 3 строки
Действительно это реализация SIFT кодирует несколько значений в пределах KeyPoint
octave
приписывать. Если вы ссылаетесь на линия 439 ты это видишь:
kpt.octave = octv + (layer << 8) + (cvRound((xi + 0.5)*255) << 16);
Это означает, что октава хранится в первом байтовом блоке, слой во втором байтовом блоке и т. Д.
Так kpt.octave & 255
(который можно найти в unpackOctave
method) просто маскирует октаву ключевой точки, чтобы получить эффективное значение октавы.
Также: эта реализация SIFT использует отрицательную первую октаву (int firstOctave = -1
) работать с изображением с более высоким разрешением. Поскольку октавные индексы начинаются с 0, вычисляется отображение:
octave index = 0 => 255
octave index = 1 => 0
octave index = 2 => 1
...
Это отображение вычисляется в линия 790:
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
вычисляется умножением:
Действительно, вы можете найти подробное описание в реализация SIFT в vlfeat:
Поддержка каждого пространственного бина имеет расширение SBP = 3 сигма
пикселей, где сигма — масштаб ключевой точки. Таким образом, все
Бункеры вместе имеют поддержку SBP x NBP пикселей шириной. поскольку
используется взвешивание и интерполяция пикселя, расширяется поддержка
другой половиной Таким образом, поддержка представляет собой квадратное окно
SBP x (NBP + 1) пикселей. Наконец, так как патч может быть
произвольно повернут, нам нужно рассмотреть окно 2W + = sqrt (2) x
SBP x (NBP + 1) пикселей в ширину.
Наконец, я настоятельно рекомендую вам обратиться к этому vlfeat SIFT документация.
Других решений пока нет …