OpenShot Library | libopenshot  0.7.0
KalmanTracker.cpp
Go to the documentation of this file.
1 // © OpenShot Studios, LLC
2 //
3 // SPDX-License-Identifier: LGPL-3.0-or-later
4 
6 // KalmanTracker.cpp: KalmanTracker Class Implementation Declaration
7 
8 #include "KalmanTracker.h"
9 #include <ctime>
10 #include <algorithm>
11 
12 using namespace std;
13 using namespace cv;
14 
15 // initialize Kalman filter
16 void KalmanTracker::init_kf(
17  StateType stateMat)
18 {
19  int stateNum = 8;
20  int measureNum = 4;
21  kf = KalmanFilter(stateNum, measureNum, 0);
22 
23  measurement = Mat::zeros(measureNum, 1, CV_32F);
24 
25  kf.transitionMatrix = (Mat_<float>(8, 8) << 1, 0, 0, 0, 1, 0, 0, 0,
26 
27  0, 1, 0, 0, 0, 1, 0, 0,
28  0, 0, 1, 0, 0, 0, 1, 0,
29  0, 0, 0, 1, 0, 0, 0, 1,
30  0, 0, 0, 0, 1, 0, 0, 0,
31  0, 0, 0, 0, 0, 1, 0, 0,
32  0, 0, 0, 0, 0, 0, 1, 0,
33  0, 0, 0, 0, 0, 0, 0, 1);
34 
35  setIdentity(kf.measurementMatrix);
36  setIdentity(kf.processNoiseCov, Scalar::all(1e-1));
37  kf.processNoiseCov.at<float>(2, 2) = 1e0; // higher noise for area (s) to adapt to size changes
38  kf.processNoiseCov.at<float>(3, 3) = 1e0; // higher noise for aspect ratio (r)
39  setIdentity(kf.measurementNoiseCov, Scalar::all(1e-4));
40  setIdentity(kf.errorCovPost, Scalar::all(1e-2));
41 
42  // initialize state vector with bounding box in [cx,cy,s,r] style
43  kf.statePost.at<float>(0, 0) = stateMat.x + stateMat.width / 2;
44  kf.statePost.at<float>(1, 0) = stateMat.y + stateMat.height / 2;
45  kf.statePost.at<float>(2, 0) = stateMat.area();
46  kf.statePost.at<float>(3, 0) = stateMat.width / stateMat.height;
47  kf.statePost.at<float>(4, 0) = 0.0f;
48  kf.statePost.at<float>(5, 0) = 0.0f;
49  kf.statePost.at<float>(6, 0) = 0.0f;
50  kf.statePost.at<float>(7, 0) = 0.0f;
51 }
52 
53 // Predict the estimated bounding box.
55 {
56  // predict
57  Mat p = kf.predict();
58  m_age += 1;
59 
60  if (m_time_since_update > 0)
61  m_hit_streak = 0;
62  m_time_since_update += 1;
63 
64  StateType predictBox = get_rect_xysr(p.at<float>(0, 0), p.at<float>(1, 0), p.at<float>(2, 0), p.at<float>(3, 0));
65 
66  m_history.push_back(predictBox);
67  return m_history.back();
68 }
69 
71 {
72  // predict
73  Mat p = kf.predict();
74 
75  StateType predictBox = get_rect_xysr(p.at<float>(0, 0), p.at<float>(1, 0), p.at<float>(2, 0), p.at<float>(3, 0));
76 
77  return predictBox;
78 }
79 
80 // Update the state vector with observed bounding box.
82  StateType stateMat)
83 {
84  m_time_since_update = 0;
85  m_history.clear();
86  m_hits += 1;
87  m_hit_streak += 1;
88 
89  // measurement
90  measurement.at<float>(0, 0) = stateMat.x + stateMat.width / 2;
91  measurement.at<float>(1, 0) = stateMat.y + stateMat.height / 2;
92  measurement.at<float>(2, 0) = stateMat.area();
93  measurement.at<float>(3, 0) = stateMat.width / stateMat.height;
94 
95  // update
96  kf.correct(measurement);
97  // time_t now = time(0);
98  // convert now to string form
99 
100  // detect_times.push_back(dt);
101 }
102 
103 void KalmanTracker::update_class_scores(const std::vector<ClassScore>& classScores, int fallbackClassId, float fallbackConfidence)
104 {
105  const double decay = 0.82;
106  const double update_weight = 1.0 - decay;
107  const bool had_history = !classScoreHistory.empty();
108 
109  for (auto it = classScoreHistory.begin(); it != classScoreHistory.end();) {
110  it->second *= decay;
111  if (it->second < 0.0001)
112  it = classScoreHistory.erase(it);
113  else
114  ++it;
115  }
116 
117  const double candidate_weight = had_history ? update_weight : 1.0;
118  if (classScores.empty()) {
119  classScoreHistory[fallbackClassId] += fallbackConfidence * candidate_weight;
120  } else {
121  for (const auto& candidate : classScores) {
122  if (candidate.classId < 0 || candidate.score <= 0.0f)
123  continue;
124  classScoreHistory[candidate.classId] += candidate.score * candidate_weight;
125  }
126  }
127 
128  if (classScoreHistory.empty()) {
129  classId = fallbackClassId;
130  return;
131  }
132 
133  auto best = std::max_element(
134  classScoreHistory.begin(), classScoreHistory.end(),
135  [](const auto& a, const auto& b) { return a.second < b.second; });
136  classId = best->first;
137 }
138 
139 // Return the current state vector
141 {
142  Mat s = kf.statePost;
143  return get_rect_xysr(s.at<float>(0, 0), s.at<float>(1, 0), s.at<float>(2, 0), s.at<float>(3, 0));
144 }
145 
146 // Convert bounding box from [cx,cy,s,r] to [x,y,w,h] style.
148  float cx,
149  float cy,
150  float s,
151  float r)
152 {
153  float w = sqrt(s * r);
154  float h = s / w;
155  float x = (cx - w / 2);
156  float y = (cy - h / 2);
157 
158  if (x < 0 && cx > 0)
159  x = 0;
160  if (y < 0 && cy > 0)
161  y = 0;
162 
163  return StateType(x, y, w, h);
164 }
StateType
#define StateType
Definition: KalmanTracker.h:18
KalmanTracker::get_rect_xysr
StateType get_rect_xysr(float cx, float cy, float s, float r)
Definition: KalmanTracker.cpp:147
KalmanTracker::predict2
StateType predict2()
Definition: KalmanTracker.cpp:70
KalmanTracker::update_class_scores
void update_class_scores(const std::vector< ClassScore > &classScores, int fallbackClassId, float fallbackConfidence)
Definition: KalmanTracker.cpp:103
KalmanTracker::update
void update(StateType stateMat)
Definition: KalmanTracker.cpp:81
KalmanTracker::get_state
StateType get_state()
Definition: KalmanTracker.cpp:140
KalmanTracker.h
KalmanTracker::predict
StateType predict()
Definition: KalmanTracker.cpp:54