Skip to content

Commit db8b4be

Browse files
committed
Refactoring CTracker
1 parent f19fa5c commit db8b4be

3 files changed

Lines changed: 174 additions & 136 deletions

File tree

src/Tracker/Ctracker.cpp

Lines changed: 163 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,35 @@
11
#include "Ctracker.h"
2-
#include "HungarianAlg/HungarianAlg.h"
32

43
#include <GTL/GTL.h>
54
#include "mygraph.h"
65
#include "mwbmatching.h"
76
#include "tokenise.h"
87

9-
// ---------------------------------------------------------------------------
10-
// Tracker. Manage tracks. Create, remove, update.
11-
// ---------------------------------------------------------------------------
8+
///
9+
/// \brief CTracker::CTracker
10+
/// Tracker. Manage tracks. Create, remove, update.
11+
/// \param settings
12+
///
1213
CTracker::CTracker(const TrackerSettings& settings)
1314
:
1415
m_settings(settings),
1516
m_nextTrackID(0)
1617
{
1718
}
1819

19-
// ---------------------------------------------------------------------------
20-
//
21-
// ---------------------------------------------------------------------------
20+
///
21+
/// \brief CTracker::~CTracker
22+
///
2223
CTracker::~CTracker(void)
2324
{
2425
}
2526

26-
// ---------------------------------------------------------------------------
27-
//
28-
// ---------------------------------------------------------------------------
27+
///
28+
/// \brief CTracker::Update
29+
/// \param regions
30+
/// \param grayFrame
31+
/// \param fps
32+
///
2933
void CTracker::Update(
3034
const regions_t& regions,
3135
cv::UMat grayFrame,
@@ -40,148 +44,52 @@ void CTracker::Update(
4044
}
4145
}
4246

43-
UpdateHungrian(regions, grayFrame, fps);
47+
UpdateTrackingState(regions, grayFrame, fps);
4448

4549
grayFrame.copyTo(m_prevFrame);
4650
}
4751

48-
// ---------------------------------------------------------------------------
49-
//
50-
// ---------------------------------------------------------------------------
51-
void CTracker::UpdateHungrian(
52+
///
53+
/// \brief CTracker::UpdateTrackingState
54+
/// \param regions
55+
/// \param grayFrame
56+
/// \param fps
57+
///
58+
void CTracker::UpdateTrackingState(
5259
const regions_t& regions,
5360
cv::UMat grayFrame,
5461
float fps
5562
)
5663
{
57-
size_t N = tracks.size(); // треки
58-
size_t M = regions.size(); // детекты
64+
const size_t N = tracks.size(); // Tracking objects
65+
const size_t M = regions.size(); // Detections or regions
5966

60-
assignments_t assignment(N, -1); // назначения
67+
assignments_t assignment(N, -1); // Assignments regions -> tracks
6168

6269
if (!tracks.empty())
6370
{
64-
// Матрица расстояний от N-ного трека до M-ного детекта.
65-
distMatrix_t Cost(N * M);
66-
67-
// -----------------------------------
68-
// Треки уже есть, составим матрицу расстояний
69-
// -----------------------------------
71+
// Distance matrix between all tracks to all regions
72+
distMatrix_t costMatrix(N * M);
7073
const track_t maxPossibleCost = static_cast<track_t>(grayFrame.cols * grayFrame.rows);
7174
track_t maxCost = 0;
72-
switch (m_settings.m_distType)
73-
{
74-
case tracking::DistCenters:
75-
for (size_t i = 0; i < tracks.size(); i++)
76-
{
77-
for (size_t j = 0; j < regions.size(); j++)
78-
{
79-
auto dist = tracks[i]->CheckType(regions[j].m_type) ? tracks[i]->CalcDist((regions[j].m_rect.tl() + regions[j].m_rect.br()) / 2) : maxPossibleCost;
80-
Cost[i + j * N] = dist;
81-
if (dist > maxCost)
82-
{
83-
maxCost = dist;
84-
}
85-
}
86-
}
87-
break;
88-
89-
case tracking::DistRects:
90-
for (size_t i = 0; i < tracks.size(); i++)
91-
{
92-
for (size_t j = 0; j < regions.size(); j++)
93-
{
94-
auto dist = tracks[i]->CheckType(regions[j].m_type) ? tracks[i]->CalcDist(regions[j].m_rect) : maxPossibleCost;
95-
Cost[i + j * N] = dist;
96-
if (dist > maxCost)
97-
{
98-
maxCost = dist;
99-
}
100-
}
101-
}
102-
break;
75+
CreateDistaceMatrix(regions, costMatrix, maxPossibleCost, maxCost);
10376

104-
case tracking::DistJaccard:
105-
for (size_t i = 0; i < tracks.size(); i++)
106-
{
107-
for (size_t j = 0; j < regions.size(); j++)
108-
{
109-
auto dist = tracks[i]->CheckType(regions[j].m_type) ? tracks[i]->CalcDistJaccard(regions[j].m_rect) : 1;
110-
Cost[i + j * N] = dist;
111-
if (dist > maxCost)
112-
{
113-
maxCost = dist;
114-
}
115-
}
116-
}
117-
break;
118-
}
119-
// -----------------------------------
12077
// Solving assignment problem (tracks and predictions of Kalman filter)
121-
// -----------------------------------
12278
if (m_settings.m_matchType == tracking::MatchHungrian)
12379
{
124-
AssignmentProblemSolver APS;
125-
APS.Solve(Cost, N, M, assignment, AssignmentProblemSolver::optimal);
80+
SolveHungrian(costMatrix, N, M, assignment);
12681
}
12782
else
12883
{
129-
MyGraph G;
130-
G.make_directed();
131-
132-
std::vector<node> nodes(N + M);
133-
134-
for (size_t i = 0; i < nodes.size(); ++i)
135-
{
136-
nodes[i] = G.new_node();
137-
}
138-
139-
edge_map<int> weights(G, 100);
140-
for (size_t i = 0; i < tracks.size(); i++)
141-
{
142-
bool hasZeroEdge = false;
143-
144-
for (size_t j = 0; j < regions.size(); j++)
145-
{
146-
track_t currCost = Cost[i + j * N];
147-
148-
edge e = G.new_edge(nodes[i], nodes[N + j]);
149-
150-
if (currCost < m_settings.m_distThres)
151-
{
152-
int weight = static_cast<int>(maxCost - currCost + 1);
153-
G.set_edge_weight(e, weight);
154-
weights[e] = weight;
155-
}
156-
else
157-
{
158-
if (!hasZeroEdge)
159-
{
160-
G.set_edge_weight(e, 0);
161-
weights[e] = 0;
162-
}
163-
hasZeroEdge = true;
164-
}
165-
}
166-
}
167-
168-
edges_t L = MAX_WEIGHT_BIPARTITE_MATCHING(G, weights);
169-
for (edges_t::iterator it = L.begin(); it != L.end(); ++it)
170-
{
171-
node a = it->source();
172-
node b = it->target();
173-
assignment[b.id()] = static_cast<assignments_t::value_type>(a.id() - N);
174-
}
84+
SolveBipartiteGraphs(costMatrix, N, M, assignment, maxCost);
17585
}
17686

177-
// -----------------------------------
17887
// clean assignment from pairs with large distance
179-
// -----------------------------------
18088
for (size_t i = 0; i < assignment.size(); i++)
18189
{
18290
if (assignment[i] != -1)
18391
{
184-
if (Cost[i + assignment[i] * N] > m_settings.m_distThres)
92+
if (costMatrix[i + assignment[i] * N] > m_settings.m_distThres)
18593
{
18694
assignment[i] = -1;
18795
tracks[i]->m_skippedFrames++;
@@ -194,9 +102,7 @@ void CTracker::UpdateHungrian(
194102
}
195103
}
196104

197-
// -----------------------------------
198105
// If track didn't get detects long time, remove it.
199-
// -----------------------------------
200106
for (int i = 0; i < static_cast<int>(tracks.size()); i++)
201107
{
202108
if (tracks[i]->m_skippedFrames > m_settings.m_maximumAllowedSkippedFrames ||
@@ -209,9 +115,7 @@ void CTracker::UpdateHungrian(
209115
}
210116
}
211117

212-
// -----------------------------------
213118
// Search for unassigned detects and start new tracks for them.
214-
// -----------------------------------
215119
for (size_t i = 0; i < regions.size(); ++i)
216120
{
217121
if (find(assignment.begin(), assignment.end(), i) == assignment.end())
@@ -227,12 +131,11 @@ void CTracker::UpdateHungrian(
227131
}
228132

229133
// Update Kalman Filters state
230-
const int stop_i = static_cast<int>(assignment.size());
134+
const ptrdiff_t stop_i = static_cast<int>(assignment.size());
231135
#pragma omp parallel for
232136
for (int i = 0; i < stop_i; ++i)
233137
{
234138
// If track updated less than one time, than filter state is not correct.
235-
236139
if (assignment[i] != -1) // If we have assigned detect, then update using its coordinates,
237140
{
238141
tracks[i]->m_skippedFrames = 0;
@@ -248,3 +151,134 @@ void CTracker::UpdateHungrian(
248151
}
249152
}
250153
}
154+
155+
///
156+
/// \brief CTracker::CreateDistaceMatrix
157+
/// \param regions
158+
/// \param costMatrix
159+
/// \param maxPossibleCost
160+
/// \param maxCost
161+
///
162+
void CTracker::CreateDistaceMatrix(const regions_t& regions, distMatrix_t& costMatrix, track_t maxPossibleCost, track_t& maxCost)
163+
{
164+
const size_t N = tracks.size(); // Tracking objects
165+
maxCost = 0;
166+
switch (m_settings.m_distType)
167+
{
168+
case tracking::DistCenters:
169+
for (size_t i = 0; i < tracks.size(); i++)
170+
{
171+
for (size_t j = 0; j < regions.size(); j++)
172+
{
173+
auto dist = tracks[i]->CheckType(regions[j].m_type) ? tracks[i]->CalcDist((regions[j].m_rect.tl() + regions[j].m_rect.br()) / 2) : maxPossibleCost;
174+
costMatrix[i + j * N] = dist;
175+
if (dist > maxCost)
176+
{
177+
maxCost = dist;
178+
}
179+
}
180+
}
181+
break;
182+
183+
case tracking::DistRects:
184+
for (size_t i = 0; i < tracks.size(); i++)
185+
{
186+
for (size_t j = 0; j < regions.size(); j++)
187+
{
188+
auto dist = tracks[i]->CheckType(regions[j].m_type) ? tracks[i]->CalcDist(regions[j].m_rect) : maxPossibleCost;
189+
costMatrix[i + j * N] = dist;
190+
if (dist > maxCost)
191+
{
192+
maxCost = dist;
193+
}
194+
}
195+
}
196+
break;
197+
198+
case tracking::DistJaccard:
199+
for (size_t i = 0; i < tracks.size(); i++)
200+
{
201+
for (size_t j = 0; j < regions.size(); j++)
202+
{
203+
auto dist = tracks[i]->CheckType(regions[j].m_type) ? tracks[i]->CalcDistJaccard(regions[j].m_rect) : 1;
204+
costMatrix[i + j * N] = dist;
205+
if (dist > maxCost)
206+
{
207+
maxCost = dist;
208+
}
209+
}
210+
}
211+
break;
212+
}
213+
}
214+
215+
///
216+
/// \brief CTracker::SolveHungrian
217+
/// \param costMatrix
218+
/// \param N
219+
/// \param M
220+
/// \param assignment
221+
///
222+
void CTracker::SolveHungrian(const distMatrix_t& costMatrix, size_t N, size_t M, assignments_t& assignment)
223+
{
224+
AssignmentProblemSolver APS;
225+
APS.Solve(costMatrix, N, M, assignment, AssignmentProblemSolver::optimal);
226+
}
227+
228+
///
229+
/// \brief CTracker::SolveBipartiteGraphs
230+
/// \param costMatrix
231+
/// \param N
232+
/// \param M
233+
/// \param assignment
234+
/// \param maxCost
235+
///
236+
void CTracker::SolveBipartiteGraphs(const distMatrix_t& costMatrix, size_t N, size_t M, assignments_t& assignment, track_t maxCost)
237+
{
238+
MyGraph G;
239+
G.make_directed();
240+
241+
std::vector<node> nodes(N + M);
242+
243+
for (size_t i = 0; i < nodes.size(); ++i)
244+
{
245+
nodes[i] = G.new_node();
246+
}
247+
248+
edge_map<int> weights(G, 100);
249+
for (size_t i = 0; i < N; i++)
250+
{
251+
bool hasZeroEdge = false;
252+
253+
for (size_t j = 0; j < M; j++)
254+
{
255+
track_t currCost = costMatrix[i + j * N];
256+
257+
edge e = G.new_edge(nodes[i], nodes[N + j]);
258+
259+
if (currCost < m_settings.m_distThres)
260+
{
261+
int weight = static_cast<int>(maxCost - currCost + 1);
262+
G.set_edge_weight(e, weight);
263+
weights[e] = weight;
264+
}
265+
else
266+
{
267+
if (!hasZeroEdge)
268+
{
269+
G.set_edge_weight(e, 0);
270+
weights[e] = 0;
271+
}
272+
hasZeroEdge = true;
273+
}
274+
}
275+
}
276+
277+
edges_t L = MAX_WEIGHT_BIPARTITE_MATCHING(G, weights);
278+
for (edges_t::iterator it = L.begin(); it != L.end(); ++it)
279+
{
280+
node a = it->source();
281+
node b = it->target();
282+
assignment[b.id()] = static_cast<assignments_t::value_type>(a.id() - N);
283+
}
284+
}

0 commit comments

Comments
 (0)