]> rtime.felk.cvut.cz Git - hercules2020/kcf.git/blob - src/kcf.cpp
7aebe6acc538e5ee8e7d84431c1be6ecac1c2606
[hercules2020/kcf.git] / src / kcf.cpp
1 #include "kcf.h"
2 #include <numeric>
3 #include <thread>
4 #include <future>
5 #include <algorithm>
6
7 #ifdef OPENCV_CUFFT
8 #include <cuda.h>
9 #include <cuda_runtime.h>
10 #endif //OPENCV_CUFFT
11
12 #ifdef FFTW
13   #ifndef CUFFTW
14     #include <fftw3.h>
15   #else
16     #include <cufftw.h>
17   #endif //CUFFTW
18 #endif //FFTW
19
20 #ifdef OPENMP
21 #include <omp.h>
22 #endif //OPENMP
23
24 void KCF_Tracker::init(cv::Mat &img, const cv::Rect & bbox)
25 {
26     //check boundary, enforce min size
27     double x1 = bbox.x, x2 = bbox.x + bbox.width, y1 = bbox.y, y2 = bbox.y + bbox.height;
28     if (x1 < 0) x1 = 0.;
29     if (x2 > img.cols-1) x2 = img.cols - 1;
30     if (y1 < 0) y1 = 0;
31     if (y2 > img.rows-1) y2 = img.rows - 1;
32
33     if (x2-x1 < 2*p_cell_size) {
34         double diff = (2*p_cell_size -x2+x1)/2.;
35         if (x1 - diff >= 0 && x2 + diff < img.cols){
36             x1 -= diff;
37             x2 += diff;
38         } else if (x1 - 2*diff >= 0) {
39             x1 -= 2*diff;
40         } else {
41             x2 += 2*diff;
42         }
43     }
44     if (y2-y1 < 2*p_cell_size) {
45         double diff = (2*p_cell_size -y2+y1)/2.;
46         if (y1 - diff >= 0 && y2 + diff < img.rows){
47             y1 -= diff;
48             y2 += diff;
49         } else if (y1 - 2*diff >= 0) {
50             y1 -= 2*diff;
51         } else {
52             y2 += 2*diff;
53         }
54     }
55
56     p_pose.w = x2-x1;
57     p_pose.h = y2-y1;
58     p_pose.cx = x1 + p_pose.w/2.;
59     p_pose.cy = y1 + p_pose.h/2.;
60
61
62     cv::Mat input_gray, input_rgb = img.clone();
63     if (img.channels() == 3){
64         cv::cvtColor(img, input_gray, CV_BGR2GRAY);
65         input_gray.convertTo(input_gray, CV_32FC1);
66     }else
67         img.convertTo(input_gray, CV_32FC1);
68
69     // don't need too large image
70     if (p_pose.w * p_pose.h > 100.*100.) {
71         std::cout << "resizing image by factor of " << 1/p_downscale_factor << std::endl;
72         p_resize_image = true;
73         p_pose.scale(p_downscale_factor);
74         cv::resize(input_gray, input_gray, cv::Size(0,0), p_downscale_factor, p_downscale_factor, cv::INTER_AREA);
75         cv::resize(input_rgb, input_rgb, cv::Size(0,0), p_downscale_factor, p_downscale_factor, cv::INTER_AREA);
76     }
77
78     //compute win size + fit to fhog cell size
79     p_windows_size[0] = round(p_pose.w * (1. + p_padding) / p_cell_size) * p_cell_size;
80     p_windows_size[1] = round(p_pose.h * (1. + p_padding) / p_cell_size) * p_cell_size;
81
82     p_scales.clear();
83     if (m_use_scale)
84         for (int i = -p_num_scales/2; i <= p_num_scales/2; ++i)
85             p_scales.push_back(std::pow(p_scale_step, i));
86     else
87         p_scales.push_back(1.);
88
89     p_current_scale = 1.;
90
91     double min_size_ratio = std::max(5.*p_cell_size/p_windows_size[0], 5.*p_cell_size/p_windows_size[1]);
92     double max_size_ratio = std::min(floor((img.cols + p_windows_size[0]/3)/p_cell_size)*p_cell_size/p_windows_size[0], floor((img.rows + p_windows_size[1]/3)/p_cell_size)*p_cell_size/p_windows_size[1]);
93     p_min_max_scale[0] = std::pow(p_scale_step, std::ceil(std::log(min_size_ratio) / log(p_scale_step)));
94     p_min_max_scale[1] = std::pow(p_scale_step, std::floor(std::log(max_size_ratio) / log(p_scale_step)));
95
96     std::cout << "init: img size " << img.cols << " " << img.rows << std::endl;
97     std::cout << "init: win size. " << p_windows_size[0] << " " << p_windows_size[1] << std::endl;
98     std::cout << "init: min max scales factors: " << p_min_max_scale[0] << " " << p_min_max_scale[1] << std::endl;
99
100     p_output_sigma = std::sqrt(p_pose.w*p_pose.h) * p_output_sigma_factor / static_cast<double>(p_cell_size);
101
102 #if defined(FFTW) && defined(OPENMP)
103     fftw_init_threads();
104 #endif //defined(FFTW) && defined(OPENMP)
105
106     //window weights, i.e. labels
107     p_yf = fft2(gaussian_shaped_labels(p_output_sigma, p_windows_size[0]/p_cell_size, p_windows_size[1]/p_cell_size));
108     p_cos_window = cosine_window_function(p_yf.cols, p_yf.rows);
109     //obtain a sub-window for training initial model
110     std::vector<cv::Mat> path_feat = get_features(input_rgb, input_gray, p_pose.cx, p_pose.cy, p_windows_size[0], p_windows_size[1]);
111     p_model_xf = fft2(path_feat, p_cos_window);
112
113     if (m_use_linearkernel) {
114         ComplexMat xfconj = p_model_xf.conj();
115         p_model_alphaf_num = xfconj.mul(p_yf);
116         p_model_alphaf_den = (p_model_xf * xfconj);
117     } else {
118         //Kernel Ridge Regression, calculate alphas (in Fourier domain)
119         ComplexMat kf = gaussian_correlation(p_model_xf, p_model_xf, p_kernel_sigma, true);
120         p_model_alphaf_num = p_yf * kf;
121         p_model_alphaf_den = kf * (kf + p_lambda);
122     }
123     p_model_alphaf = p_model_alphaf_num / p_model_alphaf_den;
124 //        p_model_alphaf = p_yf / (kf + p_lambda);   //equation for fast training
125 }
126
127 void KCF_Tracker::setTrackerPose(BBox_c &bbox, cv::Mat & img)
128 {
129     init(img, bbox.get_rect());
130 }
131
132 void KCF_Tracker::updateTrackerPosition(BBox_c &bbox)
133 {
134     if (p_resize_image) {
135         BBox_c tmp = bbox;
136         tmp.scale(p_downscale_factor);
137         p_pose.cx = tmp.cx;
138         p_pose.cy = tmp.cy;
139     } else {
140         p_pose.cx = bbox.cx;
141         p_pose.cy = bbox.cy;
142     }
143 }
144
145 BBox_c KCF_Tracker::getBBox()
146 {
147     BBox_c tmp = p_pose;
148     tmp.w *= p_current_scale;
149     tmp.h *= p_current_scale;
150
151     if (p_resize_image)
152         tmp.scale(1/p_downscale_factor);
153
154     return tmp;
155 }
156
157 void KCF_Tracker::track(cv::Mat &img)
158 {
159
160     cv::Mat input_gray, input_rgb = img.clone();
161     if (img.channels() == 3){
162         cv::cvtColor(img, input_gray, CV_BGR2GRAY);
163         input_gray.convertTo(input_gray, CV_32FC1);
164     }else
165         img.convertTo(input_gray, CV_32FC1);
166
167     // don't need too large image
168     if (p_resize_image) {
169         cv::resize(input_gray, input_gray, cv::Size(0, 0), p_downscale_factor, p_downscale_factor, cv::INTER_AREA);
170         cv::resize(input_rgb, input_rgb, cv::Size(0, 0), p_downscale_factor, p_downscale_factor, cv::INTER_AREA);
171     }
172
173
174     std::vector<cv::Mat> patch_feat;
175     double max_response = -1.;
176     cv::Mat max_response_map;
177     cv::Point2i max_response_pt;
178     int scale_index = 0;
179     std::vector<double> scale_responses;
180
181     if (m_use_multithreading){
182         std::vector<std::future<cv::Mat>> async_res(p_scales.size());
183         for (size_t i = 0; i < p_scales.size(); ++i) {
184             async_res[i] = std::async(std::launch::async,
185                                       [this, &input_gray, &input_rgb, i]() -> cv::Mat
186                                       {
187                                           std::vector<cv::Mat> patch_feat_async = get_features(input_rgb, input_gray, this->p_pose.cx, this->p_pose.cy, this->p_windows_size[0],
188                                                                                                this->p_windows_size[1], this->p_current_scale * this->p_scales[i]);
189                                           ComplexMat zf = fft2(patch_feat_async, this->p_cos_window);
190                                           if (m_use_linearkernel)
191                                               return ifft2((p_model_alphaf * zf).sum_over_channels());
192                                           else {
193                                               ComplexMat kzf = gaussian_correlation(zf, this->p_model_xf, this->p_kernel_sigma);
194                                               return ifft2(this->p_model_alphaf * kzf);
195                                           }
196                                       });
197         }
198
199         for (size_t i = 0; i < p_scales.size(); ++i) {
200             // wait for result
201             async_res[i].wait();
202             cv::Mat response = async_res[i].get();
203
204             double min_val, max_val;
205             cv::Point2i min_loc, max_loc;
206             cv::minMaxLoc(response, &min_val, &max_val, &min_loc, &max_loc);
207
208             double weight = p_scales[i] < 1. ? p_scales[i] : 1./p_scales[i];
209             if (max_val*weight > max_response) {
210                 max_response = max_val*weight;
211                 max_response_map = response;
212                 max_response_pt = max_loc;
213                 scale_index = i;
214             }
215             scale_responses.push_back(max_val*weight);
216         }
217     } else {
218 #pragma omp parallel for ordered  private(patch_feat) schedule(dynamic)
219         for (size_t i = 0; i < p_scales.size(); ++i) {
220             patch_feat = get_features(input_rgb, input_gray, p_pose.cx, p_pose.cy, p_windows_size[0], p_windows_size[1], p_current_scale * p_scales[i]);
221             ComplexMat zf = fft2(patch_feat, p_cos_window);
222             cv::Mat response;
223             if (m_use_linearkernel)
224                 response = ifft2((p_model_alphaf * zf).sum_over_channels());
225             else {
226                 ComplexMat kzf = gaussian_correlation(zf, p_model_xf, p_kernel_sigma);
227                 response = ifft2(p_model_alphaf * kzf);
228             }
229
230             /* target location is at the maximum response. we must take into
231                account the fact that, if the target doesn't move, the peak
232                will appear at the top-left corner, not at the center (this is
233                discussed in the paper). the responses wrap around cyclically. */
234             double min_val, max_val;
235             cv::Point2i min_loc, max_loc;
236             cv::minMaxLoc(response, &min_val, &max_val, &min_loc, &max_loc);
237
238             double weight = p_scales[i] < 1. ? p_scales[i] : 1./p_scales[i];
239 #pragma omp critical
240             {
241                 if (max_val*weight > max_response) {
242                     max_response = max_val*weight;
243                     max_response_map = response;
244                     max_response_pt = max_loc;
245                     scale_index = i;
246                 }
247             }
248 #pragma omp ordered
249             scale_responses.push_back(max_val*weight);
250         }
251     }
252     //sub pixel quadratic interpolation from neighbours
253     if (max_response_pt.y > max_response_map.rows / 2) //wrap around to negative half-space of vertical axis
254         max_response_pt.y = max_response_pt.y - max_response_map.rows;
255     if (max_response_pt.x > max_response_map.cols / 2) //same for horizontal axis
256         max_response_pt.x = max_response_pt.x - max_response_map.cols;
257
258     cv::Point2f new_location(max_response_pt.x, max_response_pt.y);
259
260     if (m_use_subpixel_localization)
261         new_location = sub_pixel_peak(max_response_pt, max_response_map);
262
263     p_pose.cx += p_current_scale*p_cell_size*new_location.x;
264     p_pose.cy += p_current_scale*p_cell_size*new_location.y;
265     if (p_pose.cx < 0) p_pose.cx = 0;
266     if (p_pose.cx > img.cols-1) p_pose.cx = img.cols-1;
267     if (p_pose.cy < 0) p_pose.cy = 0;
268     if (p_pose.cy > img.rows-1) p_pose.cy = img.rows-1;
269
270     //sub grid scale interpolation
271     double new_scale = p_scales[scale_index];
272     if (m_use_subgrid_scale)
273         new_scale = sub_grid_scale(scale_responses, scale_index);
274
275     p_current_scale *= new_scale;
276
277     if (p_current_scale < p_min_max_scale[0])
278         p_current_scale = p_min_max_scale[0];
279     if (p_current_scale > p_min_max_scale[1])
280         p_current_scale = p_min_max_scale[1];
281     //obtain a subwindow for training at newly estimated target position
282     patch_feat = get_features(input_rgb, input_gray, p_pose.cx, p_pose.cy, p_windows_size[0], p_windows_size[1], p_current_scale);
283     ComplexMat xf = fft2(patch_feat, p_cos_window);
284
285     //subsequent frames, interpolate model
286     p_model_xf = p_model_xf * (1. - p_interp_factor) + xf * p_interp_factor;
287
288     ComplexMat alphaf_num, alphaf_den;
289
290     if (m_use_linearkernel) {
291         ComplexMat xfconj = xf.conj();
292         alphaf_num = xfconj.mul(p_yf);
293         alphaf_den = (xf * xfconj);
294     } else {
295         //Kernel Ridge Regression, calculate alphas (in Fourier domain)
296         ComplexMat kf = gaussian_correlation(xf, xf, p_kernel_sigma, true);
297 //        ComplexMat alphaf = p_yf / (kf + p_lambda); //equation for fast training
298 //        p_model_alphaf = p_model_alphaf * (1. - p_interp_factor) + alphaf * p_interp_factor;
299         alphaf_num = p_yf * kf;
300         alphaf_den = kf * (kf + p_lambda);
301     }
302
303     p_model_alphaf_num = p_model_alphaf_num * (1. - p_interp_factor) + alphaf_num * p_interp_factor;
304     p_model_alphaf_den = p_model_alphaf_den * (1. - p_interp_factor) + alphaf_den * p_interp_factor;
305     p_model_alphaf = p_model_alphaf_num / p_model_alphaf_den;
306 }
307
308 // ****************************************************************************
309
310 std::vector<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)
311 {
312     int size_x_scaled = floor(size_x*scale);
313     int size_y_scaled = floor(size_y*scale);
314
315     cv::Mat patch_gray = get_subwindow(input_gray, cx, cy, size_x_scaled, size_y_scaled);
316     cv::Mat patch_rgb = get_subwindow(input_rgb, cx, cy, size_x_scaled, size_y_scaled);
317
318     //resize to default size
319     if (scale > 1.){
320         //if we downsample use  INTER_AREA interpolation
321         cv::resize(patch_gray, patch_gray, cv::Size(size_x, size_y), 0., 0., cv::INTER_AREA);
322     }else {
323         cv::resize(patch_gray, patch_gray, cv::Size(size_x, size_y), 0., 0., cv::INTER_LINEAR);
324     }
325
326     // get hog(Histogram of Oriented Gradients) features
327     std::vector<cv::Mat> hog_feat = FHoG::extract(patch_gray, 2, p_cell_size, 9);
328
329     //get color rgb features (simple r,g,b channels)
330     std::vector<cv::Mat> color_feat;
331     if ((m_use_color || m_use_cnfeat) && input_rgb.channels() == 3) {
332         //resize to default size
333         if (scale > 1.){
334             //if we downsample use  INTER_AREA interpolation
335             cv::resize(patch_rgb, patch_rgb, cv::Size(size_x/p_cell_size, size_y/p_cell_size), 0., 0., cv::INTER_AREA);
336         }else {
337             cv::resize(patch_rgb, patch_rgb, cv::Size(size_x/p_cell_size, size_y/p_cell_size), 0., 0., cv::INTER_LINEAR);
338         }
339     }
340
341     if (m_use_color && input_rgb.channels() == 3) {
342         //use rgb color space
343         cv::Mat patch_rgb_norm;
344         patch_rgb.convertTo(patch_rgb_norm, CV_32F, 1. / 255., -0.5);
345         cv::Mat ch1(patch_rgb_norm.size(), CV_32FC1);
346         cv::Mat ch2(patch_rgb_norm.size(), CV_32FC1);
347         cv::Mat ch3(patch_rgb_norm.size(), CV_32FC1);
348         std::vector<cv::Mat> rgb = {ch1, ch2, ch3};
349         cv::split(patch_rgb_norm, rgb);
350         color_feat.insert(color_feat.end(), rgb.begin(), rgb.end());
351     }
352
353     if (m_use_cnfeat && input_rgb.channels() == 3) {
354         std::vector<cv::Mat> cn_feat = CNFeat::extract(patch_rgb);
355         color_feat.insert(color_feat.end(), cn_feat.begin(), cn_feat.end());
356     }
357
358     hog_feat.insert(hog_feat.end(), color_feat.begin(), color_feat.end());
359     return hog_feat;
360 }
361
362 cv::Mat KCF_Tracker::gaussian_shaped_labels(double sigma, int dim1, int dim2)
363 {
364     cv::Mat labels(dim2, dim1, CV_32FC1);
365     int range_y[2] = {-dim2 / 2, dim2 - dim2 / 2};
366     int range_x[2] = {-dim1 / 2, dim1 - dim1 / 2};
367
368     double sigma_s = sigma*sigma;
369
370     for (int y = range_y[0], j = 0; y < range_y[1]; ++y, ++j){
371         float * row_ptr = labels.ptr<float>(j);
372         double y_s = y*y;
373         for (int x = range_x[0], i = 0; x < range_x[1]; ++x, ++i){
374             row_ptr[i] = std::exp(-0.5 * (y_s + x*x) / sigma_s);//-1/2*e^((y^2+x^2)/sigma^2)
375         }
376     }
377
378     //rotate so that 1 is at top-left corner (see KCF paper for explanation)
379     cv::Mat rot_labels = circshift(labels, range_x[0], range_y[0]);
380     //sanity check, 1 at top left corner
381     assert(rot_labels.at<float>(0,0) >= 1.f - 1e-10f);
382
383     return rot_labels;
384 }
385
386 cv::Mat KCF_Tracker::circshift(const cv::Mat &patch, int x_rot, int y_rot)
387 {
388     cv::Mat rot_patch(patch.size(), CV_32FC1);
389     cv::Mat tmp_x_rot(patch.size(), CV_32FC1);
390
391     //circular rotate x-axis
392     if (x_rot < 0) {
393         //move part that does not rotate over the edge
394         cv::Range orig_range(-x_rot, patch.cols);
395         cv::Range rot_range(0, patch.cols - (-x_rot));
396         patch(cv::Range::all(), orig_range).copyTo(tmp_x_rot(cv::Range::all(), rot_range));
397
398         //rotated part
399         orig_range = cv::Range(0, -x_rot);
400         rot_range = cv::Range(patch.cols - (-x_rot), patch.cols);
401         patch(cv::Range::all(), orig_range).copyTo(tmp_x_rot(cv::Range::all(), rot_range));
402     }else if (x_rot > 0){
403         //move part that does not rotate over the edge
404         cv::Range orig_range(0, patch.cols - x_rot);
405         cv::Range rot_range(x_rot, patch.cols);
406         patch(cv::Range::all(), orig_range).copyTo(tmp_x_rot(cv::Range::all(), rot_range));
407
408         //rotated part
409         orig_range = cv::Range(patch.cols - x_rot, patch.cols);
410         rot_range = cv::Range(0, x_rot);
411         patch(cv::Range::all(), orig_range).copyTo(tmp_x_rot(cv::Range::all(), rot_range));
412     }else {    //zero rotation
413         //move part that does not rotate over the edge
414         cv::Range orig_range(0, patch.cols);
415         cv::Range rot_range(0, patch.cols);
416         patch(cv::Range::all(), orig_range).copyTo(tmp_x_rot(cv::Range::all(), rot_range));
417     }
418
419     //circular rotate y-axis
420     if (y_rot < 0) {
421         //move part that does not rotate over the edge
422         cv::Range orig_range(-y_rot, patch.rows);
423         cv::Range rot_range(0, patch.rows - (-y_rot));
424         tmp_x_rot(orig_range, cv::Range::all()).copyTo(rot_patch(rot_range, cv::Range::all()));
425
426         //rotated part
427         orig_range = cv::Range(0, -y_rot);
428         rot_range = cv::Range(patch.rows - (-y_rot), patch.rows);
429         tmp_x_rot(orig_range, cv::Range::all()).copyTo(rot_patch(rot_range, cv::Range::all()));
430     }else if (y_rot > 0){
431         //move part that does not rotate over the edge
432         cv::Range orig_range(0, patch.rows - y_rot);
433         cv::Range rot_range(y_rot, patch.rows);
434         tmp_x_rot(orig_range, cv::Range::all()).copyTo(rot_patch(rot_range, cv::Range::all()));
435
436         //rotated part
437         orig_range = cv::Range(patch.rows - y_rot, patch.rows);
438         rot_range = cv::Range(0, y_rot);
439         tmp_x_rot(orig_range, cv::Range::all()).copyTo(rot_patch(rot_range, cv::Range::all()));
440     }else { //zero rotation
441         //move part that does not rotate over the edge
442         cv::Range orig_range(0, patch.rows);
443         cv::Range rot_range(0, patch.rows);
444         tmp_x_rot(orig_range, cv::Range::all()).copyTo(rot_patch(rot_range, cv::Range::all()));
445     }
446
447     return rot_patch;
448 }
449
450 ComplexMat KCF_Tracker::fft2(const cv::Mat &input)
451 {
452     cv::Mat complex_result;
453 #ifdef OPENCV_CUFFT
454     cv::Mat flip_h,imag_h;
455
456     cv::cuda::HostMem hostmem_input(input, cv::cuda::HostMem::SHARED);
457     cv::cuda::HostMem hostmem_real(cv::Size(input.cols,input.rows/2+1), CV_32FC2, cv::cuda::HostMem::SHARED);
458
459     cv::cuda::dft(hostmem_input,hostmem_real,hostmem_input.size(),0,stream);
460     stream.waitForCompletion();
461
462     cv::Mat real_h = hostmem_real.createMatHeader();
463
464     //create reversed copy of result and merge them
465     cv::flip(hostmem_real,flip_h,1);
466     flip_h(cv::Range(0, flip_h.rows), cv::Range(1, flip_h.cols)).copyTo(imag_h);
467
468     std::vector<cv::Mat> matarray = {real_h,imag_h};
469
470     cv::hconcat(matarray,complex_result);
471 #endif
472 #ifdef FFTW
473     if(input.type()!=CV_32FC2){
474       cv::Mat planes[]={cv::Mat_<float>(input),cv::Mat::zeros(input.size(),CV_32F)};
475       merge(planes,2,complex_result);
476     }
477
478     fftwf_plan plan_f;
479
480     int width = input.cols;
481     int height = input.rows;
482 #pragma omp critical
483     {
484 #ifdef ASYNC
485       std::unique_lock<std::mutex> lock_i(fftw_mut);
486 #endif //ASYNC
487
488 #ifdef OPENMP
489     fftw_plan_with_nthreads(omp_get_max_threads());
490 #endif //OPENMP
491     plan_f=fftwf_plan_dft_2d(height,width,(fftwf_complex*)complex_result.data,(fftwf_complex*)complex_result.data,FFTW_FORWARD,FFTW_ESTIMATE);
492 #ifdef ASYNC
493     lock_i.unlock();
494 #endif // ASYNC
495     }
496
497     // Exectue fft
498     fftwf_execute( plan_f );
499
500     // Destroy FFTW plan
501 #pragma omp critical
502     {
503 #ifdef ASYNC
504       std::unique_lock<std::mutex> lock_d(fftw_mut);
505 #endif //ASYNC
506     fftwf_destroy_plan(plan_f);
507 #ifdef ASYNC
508       lock_d.unlock();
509 #endif //ASYNC
510     }
511 #endif //FFTW
512 #if !defined OPENCV_CUFFT || !defined FFTW
513     cv::dft(input, complex_result, cv::DFT_COMPLEX_OUTPUT);
514 #endif //!defined OPENCV_CUFFT || !defined FFTW
515     
516     if (m_debug) {
517         //extraxt x and y channels
518         cv::Mat xy[2]; //X,Y
519         cv::split(complex_result, xy);
520
521         //calculate angle and magnitude
522         cv::Mat magnitude, angle;
523         cv::cartToPolar(xy[0], xy[1], magnitude, angle, true);
524
525         //translate magnitude to range [0;1]
526         double mag_max;
527         cv::minMaxLoc(magnitude, 0, &mag_max);
528         magnitude.convertTo(magnitude, -1, 1.0 / mag_max);
529
530         //build hsv image
531         cv::Mat _hsv[3], hsv;
532         _hsv[0] = angle;
533         _hsv[1] = cv::Mat::ones(angle.size(), CV_32F);
534         _hsv[2] = magnitude;
535         cv::merge(_hsv, 3, hsv);
536
537         //convert to BGR and show
538         cv::Mat bgr;//CV_32FC3 matrix
539         cv::cvtColor(hsv, bgr, cv::COLOR_HSV2BGR);
540         cv::resize(bgr, bgr, cv::Size(600,600));
541         cv::imshow("DFT", bgr);
542         cv::waitKey(10);
543     }
544     
545     return ComplexMat(complex_result);
546 }
547
548 ComplexMat KCF_Tracker::fft2(const std::vector<cv::Mat> &input, const cv::Mat &cos_window)
549 {
550     int n_channels = input.size();
551     cv::Mat complex_result;
552
553 #ifdef OPENCV_CUFFT
554     cv::Mat flip_h,imag_h;
555     cv::cuda::GpuMat src_gpu;
556     cv::cuda::HostMem hostmem_real(cv::Size(input[0].cols,input[0].rows/2+1), CV_32FC2, cv::cuda::HostMem::SHARED);
557 #endif //OPENCV_CUFFT
558 #ifdef FFTW
559     // Prepare variables and FFTW plan for float precision FFT
560
561     fftwf_plan       plan_f;
562
563     int width = input[0].cols;
564     int height = input[0].rows;
565
566     complex_result  = cv::Mat::zeros(height, width, CV_32FC2);
567 #pragma omp critical 
568     {
569 #ifdef ASYNC
570       std::unique_lock<std::mutex> lock_i(fftw_mut);
571 #endif //ASYNC
572 #ifdef OPENMP
573     fftw_plan_with_nthreads(omp_get_max_threads());
574 #endif //OPENMP
575     plan_f=fftwf_plan_dft_2d( height , width , (fftwf_complex*) complex_result.data ,(fftwf_complex*) complex_result.data ,FFTW_FORWARD,FFTW_MEASURE);
576 #ifdef ASYNC
577       lock_i.unlock();
578 #endif //ASYNC
579     }
580 #endif //FFTW
581
582     ComplexMat result(input[0].rows, input[0].cols, n_channels);
583     for (int i = 0; i < n_channels; ++i){
584 #ifdef OPENCV_CUFFT
585         cv::cuda::HostMem hostmem_input(input[i], cv::cuda::HostMem::SHARED);
586         cv::cuda::multiply(hostmem_input,p_cos_window_d,src_gpu);
587         cv::cuda::dft(src_gpu,hostmem_real,src_gpu.size(),0,stream);
588         stream.waitForCompletion();
589
590         cv::Mat real_h = hostmem_real.createMatHeader();
591
592         //create reversed copy of result and merge them
593         cv::flip(hostmem_real,flip_h,1);
594         flip_h(cv::Range(0, flip_h.rows), cv::Range(1, flip_h.cols)).copyTo(imag_h);
595
596         std::vector<cv::Mat> matarray = {real_h,imag_h};
597
598         cv::hconcat(matarray,complex_result);
599 #endif //OPENCV_CUFFT
600 #ifdef FFTW
601         cv::Mat tmp = input[i].mul(cos_window);
602         cv::Mat planes[]={cv::Mat_<float>(tmp),cv::Mat::zeros(tmp.size(),CV_32F)};
603         merge(planes,2,complex_result);
604
605         // Execute FFT
606         fftwf_execute( plan_f );
607 #endif //FFTW
608 #if !defined OPENCV_CUFFT || !defined FFTW
609         cv::dft(input[i].mul(cos_window), complex_result, cv::DFT_COMPLEX_OUTPUT);
610 #endif //!defined OPENCV_CUFFT || !defined FFTW
611         result.set_channel(i, complex_result);
612     }
613 #ifdef FFTW
614     // Destroy FFT plan
615 #pragma omp critical
616 {
617 #if defined(FFTW) && defined(ASYNC)
618       std::unique_lock<std::mutex> lock_d(fftw_mut);
619 #endif
620     fftwf_destroy_plan(plan_f);
621 #ifdef ASYNC
622       lock_d.unlock();
623 #endif //ASYNC
624 }
625 #endif //FFTW
626     return result;
627 }
628
629 cv::Mat KCF_Tracker::ifft2(const ComplexMat &inputf)
630 {
631 #ifdef FFTW
632     // Prepare variables and FFTW plan for float precision IFFT
633     fftwf_plan plan_if;
634     int  width, height;
635 #endif //FFTW
636     cv::Mat real_result;
637
638     if (inputf.n_channels == 1){
639 #ifdef FFTW
640         real_result=inputf.to_cv_mat();
641
642         width=real_result.cols;
643         height=real_result.rows;
644
645 #pragma omp critical
646         {
647 #ifdef ASYNC
648       std::unique_lock<std::mutex> lock_i(fftw_mut);
649 #endif //ASYNC
650 #ifdef OPENMP
651         fftw_plan_with_nthreads(omp_get_max_threads());
652 #endif //OPENMP
653         plan_if=fftwf_plan_dft_2d( height , width , (fftwf_complex*) real_result.data , (fftwf_complex*) real_result.data ,FFTW_BACKWARD,FFTW_ESTIMATE);
654 #ifdef ASYNC
655       lock_i.unlock();
656 #endif //ASYNC
657         }
658         // Execute IFFT
659         fftwf_execute( plan_if );
660         cv::Mat planes[2];
661         cv::split(real_result,planes);
662         real_result=planes[0].clone();
663         real_result=real_result/(height*width);
664         // Destroy FFTW plan
665 #pragma omp critical
666         {
667 #ifdef ASYNC
668       std::unique_lock<std::mutex> lock_d(fftw_mut);
669 #endif //ASYNC
670         fftwf_destroy_plan(plan_if);
671 #ifdef ASYNC
672       lock_d.unlock();
673 #endif //ASYNC
674         }
675 #endif //FFTW
676 #ifndef FFTW
677         cv::dft(inputf.to_cv_mat(),real_result, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT | cv::DFT_SCALE);
678 #endif //FFTW
679
680     } else {
681         std::vector<cv::Mat> mat_channels = inputf.to_cv_mat_vector();
682         std::vector<cv::Mat> ifft_mats(inputf.n_channels);
683 #ifdef FFTW
684         width=mat_channels[0].cols;
685         height=mat_channels[0].rows;
686
687         real_result=cv::Mat::zeros(height,width,CV_32FC2);
688 #pragma omp critical
689         {
690 #ifdef ASYNC
691       std::unique_lock<std::mutex> lock_i(fftw_mut);
692 #endif //ASYNC
693 #ifdef OPENMP
694         fftw_plan_with_nthreads(omp_get_max_threads());
695 #endif //OPENMP
696         plan_if=fftwf_plan_dft_2d( height , width , (fftwf_complex*) real_result.data , (fftwf_complex*) real_result.data ,FFTW_BACKWARD,FFTW_MEASURE);
697 #ifdef ASYNC
698       lock_i.unlock();
699 #endif //ASYNC
700         }
701 #endif //FFTW
702         for (int i = 0; i < inputf.n_channels; ++i) {
703 #ifdef FFTW
704           mat_channels[i].copyTo(real_result);
705             // Execute IFFT
706           fftwf_execute( plan_if );
707
708           cv::Mat planes[2];
709           cv::split(real_result,planes);
710           ifft_mats[i]=planes[0].clone();
711           ifft_mats[i]=ifft_mats[i]/(height*width);
712
713 #else
714             cv::dft(mat_channels[i], ifft_mats[i], cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT | cv::DFT_SCALE);
715 #endif //FFTW
716         }
717 #ifdef FFTW
718         // Destroy FFTW plan
719 #pragma omp critical
720 {
721 #ifdef ASYNC
722       std::unique_lock<std::mutex> lock_d(fftw_mut);
723 #endif //ASYNC
724       fftwf_destroy_plan(plan_if);
725 #ifdef ASYNC
726       lock_d.unlock();
727 #endif //ASYNC
728 }
729 #endif //FFTW
730         cv::merge(ifft_mats, real_result);
731     }
732     return real_result;
733 }
734
735 //hann window actually (Power-of-cosine windows)
736 cv::Mat KCF_Tracker::cosine_window_function(int dim1, int dim2)
737 {
738     cv::Mat m1(1, dim1, CV_32FC1), m2(dim2, 1, CV_32FC1);
739     double N_inv = 1./(static_cast<double>(dim1)-1.);
740     for (int i = 0; i < dim1; ++i)
741         m1.at<float>(i) = 0.5*(1. - std::cos(2. * CV_PI * static_cast<double>(i) * N_inv));
742     N_inv = 1./(static_cast<double>(dim2)-1.);
743     for (int i = 0; i < dim2; ++i)
744         m2.at<float>(i) = 0.5*(1. - std::cos(2. * CV_PI * static_cast<double>(i) * N_inv));
745     cv::Mat ret = m2*m1;
746 #ifdef OPENCV_CUFFT
747     cv::cuda::createContinuous(cv::Size(ret.cols,ret.rows),CV_32FC1,p_cos_window_d);
748     p_cos_window_d.upload(ret);
749 #endif
750     return ret;
751 }
752
753 // Returns sub-window of image input centered at [cx, cy] coordinates),
754 // with size [width, height]. If any pixels are outside of the image,
755 // they will replicate the values at the borders.
756 cv::Mat KCF_Tracker::get_subwindow(const cv::Mat &input, int cx, int cy, int width, int height)
757 {
758     cv::Mat patch;
759
760     int x1 = cx - width/2;
761     int y1 = cy - height/2;
762     int x2 = cx + width/2;
763     int y2 = cy + height/2;
764
765     //out of image
766     if (x1 >= input.cols || y1 >= input.rows || x2 < 0 || y2 < 0) {
767         patch.create(height, width, input.type());
768         patch.setTo(0.f);
769         return patch;
770     }
771
772     int top = 0, bottom = 0, left = 0, right = 0;
773
774     //fit to image coordinates, set border extensions;
775     if (x1 < 0) {
776         left = -x1;
777         x1 = 0;
778     }
779     if (y1 < 0) {
780         top = -y1;
781         y1 = 0;
782     }
783     if (x2 >= input.cols) {
784         right = x2 - input.cols + width % 2;
785         x2 = input.cols;
786     } else
787         x2 += width % 2;
788
789     if (y2 >= input.rows) {
790         bottom = y2 - input.rows + height % 2;
791         y2 = input.rows;
792     } else
793         y2 += height % 2;
794
795     if (x2 - x1 == 0 || y2 - y1 == 0)
796         patch = cv::Mat::zeros(height, width, CV_32FC1);
797     else
798         {
799             cv::copyMakeBorder(input(cv::Range(y1, y2), cv::Range(x1, x2)), patch, top, bottom, left, right, cv::BORDER_REPLICATE);
800 //      imshow( "copyMakeBorder", patch);
801 //      cv::waitKey();
802         }
803
804     //sanity check
805     assert(patch.cols == width && patch.rows == height);
806
807     return patch;
808 }
809
810 ComplexMat KCF_Tracker::gaussian_correlation(const ComplexMat &xf, const ComplexMat &yf, double sigma, bool auto_correlation)
811 {
812     float xf_sqr_norm = xf.sqr_norm();
813     float yf_sqr_norm = auto_correlation ? xf_sqr_norm : yf.sqr_norm();
814
815     ComplexMat xyf = auto_correlation ? xf.sqr_mag() : xf * yf.conj();
816
817     //ifft2 and sum over 3rd dimension, we dont care about individual channels
818     cv::Mat xy_sum(xf.rows, xf.cols, CV_32FC1);
819     xy_sum.setTo(0);
820     cv::Mat ifft2_res = ifft2(xyf);
821     for (int y = 0; y < xf.rows; ++y) {
822         float * row_ptr = ifft2_res.ptr<float>(y);
823         float * row_ptr_sum = xy_sum.ptr<float>(y);
824         for (int x = 0; x < xf.cols; ++x){
825             row_ptr_sum[x] = std::accumulate((row_ptr + x*ifft2_res.channels()), (row_ptr + x*ifft2_res.channels() + ifft2_res.channels()), 0.f);
826         }
827     }
828
829     float numel_xf_inv = 1.f/(xf.cols * xf.rows * xf.n_channels);
830     cv::Mat tmp;
831     cv::exp(- 1.f / (sigma * sigma) * cv::max((xf_sqr_norm + yf_sqr_norm - 2 * xy_sum) * numel_xf_inv, 0), tmp);
832
833     return fft2(tmp);
834 }
835
836 float get_response_circular(cv::Point2i & pt, cv::Mat & response)
837 {
838     int x = pt.x;
839     int y = pt.y;
840     if (x < 0)
841         x = response.cols + x;
842     if (y < 0)
843         y = response.rows + y;
844     if (x >= response.cols)
845         x = x - response.cols;
846     if (y >= response.rows)
847         y = y - response.rows;
848
849     return response.at<float>(y,x);
850 }
851
852 cv::Point2f KCF_Tracker::sub_pixel_peak(cv::Point & max_loc, cv::Mat & response)
853 {
854     //find neighbourhood of max_loc (response is circular)
855     // 1 2 3
856     // 4   5
857     // 6 7 8
858     cv::Point2i p1(max_loc.x-1, max_loc.y-1), p2(max_loc.x, max_loc.y-1), p3(max_loc.x+1, max_loc.y-1);
859     cv::Point2i p4(max_loc.x-1, max_loc.y), p5(max_loc.x+1, max_loc.y);
860     cv::Point2i p6(max_loc.x-1, max_loc.y+1), p7(max_loc.x, max_loc.y+1), p8(max_loc.x+1, max_loc.y+1);
861
862     // fit 2d quadratic function f(x, y) = a*x^2 + b*x*y + c*y^2 + d*x + e*y + f
863     cv::Mat A = (cv::Mat_<float>(9, 6) <<
864                  p1.x*p1.x, p1.x*p1.y, p1.y*p1.y, p1.x, p1.y, 1.f,
865                  p2.x*p2.x, p2.x*p2.y, p2.y*p2.y, p2.x, p2.y, 1.f,
866                  p3.x*p3.x, p3.x*p3.y, p3.y*p3.y, p3.x, p3.y, 1.f,
867                  p4.x*p4.x, p4.x*p4.y, p4.y*p4.y, p4.x, p4.y, 1.f,
868                  p5.x*p5.x, p5.x*p5.y, p5.y*p5.y, p5.x, p5.y, 1.f,
869                  p6.x*p6.x, p6.x*p6.y, p6.y*p6.y, p6.x, p6.y, 1.f,
870                  p7.x*p7.x, p7.x*p7.y, p7.y*p7.y, p7.x, p7.y, 1.f,
871                  p8.x*p8.x, p8.x*p8.y, p8.y*p8.y, p8.x, p8.y, 1.f,
872                  max_loc.x*max_loc.x, max_loc.x*max_loc.y, max_loc.y*max_loc.y, max_loc.x, max_loc.y, 1.f);
873     cv::Mat fval = (cv::Mat_<float>(9, 1) <<
874                     get_response_circular(p1, response),
875                     get_response_circular(p2, response),
876                     get_response_circular(p3, response),
877                     get_response_circular(p4, response),
878                     get_response_circular(p5, response),
879                     get_response_circular(p6, response),
880                     get_response_circular(p7, response),
881                     get_response_circular(p8, response),
882                     get_response_circular(max_loc, response));
883     cv::Mat x;
884     cv::solve(A, fval, x, cv::DECOMP_SVD);
885
886     double a = x.at<float>(0), b = x.at<float>(1), c = x.at<float>(2),
887            d = x.at<float>(3), e = x.at<float>(4);
888
889     cv::Point2f sub_peak(max_loc.x, max_loc.y);
890     if (b > 0 || b < 0) {
891         sub_peak.y = ((2.f * a * e) / b - d) / (b - (4 * a * c) / b);
892         sub_peak.x = (-2 * c * sub_peak.y - e) / b;
893     }
894
895     return sub_peak;
896 }
897
898 double KCF_Tracker::sub_grid_scale(std::vector<double> & responses, int index)
899 {
900     cv::Mat A, fval;
901     if (index < 0 || index > (int)p_scales.size()-1) {
902         // interpolate from all values
903         // fit 1d quadratic function f(x) = a*x^2 + b*x + c
904         A.create(p_scales.size(), 3, CV_32FC1);
905         fval.create(p_scales.size(), 1, CV_32FC1);
906         for (size_t i = 0; i < p_scales.size(); ++i) {
907             A.at<float>(i, 0) = p_scales[i] * p_scales[i];
908             A.at<float>(i, 1) = p_scales[i];
909             A.at<float>(i, 2) = 1;
910             fval.at<float>(i) = responses[i];
911         }
912     } else {
913         //only from neighbours
914         if (index == 0 || index == (int)p_scales.size()-1)
915             return p_scales[index];
916
917         A = (cv::Mat_<float>(3, 3) <<
918              p_scales[index-1] * p_scales[index-1], p_scales[index-1], 1,
919              p_scales[index] * p_scales[index], p_scales[index], 1,
920              p_scales[index+1] * p_scales[index+1], p_scales[index+1], 1);
921         fval = (cv::Mat_<float>(3, 1) << responses[index-1], responses[index], responses[index+1]);
922     }
923
924     cv::Mat x;
925     cv::solve(A, fval, x, cv::DECOMP_SVD);
926     double a = x.at<float>(0), b = x.at<float>(1);
927     double scale = p_scales[index];
928     if (a > 0 || a < 0)
929         scale = -b / (2 * a);
930     return scale;
931 }