@@ -108,16 +108,16 @@ std::vector<phg::SIFT::Octave> phg::buildOctaves(const cv::Mat& img, const phg::
108108 // можно подумать, как сделать эффективнее - для построения n+1 слоя доблюревать уже поблюренный n-ый слой, так чтобы в итоге получилась такая же сигма
109109 // это будет немного быстрее, тк нужно более маленькое ядро свертки на каждый шаг
110110 for (int i = 1 ; i < n_layers; i++) {
111- // TODO double sigma_layer = sigma0 * корень из двух нужной степени, чтобы при i==s получали удвоение базового блюра ;
111+ double sigma_layer = sigma0 * std::pow ( 2.0 , static_cast < double >(i) / s) ;
112112 // // вычтем sigma0 чтобы размыть ровно до нужной суммарной сигмы
113- // TODO sigma_layer = ... (вычитаем как в sigma base );
114- // cv::GaussianBlur(oct.layers[0], oct.layers[i], cv::Size(), sigma_layer, sigma_layer);
113+ sigma_layer = std::sqrt (sigma_layer * sigma_layer - sigma0 * sigma0 );
114+ cv::GaussianBlur (oct.layers [0 ], oct.layers [i], cv::Size (), sigma_layer, sigma_layer);
115115 }
116116
117117 // подготавливаем базовый слой для следующей октавы
118118 if (o + 1 < n_octaves) {
119119 // используется в opencv, формула для пересчета ключевых точек: pt_upscaled = 2^o * pt_downscaled
120- // TODO cv::resize(даунскейлим текущий слой в два раза, без интерполяции, просто сабсепмлинг );
120+ base = downsample2x (oct. layers [s] );
121121
122122 // можно использовать и downsample2x_avg(oct.layers[s]), это позволяет потом заапскейлить слои обратно до оригинального разрешения без сдвига
123123 // но потребуется везде изменить формулу для пересчета ключевых точек: pt_upscaled = (pt_downscaled + 0.5) * 2^o - 0.5
@@ -138,7 +138,9 @@ std::vector<phg::SIFT::Octave> phg::buildDoG(const std::vector<phg::SIFT::Octave
138138 const phg::SIFT ::Octave& octave = octaves[o];
139139 dog[o].layers .resize (octave.layers .size () - 1 );
140140
141- // TODO каждый слой дога это разница n+1 и n-й гауссианы
141+ for (size_t i = 0 ; i < octave.layers .size () - 1 ; ++i) {
142+ dog[o].layers [i] = octave.layers [i + 1 ] - octave.layers [i];
143+ }
142144 }
143145
144146 return dog;
@@ -207,17 +209,49 @@ std::vector<cv::KeyPoint> phg::findScaleSpaceExtrema(const std::vector<phg::SIFT
207209 is_min = false ;
208210 };
209211
210- // TODO проверить локальный максимум на текущем скейле
212+ // проверить локальный максимум на текущем скейле
213+ check (cp[x - 1 ]);
214+ check (cp[x]);
215+ check (cp[x + 1 ]);
216+
217+ check (c[x - 1 ]);
218+ check (c[x + 1 ]);
219+
220+ check (cn[x - 1 ]);
221+ check (cn[x]);
222+ check (cn[x + 1 ]);
211223
212224 if (!is_max && !is_min)
213225 continue ;
214226
215- // TODO проверить локальный максимум на предыдущем скейле
227+ // проверить локальный максимум на предыдущем скейле
228+ check (pp[x - 1 ]);
229+ check (pp[x]);
230+ check (pp[x + 1 ]);
231+
232+ check (p[x - 1 ]);
233+ check (p[x]);
234+ check (p[x + 1 ]);
235+
236+ check (pn[x - 1 ]);
237+ check (pn[x]);
238+ check (pn[x + 1 ]);
216239
217240 if (!is_max && !is_min)
218241 continue ;
219242
220- // TODO проверить локальный максимум на следующем скейле
243+ // проверить локальный максимум на следующем скейле
244+ check (np[x - 1 ]);
245+ check (np[x]);
246+ check (np[x + 1 ]);
247+
248+ check (n[x - 1 ]);
249+ check (n[x]);
250+ check (n[x + 1 ]);
251+
252+ check (nn[x - 1 ]);
253+ check (nn[x]);
254+ check (nn[x + 1 ]);
221255
222256 if (!is_max && !is_min)
223257 continue ;
@@ -237,14 +271,13 @@ std::vector<cv::KeyPoint> phg::findScaleSpaceExtrema(const std::vector<phg::SIFT
237271 float ds = (nL.at <float >(yi, xi) - pL.at <float >(yi, xi)) * 0 .5f ;
238272
239273 // гессиан
240- float dxx, dxy, dyy, dxs, dys, dss;
241- // float dxx = cL.at<float>(yi, xi + 1) + cL.at<float>(yi, xi - 1) - 2.f * resp_center;
242- // float dyy = TODO;
243- // float dss = TODO;
244- //
245- // float dxy = (cL.at<float>(yi + 1, xi + 1) - cL.at<float>(yi + 1, xi - 1) - cL.at<float>(yi - 1, xi + 1) + cL.at<float>(yi - 1, xi - 1)) * 0.25f;
246- // float dxs = TODO;
247- // float dys = TODO;
274+ float dxx = cL.at <float >(yi, xi + 1 ) + cL.at <float >(yi, xi - 1 ) - 2 .f * resp_center;
275+ float dyy = cL.at <float >(yi + 1 , xi) + cL.at <float >(yi - 1 , xi) - 2 .f * resp_center;
276+ float dss = nL.at <float >(yi, xi) + pL.at <float >(yi, xi) - 2 .f * resp_center;
277+
278+ float dxy = (cL.at <float >(yi + 1 , xi + 1 ) - cL.at <float >(yi + 1 , xi - 1 ) - cL.at <float >(yi - 1 , xi + 1 ) + cL.at <float >(yi - 1 , xi - 1 )) * 0 .25f ;
279+ float dxs = (nL.at <float >(yi, xi + 1 ) - nL.at <float >(yi, xi - 1 ) - pL.at <float >(yi, xi + 1 ) + pL.at <float >(yi, xi - 1 )) * 0 .25f ;
280+ float dys = (nL.at <float >(yi + 1 , xi) - nL.at <float >(yi + 1 , xi) - pL.at <float >(yi - 1 , xi) + pL.at <float >(yi - 1 , xi)) * 0 .25f ;
248281
249282 cv::Matx33f H (dxx, dxy, dxs, dxy, dyy, dys, dxs, dys, dss);
250283
@@ -273,21 +306,21 @@ std::vector<cv::KeyPoint> phg::findScaleSpaceExtrema(const std::vector<phg::SIFT
273306 // из линейной алгебры, сумма диагональных элементов матрицы (след) равна сумме собственных чисел
274307 // определитель матрицы равен произведению собственных чисел
275308 // в случае гессиана (пространственной части: (dxx dxy, dxy, dyy)), собственные числа lambda1, lambda2 - силы кривизны в направлении максимальной кривизны и в ортогональном
276- // float trace = //TODO ; // = lambda1 + lambda2
277- // float det = // TODO ; // = lambda1 * lambda2
278- // if (det <= 0)
279- // break; // если произведение кривизн отрицательное, то мы находимся в седловой точке, а не в максимуме/минимуме. если нулевое, то это ровная граница вообще
280- //
281- // // если граница незацепистая = грань, то одна кривизна сильно больше чем другая. хотим, чтобы обе кривизны были примерно сопоставимы
282- // // тогда их отношение r = lambda1/lambda2 будет не очень большим
283- // // если расписать trace * trace / det через r, то получится (r + 1) ^ 2 / r
284- // // функция растущая по r, так что если наше фактическое значение trace * trace / det выше (r + 1) ^ 2 / r, то и наше отношение кривизн больше порога, значит плохая зацепистость
285- // // и просто как интуиция, при больших r это выражение просто до r сокращается
286- //
287- // // в итоге получается что порог edge_threshold в отличие от response_threshold наоборот, чем больше тем расслабленнее
288- // float r = edge_threshold;
289- // if (TODO )
290- // break;
309+ float trace = dxx + dyy ; // = lambda1 + lambda2
310+ float det = dxx * dyy - dxy * dxy ; // = lambda1 * lambda2
311+ if (det <= 0 )
312+ break ; // если произведение кривизн отрицательное, то мы находимся в седловой точке, а не в максимуме/минимуме. если нулевое, то это ровная граница вообще
313+
314+ // если граница незацепистая = грань, то одна кривизна сильно больше чем другая. хотим, чтобы обе кривизны были примерно сопоставимы
315+ // тогда их отношение r = lambda1/lambda2 будет не очень большим
316+ // если расписать trace * trace / det через r, то получится (r + 1) ^ 2 / r
317+ // функция растущая по r, так что если наше фактическое значение trace * trace / det выше (r + 1) ^ 2 / r, то и наше отношение кривизн больше порога, значит плохая зацепистость
318+ // и просто как интуиция, при больших r это выражение просто до r сокращается
319+
320+ // в итоге получается что порог edge_threshold в отличие от response_threshold наоборот, чем больше тем расслабленнее
321+ float r = edge_threshold;
322+ if (trace * trace / det > (r + 1 ) * (r + 1 ) / r )
323+ break ;
291324 }
292325
293326 // скейлим координаты точек обратно до родных размеров картинки
@@ -379,39 +412,39 @@ std::vector<cv::KeyPoint> phg::computeOrientations(const std::vector<cv::KeyPoin
379412
380413 for (int dy = -radius; dy <= radius; dy++) {
381414 for (int dx = -radius; dx <= radius; dx++) {
382- // int px = xi + dx;
383- // int py = yi + dy;
384- //
385- // // градиент
386- // float gx = img.at<float>(py, px + 1) - img.at<float>(py, px - 1);
387- // float gy = img.at<float>(py + 1, px) - img.at<float>(py - 1, px);
388- //
389- // float mag = TODO ;
390- // float angle = std::atan2(TODO ); // [-pi, pi]
391- //
392- // float angle_deg = angle * 180.f / (float) CV_PI;
393- // if (angle_deg < 0.f) angle_deg += 360.f;
394- //
395- // // гауссово взвешивание голоса точки с затуханием к краям
396- // float weight = std::exp(-(TODO ) / (2.f * sigma_win * sigma_win));
397- // if (!params.enable_orientation_gaussian_weighting) {
398- // weight = 1.f;
399- // }
400- //
401- // // голосуем в гистограмме направлений. находим два ближайших бина и гладко распределяем голос между ними
402- // // в таком случае, голос попавший близко к границе между бинами, проголосует поровну за оба бина
403- // float bin = TODO ;
404- // if (bin >= n_bins) bin -= n_bins;
405- // int bin0 = (int) bin;
406- // int bin1 = (bin0 + 1) % n_bins;
407- //
408- // float frac = bin - bin0;
409- // if (!params.enable_orientation_bin_interpolation) {
410- // frac = 0.f;
411- // }
412- //
413- // histogram[bin0] += TODO ;
414- // histogram[bin1] += TODO ;
415+ int px = xi + dx;
416+ int py = yi + dy;
417+
418+ // градиент
419+ float gx = img.at <float >(py, px + 1 ) - img.at <float >(py, px - 1 );
420+ float gy = img.at <float >(py + 1 , px) - img.at <float >(py - 1 , px);
421+
422+ float mag = std::sqrt (gx * gx + gy * gy) ;
423+ float angle = std::atan2 (gy, gx ); // [-pi, pi]
424+
425+ float angle_deg = angle * 180 .f / (float ) CV_PI ;
426+ if (angle_deg < 0 .f ) angle_deg += 360 .f ;
427+
428+ // гауссово взвешивание голоса точки с затуханием к краям
429+ float weight = std::exp (-(dx * dx + dy * dy ) / (2 .f * sigma_win * sigma_win));
430+ if (!params.enable_orientation_gaussian_weighting ) {
431+ weight = 1 .f ;
432+ }
433+
434+ // голосуем в гистограмме направлений. находим два ближайших бина и гладко распределяем голос между ними
435+ // в таком случае, голос попавший близко к границе между бинами, проголосует поровну за оба бина
436+ float bin = n_bins * angle_deg / 360.0 ;
437+ if (bin >= n_bins) bin -= n_bins;
438+ int bin0 = (int ) bin;
439+ int bin1 = (bin0 + 1 ) % n_bins;
440+
441+ float frac = bin - bin0;
442+ if (!params.enable_orientation_bin_interpolation ) {
443+ frac = 0 .f ;
444+ }
445+
446+ histogram[bin0] += ( 1.0 - frac) * mag * weight ;
447+ histogram[bin1] += frac * mag * weight ;
415448 }
416449 }
417450
@@ -450,20 +483,20 @@ std::vector<cv::KeyPoint> phg::computeOrientations(const std::vector<cv::KeyPoin
450483 // f(1) + f(-1) = 2a + 2c -> a = (left + right - 2 * center) / 2
451484 // f(1) - f(-1) = 2b -> b = (right - left) / 2
452485
453- // float offset = TODO ;
454- // if (!params.enable_orientation_subpixel_localization) {
455- // offset = 0.f;
456- // }
457- //
458- // float bin_real = i + offset;
459- // if (bin_real < 0.f) bin_real += n_bins;
460- // if (bin_real >= n_bins) bin_real -= n_bins;
461- //
462- // float angle = bin_real * 360.f / n_bins;
463- //
464- // cv::KeyPoint new_kp = kp;
465- // new_kp.angle = angle;
466- // oriented_kpts.push_back(new_kp);
486+ float offset = -(right - left) / ( 2 * (left + right - 2 * center)) ;
487+ if (!params.enable_orientation_subpixel_localization ) {
488+ offset = 0 .f ;
489+ }
490+
491+ float bin_real = i + offset;
492+ if (bin_real < 0 .f ) bin_real += n_bins;
493+ if (bin_real >= n_bins) bin_real -= n_bins;
494+
495+ float angle = bin_real * 360 .f / n_bins;
496+
497+ cv::KeyPoint new_kp = kp;
498+ new_kp.angle = angle;
499+ oriented_kpts.push_back (new_kp);
467500 }
468501 }
469502 }
@@ -574,11 +607,11 @@ std::pair<cv::Mat, std::vector<cv::KeyPoint>> phg::computeDescriptors(const std:
574607 bin_o -= n_orient_bins;
575608
576609 // семплы вблизи края патча взвешиваем с меньшим весом
577- // float weight = std::exp(-(TODO ) / (2.f * sigma_desc * sigma_desc));
578- // if (!params.enable_descriptor_gaussian_weighting) {
579- // weight = 1.f;
580- // }
581- // float weighted_mag = mag * weight;
610+ float weight = std::exp (-(rot_x * rot_x + rot_y * rot_y ) / (2 .f * sigma_desc * sigma_desc));
611+ if (!params.enable_descriptor_gaussian_weighting ) {
612+ weight = 1 .f ;
613+ }
614+ float weighted_mag = mag * weight;
582615
583616 if (params.enable_descriptor_bin_interpolation ) {
584617 // размажем вклад weighted_mag по пространственным бинам и по бинам гистограммок трилинейной интерполяцией
@@ -609,8 +642,8 @@ std::pair<cv::Mat, std::vector<cv::KeyPoint>> phg::computeDescriptors(const std:
609642 io += n_orient_bins;
610643 float wo = (dio == 0 ) ? (1 .f - fo) : fo;
611644
612- // int idx = TODO ;
613- // desc[idx] += TODO ;
645+ int idx = (iy * n_spatial_bins + ix) * n_orient_bins + io ;
646+ desc[idx] += weighted_mag * wx * wy * wo ;
614647 }
615648 }
616649 }
@@ -620,9 +653,8 @@ std::pair<cv::Mat, std::vector<cv::KeyPoint>> phg::computeDescriptors(const std:
620653 int io_nearest = (int )std::round (bin_o) % n_orient_bins;
621654
622655 if (ix_nearest >= 0 && ix_nearest < n_spatial_bins && iy_nearest >= 0 && iy_nearest < n_spatial_bins) {
623- // TODO uncomment
624- // int idx = (iy_nearest * n_spatial_bins + ix_nearest) * n_orient_bins + io_nearest;
625- // desc[idx] += weighted_mag;
656+ int idx = (iy_nearest * n_spatial_bins + ix_nearest) * n_orient_bins + io_nearest;
657+ desc[idx] += weighted_mag;
626658 }
627659 }
628660 }
0 commit comments