OpenShot Library | libopenshot 1.1.1
Loading...
Searching...
No Matches
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
12using namespace std;
13using namespace cv;
14
15// initialize Kalman filter
16void 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;
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{
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
103void 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(
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}
#define StateType
void update_class_scores(const std::vector< ClassScore > &classScores, int fallbackClassId, float fallbackConfidence)
StateType predict()
std::map< int, double > classScoreHistory
StateType get_state()
void update(StateType stateMat)
StateType predict2()
StateType get_rect_xysr(float cx, float cy, float s, float r)