X-Git-Url: http://rtime.felk.cvut.cz/gitweb/hercules2020/kcf.git/blobdiff_plain/61c86a6cffb5c71beee1c271f69672854f80df3f..7822cf9f1c5cef7d15e30e7c416d0e8b6e3d7c3a:/src/kcf.cpp diff --git a/src/kcf.cpp b/src/kcf.cpp index 32cd950..a637ec7 100644 --- a/src/kcf.cpp +++ b/src/kcf.cpp @@ -4,6 +4,7 @@ #include #include "threadctx.hpp" #include "debug.h" +#include #ifdef FFTW #include "fft_fftw.h" @@ -34,6 +35,14 @@ void clamp2(T& n, const T& lower, const T& upper) n = std::max(lower, std::min(n, upper)); } +#if CV_MAJOR_VERSION < 3 +template static inline +cv::Size_<_Tp> operator / (const cv::Size_<_Tp>& a, _Tp b) +{ + return cv::Size_<_Tp>(a.width / b, a.height / b); +} +#endif + class Kcf_Tracker_Private { friend KCF_Tracker; std::vector threadctxs; @@ -59,39 +68,42 @@ void KCF_Tracker::train(cv::Mat input_rgb, cv::Mat input_gray, double interp_fac TRACE(""); // obtain a sub-window for training - // TODO: Move Mats outside from here - MatScaleFeats patch_feats(1, p_num_of_feats, feature_size); - DEBUG_PRINT(patch_feats); - MatScaleFeats temp(1, p_num_of_feats, feature_size); - get_features(input_rgb, input_gray, p_current_center.x, p_current_center.y, + get_features(input_rgb, input_gray, nullptr, p_current_center.x, p_current_center.y, p_windows_size.width, p_windows_size.height, - p_current_scale).copyTo(patch_feats.scale(0)); - DEBUG_PRINT(patch_feats); - fft.forward_window(patch_feats, p_xf, temp); - DEBUG_PRINTM(p_xf); - p_model_xf = p_model_xf * (1. - interp_factor) + p_xf * interp_factor; - DEBUG_PRINTM(p_model_xf); - - ComplexMat alphaf_num, alphaf_den; + p_current_scale).copyTo(model->patch_feats.scale(0)); + DEBUG_PRINT(model->patch_feats); + fft.forward_window(model->patch_feats, model->xf, model->temp); + DEBUG_PRINTM(model->xf); + model->model_xf = model->model_xf * (1. - interp_factor) + model->xf * interp_factor; + DEBUG_PRINTM(model->model_xf); if (m_use_linearkernel) { - ComplexMat xfconj = p_xf.conj(); - alphaf_num = xfconj.mul(p_yf); - alphaf_den = (p_xf * xfconj); + ComplexMat xfconj = model->xf.conj(); + model->model_alphaf_num = xfconj.mul(model->yf); + model->model_alphaf_den = (model->xf * xfconj); } else { // Kernel Ridge Regression, calculate alphas (in Fourier domain) cv::Size sz(Fft::freq_size(feature_size)); ComplexMat kf(sz.height, sz.width, 1); - (*gaussian_correlation)(kf, p_model_xf, p_model_xf, p_kernel_sigma, true, *this); + (*gaussian_correlation)(kf, model->model_xf, model->model_xf, p_kernel_sigma, true, *this); DEBUG_PRINTM(kf); - p_model_alphaf_num = p_yf * kf; - p_model_alphaf_den = kf * (kf + p_lambda); + model->model_alphaf_num = model->yf * kf; + model->model_alphaf_den = kf * (kf + p_lambda); } - p_model_alphaf = p_model_alphaf_num / p_model_alphaf_den; - DEBUG_PRINTM(p_model_alphaf); + model->model_alphaf = model->model_alphaf_num / model->model_alphaf_den; + DEBUG_PRINTM(model->model_alphaf); // p_model_alphaf = p_yf / (kf + p_lambda); //equation for fast training } +static int round_pw2_down(int x) +{ + for (int i = 1; i < 32; i <<= 1) + x |= x >> i; + x++; + return x >> 1; +} + + void KCF_Tracker::init(cv::Mat &img, const cv::Rect &bbox, int fit_size_x, int fit_size_y) { __dbgTracer.debug = m_debug; @@ -140,72 +152,46 @@ void KCF_Tracker::init(cv::Mat &img, const cv::Rect &bbox, int fit_size_x, int f img.convertTo(input_gray, CV_32FC1); // don't need too large image - if (p_init_pose.w * p_init_pose.h > 100. * 100. && (fit_size_x == -1 || fit_size_y == -1)) { + if (p_init_pose.w * p_init_pose.h > 100. * 100.) { std::cout << "resizing image by factor of " << 1 / p_downscale_factor << std::endl; p_resize_image = true; p_init_pose.scale(p_downscale_factor); cv::resize(input_gray, input_gray, cv::Size(0, 0), p_downscale_factor, p_downscale_factor, cv::INTER_AREA); cv::resize(input_rgb, input_rgb, cv::Size(0, 0), p_downscale_factor, p_downscale_factor, cv::INTER_AREA); - } else if (!(fit_size_x == -1 && fit_size_y == -1)) { - if (fit_size_x % p_cell_size != 0 || fit_size_y % p_cell_size != 0) { - std::cerr << "Error: Fit size is not multiple of HOG cell size (" << p_cell_size << ")" << std::endl; - std::exit(EXIT_FAILURE); - } - p_fit_factor_x = (double)fit_size_x / round(p_init_pose.w * (1. + p_padding)); - p_fit_factor_y = (double)fit_size_y / round(p_init_pose.h * (1. + p_padding)); - std::cout << "resizing image horizontaly by factor of " << p_fit_factor_x << " and verticaly by factor of " - << p_fit_factor_y << std::endl; - p_fit_to_pw2 = true; - p_init_pose.scale_x(p_fit_factor_x); - p_init_pose.scale_y(p_fit_factor_y); - if (fabs(p_fit_factor_x - 1) > p_floating_error || fabs(p_fit_factor_y - 1) > p_floating_error) { - if (p_fit_factor_x < 1 && p_fit_factor_y < 1) { - cv::resize(input_gray, input_gray, cv::Size(0, 0), p_fit_factor_x, p_fit_factor_y, cv::INTER_AREA); - cv::resize(input_rgb, input_rgb, cv::Size(0, 0), p_fit_factor_x, p_fit_factor_y, cv::INTER_AREA); - } else { - cv::resize(input_gray, input_gray, cv::Size(0, 0), p_fit_factor_x, p_fit_factor_y, cv::INTER_LINEAR); - cv::resize(input_rgb, input_rgb, cv::Size(0, 0), p_fit_factor_x, p_fit_factor_y, cv::INTER_LINEAR); - } - } } - // compute win size + fit to fhog cell size p_windows_size.width = round(p_init_pose.w * (1. + p_padding) / p_cell_size) * p_cell_size; p_windows_size.height = round(p_init_pose.h * (1. + p_padding) / p_cell_size) * p_cell_size; - feature_size.width = p_windows_size.width / p_cell_size; - feature_size.height = p_windows_size.height / p_cell_size; + + if (fit_size_x == 0 || fit_size_y == 0) { + // Round down to the next highest power of 2 + fit_size = cv::Size(round_pw2_down(p_windows_size.width), + round_pw2_down(p_windows_size.height)); + } else if (fit_size_x == -1 || fit_size_y == -1) { + fit_size = p_windows_size; + } else { + fit_size = cv::Size(fit_size_x, fit_size_y); + } + + feature_size = fit_size / p_cell_size; p_scales.clear(); - for (int i = -int(p_num_scales) / 2; i <= int(p_num_scales) / 2; ++i) + for (int i = -int(p_num_scales - 1) / 2; i <= int(p_num_scales) / 2; ++i) p_scales.push_back(std::pow(p_scale_step, i)); -#ifdef CUFFT - if (feature_size.height * (feature_size.width / 2 + 1) > 1024) { - std::cerr << "Window after forward FFT is too big for CUDA kernels. Plese use -f to set " - "the window dimensions so its size is less or equal to " - << 1024 * p_cell_size * p_cell_size * 2 + 1 - << " pixels . Currently the size of the window is: " << p_windows_size.width << "x" << p_windows_size.height - << " which is " << p_windows_size.width * p_windows_size.height << " pixels. " << std::endl; - std::exit(EXIT_FAILURE); - } + p_angles.clear(); + for (int i = -int(p_num_angles - 1) / 2; i <= int(p_num_angles) / 2; ++i) + p_angles.push_back(i * p_angle_step); +#ifdef CUFFT if (m_use_linearkernel) { std::cerr << "cuFFT supports only Gaussian kernel." << std::endl; std::exit(EXIT_FAILURE); } -#else - p_xf.create(feature_size.height, feature_size.height / 2 + 1, p_num_of_feats); #endif -#if defined(CUFFT) || defined(FFTW) - uint width = feature_size.width / 2 + 1; -#else - uint width = feature_size.width; -#endif - p_model_xf.create(feature_size.height, width, p_num_of_feats); - p_yf.create(feature_size.height, width, 1); - p_xf.create(feature_size.height, width, p_num_of_feats); + model.reset(new Model(feature_size, p_num_of_feats)); #ifndef BIG_BATCH for (auto scale: p_scales) @@ -214,7 +200,7 @@ void KCF_Tracker::init(cv::Mat &img, const cv::Rect &bbox, int fit_size_x, int f d.threadctxs.emplace_back(feature_size, p_num_of_feats, p_num_scales); #endif - gaussian_correlation.reset(new GaussianCorrelation(1, feature_size)); + gaussian_correlation.reset(new GaussianCorrelation(1, p_num_of_feats, feature_size)); p_current_center = p_init_pose.center(); p_current_scale = 1.; @@ -226,12 +212,16 @@ void KCF_Tracker::init(cv::Mat &img, const cv::Rect &bbox, int fit_size_x, int f p_min_max_scale[0] = std::pow(p_scale_step, std::ceil(std::log(min_size_ratio) / log(p_scale_step))); p_min_max_scale[1] = std::pow(p_scale_step, std::floor(std::log(max_size_ratio) / log(p_scale_step))); - std::cout << "init: img size " << img.cols << "x" << img.rows << std::endl; - std::cout << "init: win size " << p_windows_size.width << "x" << p_windows_size.height << std::endl; - std::cout << "init: FFT size " << feature_size.width << "x" << feature_size.height << std::endl; + std::cout << "init: img size " << img.size() << std::endl; + std::cout << "init: win size " << p_windows_size; + if (p_windows_size != fit_size) + std::cout << " resized to " << fit_size; + std::cout << std::endl; + std::cout << "init: FFT size " << feature_size << std::endl; std::cout << "init: min max scales factors: " << p_min_max_scale[0] << " " << p_min_max_scale[1] << std::endl; - p_output_sigma = std::sqrt(p_init_pose.w * p_init_pose.h) * p_output_sigma_factor / p_cell_size; + p_output_sigma = std::sqrt(p_init_pose.w * p_init_pose.h * double(fit_size.area()) / p_windows_size.area()) + * p_output_sigma_factor / p_cell_size; fft.init(feature_size.width, feature_size.height, p_num_of_feats, p_num_scales); fft.set_window(MatDynMem(cosine_window_function(feature_size.width, feature_size.height))); @@ -239,8 +229,8 @@ void KCF_Tracker::init(cv::Mat &img, const cv::Rect &bbox, int fit_size_x, int f // window weights, i.e. labels MatScales gsl(1, feature_size); gaussian_shaped_labels(p_output_sigma, feature_size.width, feature_size.height).copyTo(gsl.plane(0)); - fft.forward(gsl, p_yf); - DEBUG_PRINTM(p_yf); + fft.forward(gsl, model->yf); + DEBUG_PRINTM(model->yf); // train initial model train(input_rgb, input_gray, 1.0); @@ -256,9 +246,6 @@ void KCF_Tracker::updateTrackerPosition(BBox_c &bbox) BBox_c tmp = bbox; if (p_resize_image) { tmp.scale(p_downscale_factor); - } else if (p_fit_to_pw2) { - tmp.scale_x(p_fit_factor_x); - tmp.scale_y(p_fit_factor_y); } p_current_center = tmp.center(); } @@ -270,13 +257,10 @@ BBox_c KCF_Tracker::getBBox() tmp.cy = p_current_center.y; tmp.w = p_init_pose.w * p_current_scale; tmp.h = p_init_pose.h * p_current_scale; + tmp.a = 0; if (p_resize_image) tmp.scale(1 / p_downscale_factor); - if (p_fit_to_pw2) { - tmp.scale_x(1 / p_fit_factor_x); - tmp.scale_y(1 / p_fit_factor_y); - } return tmp; } @@ -291,21 +275,14 @@ void KCF_Tracker::resizeImgs(cv::Mat &input_rgb, cv::Mat &input_gray) if (p_resize_image) { cv::resize(input_gray, input_gray, cv::Size(0, 0), p_downscale_factor, p_downscale_factor, cv::INTER_AREA); cv::resize(input_rgb, input_rgb, cv::Size(0, 0), p_downscale_factor, p_downscale_factor, cv::INTER_AREA); - } else if (p_fit_to_pw2 && fabs(p_fit_factor_x - 1) > p_floating_error && - fabs(p_fit_factor_y - 1) > p_floating_error) { - if (p_fit_factor_x < 1 && p_fit_factor_y < 1) { - cv::resize(input_gray, input_gray, cv::Size(0, 0), p_fit_factor_x, p_fit_factor_y, cv::INTER_AREA); - cv::resize(input_rgb, input_rgb, cv::Size(0, 0), p_fit_factor_x, p_fit_factor_y, cv::INTER_AREA); - } else { - cv::resize(input_gray, input_gray, cv::Size(0, 0), p_fit_factor_x, p_fit_factor_y, cv::INTER_LINEAR); - cv::resize(input_rgb, input_rgb, cv::Size(0, 0), p_fit_factor_x, p_fit_factor_y, cv::INTER_LINEAR); - } } } double KCF_Tracker::findMaxReponse(uint &max_idx, cv::Point2d &new_location) const { double max = -1.; + max_idx = std::numeric_limits::max(); + #ifndef BIG_BATCH for (uint j = 0; j < d.threadctxs.size(); ++j) { if (d.threadctxs[j].max.response > max) { @@ -321,37 +298,31 @@ double KCF_Tracker::findMaxReponse(uint &max_idx, cv::Point2d &new_location) con } } #endif + assert(max_idx < IF_BIG_BATCH(p_scales.size(), d.threadctxs.size())); if (m_visual_debug) { - cv::Mat all_responses(cv::Size(p_num_angles * 100, p_num_scales * 100), - d.threadctxs[max_idx].response.plane(0).type(), cv::Scalar::all(0)); + const bool rgb = true; + int type = rgb ? d.threadctxs[0].dbg_patch[0].type() : d.threadctxs[0].response.type(); + int w = true ? 100 : (rgb ? fit_size.width : feature_size.width); + int h = true ? 100 : (rgb ? fit_size.height : feature_size.height); + cv::Mat all_responses((h + 1) * p_num_scales - 1, + (w + 1) * p_num_angles - 1, type, cv::Scalar::all(0)); for (size_t i = 0; i < p_num_scales; ++i) { for (size_t j = 0; j < p_num_angles; ++j) { - cv::Mat in_roi(all_responses, cv::Rect(j * 100, i * 100, 100, 100)); - cv::Mat copy_response = d.threadctxs[p_num_angles * i + j].response.plane(0).clone(); - - copy_response = copy_response(cv::Rect(0, 0, copy_response.cols & -2, copy_response.rows & -2)); - - int cx = copy_response.cols / 2; - int cy = copy_response.rows / 2; - cv::Mat q0(copy_response, cv::Rect(0, 0, cx, cy)); - cv::Mat q1(copy_response, cv::Rect(cx, 0, cx, cy)); - cv::Mat q2(copy_response, cv::Rect(0, cy, cx, cy)); - cv::Mat q3(copy_response, cv::Rect(cx, cy, cx, cy)); cv::Mat tmp; - q0.copyTo(tmp); - q3.copyTo(q0); - tmp.copyTo(q3); - q1.copyTo(tmp); - q2.copyTo(q1); - tmp.copyTo(q2); - - copy_response.copyTo(in_roi); + if (rgb) { + tmp = d.threadctxs[IF_BIG_BATCH(0, p_num_angles * i + j)].dbg_patch[IF_BIG_BATCH(p_num_angles * i + j, 0)]; + } else { + tmp = d.threadctxs[IF_BIG_BATCH(0, p_num_angles * i + j)].response.plane(IF_BIG_BATCH(p_num_angles * i + j, 0)); + tmp = circshift(tmp, -tmp.cols/2, -tmp.rows/2); + } + cv::resize(tmp, tmp, cv::Size(w, h)); + cv::Mat resp_roi(all_responses, cv::Rect(j * (w+1), i * (h+1), w, h)); + tmp.copyTo(resp_roi); } } - cv::namedWindow("All responses", CV_WINDOW_AUTOSIZE); - cv::imshow("All responses", all_responses); - cv::waitKey(); + cv::namedWindow("KCF visual debug", CV_WINDOW_AUTOSIZE); + cv::imshow("KCF visual debug", all_responses); } cv::Point2i &max_response_pt = IF_BIG_BATCH(d.threadctxs[0].max[max_idx].loc, d.threadctxs[max_idx].max.loc); @@ -409,15 +380,13 @@ void KCF_Tracker::track(cv::Mat &img) uint max_idx; max_response = findMaxReponse(max_idx, new_location); + new_location.x *= double(p_windows_size.width) / fit_size.width; + new_location.y *= double(p_windows_size.height) / fit_size.height; + p_current_center += p_current_scale * p_cell_size * new_location; - if (p_fit_to_pw2) { - clamp2(p_current_center.x, 0.0, (img.cols * p_fit_factor_x) - 1); - clamp2(p_current_center.y, 0.0, (img.rows * p_fit_factor_y) - 1); - } else { - clamp2(p_current_center.x, 0.0, img.cols - 1.0); - clamp2(p_current_center.y, 0.0, img.rows - 1.0); - } + clamp2(p_current_center.x, 0.0, img.cols - 1.0); + clamp2(p_current_center.y, 0.0, img.rows - 1.0); // sub grid scale interpolation if (m_use_subgrid_scale) { @@ -439,7 +408,8 @@ void ThreadCtx::track(const KCF_Tracker &kcf, cv::Mat &input_rgb, cv::Mat &input BIG_BATCH_OMP_PARALLEL_FOR for (uint i = 0; i < IF_BIG_BATCH(kcf.p_num_scales, 1); ++i) { - kcf.get_features(input_rgb, input_gray, kcf.p_current_center.x, kcf.p_current_center.y, + kcf.get_features(input_rgb, input_gray, &dbg_patch[i], + kcf.p_current_center.x, kcf.p_current_center.y, kcf.p_windows_size.width, kcf.p_windows_size.height, kcf.p_current_scale * IF_BIG_BATCH(kcf.p_scales[i], scale)) .copyTo(patch_feats.scale(i)); @@ -450,11 +420,11 @@ void ThreadCtx::track(const KCF_Tracker &kcf, cv::Mat &input_rgb, cv::Mat &input DEBUG_PRINTM(zf); if (kcf.m_use_linearkernel) { - kzf = zf.mul(kcf.p_model_alphaf).sum_over_channels(); + kzf = zf.mul(kcf.model->model_alphaf).sum_over_channels(); } else { - gaussian_correlation(kzf, zf, kcf.p_model_xf, kcf.p_kernel_sigma, false, kcf); + gaussian_correlation(kzf, zf, kcf.model->model_xf, kcf.p_kernel_sigma, false, kcf); DEBUG_PRINTM(kzf); - kzf = kzf.mul(kcf.p_model_alphaf); + kzf = kzf.mul(kcf.model->model_alphaf); } kcf.fft.inverse(kzf, response); @@ -488,21 +458,24 @@ void ThreadCtx::track(const KCF_Tracker &kcf, cv::Mat &input_rgb, cv::Mat &input // **************************************************************************** -cv::Mat KCF_Tracker::get_features(cv::Mat &input_rgb, cv::Mat &input_gray, int cx, int cy, - int size_x, int size_y, double scale) const +cv::Mat KCF_Tracker::get_features(cv::Mat &input_rgb, cv::Mat &input_gray, cv::Mat *dbg_patch, + int cx, int cy, int size_x, int size_y, double scale) const { - int size_x_scaled = floor(size_x * scale); - int size_y_scaled = floor(size_y * scale); + cv::Size scaled = cv::Size(floor(size_x * scale), floor(size_y * scale)); + + cv::Mat patch_gray = get_subwindow(input_gray, cx, cy, scaled.width, scaled.height); + cv::Mat patch_rgb = get_subwindow(input_rgb, cx, cy, scaled.width, scaled.height); - cv::Mat patch_gray = get_subwindow(input_gray, cx, cy, size_x_scaled, size_y_scaled); - cv::Mat patch_rgb = get_subwindow(input_rgb, cx, cy, size_x_scaled, size_y_scaled); + if (dbg_patch) + patch_rgb.copyTo(*dbg_patch); // resize to default size - if (scale > 1.) { + if (scaled.area() > fit_size.area()) { // if we downsample use INTER_AREA interpolation - cv::resize(patch_gray, patch_gray, cv::Size(size_x, size_y), 0., 0., cv::INTER_AREA); + // note: this is just a guess - we may downsample in X and upsample in Y (or vice versa) + cv::resize(patch_gray, patch_gray, fit_size, 0., 0., cv::INTER_AREA); } else { - cv::resize(patch_gray, patch_gray, cv::Size(size_x, size_y), 0., 0., cv::INTER_LINEAR); + cv::resize(patch_gray, patch_gray, fit_size, 0., 0., cv::INTER_LINEAR); } // get hog(Histogram of Oriented Gradients) features @@ -512,11 +485,11 @@ cv::Mat KCF_Tracker::get_features(cv::Mat &input_rgb, cv::Mat &input_gray, int c std::vector color_feat; if ((m_use_color || m_use_cnfeat) && input_rgb.channels() == 3) { // resize to default size - if (scale > 1.) { + if (scaled.area() > (fit_size / p_cell_size).area()) { // if we downsample use INTER_AREA interpolation - cv::resize(patch_rgb, patch_rgb, cv::Size(size_x / p_cell_size, size_y / p_cell_size), 0., 0., cv::INTER_AREA); + cv::resize(patch_rgb, patch_rgb, fit_size / p_cell_size, 0., 0., cv::INTER_AREA); } else { - cv::resize(patch_rgb, patch_rgb, cv::Size(size_x / p_cell_size, size_y / p_cell_size), 0., 0., cv::INTER_LINEAR); + cv::resize(patch_rgb, patch_rgb, fit_size / p_cell_size, 0., 0., cv::INTER_LINEAR); } } @@ -571,7 +544,7 @@ cv::Mat KCF_Tracker::gaussian_shaped_labels(double sigma, int dim1, int dim2) return rot_labels; } -cv::Mat KCF_Tracker::circshift(const cv::Mat &patch, int x_rot, int y_rot) +cv::Mat KCF_Tracker::circshift(const cv::Mat &patch, int x_rot, int y_rot) const { cv::Mat rot_patch(patch.size(), CV_32FC1); cv::Mat tmp_x_rot(patch.size(), CV_32FC1); @@ -710,12 +683,19 @@ void KCF_Tracker::GaussianCorrelation::operator()(ComplexMat &result, const Comp double sigma, bool auto_correlation, const KCF_Tracker &kcf) { TRACE(""); + DEBUG_PRINTM(xf); + DEBUG_PRINT(xf_sqr_norm.num_elem); xf.sqr_norm(xf_sqr_norm); + for (uint s = 0; s < xf.n_scales; ++s) + DEBUG_PRINT(xf_sqr_norm[s]); if (auto_correlation) { yf_sqr_norm = xf_sqr_norm; } else { + DEBUG_PRINTM(yf); yf.sqr_norm(yf_sqr_norm); } + for (uint s = 0; s < yf.n_scales; ++s) + DEBUG_PRINTM(yf_sqr_norm[s]); xyf = auto_correlation ? xf.sqr_mag() : xf * yf.conj(); // xf.muln(yf.conj()); DEBUG_PRINTM(xyf); @@ -724,12 +704,6 @@ void KCF_Tracker::GaussianCorrelation::operator()(ComplexMat &result, const Comp DEBUG_PRINTM(xyf_sum); kcf.fft.inverse(xyf_sum, ifft_res); DEBUG_PRINTM(ifft_res); -#ifdef CUFFT - // FIXME - cuda_gaussian_correlation(ifft_res.deviceMem(), k.deviceMem(), xf_sqr_norm.deviceMem(), - auto_correlation ? xf_sqr_norm.deviceMem() : yf_sqr_norm.deviceMem(), sigma, - xf.n_channels, xf.n_scales, kcf.feature_size.height, kcf.feature_size.width); -#else float numel_xf_inv = 1.f / (xf.cols * xf.rows * (xf.channels() / xf.n_scales)); for (uint i = 0; i < xf.n_scales; ++i) { @@ -739,7 +713,7 @@ void KCF_Tracker::GaussianCorrelation::operator()(ComplexMat &result, const Comp * numel_xf_inv, 0), plane); DEBUG_PRINTM(plane); } -#endif + kcf.fft.forward(ifft_res, result); }