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+ // /
1213CTracker::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+ // /
2223CTracker::~CTracker (void )
2324{
2425}
2526
26- // ---------------------------------------------------------------------------
27- //
28- // ---------------------------------------------------------------------------
27+ // /
28+ // / \brief CTracker::Update
29+ // / \param regions
30+ // / \param grayFrame
31+ // / \param fps
32+ // /
2933void 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