]> rtime.felk.cvut.cz Git - hercules2020/kcf.git/blobdiff - src/kcf.cpp
Fix sub_grid_scale calculation
[hercules2020/kcf.git] / src / kcf.cpp
index d58ee8a9dbac8f9b14bb5608694b846289f652ac..66689250c0af5e8779a26efd01731c7005eecb4e 100644 (file)
@@ -273,7 +273,7 @@ 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;
+    tmp.a = p_current_angle;
 
     if (p_resize_image)
         tmp.scale(1 / p_downscale_factor);
@@ -294,6 +294,22 @@ void KCF_Tracker::resizeImgs(cv::Mat &input_rgb, cv::Mat &input_gray)
     }
 }
 
+static void drawCross(cv::Mat &img, cv::Point center, bool green)
+{
+    cv::Scalar col = green ? cv::Scalar(0, 1, 0) : cv::Scalar(0, 0, 1);
+    cv::line(img, cv::Point(center.x, 0), cv::Point(center.x, img.size().height), col);
+    cv::line(img, cv::Point(0, center.y), cv::Point(img.size().height, center.y), col);
+}
+
+static cv::Point2d wrapAroundFreq(cv::Point2d pt, cv::Mat &resp_map)
+{
+    if (pt.y > resp_map.rows / 2) // wrap around to negative half-space of vertical axis
+        pt.y = pt.y - resp_map.rows;
+    if (pt.x > resp_map.cols / 2) // same for horizontal axis
+        pt.x = pt.x - resp_map.cols;
+    return pt;
+}
+
 double KCF_Tracker::findMaxReponse(uint &max_idx, cv::Point2d &new_location) const
 {
     double max;
@@ -311,32 +327,6 @@ double KCF_Tracker::findMaxReponse(uint &max_idx, cv::Point2d &new_location) con
     assert(max_it != vec.end());
     max = max_it->IF_BIG_BATCH(response, max.response);
 
-    if (m_visual_debug) {
-        const bool rgb = true;
-        int type = rgb ? d->threadctxs[0].IF_BIG_BATCH(dbg_patch[0], dbg_patch).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 tmp;
-                if (rgb) {
-                    tmp = d->IF_BIG_BATCH(threadctxs[0], threadctxs(i, j)).dbg_patch IF_BIG_BATCH((i, j),);
-                } else {
-                    tmp = d->IF_BIG_BATCH(threadctxs[0], threadctxs(i, j)).response.plane(IF_BIG_BATCH(d->threadctxs[0].max.getIdx(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("KCF visual debug", CV_WINDOW_AUTOSIZE);
-        cv::imshow("KCF visual debug", all_responses);
-    }
-
     max_idx = std::distance(vec.begin(), max_it);
 
     cv::Point2i max_response_pt = IF_BIG_BATCH(max_it->loc, max_it->max.loc);
@@ -346,19 +336,58 @@ double KCF_Tracker::findMaxReponse(uint &max_idx, cv::Point2d &new_location) con
     DEBUG_PRINTM(max_response_map);
     DEBUG_PRINT(max_response_pt);
 
-    // sub pixel quadratic interpolation from neighbours
-    if (max_response_pt.y > max_response_map.rows / 2) // wrap around to negative half-space of vertical axis
-        max_response_pt.y = max_response_pt.y - max_response_map.rows;
-    if (max_response_pt.x > max_response_map.cols / 2) // same for horizontal axis
-        max_response_pt.x = max_response_pt.x - max_response_map.cols;
-
+    max_response_pt = wrapAroundFreq(max_response_pt, max_response_map);
 
+    // sub pixel quadratic interpolation from neighbours
     if (m_use_subpixel_localization) {
         new_location = sub_pixel_peak(max_response_pt, max_response_map);
     } else {
         new_location = max_response_pt;
     }
     DEBUG_PRINT(new_location);
+
+    if (m_visual_debug != vd::NONE) {
+        const bool fit = 1;
+        int w = fit ? 100 : (m_visual_debug == vd::PATCH ? fit_size.width  : feature_size.width);
+        int h = fit ? 100 : (m_visual_debug == vd::PATCH ? fit_size.height : feature_size.height);
+        cv::Mat all_responses((h + 1) * p_num_scales - 1,
+                              (w + 1) * p_num_angles - 1, CV_32FC3, cv::Scalar::all(0));
+        for (size_t i = 0; i < p_num_scales; ++i) {
+            for (size_t j = 0; j < p_num_angles; ++j) {
+                auto &threadctx = d->IF_BIG_BATCH(threadctxs[0], threadctxs(i, j));
+                cv::Mat tmp;
+                cv::Point2d cross = threadctx.IF_BIG_BATCH(max(i, j), max).loc;
+                cross = wrapAroundFreq(cross, max_response_map);
+                if (m_visual_debug == vd::PATCH ) {
+                    threadctx.dbg_patch IF_BIG_BATCH((i, j),)
+                            .convertTo(tmp, all_responses.type(), 1.0 / 255);
+                    cross.x = cross.x / fit_size.width  * tmp.cols + tmp.cols / 2;
+                    cross.y = cross.y / fit_size.height * tmp.rows + tmp.rows / 2;
+                } else {
+                    cv::cvtColor(threadctx.response.plane(IF_BIG_BATCH(threadctx.max.getIdx(i, j), 0)),
+                            tmp, cv::COLOR_GRAY2BGR);
+                    tmp /= max; // Normalize to 1
+                    cross += cv::Point2d(tmp.size())/2;
+                    tmp = circshift(tmp, -tmp.cols/2, -tmp.rows/2);
+                }
+                bool green = false;
+                if (&*max_it == &IF_BIG_BATCH(threadctx.max(i, j), threadctx)) {
+                    // Show the green cross at position of sub-pixel interpolation (if enabled)
+                    cross = new_location + cv::Point2d(tmp.size())/2;
+                    green = true;
+                }
+                cross.x *= double(w)/tmp.cols;
+                cross.y *= double(h)/tmp.rows;
+                cv::resize(tmp, tmp, cv::Size(w, h));
+                drawCross(tmp, cross, green);
+                cv::Mat resp_roi(all_responses, cv::Rect(j * (w+1), i * (h+1), w, h));
+                tmp.copyTo(resp_roi);
+            }
+        }
+        cv::namedWindow("KCF visual debug", CV_WINDOW_AUTOSIZE);
+        cv::imshow("KCF visual debug", all_responses);
+    }
+
     return max;
 }
 
@@ -395,6 +424,12 @@ void KCF_Tracker::track(cv::Mat &img)
     uint max_idx;
     max_response = findMaxReponse(max_idx, new_location);
 
+    double angle_change = d->IF_BIG_BATCH(threadctxs[0].max, threadctxs).angle(max_idx);
+    p_current_angle += angle_change;
+
+    new_location.x = new_location.x * cos(-p_current_angle/180*M_PI) + new_location.y * sin(-p_current_angle/180*M_PI);
+    new_location.y = new_location.y * cos(-p_current_angle/180*M_PI) - new_location.x * sin(-p_current_angle/180*M_PI);
+
     new_location.x *= double(p_windows_size.width) / fit_size.width;
     new_location.y *= double(p_windows_size.height) / fit_size.height;
 
@@ -412,7 +447,6 @@ void KCF_Tracker::track(cv::Mat &img)
 
     clamp2(p_current_scale, p_min_max_scale[0], p_min_max_scale[1]);
 
-    p_current_angle += d->IF_BIG_BATCH(threadctxs[0].max, threadctxs).angle(max_idx);
 
     // train at newly estimated target position
     train(input_rgb, input_gray, p_interp_factor);
@@ -564,8 +598,8 @@ cv::Mat KCF_Tracker::gaussian_shaped_labels(double sigma, int dim1, int dim2)
 
 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);
+    cv::Mat rot_patch(patch.size(), patch.type());
+    cv::Mat tmp_x_rot(patch.size(), patch.type());
 
     // circular rotate x-axis
     if (x_rot < 0) {
@@ -646,12 +680,15 @@ cv::Mat KCF_Tracker::cosine_window_function(int dim1, int dim2)
 cv::Mat KCF_Tracker::get_subwindow(const cv::Mat &input, int cx, int cy, int width, int height, double angle) const
 {
     cv::Mat patch;
-    (void)angle;
 
-    int x1 = cx - width / 2;
-    int y1 = cy - height / 2;
-    int x2 = cx + width / 2;
-    int y2 = cy + height / 2;
+    cv::Size sz(width, height);
+    cv::RotatedRect rr(cv::Point2f(cx, cy), sz, angle);
+    cv::Rect bb = rr.boundingRect();
+
+    int x1 = bb.tl().x;
+    int y1 = bb.tl().y;
+    int x2 = bb.br().x;
+    int y2 = bb.br().y;
 
     // out of image
     if (x1 >= input.cols || y1 >= input.rows || x2 < 0 || y2 < 0) {
@@ -692,6 +729,12 @@ cv::Mat KCF_Tracker::get_subwindow(const cv::Mat &input, int cx, int cy, int wid
         //      cv::waitKey();
     }
 
+    cv::Point2f src_pts[4];
+    cv::RotatedRect(cv::Point2f(patch.size()) / 2.0, sz, angle).points(src_pts);
+    cv::Point2f dst_pts[3] = { cv::Point2f(0, height), cv::Point2f(0, 0),  cv::Point2f(width, 0)};
+    auto rot = cv::getAffineTransform(src_pts, dst_pts);
+    cv::warpAffine(patch, patch, rot, sz);
+
     // sanity check
     assert(patch.cols == width && patch.rows == height);
 
@@ -801,7 +844,7 @@ double KCF_Tracker::sub_grid_scale(uint max_index)
     cv::Mat A, fval;
     const auto &vec = d->IF_BIG_BATCH(threadctxs[0].max, threadctxs);
     uint index = vec.getScaleIdx(max_index);
-    uint angle_idx = vec.getAngleIdx(index);
+    uint angle_idx = vec.getAngleIdx(max_index);
 
     if (index >= vec.size()) {
         // interpolate from all values