Forráskód Böngészése

added support for csv files with a header for value specification
added a class for detection data with bounding boxes

Helge Wrede 9 éve
szülő
commit
fd3a11f115
47 módosított fájl, 2021 hozzáadás és 373 törlés
  1. 5 3
      CMakeLists.txt
  2. 2 2
      Documentation/html/TwoStage_8h_source.html
  3. 1 1
      Documentation/html/annotated.html
  4. 7 7
      Documentation/html/classalgo_1_1TwoStage-members.html
  5. 11 11
      Documentation/html/classalgo_1_1TwoStage.html
  6. 1 1
      Documentation/html/classes.html
  7. 1 1
      Documentation/html/files.html
  8. 5 5
      Documentation/html/functions.html
  9. 5 5
      Documentation/html/functions_func.html
  10. 1 1
      Documentation/html/hierarchy.html
  11. 2 2
      Documentation/html/search/all_1.js
  12. 1 1
      Documentation/html/search/all_3.js
  13. 2 2
      Documentation/html/search/all_e.js
  14. 2 2
      Documentation/html/search/functions_1.js
  15. 1 1
      Documentation/html/search/functions_3.js
  16. 1 1
      Documentation/html/search/functions_d.js
  17. 1 1
      Documentation/latex/classalgo_1_1TwoStage.tex
  18. 151 0
      algo/Berclaz.cpp
  19. 83 0
      algo/Berclaz.h
  20. 154 51
      algo/KShortestPaths.cpp
  21. 9 0
      algo/KShortestPaths.h
  22. 56 17
      algo/NStage.cpp
  23. 28 15
      algo/NStage.h
  24. 1 1
      core/DetectionSequence.cpp
  25. 14 8
      core/ObjectData.cpp
  26. 2 2
      core/ObjectData.h
  27. 85 0
      core/ObjectData2D.cpp
  28. 85 0
      core/ObjectData2D.h
  29. 21 22
      core/ObjectDataAngular.cpp
  30. 7 7
      core/ObjectDataAngular.h
  31. 75 0
      core/ObjectDataBox.cpp
  32. 35 0
      core/ObjectDataBox.h
  33. 6 0
      core/Tracklet.cpp
  34. 2 6
      graph/Definitions.h
  35. 438 122
      main/main.cpp
  36. 158 12
      util/FileIO.cpp
  37. 53 12
      util/FileIO.h
  38. 112 0
      util/Grid.cpp
  39. 179 0
      util/Grid.h
  40. 8 3
      util/Logger.cpp
  41. 6 0
      util/Logger.h
  42. 14 0
      util/MyMath.cpp
  43. 18 0
      util/MyMath.h
  44. 117 40
      util/Parser.cpp
  45. 39 1
      util/Parser.h
  46. 15 6
      util/Visualizer.cpp
  47. 1 1
      util/Visualizer.h

+ 5 - 3
CMakeLists.txt

@@ -14,14 +14,16 @@ set(SOURCE_FILES
         core/Tracklet.cpp core/Tracklet.h
         util/FileIO.cpp util/FileIO.h
         util/Parser.cpp util/Parser.h
-        algo/TwoStage.cpp algo/TwoStage.h
+        algo/NStage.cpp algo/NStage.h
         util/MyMath.cpp util/MyMath.h
         core/ObjectData3D.cpp core/ObjectData3D.h
-        visual/Visualizer.cpp visual/Visualizer.h
+        util/Visualizer.cpp util/Visualizer.h
         util/Logger.cpp util/Logger.h
         core/ObjectDataAngular.cpp core/ObjectDataAngular.h
         algo/KShortestPaths.cpp algo/KShortestPaths.h
-        graph/Definitions.h)
+        graph/Definitions.h
+        core/ObjectData2D.cpp core/ObjectData2D.h
+        algo/Berclaz.cpp algo/Berclaz.h util/Grid.cpp util/Grid.h core/ObjectDataBox.cpp core/ObjectDataBox.h)
 
 find_package(Doxygen)
 

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2 - 2
Documentation/html/TwoStage_8h_source.html


+ 1 - 1
Documentation/html/annotated.html

@@ -91,7 +91,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 <div class="levels">[detail level <span onclick="javascript:toggleLevel(1);">1</span><span onclick="javascript:toggleLevel(2);">2</span>]</div><table class="directory">
 <tr id="row_0_" class="even"><td class="entry"><span style="width:0px;display:inline-block;">&#160;</span><span id="arr_0_" class="arrow" onclick="toggleFolder('0_')">&#9660;</span><span class="icona"><span class="icon">N</span></span><b>algo</b></td><td class="desc"></td></tr>
 <tr id="row_0_0_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classalgo_1_1KShortestPaths.html" target="_self">KShortestPaths</a></td><td class="desc"></td></tr>
-<tr id="row_0_1_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classalgo_1_1TwoStage.html" target="_self">TwoStage</a></td><td class="desc"></td></tr>
+<tr id="row_0_1_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classalgo_1_1TwoStage.html" target="_self">NStage</a></td><td class="desc"></td></tr>
 <tr id="row_1_"><td class="entry"><span style="width:0px;display:inline-block;">&#160;</span><span id="arr_1_" class="arrow" onclick="toggleFolder('1_')">&#9660;</span><span class="icona"><span class="icon">N</span></span><b>core</b></td><td class="desc"></td></tr>
 <tr id="row_1_0_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classcore_1_1DetectionSequence.html" target="_self">DetectionSequence</a></td><td class="desc"></td></tr>
 <tr id="row_1_1_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classcore_1_1ObjectData.html" target="_self">ObjectData</a></td><td class="desc"></td></tr>

+ 7 - 7
Documentation/html/classalgo_1_1TwoStage-members.html

@@ -83,21 +83,21 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 
 <div id="nav-path" class="navpath">
   <ul>
-<li class="navelem"><b>algo</b></li><li class="navelem"><a class="el" href="classalgo_1_1TwoStage.html">TwoStage</a></li>  </ul>
+<li class="navelem"><b>algo</b></li><li class="navelem"><a class="el" href="classalgo_1_1TwoStage.html">NStage</a></li>  </ul>
 </div>
 </div><!-- top -->
 <div class="header">
   <div class="headertitle">
-<div class="title">algo::TwoStage Member List</div>  </div>
+<div class="title">algo::NStage Member List</div>  </div>
 </div><!--header-->
 <div class="contents">
 
-<p>This is the complete list of members for <a class="el" href="classalgo_1_1TwoStage.html">algo::TwoStage</a>, including all inherited members.</p>
+<p>This is the complete list of members for <a class="el" href="classalgo_1_1TwoStage.html">algo::NStage</a>, including all inherited members.</p>
 <table class="directory">
-  <tr class="even"><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a">CreateObjectGraph</a>(DirectedGraph &amp;graph, const core::DetectionSequence &amp;detections)</td><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html">algo::TwoStage</a></td><td class="entry"></td></tr>
-  <tr><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837">CreateTrackletGraph</a>(DirectedGraph &amp;obj_graph, DirectedGraph &amp;tlt_graph, size_t frame_count)</td><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html">algo::TwoStage</a></td><td class="entry"></td></tr>
-  <tr class="even"><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38">ExtractTracks</a>(DirectedGraph &amp;tlt_graph, size_t depth, std::vector&lt; core::TrackletPtr &gt; &amp;tracks)</td><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html">algo::TwoStage</a></td><td class="entry"></td></tr>
-  <tr><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7">TwoStage</a>(size_t max_frame_skip, double penalty_value, size_t max_tracklet_count)</td><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html">algo::TwoStage</a></td><td class="entry"></td></tr>
+  <tr class="even"><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a">CreateObjectGraph</a>(DirectedGraph &amp;graph, const core::DetectionSequence &amp;detections)</td><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html">algo::NStage</a></td><td class="entry"></td></tr>
+  <tr><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837">CreateTrackletGraph</a>(DirectedGraph &amp;obj_graph, DirectedGraph &amp;tlt_graph, size_t frame_count)</td><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html">algo::NStage</a></td><td class="entry"></td></tr>
+  <tr class="even"><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38">ExtractTracks</a>(DirectedGraph &amp;tlt_graph, size_t depth, std::vector&lt; core::TrackletPtr &gt; &amp;tracks)</td><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html">algo::NStage</a></td><td class="entry"></td></tr>
+  <tr><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7">NStage</a>(size_t max_frame_skip, double penalty_value, size_t max_tracklet_count)</td><td class="entry"><a class="el" href="classalgo_1_1TwoStage.html">algo::NStage</a></td><td class="entry"></td></tr>
 </table></div><!-- contents -->
 <!-- start footer part -->
 <hr class="footer"/><address class="footer"><small>

+ 11 - 11
Documentation/html/classalgo_1_1TwoStage.html

@@ -5,7 +5,7 @@
 <meta http-equiv="X-UA-Compatible" content="IE=9"/>
 <meta name="generator" content="Doxygen 1.8.12"/>
 <meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Tracore: algo::TwoStage Class Reference</title>
+<title>Tracore: algo::NStage Class Reference</title>
 <link href="tabs.css" rel="stylesheet" type="text/css"/>
 <script type="text/javascript" src="jquery.js"></script>
 <script type="text/javascript" src="dynsections.js"></script>
@@ -83,7 +83,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 
 <div id="nav-path" class="navpath">
   <ul>
-<li class="navelem"><b>algo</b></li><li class="navelem"><a class="el" href="classalgo_1_1TwoStage.html">TwoStage</a></li>  </ul>
+<li class="navelem"><b>algo</b></li><li class="navelem"><a class="el" href="classalgo_1_1TwoStage.html">NStage</a></li>  </ul>
 </div>
 </div><!-- top -->
 <div class="header">
@@ -91,15 +91,15 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 <a href="#pub-methods">Public Member Functions</a> &#124;
 <a href="classalgo_1_1TwoStage-members.html">List of all members</a>  </div>
   <div class="headertitle">
-<div class="title">algo::TwoStage Class Reference</div>  </div>
+<div class="title">algo::NStage Class Reference</div>  </div>
 </div><!--header-->
 <div class="contents">
 
-<p><code>#include &lt;<a class="el" href="TwoStage_8h_source.html">TwoStage.h</a>&gt;</code></p>
+<p><code>#include &lt;<a class="el" href="TwoStage_8h_source.html">NStage.h</a>&gt;</code></p>
 <table class="memberdecls">
 <tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="pub-methods"></a>
 Public Member Functions</h2></td></tr>
-<tr class="memitem:ae302f9ea93d56155a9dbd0be060500f7"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7">TwoStage</a> (size_t max_frame_skip, double penalty_value, size_t max_tracklet_count)</td></tr>
+<tr class="memitem:ae302f9ea93d56155a9dbd0be060500f7"><td class="memItemLeft" align="right" valign="top">&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7">NStage</a> (size_t max_frame_skip, double penalty_value, size_t max_tracklet_count)</td></tr>
 <tr class="separator:ae302f9ea93d56155a9dbd0be060500f7"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:a02dfe4e3fb244ecad13f676ce53d689a"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a">CreateObjectGraph</a> (DirectedGraph &amp;graph, const <a class="el" href="classcore_1_1DetectionSequence.html">core::DetectionSequence</a> &amp;detections)</td></tr>
 <tr class="separator:a02dfe4e3fb244ecad13f676ce53d689a"><td class="memSeparator" colspan="2">&#160;</td></tr>
@@ -116,7 +116,7 @@ Public Member Functions</h2></td></tr>
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">algo::TwoStage::TwoStage </td>
+          <td class="memname">algo::NStage::NStage </td>
           <td>(</td>
           <td class="paramtype">size_t&#160;</td>
           <td class="paramname"><em>max_frame_skip</em>, </td>
@@ -157,7 +157,7 @@ Public Member Functions</h2></td></tr>
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">void algo::TwoStage::CreateObjectGraph </td>
+          <td class="memname">void algo::NStage::CreateObjectGraph </td>
           <td>(</td>
           <td class="paramtype">DirectedGraph &amp;&#160;</td>
           <td class="paramname"><em>graph</em>, </td>
@@ -190,7 +190,7 @@ Public Member Functions</h2></td></tr>
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">void algo::TwoStage::CreateTrackletGraph </td>
+          <td class="memname">void algo::NStage::CreateTrackletGraph </td>
           <td>(</td>
           <td class="paramtype">DirectedGraph &amp;&#160;</td>
           <td class="paramname"><em>obj_graph</em>, </td>
@@ -230,7 +230,7 @@ Public Member Functions</h2></td></tr>
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">void algo::TwoStage::ExtractTracks </td>
+          <td class="memname">void algo::NStage::ExtractTracks </td>
           <td>(</td>
           <td class="paramtype">DirectedGraph &amp;&#160;</td>
           <td class="paramname"><em>tlt_graph</em>, </td>
@@ -266,8 +266,8 @@ Public Member Functions</h2></td></tr>
 </div>
 </div>
 <hr/>The documentation for this class was generated from the following files:<ul>
-<li>algo/<a class="el" href="TwoStage_8h_source.html">TwoStage.h</a></li>
-<li>algo/TwoStage.cpp</li>
+<li>algo/<a class="el" href="TwoStage_8h_source.html">NStage.h</a></li>
+<li>algo/NStage.cpp</li>
 </ul>
 </div><!-- contents -->
 <!-- start footer part -->

+ 1 - 1
Documentation/html/classes.html

@@ -100,7 +100,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 </td><td rowspan="2" valign="bottom"><a name="letter_L"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;L&#160;&#160;</div></td></tr></table>
 </td><td rowspan="2" valign="bottom"><a name="letter_O"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;O&#160;&#160;</div></td></tr></table>
 </td><td rowspan="2" valign="bottom"><a name="letter_P"></a><table border="0" cellspacing="0" cellpadding="0"><tr><td><div class="ah">&#160;&#160;P&#160;&#160;</div></td></tr></table>
-</td><td valign="top"><a class="el" href="classalgo_1_1TwoStage.html">TwoStage</a> (algo)&#160;&#160;&#160;</td></tr>
+</td><td valign="top"><a class="el" href="classalgo_1_1TwoStage.html">NStage</a> (algo)&#160;&#160;&#160;</td></tr>
 <tr><td></td></tr>
 <tr><td valign="top"><a class="el" href="classutil_1_1FileIO.html">FileIO</a> (util)&#160;&#160;&#160;</td><td valign="top"><a class="el" href="classutil_1_1Logger.html">Logger</a> (util)&#160;&#160;&#160;</td><td valign="top"><a class="el" href="classcore_1_1ObjectData.html">ObjectData</a> (core)&#160;&#160;&#160;</td><td valign="top"><a class="el" href="classutil_1_1Parser.html">Parser</a> (util)&#160;&#160;&#160;</td><td></td></tr>
 <tr><td></td><td></td><td></td><td></td><td></td></tr>

+ 1 - 1
Documentation/html/files.html

@@ -88,7 +88,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 <div class="levels">[detail level <span onclick="javascript:toggleLevel(1);">1</span><span onclick="javascript:toggleLevel(2);">2</span>]</div><table class="directory">
 <tr id="row_0_" class="even"><td class="entry"><span style="width:0px;display:inline-block;">&#160;</span><span id="arr_0_" class="arrow" onclick="toggleFolder('0_')">&#9660;</span><span id="img_0_" class="iconfopen" onclick="toggleFolder('0_')">&#160;</span><a class="el" href="dir_14879d16547af1f036be9d5915ae128f.html" target="_self">algo</a></td><td class="desc"></td></tr>
 <tr id="row_0_0_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><a href="KShortestPaths_8h_source.html"><span class="icondoc"></span></a><b>KShortestPaths.h</b></td><td class="desc"></td></tr>
-<tr id="row_0_1_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><a href="TwoStage_8h_source.html"><span class="icondoc"></span></a><b>TwoStage.h</b></td><td class="desc"></td></tr>
+<tr id="row_0_1_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><a href="TwoStage_8h_source.html"><span class="icondoc"></span></a><b>NStage.h</b></td><td class="desc"></td></tr>
 <tr id="row_1_"><td class="entry"><span style="width:0px;display:inline-block;">&#160;</span><span id="arr_1_" class="arrow" onclick="toggleFolder('1_')">&#9660;</span><span id="img_1_" class="iconfopen" onclick="toggleFolder('1_')">&#160;</span><a class="el" href="dir_4270bfced15e0e73154b13468c7c9ad9.html" target="_self">core</a></td><td class="desc"></td></tr>
 <tr id="row_1_0_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><a href="DetectionSequence_8h_source.html"><span class="icondoc"></span></a><b>DetectionSequence.h</b></td><td class="desc"></td></tr>
 <tr id="row_1_1_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><a href="ObjectData_8h_source.html"><span class="icondoc"></span></a><b>ObjectData.h</b></td><td class="desc"></td></tr>

+ 5 - 5
Documentation/html/functions.html

@@ -137,10 +137,10 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 , <a class="el" href="classcore_1_1Tracklet.html#a0357f2fa173941800571432dcbc96dc2">core::Tracklet</a>
 </li>
 <li>CreateObjectGraph()
-: <a class="el" href="classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a">algo::TwoStage</a>
+: <a class="el" href="classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a">algo::NStage</a>
 </li>
 <li>CreateTrackletGraph()
-: <a class="el" href="classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837">algo::TwoStage</a>
+: <a class="el" href="classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837">algo::NStage</a>
 </li>
 </ul>
 
@@ -157,7 +157,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 : <a class="el" href="classutil_1_1MyMath.html#abaf214b2fc7a31e43cf07245cf4b2e1f">util::MyMath</a>
 </li>
 <li>ExtractTracks()
-: <a class="el" href="classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38">algo::TwoStage</a>
+: <a class="el" href="classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38">algo::NStage</a>
 </li>
 </ul>
 
@@ -360,8 +360,8 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 <li>Tracklet()
 : <a class="el" href="classcore_1_1Tracklet.html#aedf59b5a9a068a28bb7570f2a031d4e7">core::Tracklet</a>
 </li>
-<li>TwoStage()
-: <a class="el" href="classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7">algo::TwoStage</a>
+<li>NStage()
+: <a class="el" href="classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7">algo::NStage</a>
 </li>
 </ul>
 

+ 5 - 5
Documentation/html/functions_func.html

@@ -137,10 +137,10 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 , <a class="el" href="classcore_1_1Tracklet.html#a0357f2fa173941800571432dcbc96dc2">core::Tracklet</a>
 </li>
 <li>CreateObjectGraph()
-: <a class="el" href="classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a">algo::TwoStage</a>
+: <a class="el" href="classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a">algo::NStage</a>
 </li>
 <li>CreateTrackletGraph()
-: <a class="el" href="classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837">algo::TwoStage</a>
+: <a class="el" href="classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837">algo::NStage</a>
 </li>
 </ul>
 
@@ -157,7 +157,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 : <a class="el" href="classutil_1_1MyMath.html#abaf214b2fc7a31e43cf07245cf4b2e1f">util::MyMath</a>
 </li>
 <li>ExtractTracks()
-: <a class="el" href="classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38">algo::TwoStage</a>
+: <a class="el" href="classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38">algo::NStage</a>
 </li>
 </ul>
 
@@ -356,8 +356,8 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 <li>Tracklet()
 : <a class="el" href="classcore_1_1Tracklet.html#aedf59b5a9a068a28bb7570f2a031d4e7">core::Tracklet</a>
 </li>
-<li>TwoStage()
-: <a class="el" href="classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7">algo::TwoStage</a>
+<li>NStage()
+: <a class="el" href="classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7">algo::NStage</a>
 </li>
 </ul>
 

+ 1 - 1
Documentation/html/hierarchy.html

@@ -100,7 +100,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
 <tr id="row_5_1_" class="even"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classcore_1_1ObjectDataMap.html" target="_self">core::ObjectDataMap</a></td><td class="desc"></td></tr>
 <tr id="row_5_2_"><td class="entry"><span style="width:32px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classcore_1_1Tracklet.html" target="_self">core::Tracklet</a></td><td class="desc"></td></tr>
 <tr id="row_6_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classutil_1_1Parser.html" target="_self">util::Parser</a></td><td class="desc"></td></tr>
-<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classalgo_1_1TwoStage.html" target="_self">algo::TwoStage</a></td><td class="desc"></td></tr>
+<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="classalgo_1_1TwoStage.html" target="_self">algo::NStage</a></td><td class="desc"></td></tr>
 </table>
 </div><!-- directory -->
 </div><!-- contents -->

+ 2 - 2
Documentation/html/search/all_1.js

@@ -3,6 +3,6 @@ var searchData=
   ['clamp',['Clamp',['../classutil_1_1MyMath.html#a367a261dc52a85cc97ba376799ed13a3',1,'util::MyMath']]],
   ['clear',['Clear',['../classcore_1_1DetectionSequence.html#ab62569a3e51d58457057deba12ef6892',1,'core::DetectionSequence']]],
   ['compareto',['CompareTo',['../classcore_1_1ObjectData.html#afbf7a1e87235f1b204d4d2eb8a37a9a6',1,'core::ObjectData::CompareTo()'],['../classcore_1_1ObjectData3D.html#abef3e4e7a0dc121d8a403d91964be576',1,'core::ObjectData3D::CompareTo()'],['../classcore_1_1ObjectDataAngular.html#a2932240c6c082b76f2c04723cdf3e4f9',1,'core::ObjectDataAngular::CompareTo()'],['../classcore_1_1ObjectDataMap.html#a7fcc9ef5b684f14d33711348610d9b74',1,'core::ObjectDataMap::CompareTo()'],['../classcore_1_1Tracklet.html#a0357f2fa173941800571432dcbc96dc2',1,'core::Tracklet::CompareTo()']]],
-  ['createobjectgraph',['CreateObjectGraph',['../classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a',1,'algo::TwoStage']]],
-  ['createtrackletgraph',['CreateTrackletGraph',['../classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837',1,'algo::TwoStage']]]
+  ['createobjectgraph',['CreateObjectGraph',['../classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a',1,'algo::NStage']]],
+  ['createtrackletgraph',['CreateTrackletGraph',['../classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837',1,'algo::NStage']]]
 ];

+ 1 - 1
Documentation/html/search/all_3.js

@@ -1,5 +1,5 @@
 var searchData=
 [
   ['euclideandistance',['EuclideanDistance',['../classutil_1_1MyMath.html#abaf214b2fc7a31e43cf07245cf4b2e1f',1,'util::MyMath']]],
-  ['extracttracks',['ExtractTracks',['../classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38',1,'algo::TwoStage']]]
+  ['extracttracks',['ExtractTracks',['../classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38',1,'algo::NStage']]]
 ];

+ 2 - 2
Documentation/html/search/all_e.js

@@ -2,6 +2,6 @@ var searchData=
 [
   ['tracklet',['Tracklet',['../classcore_1_1Tracklet.html',1,'core']]],
   ['tracklet',['Tracklet',['../classcore_1_1Tracklet.html#aedf59b5a9a068a28bb7570f2a031d4e7',1,'core::Tracklet']]],
-  ['twostage',['TwoStage',['../classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7',1,'algo::TwoStage']]],
-  ['twostage',['TwoStage',['../classalgo_1_1TwoStage.html',1,'algo']]]
+  ['twostage',['NStage',['../classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7',1,'algo::NStage']]],
+  ['twostage',['NStage',['../classalgo_1_1TwoStage.html',1,'algo']]]
 ];

+ 2 - 2
Documentation/html/search/functions_1.js

@@ -3,6 +3,6 @@ var searchData=
   ['clamp',['Clamp',['../classutil_1_1MyMath.html#a367a261dc52a85cc97ba376799ed13a3',1,'util::MyMath']]],
   ['clear',['Clear',['../classcore_1_1DetectionSequence.html#ab62569a3e51d58457057deba12ef6892',1,'core::DetectionSequence']]],
   ['compareto',['CompareTo',['../classcore_1_1ObjectData.html#afbf7a1e87235f1b204d4d2eb8a37a9a6',1,'core::ObjectData::CompareTo()'],['../classcore_1_1ObjectData3D.html#abef3e4e7a0dc121d8a403d91964be576',1,'core::ObjectData3D::CompareTo()'],['../classcore_1_1ObjectDataAngular.html#a2932240c6c082b76f2c04723cdf3e4f9',1,'core::ObjectDataAngular::CompareTo()'],['../classcore_1_1ObjectDataMap.html#a7fcc9ef5b684f14d33711348610d9b74',1,'core::ObjectDataMap::CompareTo()'],['../classcore_1_1Tracklet.html#a0357f2fa173941800571432dcbc96dc2',1,'core::Tracklet::CompareTo()']]],
-  ['createobjectgraph',['CreateObjectGraph',['../classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a',1,'algo::TwoStage']]],
-  ['createtrackletgraph',['CreateTrackletGraph',['../classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837',1,'algo::TwoStage']]]
+  ['createobjectgraph',['CreateObjectGraph',['../classalgo_1_1TwoStage.html#a02dfe4e3fb244ecad13f676ce53d689a',1,'algo::NStage']]],
+  ['createtrackletgraph',['CreateTrackletGraph',['../classalgo_1_1TwoStage.html#ae14cf79859b4275c862d6750b6bc6837',1,'algo::NStage']]]
 ];

+ 1 - 1
Documentation/html/search/functions_3.js

@@ -1,5 +1,5 @@
 var searchData=
 [
   ['euclideandistance',['EuclideanDistance',['../classutil_1_1MyMath.html#abaf214b2fc7a31e43cf07245cf4b2e1f',1,'util::MyMath']]],
-  ['extracttracks',['ExtractTracks',['../classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38',1,'algo::TwoStage']]]
+  ['extracttracks',['ExtractTracks',['../classalgo_1_1TwoStage.html#a09168d0ace15d689c9d594ca16b93c38',1,'algo::NStage']]]
 ];

+ 1 - 1
Documentation/html/search/functions_d.js

@@ -1,5 +1,5 @@
 var searchData=
 [
   ['tracklet',['Tracklet',['../classcore_1_1Tracklet.html#aedf59b5a9a068a28bb7570f2a031d4e7',1,'core::Tracklet']]],
-  ['twostage',['TwoStage',['../classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7',1,'algo::TwoStage']]]
+  ['twostage',['NStage',['../classalgo_1_1TwoStage.html#ae302f9ea93d56155a9dbd0be060500f7',1,'algo::NStage']]]
 ];

+ 1 - 1
Documentation/latex/classalgo_1_1TwoStage.tex

@@ -23,7 +23,7 @@ Implementation of the two-\/staged graph-\/based multi-\/object tracker.
 \subsection{Constructor \& Destructor Documentation}
 \index{algo\+::\+Two\+Stage@{algo\+::\+Two\+Stage}!Two\+Stage@{Two\+Stage}}
 \index{Two\+Stage@{Two\+Stage}!algo\+::\+Two\+Stage@{algo\+::\+Two\+Stage}}
-\subsubsection[{\texorpdfstring{Two\+Stage(size\+\_\+t max\+\_\+frame\+\_\+skip, double penalty\+\_\+value, size\+\_\+t max\+\_\+tracklet\+\_\+count)}{TwoStage(size\_t max\_frame\_skip, double penalty\_value, size\_t max\_tracklet\_count)}}]{\setlength{\rightskip}{0pt plus 5cm}algo\+::\+Two\+Stage\+::\+Two\+Stage (
+\subsubsection[{\texorpdfstring{Two\+Stage(size\+\_\+t max\+\_\+frame\+\_\+skip, double penalty\+\_\+value, size\+\_\+t max\+\_\+tracklet\+\_\+count)}{NStage(size\_t max\_frame\_skip, double penalty\_value, size\_t max\_tracklet\_count)}}]{\setlength{\rightskip}{0pt plus 5cm}algo\+::\+Two\+Stage\+::\+Two\+Stage (
 \begin{DoxyParamCaption}
 \item[{size\+\_\+t}]{max\+\_\+frame\+\_\+skip, }
 \item[{double}]{penalty\+\_\+value, }

+ 151 - 0
algo/Berclaz.cpp

@@ -0,0 +1,151 @@
+//
+// Created by wrede on 02.06.16.
+//
+
+#include "Berclaz.h"
+#include "KShortestPaths.h"
+#include "../util/Parser.h"
+#include "../util/Logger.h"
+#include "../util/FileIO.h"
+
+namespace algo
+{
+    Berclaz::Berclaz(int h_res, int v_res, int vicinity_size)
+    {
+        h_res_ = h_res;
+        v_res_ = v_res;
+        vicinity_size_ = vicinity_size;
+    }
+
+    void Berclaz::CreateGraph(DirectedGraph& graph, Vertex& source, Vertex& sink,
+                              util::Grid& grid)
+    {
+        // Add source vertex
+        source = boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()), graph);
+
+        // Add grid vertices
+        for (int f = 0; f < grid.GetDepthCount(); ++f)
+        {
+            for (int y = 0; y < v_res_; ++y)
+            {
+                for (int x = 0; x < h_res_; ++x)
+                {
+                    boost::add_vertex(grid.GetValue(x, y, f), graph);
+                }
+            }
+        }
+
+        // Add sink vertex
+        sink = boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()), graph);
+        
+        // Store the vertex indices
+        VertexIndexMap vertices = boost::get(boost::vertex_index, graph);
+
+        // Store the vertex values
+        VertexValueMap values = boost::get(boost::vertex_name, graph);
+
+        util::Logger::LogDebug("num vertices " + std::to_string(boost::num_vertices(graph)));
+        
+        // Iterate all vertices but source and sink
+        for (int f = 0; f < grid.GetDepthCount(); ++f)
+        {
+            for (int y = 0; y < v_res_; ++y)
+            {
+                for (int x = 0; x < h_res_; ++x)
+                {
+                    // First vertex index
+                    int vi = x + y * h_res_ + f * h_res_ * v_res_ + 1;
+                    double score = values[vi]->GetDetectionScore();
+                    if (score > MAX_SCORE_VALUE)
+                    {
+                        score = MAX_SCORE_VALUE;
+                    }
+                    else if (score < MIN_SCORE_VALUE)
+                    {
+                        score = MIN_SCORE_VALUE;
+                    }
+
+                    // Iterate all nearby cells in the next frame
+                    for (int nx = std::max(0, x - vicinity_size_);
+                         nx < std::min(h_res_, x + vicinity_size_ + 1);
+                         ++nx)
+                    {
+                        for (int ny = std::max(0, y - vicinity_size_);
+                             ny < std::min(v_res_, y + vicinity_size_ + 1);
+                             ++ny)
+                        {
+                            // Second vertex index
+                            int vj = nx + ny * h_res_ + (f + 1) * h_res_ * v_res_ + 1;
+
+                            // Connect to nearby cells
+                            double weight = -std::log(score / (1 - score));
+                            boost::add_edge(vertices[vi], vertices[vj],
+                                            weight, graph);
+                        }
+                    }
+                    
+                    // Connect with source and sink
+                    boost::add_edge(source, vertices[vi],
+                                    VIRTUAL_EDGE_WEIGHT, graph);
+
+                    boost::add_edge(vertices[vi], sink,
+                                    VIRTUAL_EDGE_WEIGHT, graph);
+                }
+            }
+        }
+
+        util::Logger::LogDebug("num edges " + std::to_string(boost::num_edges(graph)));
+    }
+
+    void Berclaz::ExtractTracks(DirectedGraph& graph,
+                                MultiPredecessorMap& map, Vertex origin,
+                                std::vector<core::TrackletPtr>& tracks)
+    {
+        VertexValueMap values = boost::get(boost::vertex_name, graph);
+
+        // Move along all paths in reverse, starting at the origin
+        for (Vertex first : map[origin])
+        {
+            core::TrackletPtr tracklet(new core::Tracklet());
+
+            // The paths are node disjoint, so there should always be only one
+            // node to proceed to
+            for (Vertex u = first, v = (*map[u].begin());
+                 u != v; u = v, v = (*map[v].begin()))
+            {
+                tracklet->AddPathObject(values[u]);
+            }
+
+            tracks.push_back(tracklet);
+        }
+    }
+
+    void Berclaz::Run(core::DetectionSequence& sequence,
+                      size_t max_track_count,
+                      std::vector<core::TrackletPtr>& tracks)
+    {
+        Vertex source, sink;
+        DirectedGraph graph;
+        util::Grid grid = util::Parser::ParseGrid(sequence,
+                                                  MIN_H_VALUE,
+                                                  MAX_H_VALUE,
+                                                  h_res_,
+                                                  MIN_V_VALUE,
+                                                  MAX_V_VALUE,
+                                                  v_res_);
+
+        util::Logger::LogDebug("create graph");
+        CreateGraph(graph, source, sink, grid);
+
+        util::FileIO::WriteCSVMatlab(graph, "/home/wrede/Dokumente/graph.csv");
+
+        util::Logger::LogDebug("init ksp");
+        KShortestPaths ksp(graph, source, sink);
+
+        util::Logger::LogDebug("run ksp");
+        MultiPredecessorMap ksp_result = ksp.Run(max_track_count);
+
+        util::Logger::LogDebug("extract tracks");
+        ExtractTracks(graph, ksp_result, sink, tracks);
+    }
+}

+ 83 - 0
algo/Berclaz.h

@@ -0,0 +1,83 @@
+//
+// Created by wrede on 02.06.16.
+//
+
+#ifndef GBMOT_BERCLAZ_H
+#define GBMOT_BERCLAZ_H
+
+#include "../graph/Definitions.h"
+#include "../core/DetectionSequence.h"
+#include "../core/Tracklet.h"
+#include "../util/Grid.h"
+
+namespace algo
+{
+    class Berclaz
+    {
+    private:
+        const double VIRTUAL_EDGE_WEIGHT = 0.0;
+        const double MAX_SCORE_VALUE = 0.9999999999;
+        const double MIN_SCORE_VALUE = 0.0000000001;
+        const double MIN_H_VALUE = 0.0;
+        const double MAX_H_VALUE = 1.0;
+        const double MIN_V_VALUE = 0.0;
+        const double MAX_V_VALUE = 1.0;
+
+        /**
+         * Horizontal grid resolution
+         */
+        int h_res_;
+
+        /**
+         * Vertical grid resolution
+         */
+        int v_res_;
+
+        /**
+         * The number of cells a detection can move within one frame
+         */
+        int vicinity_size_;
+
+        /**
+         * Creates a graph from the given sequence.
+         * @param graph The graph to write into
+         * @param source A reference to the source vertex
+         * @param sink A reference to the sink vertex
+         * @param grid The detection values as a grid
+         */
+        void CreateGraph(DirectedGraph& graph, Vertex& source, Vertex& sink,
+                         util::Grid& grid);
+
+        /**
+         * Extracts the final tracks from the given graph and predecessor map.
+         * @param graph The graph to read the values from
+         * @param map The predecessor map to read the paths from
+         * @param origin The vertex to start the reverse path traversal from
+         * @param tracks The vector to fill with the extracted tracks
+         */
+        void ExtractTracks(DirectedGraph& graph,
+                           MultiPredecessorMap& map, Vertex origin,
+                           std::vector<core::TrackletPtr>& tracks);
+    public:
+        /**
+         * Instantiate with the given parameters.
+         * @param h_res The horizontal grid resolution
+         * @param v_res The vertical grid resolution
+         * @param vicinity_size The maximum number of cells a detection can skip
+         *                      within one frame
+         */
+        Berclaz(int h_res, int v_res, int vicinity_size);
+
+        /**
+         * Runs the algorithm on the given sequence.
+         * @param sequence The detection to use
+         * @param max_track_count The maximum number of tracks to extract
+         * @param tracks The vector to store the found tracks into
+         */
+        void Run(core::DetectionSequence& sequence, size_t max_track_count,
+                 std::vector<core::TrackletPtr>& tracks);
+    };
+}
+
+
+#endif //GBMOT_BERCLAZ_H

+ 154 - 51
algo/KShortestPaths.cpp

@@ -25,13 +25,12 @@ namespace algo
 
         util::Logger::LogDebug("find shortest path #1");
 
+        util::Logger::LogDebug("find");
         FindAndAugmentPath(1, true);
 
         // Find the k shortest paths
         for (size_t i = 1; i < max_path_count; ++i)
         {
-            util::Logger::LogDebug("find shortest path #" + std::to_string(i + 1));
-
             if (i != 1)
             {
                 //If the costs are increasing, no further shortest paths will be found
@@ -41,18 +40,26 @@ namespace algo
                 }
             }
 
+            util::Logger::LogDebug("find shortest path #" + std::to_string(i + 1));
+
+            util::Logger::LogDebug("copy");
             // Create a copy of the original graph which is used
             // for the graph and edge transformations
             CopyOriginalGraph();
 
+            util::Logger::LogDebug("extend");
             // Extend the graph (has negative and positive edge weights)
             ExtendGraph(i);
 
-            //TODO (optional) Transform the edge weights (positive edge weights) and use dijkstra
+            util::Logger::LogDebug("transform");
+            // Transforms the edge costs (has only positive edge weights)
+            TransformEdgeCosts(i);
 
+            util::Logger::LogDebug("find");
             // Finds the next path and adds it to the found paths
             FindAndAugmentPath(i + 1, false);
 
+            util::Logger::LogDebug("interlace");
             // Removes the duplicate edges to make the paths node-disjoint
             Interlace(i + 1);
         }
@@ -64,16 +71,19 @@ namespace algo
     void KShortestPaths::ExtendGraph(size_t i)
     {
         boost::graph_traits<DirectedGraph>::out_edge_iterator oei, oei_end;
+        boost::graph_traits<DirectedGraph>::edge_iterator ei, ei_end;
         boost::graph_traits<DirectedGraph>::vertex_iterator vi, vi_end;
         VertexValueMap graph_values = boost::get(boost::vertex_name, copied_graph_);
 
         // Split all vertices within the paths
-        for (boost::tie(vi, vi_end) = boost::vertices(original_graph_); vi != vi_end; ++vi)
+        for (boost::tie(vi, vi_end) = boost::vertices(original_graph_);
+             vi != vi_end; ++vi)
         {
             Vertex v_original = (*vi);
 
             // Ignore vertices off the paths, the source and the sink
-            if (i_shortest_paths_[i].count(v_original) == 0 || v_original == source_ || v_original == sink_)
+            if (i_shortest_paths_[i].count(v_original) == 0 ||
+                    v_original == source_ || v_original == sink_)
             {
                 continue;
             }
@@ -83,14 +93,16 @@ namespace algo
             copy_to_original_[v_out] = v_original;
 
             // Copy outgoing edges to v_out
-            for (boost::tie(oei, oei_end) = boost::out_edges(v_in, copied_graph_); oei != oei_end; ++oei)
+            for (boost::tie(oei, oei_end) = boost::out_edges(v_in, copied_graph_);
+                 oei != oei_end; ++oei)
             {
                 QueueAddEdge(v_out, boost::target(*oei, copied_graph_),
                              boost::get(boost::edge_weight, copied_graph_, *oei));
             }
 
             // Remove outgoing edges from vertex
-            for (boost::tie(oei, oei_end) = boost::out_edges(v_in, copied_graph_); oei != oei_end; ++oei)
+            for (boost::tie(oei, oei_end) = boost::out_edges(v_in, copied_graph_);
+                 oei != oei_end; ++oei)
             {
                 QueueRemoveEdge(v_in, boost::target(*oei, copied_graph_));
             }
@@ -101,35 +113,26 @@ namespace algo
 
         UpdateEdges();
 
-        // Iterate all vertices within the copied graph
-        for (boost::tie(vi, vi_end) = boost::vertices(copied_graph_); vi != vi_end; ++vi)
+        // Iterate all edges within the copied graph
+        EdgeWeightMap weights = boost::get(boost::edge_weight, copied_graph_);
+        for (boost::tie(ei, ei_end) = boost::edges(copied_graph_);
+             ei != ei_end; ++ei)
         {
-            Vertex v_copy = (*vi);
-            Vertex v_original = copy_to_original_[v_copy];
-
-            // Ignore vertices off the paths
-            if (i_shortest_paths_[i].count(v_original) == 0)
+            Vertex s_copy = boost::source(*ei, copied_graph_);
+            Vertex t_copy = boost::target(*ei, copied_graph_);
+            Vertex s_orig = copy_to_original_[s_copy];
+            Vertex t_orig = copy_to_original_[t_copy];
+            double weight = weights[*ei];
+
+            // If the edge is part of the paths
+            if (i_shortest_paths_[i].count(t_orig) > 0 &&
+                    i_shortest_paths_[i][t_orig].count(s_orig) > 0)
             {
-                continue;
-            }
-
-            // Iterate all outgoing edges at the current vertex
-            for (boost::tie(oei, oei_end) = boost::out_edges(v_copy, copied_graph_); oei != oei_end; ++oei)
-            {
-                Vertex t_copy = boost::target(*oei, copied_graph_);
-                Vertex t_original = copy_to_original_[t_copy];
+                // Add the edge with direction and weight inverted
+                QueueAddEdge(t_copy, s_copy, -weight);
 
-                // Ignore edges off the paths
-                if (i_shortest_paths_[i].count(t_original) == 0)
-                {
-                    continue;
-                }
-
-                // Invert the edge direction and weight
-                double weight = boost::get(boost::edge_weight, copied_graph_,
-                                           *oei);
-                QueueAddEdge(t_copy, v_copy, -weight);
-                QueueRemoveEdge(v_copy, t_copy);
+                // Remove the old edge
+                QueueRemoveEdge(s_copy, t_copy);
             }
         }
 
@@ -138,23 +141,27 @@ namespace algo
 
     double KShortestPaths::OverallCosts(size_t i)
     {
-        EdgeWeightMap weights = boost::get(boost::edge_weight, original_graph_);
-        boost::graph_traits<DirectedGraph>::edge_iterator ei, ei_end;
         double value = 0.0;
 
+        EdgeWeightMap weights = boost::get(boost::edge_weight, original_graph_);
+
+        // Iterate all edges
+        boost::graph_traits<DirectedGraph>::edge_iterator ei, ei_end;
         for (boost::tie(ei, ei_end) = boost::edges(original_graph_);
              ei != ei_end; ++ei)
         {
             Vertex source = boost::source(*ei, original_graph_);
             Vertex target = boost::target(*ei, original_graph_);
 
-            // Is edge within paths?
-            if (i_shortest_paths_[i].count(target) > 0 && i_shortest_paths_[i][target].count(source) > 0)
+            if (i_shortest_paths_[i].count(target) > 0 &&
+                    i_shortest_paths_[i][target].count(source) > 0)
             {
                 value += weights[*ei];
             }
         }
 
+        util::Logger::LogDebug("cost in " + std::to_string(i) + " : " + std::to_string(value));
+
         return value;
     }
 
@@ -202,10 +209,12 @@ namespace algo
             }
 
             // Is edge within paths?
-            if (i_shortest_paths_[i].count(target) > 0 && i_shortest_paths_[i][target].count(source) > 0)
+            if (i_shortest_paths_[i].count(target) > 0 &&
+                    i_shortest_paths_[i][target].count(source) > 0)
             {
                 // Is edge duplicate?
-                if (i_shortest_paths_[i].count(source) > 0 && i_shortest_paths_[i][source].count(target) > 0)
+                if (i_shortest_paths_[i].count(source) > 0 &&
+                        i_shortest_paths_[i][source].count(target) > 0)
                 {
                     i_shortest_paths_[i][target].erase(source);
                     i_shortest_paths_[i][source].erase(target);
@@ -222,14 +231,20 @@ namespace algo
             i_shortest_paths_.push_back(MultiPredecessorMap());
         }
 
+        // Add new distance maps until the needed iteration is reached
+        while (i_distances_.size() < (i + 1))
+        {
+            i_distances_.push_back(std::unordered_map<Vertex, double>());
+        }
+
         // Only copy old paths if old paths exist
-        if (i > 0)
+        if (i > 1)
         {
             // Copy the old paths
             for (auto it = i_shortest_paths_[i - 1].begin();
                  it != i_shortest_paths_[i - 1].end(); ++it)
             {
-                i_shortest_paths_[i][(*it).first] = (*it).second;
+                i_shortest_paths_[i][it->first] = it->second;
             }
         }
 
@@ -237,25 +252,42 @@ namespace algo
         {
             // Prepare variables for path finding
             size_t graph_size = boost::num_vertices(original_graph_);
+            Vertex root_vertex = source_;
             std::vector<Vertex> pred_list(graph_size);
             std::vector<double> dist_list(graph_size);
             VertexIndexMap graph_indices = boost::get(boost::vertex_index,
                                                       original_graph_);
+            EdgeWeightMap weight_map = boost::get(boost::edge_weight,
+                                                  original_graph_);
             PredecessorMap pred_map(&pred_list[0], graph_indices);
             DistanceMap dist_map(&dist_list[0], graph_indices);
 
             // Find the shortest path
-            boost::dijkstra_shortest_paths(original_graph_,
-                                           source_,
-                                           boost::predecessor_map(pred_map)
-                                                   .distance_map(dist_map));
+            boost::bellman_ford_shortest_paths(original_graph_,
+                                               graph_size,
+                                               boost::root_vertex(root_vertex)
+                                                       .weight_map(weight_map)
+                                                       .predecessor_map(pred_map)
+                                                       .distance_map(dist_map));
+
+            // Add the new distances
+            boost::graph_traits<DirectedGraph>::vertex_iterator vi, vi_end;
+            for (boost::tie(vi, vi_end) = boost::vertices(original_graph_);
+                 vi != vi_end; ++vi)
+            {
+                i_distances_[i][*vi] = dist_map[*vi];
+            }
 
             // Add the new path
+            size_t path_length = 0;
             for (Vertex u = sink_, v = pred_map[u];
                  u != v; u = v, v = pred_map[v])
             {
                 i_shortest_paths_[i][u].insert(v);
+
+                ++path_length;
             }
+            util::Logger::LogDebug("path length " + std::to_string(path_length));
         }
         else
         {
@@ -272,15 +304,40 @@ namespace algo
             DistanceMap dist_map(&dist_list[0], graph_indices);
 
             // Find the shortest path
-            boost::bellman_ford_shortest_paths(copied_graph_,
-                                               graph_size,
-                                               boost::root_vertex(root_vertex)
-                                                       .weight_map(weight_map)
-                                                       .predecessor_map(pred_map)
-                                                       .distance_map(dist_map));
+            boost::dijkstra_shortest_paths(copied_graph_, root_vertex,
+                                           boost::predecessor_map(pred_map)
+                                                   .distance_map(dist_map));
+
+//            boost::bellman_ford_shortest_paths(copied_graph_,
+//                                               graph_size,
+//                                               boost::root_vertex(root_vertex)
+//                                                       .weight_map(weight_map)
+//                                                       .predecessor_map(pred_map)
+//                                                       .distance_map(dist_map));
+
+            util::Logger::LogDebug("add the path");
+
+            // Add the new distances
+            boost::graph_traits<DirectedGraph>::vertex_iterator vi, vi_end;
+            for (boost::tie(vi, vi_end) = boost::vertices(copied_graph_);
+                 vi != vi_end; ++vi)
+            {
+                Vertex v_copy = *vi;
+                Vertex v_orig = copy_to_original_[v_copy];
+                i_distances_[i][v_orig] = dist_map[v_copy];
+            }
+
+            // Prevent cycles
+//            unsigned long vertex_count = boost::num_vertices(original_graph_);
+//            bool* visited = new bool[vertex_count];
+//            for (unsigned long j = 0; j < vertex_count; j++)
+//            {
+//                visited[j] = false;
+//            }
 
             // Add the new path (the given path is in the copied graph, so the
             // vertices need to be mapped to the original graph)
+            size_t path_length = 0;
             Vertex sink_copy = original_to_copy_[sink_];
             for (Vertex u_copy = sink_copy, v_copy = pred_map[u_copy];
                  u_copy != v_copy; u_copy = v_copy, v_copy = pred_map[v_copy])
@@ -294,8 +351,54 @@ namespace algo
                     continue;
                 }
 
+                // Cycle found
+//                if (visited[u_original])
+//                {
+//                    break;
+//                }
+//
+//                visited[u_original] = true;
+
                 i_shortest_paths_[i][u_original].insert(v_original);
+                i_distances_[i][u_original] = dist_map[u_copy];
+
+                ++path_length;
             }
+            util::Logger::LogDebug("path length " + std::to_string(path_length));
+
+//            delete[] visited;
+        }
+
+        // Add source
+        i_shortest_paths_[i][source_].insert(source_);
+    }
+
+    void KShortestPaths::TransformEdgeCosts(size_t i)
+    {
+        EdgeWeightMap weights = boost::get(boost::edge_weight, copied_graph_);
+        boost::graph_traits<DirectedGraph>::edge_iterator ei, ei_end;
+        double min_weight = 0.0;
+
+        for (boost::tie(ei, ei_end) = boost::edges(copied_graph_);
+             ei != ei_end; ++ei)
+        {
+            Vertex s_copy = boost::source(*ei, copied_graph_);
+            Vertex t_copy = boost::target(*ei, copied_graph_);
+            Vertex s_orig = copy_to_original_[s_copy];
+            Vertex t_orig = copy_to_original_[t_copy];
+
+            weights[*ei] += i_distances_[i][s_orig] - i_distances_[i][t_orig];
+
+            if (weights[*ei] < min_weight)
+            {
+                min_weight = weights[*ei];
+            }
+        }
+
+        for (boost::tie(ei, ei_end) = boost::edges(copied_graph_);
+             ei != ei_end; ++ei)
+        {
+            weights[*ei] -= min_weight;
         }
     }
 

+ 9 - 0
algo/KShortestPaths.h

@@ -51,6 +51,12 @@ namespace algo
          */
         std::unordered_map<Vertex, Vertex> copy_to_original_;
 
+        /**
+         * Maps the vertices in the original graph to the distances of the
+         * shortest path found in the i-th iteration.
+         */
+        std::vector<std::unordered_map<Vertex, double>> i_distances_;
+
         /**
          * All found paths for every iteration of the current run.
          * Corresponds to the original graph.
@@ -72,6 +78,9 @@ namespace algo
          */
         void ExtendGraph(size_t i);
 
+        //TODO comment
+        void TransformEdgeCosts(size_t i);
+
         /**
          * Calculates the path costs of every path at the iteration given.
          * @param i The targeted shortest paths iteration

+ 56 - 17
algo/TwoStage.cpp → algo/NStage.cpp

@@ -2,20 +2,23 @@
 // Created by wrede on 25.04.16.
 //
 
-#include "TwoStage.h"
+#include "NStage.h"
 #include "../util/Logger.h"
 #include <boost/graph/dijkstra_shortest_paths.hpp>
 
 namespace algo
 {
-    TwoStage::TwoStage(size_t max_frame_skip, double penalty_value,
-                       size_t max_tracklet_count)
-        : max_frame_skip_(max_frame_skip), penalty_value_(penalty_value),
-          max_tracklet_count_(max_tracklet_count)
+    NStage::NStage(size_t max_frame_skip,
+                       std::vector<double> penalty_value,
+                       std::vector<size_t> max_tracklet_count)
     {
+        max_frame_skip_ = max_frame_skip;
+        penalty_values_ = penalty_value;
+        max_tracklet_counts_ = max_tracklet_count;
+        iterations_ = std::min(max_tracklet_count.size(), penalty_value.size());
     }
 
-    void TwoStage::CreateObjectGraph(DirectedGraph& graph,
+    void NStage::CreateObjectGraph(DirectedGraph& graph,
                                      const core::DetectionSequence& detections)
     {
         util::Logger::LogInfo("Creating object graph");
@@ -59,7 +62,7 @@ namespace algo
 
                 // For each next frame/layer until maxFrameSkip or end
                 for (size_t k = 1;
-                     k <= max_frame_skip_ && i + k < layers.size();
+                     k != (max_frame_skip_ + 1) && i + k < layers.size();
                      ++k)
                 {
                     // To every edge in the next frame/layer
@@ -75,11 +78,11 @@ namespace algo
 
                 // From source to vertex and from vertex to sink
                 boost::add_edge(source, u,
-                                (i + 1) * penalty_value_,
+                                (i + 1) * penalty_values_[0],
                                 graph);
 
                 boost::add_edge(u, sink,
-                                (layers.size() - i) * penalty_value_,
+                                (layers.size() - i) * penalty_values_[0],
                                 graph);
             }
         }
@@ -88,9 +91,10 @@ namespace algo
         util::Logger::LogDebug("edge count " + std::to_string(boost::num_edges(graph)));
     }
 
-    void TwoStage::CreateTrackletGraph(DirectedGraph& obj_graph,
+    void NStage::CreateTrackletGraph(DirectedGraph& obj_graph,
                                        DirectedGraph& tlt_graph,
-                                       size_t frame_count)
+                                       size_t frame_count,
+                                       size_t iteration)
     {
         util::Logger::LogInfo("Creating tracklet graph");
 
@@ -112,7 +116,7 @@ namespace algo
         Vertex obj_snk = obj_indices[obj_graph_size - 1];
 
         // Iteratively run dijkstra to extract tracklets
-        for (size_t i = 0; i < max_tracklet_count_; ++i)
+        for (size_t i = 0; i != max_tracklet_counts_[iteration]; ++i)
         {
             boost::dijkstra_shortest_paths(obj_graph, obj_src,
                                            boost::predecessor_map(obj_pred_map)
@@ -137,8 +141,7 @@ namespace algo
                     // Remove the path by setting all used edges to a weight of
                     // infinity
                     std::pair<DirectedGraph::out_edge_iterator,
-                              DirectedGraph::out_edge_iterator>
-                              edge_iter = boost::out_edges(u, obj_graph);
+                              DirectedGraph::out_edge_iterator> edge_iter = boost::out_edges(u, obj_graph);
 
                     for (DirectedGraph::out_edge_iterator iter = edge_iter.first;
                          iter != edge_iter.second;
@@ -184,6 +187,7 @@ namespace algo
                             std::static_pointer_cast<core::Tracklet>(tlt_values[v]);
                     size_t v_first_frame = v_ptr->GetFirstFrameIndex();
 
+                    // Link only tracklets that are in temporal order
                     if (u_last_frame < v_first_frame)
                     {
                         boost::add_edge(u, v,
@@ -195,12 +199,12 @@ namespace algo
 
             // From source
             boost::add_edge(tlt_src, u,
-                            (u_first_frame + 1) * penalty_value_,
+                            (u_first_frame + 1) * penalty_values_[iteration],
                             tlt_graph);
 
             // To sink
             boost::add_edge(u, tlt_snk,
-                            (frame_count - u_last_frame) * penalty_value_,
+                            (frame_count - u_last_frame) * penalty_values_[iteration],
                             tlt_graph);
         }
 
@@ -208,7 +212,7 @@ namespace algo
         util::Logger::LogDebug("edge count " + std::to_string(boost::num_edges(tlt_graph)));
     }
 
-    void TwoStage::ExtractTracks(DirectedGraph& tlt_graph, size_t depth,
+    void NStage::ExtractTracks(DirectedGraph& tlt_graph, size_t depth,
                                  std::vector<core::TrackletPtr>& tracks)
     {
         util::Logger::LogInfo("Extracting tracks");
@@ -232,4 +236,39 @@ namespace algo
 
         util::Logger::LogDebug("track count " + std::to_string(tracks.size()));
     }
+
+    void NStage::Run(const core::DetectionSequence& sequence,
+                       std::vector<core::TrackletPtr>& tracks)
+    {
+        // Running the two stage graph algorithm
+        DirectedGraph obj_graph;
+        CreateObjectGraph(obj_graph, sequence);
+
+        // Run the tracklet creation at least once
+        DirectedGraph tlt_graph_1, tlt_graph_2;
+        CreateTrackletGraph(obj_graph, tlt_graph_1, sequence.GetFrameCount(), 0);
+
+        // Run the tracklet creation iteratively
+        for (size_t i = 1; i < iterations_; ++i)
+        {
+            if (i % 2 == 0)
+            {
+                CreateTrackletGraph(tlt_graph_2, tlt_graph_1, sequence.GetFrameCount(), i);
+            }
+            else
+            {
+                CreateTrackletGraph(tlt_graph_1, tlt_graph_2, sequence.GetFrameCount(), i);
+            }
+        }
+
+        // Extract tracklets and flatten tracklets
+        if (iterations_ % 2 == 0)
+        {
+            ExtractTracks(tlt_graph_2, iterations_ - 1, tracks);
+        }
+        else
+        {
+            ExtractTracks(tlt_graph_1, iterations_ - 1, tracks);
+        }
+    }
 }

+ 28 - 15
algo/TwoStage.h → algo/NStage.h

@@ -2,8 +2,8 @@
 // Created by wrede on 25.04.16.
 //
 
-#ifndef GBMOT_KOERNERTRACKING_H
-#define GBMOT_KOERNERTRACKING_H
+#ifndef GBMOT_NSTAGE_H
+#define GBMOT_NSTAGE_H
 
 #include "../core/DetectionSequence.h"
 #include "../core/Tracklet.h"
@@ -13,33 +13,30 @@ namespace algo
 {
     /**
      * Implementation of the two-staged graph-based multi-object tracker.
+     * Extended to allow N stages.
      */
-    class TwoStage
+    class NStage
     {
     private:
         /**
          * Maximum edge length to link object
          */
-        const size_t max_frame_skip_;
+        size_t max_frame_skip_;
 
         /**
          * Edge value to link to source and sink
          */
-        const double penalty_value_;
+        std::vector<double> penalty_values_;
 
         /**
          * Maximum dijkstra iterations / number of tracklets to create
          */
-        const size_t max_tracklet_count_;
-    public:
+        std::vector<size_t> max_tracklet_counts_;
+
         /**
-         * Initializes the algorithm wih the given values.
-         * @param max_frame_skip The maximum edge length to link objects
-         * @param penalty_value The Edge value to link to source and sink
-         * @param max_tracklet_count The maximum number of tracklets to create
+         * Number of iterations
          */
-        TwoStage(size_t max_frame_skip, double penalty_value,
-                 size_t max_tracklet_count);
+        size_t iterations_;
 
         /**
          * Creates a graph with vertices for every detected object
@@ -54,10 +51,12 @@ namespace algo
          * @param obj_graph The object graph to reduce
          * @param tlt_graph The graph to write the tracklets in
          * @param frame_count The frame count of the object graph
+         * @param iteration The current iteration
          */
         void CreateTrackletGraph(DirectedGraph& obj_graph,
                                  DirectedGraph& tlt_graph,
-                                 size_t frame_count);
+                                 size_t frame_count,
+                                 size_t iteration);
 
         /**
          * Extracts the finished tracks from the given tracklet graph.
@@ -68,8 +67,22 @@ namespace algo
         void ExtractTracks(DirectedGraph& tlt_graph,
                            size_t depth,
                            std::vector<core::TrackletPtr>& tracks);
+    public:
+        /**
+         * Initializes the algorithm wih the given values.
+         * The number of stages is determined by the size of the given
+         * vectors.
+         * @param max_frame_skip The maximum edge length to link objects
+         * @param penalty_value The edge value to link to source and sink
+         * @param max_tracklet_count The maximum number of tracklets to create
+         */
+        NStage(size_t max_frame_skip, std::vector<double> penalty_value,
+                 std::vector<size_t> max_tracklet_count);
+
+        void Run(const core::DetectionSequence& sequence,
+                 std::vector<core::TrackletPtr>& tracks);
     };
 }
 
 
-#endif //GBMOT_KOERNERTRACKING_H
+#endif //GBMOT_NSTAGE_H

+ 1 - 1
core/DetectionSequence.cpp

@@ -14,7 +14,7 @@ namespace core
 
     void DetectionSequence::AddObject(ObjectDataPtr object_data)
     {
-        if (object_data->GetFrameIndex() >= objects_.size())
+        while (object_data->GetFrameIndex() >= objects_.size())
         {
             objects_.push_back(std::vector<ObjectDataPtr>());
         }

+ 14 - 8
core/ObjectData.cpp

@@ -9,17 +9,15 @@
 namespace core
 {
     ObjectData::ObjectData()
+            : frame_index_(0), is_virtual_(true), detection_score_(0.0)
     {
-        frame_index_ = 0;
-        is_virtual_ = true;
-        detection_score_ = 0.0;
+        /* EMPTY */
     }
 
     ObjectData::ObjectData(std::size_t frame_index)
+            : frame_index_(frame_index), is_virtual_(false), detection_score_(0.0)
     {
-        frame_index_ = frame_index;
-        is_virtual_ = false;
-        detection_score_ = 0.0;
+        /* EMPTY */
     }
 
     std::size_t ObjectData::GetFrameIndex() const
@@ -34,11 +32,19 @@ namespace core
 
     void ObjectData::Print(std::ostream &os) const
     {
-        os << "Object in frame " << frame_index_;
+        if (is_virtual_)
+        {
+            os << "Object{-}";
+        }
+        else
+        {
+            os << "Object{" << frame_index_ << "}";
+        }
     }
 
     double ObjectData::CompareTo(ObjectDataPtr obj) const
     {
+        /* EMPTY */
         return 0.0;
     }
 
@@ -73,7 +79,7 @@ namespace core
         detection_score_ = score;
     }
 
-    double ObjectData::GetDetectionScore()
+    double ObjectData::GetDetectionScore() const
     {
         return detection_score_;
     }

+ 2 - 2
core/ObjectData.h

@@ -28,7 +28,7 @@ namespace core
         /**
          * If this node is considered virtual
          */
-        bool is_virtual_;
+        const bool is_virtual_;
 
         /**
          * The frame the object was detected in
@@ -80,7 +80,7 @@ namespace core
          * Gets the detection score
          * @return The detection score
          */
-        double GetDetectionScore();
+        double GetDetectionScore() const;
 
         /**
          * Is this node considered a virtual node

+ 85 - 0
core/ObjectData2D.cpp

@@ -0,0 +1,85 @@
+//
+// Created by wrede on 02.06.16.
+//
+
+#include "ObjectData2D.h"
+#include "../util/MyMath.h"
+
+namespace core
+{
+    ObjectData2D::ObjectData2D(size_t frame_index, cv::Point2d position)
+            : ObjectData(frame_index),
+              position_(position),
+              temporal_weight_(1.0),
+              spatial_weight_(1.0)
+    {
+    }
+
+    void ObjectData2D::SetTemporalWeight(double weight)
+    {
+        temporal_weight_ = weight;
+    }
+
+    void ObjectData2D::SetSpatialWeight(double weight)
+    {
+        spatial_weight_ = weight;
+    }
+
+    cv::Point2d ObjectData2D::GetPosition() const
+    {
+        return position_;
+    }
+
+    double ObjectData2D::GetTemporalWeight() const
+    {
+        return temporal_weight_;
+    }
+
+    double ObjectData2D::GetSpatialWeight() const
+    {
+        return spatial_weight_;
+    }
+
+    double ObjectData2D::CompareTo(ObjectDataPtr obj) const
+    {
+        ObjectData2DPtr obj_2d = std::static_pointer_cast<ObjectData2D>(obj);
+
+        double d_temp = obj_2d->GetFrameIndex() - GetFrameIndex();
+        double d_spat = util::MyMath::EuclideanDistance(position_, obj_2d->position_);
+
+        return d_temp * temporal_weight_ + d_spat * spatial_weight_;
+    }
+
+    ObjectDataPtr ObjectData2D::Interpolate(ObjectDataPtr obj,
+                                            double fraction) const
+    {
+        ObjectDataPtr obj_in = ObjectData::Interpolate(obj, fraction);
+
+        ObjectData2DPtr obj_2d = std::static_pointer_cast<ObjectData2D>(obj);
+
+        double x = util::MyMath::Lerp(position_.x, obj_2d->position_.x, fraction);
+        double y = util::MyMath::Lerp(position_.y, obj_2d->position_.y, fraction);
+
+        ObjectData2DPtr obj_out(
+                new ObjectData2D(obj_in->GetFrameIndex(), cv::Point2d(x, y)));
+
+        return obj_out;
+    }
+
+    void ObjectData2D::Print(std::ostream& os) const
+    {
+        os << "ObjectData2D{"
+           << "frame: " << GetFrameIndex() << ","
+           << "x: " << position_.x << ","
+           << "y: " << position_.y << "}";
+    }
+
+    void ObjectData2D::Visualize(cv::Mat& image, cv::Scalar& color) const
+    {
+        double x = position_.x * image.cols;
+        double y = position_.y * image.rows;
+        int r = (int) (0.005 * (image.rows + image.cols) * 0.5);
+
+        cv::circle(image, cv::Point2d(x, y), r, color);
+    }
+}

+ 85 - 0
core/ObjectData2D.h

@@ -0,0 +1,85 @@
+//
+// Created by wrede on 02.06.16.
+//
+
+#ifndef GBMOT_OBJECTDATA2D_H
+#define GBMOT_OBJECTDATA2D_H
+
+#include "ObjectData.h"
+
+namespace core
+{
+    class ObjectData2D;
+    typedef std::shared_ptr<ObjectData2D> ObjectData2DPtr;
+
+    /**
+     * Class for storing a detection in two dimensional space.
+     */
+    class ObjectData2D : public ObjectData
+    {
+    private:
+        /**
+         * The position in the two dimensional space
+         */
+        const cv::Point2d position_;
+
+        /**
+         * The weight of the temporal distance for the comparison.
+         * The temporal distance is the frame difference.
+         */
+        double temporal_weight_;
+
+        /**
+         * The weight of the spatial distance for the comparison.
+         * The spatial distance is the euclidean distance of the positions.
+         */
+        double spatial_weight_;
+
+        virtual void Print(std::ostream& os) const override;
+    public:
+        /**
+         * Creates a new detection with the given index and position.
+         * @param frame_index The frame index
+         * @param position The position in three dimensional space
+         */
+        ObjectData2D(size_t frame_index, cv::Point2d position);
+
+        /**
+         * Sets the temporal weight.
+         * @param weight The temporal weight
+         */
+        void SetTemporalWeight(double weight);
+
+        /**
+         * Sets the spatial weight
+         * @param weight The spatial weight
+         */
+        void SetSpatialWeight(double weight);
+
+        /**
+         * Gets the position in two dimensional space.
+         * @return The position
+         */
+        cv::Point2d GetPosition() const;
+
+        /**
+         * Gets the temporal weight.
+         * @return The temporal weight
+         */
+        double GetTemporalWeight() const;
+
+        /**
+         * Gets the spatial weight
+         * @return The spatial weight
+         */
+        double GetSpatialWeight() const;
+
+        virtual double CompareTo(ObjectDataPtr obj) const override;
+        virtual ObjectDataPtr Interpolate(ObjectDataPtr obj,
+                                          double fraction) const override;
+        virtual void Visualize(cv::Mat& image, cv::Scalar& color) const override;
+    };
+}
+
+
+#endif //GBMOT_OBJECTDATA2D_H

+ 21 - 22
core/ObjectDataAngular.cpp

@@ -8,12 +8,27 @@
 namespace core
 {
     ObjectDataAngular::ObjectDataAngular(size_t frame_index,
-                                         const cv::Point3d& position,
+                                         const cv::Point2d& position,
                                          double angle)
-            : ObjectData3D(frame_index, position), angle_(angle), angular_weight_(1.0)
+            : ObjectData2D(frame_index, position), angle_(angle), angular_weight_(1.0)
     {
     }
 
+    ObjectDataAngular::ObjectDataAngular(size_t frame_index,
+                                         const cv::Point2d& position,
+                                         double angle,
+                                         double temporal_weight,
+                                         double spatial_weight,
+                                         double angular_weight)
+            : ObjectData2D(frame_index, position)
+    {
+        angle_ = angle;
+        angular_weight_ = angular_weight;
+
+        SetTemporalWeight(temporal_weight);
+        SetSpatialWeight(spatial_weight);
+    }
+
     void ObjectDataAngular::SetAngularWeight(double weight)
     {
         angular_weight_ = weight;
@@ -36,15 +51,15 @@ namespace core
 
         double d_ang = std::abs(obj_ang->angle_ - angle_);
 
-        return ObjectData3D::CompareTo(obj) + d_ang * angular_weight_;
+        return ObjectData2D::CompareTo(obj) + d_ang * angular_weight_;
     }
 
     ObjectDataPtr ObjectDataAngular::Interpolate(ObjectDataPtr obj,
                                                  double fraction) const
     {
-        ObjectData3DPtr obj_in =
-                std::static_pointer_cast<ObjectData3D>(
-                        ObjectData3D::Interpolate(obj, fraction));
+        ObjectData2DPtr obj_in =
+                std::static_pointer_cast<ObjectData2D>(
+                        ObjectData2D::Interpolate(obj, fraction));
 
         ObjectDataAngularPtr obj_ang =
                 std::static_pointer_cast<ObjectDataAngular>(obj);
@@ -76,22 +91,6 @@ namespace core
         << "f:" << GetFrameIndex() << ", "
         << "x:" << GetPosition().x << ", "
         << "y:" << GetPosition().y << ", "
-        << "z:" << GetPosition().z << ", "
         << "a:" << GetAngle() << "}";
     }
-
-    ObjectDataAngular::ObjectDataAngular(size_t frame_index,
-                                         const cv::Point3d& position,
-                                         double angle,
-                                         double temporal_weight,
-                                         double spatial_weight,
-                                         double angular_weight)
-            : ObjectData3D(frame_index, position)
-    {
-        angle_ = angle;
-        angular_weight_ = angular_weight;
-
-        SetTemporalWeight(temporal_weight);
-        SetSpatialWeight(spatial_weight);
-    }
 }

+ 7 - 7
core/ObjectDataAngular.h

@@ -5,7 +5,7 @@
 #ifndef GBMOT_OBJECTDATAANGULAR_H
 #define GBMOT_OBJECTDATAANGULAR_H
 
-#include "ObjectData3D.h"
+#include "ObjectData2D.h"
 
 namespace core
 {
@@ -13,10 +13,10 @@ namespace core
     typedef std::shared_ptr<ObjectDataAngular> ObjectDataAngularPtr;
 
     /**
-     * Class for storing a detection in three dimensional space with an rotation
+     * Class for storing a detection in two dimensional space with an rotation
      * angle in radians.
      */
-    class ObjectDataAngular : public ObjectData3D
+    class ObjectDataAngular : public ObjectData2D
     {
     private:
         /**
@@ -35,22 +35,22 @@ namespace core
          * Creates a new object in the given frame, with the given position and
          * the given angle.
          * @param frame_index The index of the frame
-         * @param position The position in three dimensional space
+         * @param position The position in two dimensional space
          * @param angle The rotation angle in radians
          */
-        ObjectDataAngular(size_t frame_index, const cv::Point3d& position, double angle);
+        ObjectDataAngular(size_t frame_index, const cv::Point2d& position, double angle);
 
         /**
          * Creates a new object in the given frame, with the given position and
          * the given angle. The weights are used in the comparison calculation.
          * @param frame_index The index of the frame
-         * @param position The position in three dimensional space
+         * @param position The position in two dimensional space
          * @param angle The rotation angle in radians
          * @param temporal_weight The temporal weight
          * @param spatial_weight The spatial weight
          * @param angular_weight The angular weight
          */
-        ObjectDataAngular(size_t frame_index, const cv::Point3d& position,
+        ObjectDataAngular(size_t frame_index, const cv::Point2d& position,
                           double angle, double temporal_weight,
                           double spatial_weight, double angular_weight);
 

+ 75 - 0
core/ObjectDataBox.cpp

@@ -0,0 +1,75 @@
+//
+// Created by wrede on 09.06.16.
+//
+
+#include "ObjectDataBox.h"
+#include "../util/MyMath.h"
+
+namespace core
+{
+    ObjectDataBox::ObjectDataBox(size_t frame_index, cv::Point2d anchor,
+                                 cv::Point2d size)
+            : ObjectData2D(frame_index, anchor),
+              size_(size)
+    {
+    }
+
+    void ObjectDataBox::Print(std::ostream& os) const
+    {
+        os << "ObjectDataBox{"
+           << "frame: " << GetFrameIndex() << ","
+           << "x: " << GetPosition().x << ","
+           << "x: " << GetPosition().y << ","
+           << "width: " << size_.x << ","
+           << "height: " << size_.y << "}";
+    }
+
+    double ObjectDataBox::CompareTo(ObjectDataPtr obj) const
+    {
+        ObjectDataBoxPtr other = std::static_pointer_cast<ObjectDataBox>(obj);
+
+        cv::Point2d this_center = GetPosition() + size_ * 0.5;
+        cv::Point2d other_center = other->GetPosition() + other->size_ * 0.5;
+
+        double d_temp = other->GetFrameIndex() - GetFrameIndex();
+        double d_spat = util::MyMath::EuclideanDistance(this_center,
+                                                        other_center);
+
+        return d_temp * GetTemporalWeight() + d_spat * GetSpatialWeight();
+    }
+
+    ObjectDataPtr ObjectDataBox::Interpolate(ObjectDataPtr obj,
+                                             double fraction) const
+    {
+        ObjectDataBoxPtr other = std::static_pointer_cast<ObjectDataBox>(obj);
+
+        size_t frame = (size_t) fabs(util::MyMath::Lerp(GetFrameIndex(),
+                                                        other->GetFrameIndex(),
+                                                        fraction));
+        double x = util::MyMath::Lerp(GetPosition().x, other->GetPosition().x,
+                                      fraction);
+        double y = util::MyMath::Lerp(GetPosition().y, other->GetPosition().y,
+                                      fraction);
+        double w = util::MyMath::Lerp(size_.x, other->size_.x, fraction);
+        double h = util::MyMath::Lerp(size_.y, other->size_.y, fraction);
+
+        ObjectDataBoxPtr result(
+                new ObjectDataBox(frame, cv::Point2d(x, y), cv::Point2d(w, h)));
+
+        return result;
+    }
+
+    void ObjectDataBox::Visualize(cv::Mat& image, cv::Scalar& color) const
+    {
+        cv::Point2d position(GetPosition().x * image.cols,
+                             GetPosition().y * image.rows);
+        cv::Point2d size(size_.x * image.cols, size_.y * image.rows);
+
+        cv::rectangle(image, position, position + size, color);
+    }
+
+    cv::Point2d ObjectDataBox::GetSize() const
+    {
+        return size_;
+    }
+}

+ 35 - 0
core/ObjectDataBox.h

@@ -0,0 +1,35 @@
+//
+// Created by wrede on 09.06.16.
+//
+
+#ifndef GBMOT_OBJECTDATABOX_H
+#define GBMOT_OBJECTDATABOX_H
+
+#include "ObjectData2D.h"
+
+namespace core
+{
+    //TODO comment
+    class ObjectDataBox;
+    typedef std::shared_ptr<ObjectDataBox> ObjectDataBoxPtr;
+
+    class ObjectDataBox : public ObjectData2D
+    {
+    private:
+        const cv::Point2d size_;
+
+        virtual void Print(std::ostream& os) const override;
+    public:
+        ObjectDataBox(size_t frame_index, cv::Point2d anchor, cv::Point2d size);
+
+        cv::Point2d GetSize() const;
+
+        virtual double CompareTo(ObjectDataPtr obj) const override;
+        virtual ObjectDataPtr Interpolate(ObjectDataPtr obj,
+                                          double fraction) const override;
+        virtual void Visualize(cv::Mat& image, cv::Scalar& color) const override;
+    };
+}
+
+
+#endif //GBMOT_OBJECTDATABOX_H

+ 6 - 0
core/Tracklet.cpp

@@ -3,6 +3,7 @@
 //
 
 #include "Tracklet.h"
+#include "../util/Logger.h"
 
 namespace core
 {
@@ -101,6 +102,11 @@ namespace core
     void Tracklet::Visualize(cv::Mat& image, cv::Scalar& color, size_t frame,
                              size_t predecessor_count, size_t successor_count) const
     {
+        if (frame == 0)
+        {
+            predecessor_count = 0;
+        }
+
         size_t start = (frame - predecessor_count > GetFirstFrameIndex()) ?
                        frame - predecessor_count : GetFirstFrameIndex();
         size_t end = (frame + successor_count < GetLastFrameIndex()) ?

+ 2 - 6
graph/Definitions.h

@@ -6,12 +6,8 @@
 #define GBMOT_DEFINITIONS_H
 
 #include "../core/ObjectData.h"
-#include "../../../../../usr/include/boost/graph/properties.hpp"
-#include "../../../../../usr/include/boost/pending/property.hpp"
-#include "../../../../../usr/include/boost/graph/adjacency_list.hpp"
-#include "../../../../../usr/include/boost/graph/graph_selectors.hpp"
-#include "../../../../../usr/include/boost/graph/graph_traits.hpp"
-#include "../../../../../usr/include/boost/property_map/property_map.hpp"
+#include <boost/graph/properties.hpp>
+#include <boost/graph/adjacency_list.hpp>
 
 typedef boost::property<boost::edge_weight_t, double> EdgeProp;
 typedef boost::property <boost::vertex_name_t, core::ObjectDataPtr>

+ 438 - 122
main/main.cpp

@@ -4,88 +4,113 @@
 #include "../core/DetectionSequence.h"
 #include "../util/FileIO.h"
 #include "../util/Parser.h"
-#include "../algo/TwoStage.h"
+#include "../algo/NStage.h"
 #include "../algo/KShortestPaths.h"
-#include "../visual/Visualizer.h"
+#include "../util/Visualizer.h"
 #include "../util/Logger.h"
 #include "../core/ObjectDataAngular.h"
+#include "../algo/Berclaz.h"
 #include <boost/program_options.hpp>
 
-void ReadInput(const std::string& input_file, core::DetectionSequence& sequence,
-               double temporal_weight, double spatial_weight, double angular_weight)
-{
-    util::Logger::LogInfo("Reading input");
-
-    util::Vector3d values;
-    util::FileIO::ReadCSV(values, input_file);
-    util::Parser::ParseObjectDataAngular(values, sequence,
-                                         temporal_weight,
-                                         spatial_weight,
-                                         angular_weight);
-
-    if (util::Logger::IsDebugEnabled())
-    {
-        size_t sequence_object_count = 0;
-        for (size_t i = 0; i < sequence.GetFrameCount(); i++)
-        {
-            sequence_object_count += sequence.GetObjectCount(i);
-        }
-        util::Logger::LogDebug("sequence object count " + std::to_string(sequence_object_count));
-    }
-}
-
 struct
 {
-    size_t iterations;
     size_t max_frame_skip;
-    size_t max_tracklet_count;
-    double penalty_value;
-} two_stage_params;
-
-void RunTwoStage(core::DetectionSequence& sequence, const std::string& output_file,
-                 const std::string& images_folder, bool display)
+    std::string max_tracklet_count;
+    std::string penalty_value;
+} n_stage_params;
+
+void RunNStage(core::DetectionSequence& sequence,
+               const std::string& output_file,
+               const std::string& images_folder,
+               bool display)
 {
-    util::Logger::LogInfo("Running two-stage");
+    util::Logger::LogInfo("Running n-stage");
 
-    algo::TwoStage two_stage(two_stage_params.max_frame_skip,
-                             two_stage_params.penalty_value,
-                             two_stage_params.max_tracklet_count);
+    std::vector<double> penalty_values;
+    std::vector<size_t> max_tracklet_counts;
 
-    // Running the two stage graph algorithm
-    DirectedGraph obj_graph;
-    two_stage.CreateObjectGraph(obj_graph, sequence);
+    // Parse strings to vectors
+    size_t d_index;
+    std::string str, part;
+    str = n_stage_params.max_tracklet_count;
+    do
+    {
+        d_index = str.find(",");
 
-    // Run the tracklet creation at least once
-    DirectedGraph tlt_graph_1, tlt_graph_2;
-    two_stage.CreateTrackletGraph(obj_graph, tlt_graph_1,
-                                  sequence.GetFrameCount());
+        part = str.substr(0, d_index);
 
-    // Run the tracklet creation iteratively
-    for (size_t i = 1; i < two_stage_params.iterations; ++i)
-    {
-        if (i % 2 == 0)
+        if (part.size() > 0)
         {
-            two_stage.CreateTrackletGraph(tlt_graph_2, tlt_graph_1,
-                                          sequence.GetFrameCount());
+            max_tracklet_counts.push_back((unsigned long&&) std::atoi(part.c_str()));
         }
-        else
+
+        str = str.substr(d_index + 1);
+    }
+    while (d_index != std::string::npos);
+    str = n_stage_params.penalty_value;
+    do
+    {
+        d_index = str.find(",");
+
+        part = str.substr(0, d_index);
+
+        if (part.size() > 0)
         {
-            two_stage.CreateTrackletGraph(tlt_graph_1, tlt_graph_2,
-                                          sequence.GetFrameCount());
+            penalty_values.push_back(std::atof(part.c_str()));
         }
+
+        str = str.substr(d_index + 1);
     }
+    while (d_index != std::string::npos);
+
+    // Init n stage
+    algo::NStage n_stage(n_stage_params.max_frame_skip,
+                         penalty_values, max_tracklet_counts);
 
-    // Extract tracklets and flatten tracklets
     std::vector<core::TrackletPtr> tracks;
-    if (two_stage_params.iterations % 2 == 0)
+    n_stage.Run(sequence, tracks);
+
+    // Interpolate tracks
+    for (auto track : tracks)
     {
-        two_stage.ExtractTracks(tlt_graph_2, two_stage_params.iterations - 1, tracks);
+        track->InterpolateMissingFrames();
     }
-    else
+
+    // Display the tracking data
+    if (display)
     {
-        two_stage.ExtractTracks(tlt_graph_1, two_stage_params.iterations - 1, tracks);
+        util::Visualizer vis;
+        vis.Display(tracks, images_folder);
     }
 
+    util::Logger::LogInfo("Finished");
+}
+
+struct
+{
+    int h_res;
+    int v_res;
+    int vicinity_size;
+    size_t max_track_count;
+} berclaz_params;
+
+
+void RunBerclaz(core::DetectionSequence& sequence,
+                const std::string& output_file,
+                const std::string& images_folder,
+                bool display)
+{
+    util::Logger::LogInfo("Running berclaz");
+
+    // Init berclaz
+    algo::Berclaz berclaz(berclaz_params.h_res,
+                          berclaz_params.v_res,
+                          berclaz_params.vicinity_size);
+    std::vector<core::TrackletPtr> tracks;
+    berclaz.Run(sequence, berclaz_params.max_track_count, tracks);
+
+    util::Logger::LogInfo("Interpolate tracks");
+
     // Interpolate tracks
     for (auto track : tracks)
     {
@@ -95,9 +120,7 @@ void RunTwoStage(core::DetectionSequence& sequence, const std::string& output_fi
     // Display the tracking data
     if (display)
     {
-        util::Logger::LogInfo("Displaying data");
-
-        visual::Visualizer vis;
+        util::Visualizer vis;
         vis.Display(tracks, images_folder);
     }
 
@@ -107,91 +130,167 @@ void RunTwoStage(core::DetectionSequence& sequence, const std::string& output_fi
 void Run(int argc, char** argv)
 {
     // Algorithm independent values
-    std::string input_file, output_file, images_folder, algorithm;
-    bool display;
+    std::string input_file, output_file, images_folder, algorithm, config_path;
+    bool info, debug, display;
 
     // Input dependent variables
+    std::string header;
     double temporal_weight, spatial_weight, angular_weight;
+    double image_width, image_height;
 
     boost::program_options::options_description opts("Allowed options");
     opts.add_options()
             ("help",
              "produce help message")
             ("info",
+             boost::program_options::value<bool>(&info)
+                    ->default_value(false),
              "if the program should show progress information")
             ("debug",
+             boost::program_options::value<bool>(&debug)
+                     ->default_value(false),
              "if the program should show debug messages")
+            ("display",
+             boost::program_options::value<bool>(&display)
+                     ->default_value(false),
+             "if a window with the images and the detected tracks should be opened")
+            ("config",
+             boost::program_options::value<std::string>(&config_path),
+             "the path to the config file, if no path is given the command line arguments are read")
             ("input-file,i",
              boost::program_options::value<std::string>(&input_file),
              "set detections file path")
             ("output-file,o",
              boost::program_options::value<std::string>(&output_file),
              "set the output file path")
-            ("algorithm,a",
-             boost::program_options::value<std::string>(&algorithm),
-             "set the algorithm to use, current viable options: two-stage")
-            ("display",
-             "if a window with the images and the detected tracks should be opened")
             ("images-folder,f",
              boost::program_options::value<std::string>(&images_folder),
              "set images folder path")
-            ("iterations",
-             boost::program_options::value<size_t>(&two_stage_params.iterations)->default_value((2)),
-             "(two-stage) number of tracklet extraction iterations")
+            ("input-header",
+             boost::program_options::value<std::string>(&header)
+                    ->default_value(""),
+             "sets the input header, this value is optional if the input file has a header labeling the values,"
+                     "the delimiter used for the header needs to be the same as for the rest of the file")
+            ("algorithm,a",
+             boost::program_options::value<std::string>(&algorithm),
+             "set the algorithm to use, current viable options: n-stage berclaz")
             ("max-frame-skip",
-             boost::program_options::value<size_t>(&two_stage_params.max_frame_skip)->default_value(1),
-             "(two stage) set the maximum number of frames a track can skip between two detections,"
+             boost::program_options::value<size_t>(&n_stage_params.max_frame_skip)
+                     ->default_value(1),
+             "(n stage) set the maximum number of frames a track can skip between two detections,"
                      " if set to less or equal than zero all frames are linked")
             ("max-tracklet-count",
-             boost::program_options::value<size_t>(&two_stage_params.max_tracklet_count)->default_value(1),
-             "(two stage) set the maximum number of tracklets to be extracted")
+             boost::program_options::value<std::string>(&n_stage_params.max_tracklet_count)
+                     ->default_value("-1,1"),
+             "(n stage) set the maximum number of tracklets to be extracted")
             ("penalty-value",
-             boost::program_options::value<double>(&two_stage_params.penalty_value)->default_value(0.0),
-             "(two stage) set the penalty value for edges from and to source and sink")
+             boost::program_options::value<std::string>(&n_stage_params.penalty_value)
+                     ->default_value("0,0"),
+             "(n stage) set the penalty value for edges from and to source and sink")
             ("temporal-weight",
-             boost::program_options::value<double>(&temporal_weight)->default_value(1.0),
-             "temporal weight for difference calculations between two detections")
+             boost::program_options::value<double>(&temporal_weight)
+                     ->default_value(1.0),
+             "(n stage) temporal weight for difference calculations between two detections")
             ("spatial-weight",
-             boost::program_options::value<double>(&spatial_weight)->default_value(1.0),
-             "spatial weight for difference calculations between two detections")
+             boost::program_options::value<double>(&spatial_weight)
+                     ->default_value(1.0),
+             "(n stage) spatial weight for difference calculations between two detections")
             ("angular-weight",
-             boost::program_options::value<double>(&angular_weight)->default_value(1.0),
-             "angular weight for difference calculations between two detections");
+             boost::program_options::value<double>(&angular_weight)
+                     ->default_value(1.0),
+             "(n stage) angular weight for difference calculations between two detections")
+            ("horizontal-resolution",
+             boost::program_options::value<int>(&berclaz_params.h_res)
+                     ->default_value(10),
+             "(berclaz) the number of horizontal grid cells")
+            ("vertical-resolution",
+             boost::program_options::value<int>(&berclaz_params.v_res)
+                     ->default_value(10),
+             "(berclaz) the number of vertical grid cells")
+            ("vicinity-size",
+             boost::program_options::value<int>(&berclaz_params.vicinity_size)
+                     ->default_value(1),
+             "(berclaz) the vicinity size, the number of cells a detection can travel between two frames")
+            ("max-track-count",
+             boost::program_options::value<size_t>(&berclaz_params.max_track_count)
+                     ->default_value(1),
+             "(berclaz) the maximal number of tracks to extract")
+            ("image-width",
+             boost::program_options::value<double>(&image_width)
+                    ->default_value(1920),
+             "the width of the image")
+            ("image-height",
+             boost::program_options::value<double>(&image_height)
+                     ->default_value(1080),
+             "the height of the image");
 
     boost::program_options::variables_map opt_var_map;
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
-    boost::program_options::store(boost::program_options::parse_command_line(argc, argv, opts), opt_var_map);
+    boost::program_options::store(
+            boost::program_options::parse_command_line(argc, argv, opts),
+            opt_var_map);
 #pragma clang diagnostic pop
     boost::program_options::notify(opt_var_map);
 
+    // Display help
     if (opt_var_map.count("help") != 0)
     {
         std::cout << opts << std::endl;
         exit(0);
     }
 
-    if (opt_var_map.count("info") != 0)
+    // Read config
+    if (opt_var_map.count("config") != 0)
+    {
+        std::ifstream config_file(config_path , std::ifstream::in);
+        boost::program_options::store(
+                boost::program_options::parse_config_file(config_file , opts),
+                opt_var_map);
+        config_file.close();
+        boost::program_options::notify(opt_var_map);
+    }
+
+    // Enable info logging
+    if (info != 0)
     {
         util::Logger::SetInfo(true);
         util::Logger::LogInfo("Enabled");
     }
 
-    if (opt_var_map.count("debug") != 0)
+    // Enable debug logging
+    if (debug != 0)
     {
         util::Logger::SetDebug(true);
         util::Logger::LogDebug("Enabled");
     }
 
-    display = opt_var_map.count("display") != 0;
+    // Reading the input file
+    util::Logger::LogInfo("Reading input");
+    util::ValueMapVector values;
+    if (header.size() > 0)
+    {
+        util::FileIO::ReadCSV(values, header, input_file);
+    }
+    else
+    {
+        util::FileIO::ReadCSV(values, input_file);
+    }
 
+    // Parsing the read input
     core::DetectionSequence sequence;
+    util::Parser::ParseObjectDataBox(values, sequence,
+                                     image_width, image_height,
+                                     temporal_weight, spatial_weight);
 
-    ReadInput(input_file, sequence, temporal_weight, spatial_weight, angular_weight);
-
-    if (algorithm == "two-stage")
+    // Running the specified algorithm
+    if (algorithm == "n-stage")
+    {
+        RunNStage(sequence, output_file, images_folder, display);
+    }
+    else if (algorithm == "berclaz")
     {
-        RunTwoStage(sequence, output_file, images_folder, display);
+        RunBerclaz(sequence, output_file, images_folder, display);
     }
     else
     {
@@ -235,9 +334,9 @@ void CreateTestGraph(DirectedGraph& graph, Vertex& source, Vertex& sink)
 //    source = vertices[0];
 //    sink = vertices[5];
 
-    // Create test graph (disjoint path finding example)
+    // Create test graph
     std::vector<Vertex> vertices;
-    for (size_t i = 0; i < 8; ++i)
+    for (size_t i = 0; i < 11; ++i)
     {
         vertices.push_back(
                 boost::add_vertex(
@@ -245,51 +344,268 @@ void CreateTestGraph(DirectedGraph& graph, Vertex& source, Vertex& sink)
     }
 
     boost::add_edge(vertices[0], vertices[1], 1.0, graph);
+    boost::add_edge(vertices[0], vertices[8], 1.0, graph);
     boost::add_edge(vertices[0], vertices[4], 1.0, graph);
-    boost::add_edge(vertices[1], vertices[2], 1.0, graph);
+    boost::add_edge(vertices[1], vertices[2], 2.0, graph);
+    boost::add_edge(vertices[1], vertices[5], 1.0, graph);
     boost::add_edge(vertices[2], vertices[3], 1.0, graph);
+    boost::add_edge(vertices[2], vertices[6], 2.0, graph);
+    boost::add_edge(vertices[2], vertices[10], 2.0, graph);
     boost::add_edge(vertices[3], vertices[7], 1.0, graph);
-    boost::add_edge(vertices[4], vertices[3], 1.0, graph);
-    boost::add_edge(vertices[4], vertices[5], 3.0, graph);
+    boost::add_edge(vertices[4], vertices[2], 1.0, graph);
+    boost::add_edge(vertices[4], vertices[5], 2.0, graph);
+    boost::add_edge(vertices[4], vertices[9], 2.0, graph);
     boost::add_edge(vertices[5], vertices[6], 1.0, graph);
-    boost::add_edge(vertices[5], vertices[3], 1.0, graph);
+    boost::add_edge(vertices[5], vertices[3], 2.0, graph);
     boost::add_edge(vertices[6], vertices[7], 1.0, graph);
+    boost::add_edge(vertices[8], vertices[2], 2.0, graph);
+    boost::add_edge(vertices[8], vertices[9], 1.0, graph);
+    boost::add_edge(vertices[9], vertices[3], 2.0, graph);
+    boost::add_edge(vertices[9], vertices[10], 1.0, graph);
+    boost::add_edge(vertices[10], vertices[7], 1.0, graph);
 
     source = vertices[0];
     sink = vertices[7];
 }
 
+void TestKSP()
+{
+    Vertex source, sink;
+    DirectedGraph graph;
+
+    util::Logger::SetDebug(true);
+    util::Logger::SetInfo(true);
+
+    CreateTestGraph(graph, source, sink);
+
+    algo::KShortestPaths ksp(graph, source, sink);
+    MultiPredecessorMap paths = ksp.Run(5);
+
+    util::FileIO::WriteCSVMatlab(graph, "/home/wrede/Dokumente/graph.csv");
+    util::FileIO::WriteCSVMatlab(paths,
+                                 sink, "/home/wrede/Dokumente/paths.csv");
+}
+
+void TestGrid()
+{
+    int lower_index = 0;
+    int upper_index = 5;
+    double lower_bound = 0.0;
+    double upper_bound = 50.0;
+    util::Grid grid(upper_index, upper_index, upper_index,
+                    upper_bound, upper_bound, upper_bound);
+
+    std::uniform_int_distribution<int> unii(lower_index, upper_index - 1);
+    std::uniform_real_distribution<double> unif(lower_bound, upper_bound);
+    std::default_random_engine re;
+
+    // Fill with empty values
+    std::cout << "fill with empty values\n";
+    for (int z = lower_index; z < upper_index; ++z)
+    {
+        for (int y = lower_index; y < upper_index; ++y)
+        {
+            for (int x = lower_index; y < upper_index; ++y)
+            {
+                grid.SetValue(nullptr, x, y, z);
+            }
+        }
+    }
+
+    // Randomly add data
+    std::cout << "randomly add data\n";
+    for (int i = 0; i < 10; ++i)
+    {
+        int xi = unii(re);
+        int yi = unii(re);
+        int zi = unii(re);
+
+        core::ObjectDataPtr value(new core::ObjectData((size_t)i));
+        grid.SetValue(value, xi, yi, zi);
+
+        std::cout << xi << "," << yi << "," << zi << " = " << *value << std::endl;
+    }
+
+    // Randomly get data
+    std::cout << "randomly get data\n";
+    for (int i = 0; i < 10; ++i)
+    {
+        double x = unif(re);
+        double y = unif(re);
+        double z = unif(re);
+
+        std::cout << x << "," << y << "," << z << " = ";
+        core::ObjectDataPtr value = grid.GetValue(x, y, z);
+        if (value)
+        {
+            std::cout << *value << std::endl;
+        }
+        else
+        {
+            std::cout << "nullptr" << std::endl;
+        }
+    }
+}
+
+void TestBerclazGraph()
+{
+    std::cout << "init\n";
+
+    // Init grid with data
+    util::Grid grid(3, 3, 3, 9.0, 9.0, 9.0);
+    for (int z = 0; z < grid.GetDepthCount(); ++z)
+    {
+        for (int y = 0; y < grid.GetHeightCount(); ++y)
+        {
+            for (int x = 0; x < grid.GetWidthCount(); ++x)
+            {
+                core::ObjectDataPtr value(new core::ObjectData(10));
+                grid.SetValue(value, x, y, z);
+            }
+        }
+    }
+
+    // Add path source->0,0,0->0,0,1->0,0,2->sink
+    core::ObjectDataPtr value0(new core::ObjectData(1));
+    value0->SetDetectionScore(1.0);
+    grid.SetValue(value0, 0, 0, 0);
+    core::ObjectDataPtr value1(new core::ObjectData(2));
+    value1->SetDetectionScore(1.0);
+    grid.SetValue(value1, 0, 0, 1);
+    core::ObjectDataPtr value2(new core::ObjectData(3));
+    value2->SetDetectionScore(1.0);
+    grid.SetValue(value2, 0, 0, 2);
+
+    // Add path source->1,1,0->1,1,0->1,1,2->sink
+    core::ObjectDataPtr value3(new core::ObjectData(4));
+    value3->SetDetectionScore(0.6);
+    grid.SetValue(value3, 0, 1, 0);
+    core::ObjectDataPtr value4(new core::ObjectData(5));
+    value4->SetDetectionScore(0.6);
+    grid.SetValue(value4, 0, 1, 1);
+    core::ObjectDataPtr value5(new core::ObjectData(6));
+    value5->SetDetectionScore(0.6);
+    grid.SetValue(value5, 0, 1, 2);
+
+    // Add path source->2,2,0->2,2,0->2,2,2->sink
+    core::ObjectDataPtr value6(new core::ObjectData(7));
+    value6->SetDetectionScore(0.3);
+    grid.SetValue(value6, 0, 2, 0);
+    core::ObjectDataPtr value7(new core::ObjectData(8));
+    value7->SetDetectionScore(0.3);
+    grid.SetValue(value7, 0, 2, 1);
+    core::ObjectDataPtr value8(new core::ObjectData(9));
+    value8->SetDetectionScore(0.3);
+    grid.SetValue(value8, 0, 2, 2);
+
+    std::cout << "add vertices\n";
+
+    // Add grid vertices
+    DirectedGraph graph;
+    for (int z = 0; z < grid.GetDepthCount(); ++z)
+    {
+        for (int y = 0; y < grid.GetHeightCount(); ++y)
+        {
+            for (int x = 0; x < grid.GetWidthCount(); ++x)
+            {
+                boost::add_vertex(grid.GetValue(x, y, z), graph);
+            }
+        }
+    }
+
+    std::cout << "vertex count = " << boost::num_vertices(graph) << std::endl;
+    std::cout << "edge count = " << boost::num_edges(graph) << std::endl;
+
+    // Add source and sink vertex
+    Vertex source = boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()), graph);
+    Vertex sink = boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()), graph);
+
+    std::cout << "add edges\n";
+
+    // Iterate all vertices but source and sink
+    VertexIndexMap vertices = boost::get(boost::vertex_index, graph);
+    VertexValueMap values = boost::get(boost::vertex_name, graph);
+    int vicinity_size = 1;
+    int layer_size = grid.GetWidthCount() * grid.GetHeightCount();
+    for (int z = 0; z < grid.GetDepthCount(); ++z)
+    {
+        for (int y = 0; y < grid.GetHeightCount(); ++y)
+        {
+            for (int x = 0; x < grid.GetWidthCount(); ++x)
+            {
+                // First vertex index
+                int vi = x + y * grid.GetHeightCount() + z * layer_size;
+
+                // Connect with the next frame only if there is a next frame
+                if (z < grid.GetDepthCount() - 1)
+                {
+                    // Get the score, clamp it, prevent division by zero and
+                    // logarithm of zero
+                    double score = values[vi]->GetDetectionScore();
+                    if (score > 0.999999)
+                    {
+                        score = 0.999999;
+                    }
+                    else if (score < 0.000001)
+                    {
+                        score = 0.000001;
+                    }
+
+                    // Calculate the edge weight
+                    double weight = -std::log(score / (1 - score));
+
+                    // Iterate all nearby cells in the next frame
+                    for (int ny = std::max(0, y - vicinity_size);
+                         ny <
+                         std::min(grid.GetHeightCount(), y + vicinity_size + 1);
+                         ++ny)
+                    {
+                        for (int nx = std::max(0, x - vicinity_size);
+                             nx < std::min(grid.GetWidthCount(),
+                                           x + vicinity_size + 1);
+                             ++nx)
+                        {
+                            // Second vertex index
+                            int vj = nx + ny * grid.GetHeightCount() +
+                                     (z + 1) * layer_size;
+
+                            // Connect to nearby cells
+                            boost::add_edge(vertices[vi], vertices[vj],
+                                            weight, graph);
+                        }
+                    }
+                }
+
+                // Connect with source and sink
+                boost::add_edge(source, vertices[vi], 0.0, graph);
+                boost::add_edge(vertices[vi], sink, 0.0, graph);
+            }
+        }
+    }
+
+    std::cout << "vertex count = " << boost::num_vertices(graph) << std::endl;
+    std::cout << "edge count = " << boost::num_edges(graph) << std::endl;
+
+    // Running KSP with 5 possible paths although only 3 are worth it
+    algo::KShortestPaths ksp(graph, source, sink);
+    MultiPredecessorMap ksp_result = ksp.Run(5);
+
+    util::FileIO::WriteCSVMatlab(graph, "/home/wrede/Dokumente/graph.csv");
+    util::FileIO::WriteCSVMatlab(ksp_result,
+                                 sink, "/home/wrede/Dokumente/paths.csv");
+}
+
 int main(int argc, char** argv)
 {
-    Run(argc, argv);
+    //Run(argc, argv);
 
     //TestTracklet();
 
-//    Vertex source, sink;
-//    DirectedGraph graph;
-//
-//    util::Logger::SetDebug(true);
-//    util::Logger::SetInfo(true);
-//
-//    CreateTestGraph(graph, source, sink);
-//
-//    algo::KShortestPaths ksp(graph, source, sink);
-//    MultiPredecessorMap paths = ksp.Run(3);
-//
-//    util::Logger::LogDebug("found paths:");
-//    for (Vertex first : paths[sink])
-//    {
-//        std::string path;
-//        path += std::to_string(sink) + "->" + std::to_string(first);
-//
-//        for (Vertex u = first, v = (*paths[u].begin());
-//             u != v; u = v, v = (*paths[v].begin()))
-//        {
-//            path += "->" + std::to_string(v);
-//        }
-//
-//        util::Logger::LogDebug(path);
-//    }
+    TestKSP();
+
+    //TestGrid();
+
+    //TestBerclazGraph();
 
     return 0;
 }

+ 158 - 12
util/FileIO.cpp

@@ -10,12 +10,12 @@
 namespace util
 {
     void FileIO::ReadCSV(Vector3d& values,
-                         const std::string& filename,
+                         const std::string& file_name,
                          char delimiter)
     {
         Logger::LogInfo("Reading CSV file");
 
-        std::ifstream in(filename, std::ifstream::in);
+        std::ifstream in(file_name, std::ifstream::in);
         std::string line;
 
         // Read lines while the reader is in good condition
@@ -28,7 +28,8 @@ namespace util
 
             // Get frame index
             size_t dIndex = line.find(delimiter);
-            size_t frameIndex = std::stoul(line.substr(0, dIndex).c_str());
+            std::string part = line.substr(0, dIndex);
+            size_t frameIndex = std::stoul(part.c_str());
 
             // Extract point values
             std::vector<double> pointValues;
@@ -36,7 +37,20 @@ namespace util
             {
                 line = line.substr(dIndex + 1);
                 dIndex = line.find(delimiter);
-                pointValues.push_back(std::stof(line.substr(0, dIndex).c_str()));
+                part = line.substr(0, dIndex);
+
+                if (part.size() > 0)
+                {
+                    try
+                    {
+                        pointValues.push_back(std::stof(part.c_str()));
+                    }
+                    catch (const std::exception& e)
+                    {
+                        /* EMPTY */
+                        // Possible cause: "\n"
+                    }
+                }
             }
 
             // Add point data to detection data
@@ -54,12 +68,12 @@ namespace util
     }
 
     void FileIO::ReadCSV(Vector2d& values,
-                         const std::string& filename,
+                         const std::string& file_name,
                          char delimiter)
     {
         Logger::LogInfo("Reading CSV file");
 
-        std::ifstream in(filename, std::ifstream::in);
+        std::ifstream in(file_name, std::ifstream::in);
         std::string line;
 
         // Read lines while the reader is in good condition and the
@@ -73,13 +87,18 @@ namespace util
 
             // Extract point values
             size_t dIndex;
+            std::string part;
             std::vector<double> pointValues;
             do
             {
                 dIndex = line.find(delimiter);
 
-                pointValues.push_back(
-                        std::stof(line.substr(0, dIndex).c_str()));
+                part = line.substr(0, dIndex);
+
+                if (part.size() > 0)
+                {
+                    pointValues.push_back(std::stof(part.c_str()));
+                }
 
                 line = line.substr(dIndex + 1);
             }
@@ -129,9 +148,10 @@ namespace util
     }
 
     void FileIO::WriteCSVMatlab(DirectedGraph& graph,
-                                const std::string& file_name,
-                                char delimiter)
+                                const std::string& file_name)
     {
+        char delimiter = ',';
+
         std::ofstream out(file_name, std::ofstream::out);
 
         // Iterate all outgoing edges of every vertex
@@ -144,14 +164,140 @@ namespace util
             for (boost::tie(oei, oei_end) = boost::out_edges(*vi, graph);
                  oei != oei_end; ++oei)
             {
+                unsigned long si = indices[boost::source(*oei, graph)];
+                unsigned long ti = indices[boost::target(*oei, graph)];
                 // Write the edge to file
-                out << indices[boost::source(*oei, graph)] << delimiter
-                    << indices[boost::target(*oei, graph)] << delimiter
+                out << (si + 1) << delimiter
+                    << (ti + 1) << delimiter
                     << weights[*oei] << std::endl;
             }
         }
 
         out.close();
     }
+
+    void FileIO::WriteCSVMatlab(MultiPredecessorMap& map,
+                                Vertex& origin,
+                                const std::string& file_name)
+    {
+        char delimiter = ',';
+
+        std::ofstream out("/home/wrede/Dokumente/paths.csv", std::ofstream::out);
+        for (Vertex first : map[origin])
+        {
+            out << (origin + 1) << delimiter << (first + 1);
+
+            for (Vertex u = first, v = (*map[u].begin());
+                 u != v; u = v, v = (*map[v].begin()))
+            {
+                out << delimiter << (v + 1);
+            }
+
+            out << std::endl;
+        }
+        out.close();
+    }
+
+    void FileIO::ReadCSV(ValueMapVector& values,
+                         const std::string& file_name,
+                         char delimiter)
+    {
+        // Read the file
+        std::ifstream in(file_name, std::ifstream::in);
+        std::string line;
+
+        // Get the first line that is not empty
+        while (in.good() && !in.eof())
+        {
+            getline(in, line);
+
+            if (line.size() > 0) break;
+        }
+
+        in.close();
+
+        ReadCSV(values, line, file_name, delimiter);
+    }
+
+    void FileIO::ReadCSV(ValueMapVector& values, const std::string& header,
+                         const std::string& file_name, char delimiter)
+    {
+        Logger::LogInfo("Reading CSV file");
+
+        // Read the file
+        std::ifstream in(file_name, std::ifstream::in);
+        std::string line, part;
+        size_t d_index;
+
+        // Split the first line into separate keys
+        std::vector<std::string> key_vector;
+        line = header;
+        do
+        {
+            d_index = line.find(delimiter);
+            part = line.substr(0, d_index);
+
+            key_vector.push_back(part);
+
+            line = line.substr(d_index + 1);
+        }
+        while (d_index != std::string::npos);
+
+        util::Logger::LogDebug("parsed keys:");
+        for (std::string str : key_vector)
+        {
+            util::Logger::LogDebug(str);
+        }
+
+        // Read lines while the reader is in good condition and the
+        // end of file is not reached
+        while (in.good() && !in.eof())
+        {
+            getline(in, line);
+
+            // Ignore empty lines
+            if (line.size() == 0) continue;
+
+            // Extract detection values
+            size_t key_index = 0;
+            ValueMap detection_values;
+            do
+            {
+                d_index = line.find(delimiter);
+                part = line.substr(0, d_index);
+
+                // Try to parse the value
+                double value;
+                try
+                {
+                    value = std::stof(part.c_str());
+                }
+                catch (std::exception& e)
+                {
+                    util::Logger::LogError(e.what());
+                    value = 0.0;
+                }
+
+                // Store the value
+                detection_values[key_vector[key_index]] = value;
+                ++key_index;
+
+                line = line.substr(d_index + 1);
+            }
+            while (d_index != std::string::npos &&
+                   key_index < key_vector.size());
+
+            // Add point data to detection data
+            values.push_back(detection_values);
+        }
+
+        util::Logger::LogDebug("parsed values in line 1:");
+        for (std::string str : key_vector)
+        {
+            util::Logger::LogDebug(str + "=" + std::to_string(values[0][str]));
+        }
+
+        in.close();
+    }
 }
 

+ 53 - 12
util/FileIO.h

@@ -15,6 +15,8 @@ namespace util
 {
     typedef std::vector<std::vector<std::vector<double>>> Vector3d;
     typedef std::vector<std::vector<double>> Vector2d;
+    typedef std::unordered_map<std::string, double> ValueMap;
+    typedef std::vector<ValueMap> ValueMapVector;
 
     /**
      * Utility class for file in- and output.
@@ -30,28 +32,28 @@ namespace util
          * The second dimension is the row in the row bundle.
          * The third dimension is the value in that row.
          * @param values The 3D array of values to store the read values in
-         * @param filename The filename to read from
-         * @param delimiter The delimiter used to separate the values in the file
+         * @param file_name The name of the file to read
+         * @param delimiter The value delimiter of the file
          */
         static void ReadCSV(Vector3d& values,
-                            const std::string& filename,
+                            const std::string& file_name,
                             char delimiter = ';');
 
         /**
          * Reads a CSV file and stores the values in a 2D array.
          * The first dimension is the row and the second the value in that row.
          * @param values The 2D array of values to store the read values in
-         * @param filename The filename to read from
-         * @param delimiter The delimiter used to separate the values in the file
+         * @param file_name The name of the file to read
+         * @param delimiter The value delimiter of the file
          */
         static void ReadCSV(Vector2d& values,
-                            const std::string& filename,
+                            const std::string& file_name,
                             char delimiter = ';');
 
         /**
          * Lists all file names in the given folder.
          * @param folder The folder to look into
-         * @param file_names The vector to store the file names into
+         * @param file_names The name of the files in the folder
          * @param sort True, if the files should be sorted alphabetically
          */
         static void ListFiles(const std::string& folder,
@@ -59,15 +61,54 @@ namespace util
                               bool sort = true);
 
         /**
-         * Writes the given graph into a CSV file with an format readable by
+         * Writes the specified graph into a CSV file with an format readable by
          * Matlab.
+         *
          * @param graph The graph to write
-         * @param file_name The name of the file to write into
-         * @param delimiter The delimiter to use
+         * @param file_name The name of the file to write
          */
         static void WriteCSVMatlab(DirectedGraph& graph,
-                                   const std::string& file_name,
-                                   char delimiter = ';');
+                                   const std::string& file_name);
+
+        /**
+         * Writes the specified multi predecessor map into a CSV format
+         * readable by Matlab to display all paths in the corresponding graph.
+         *
+         * @param map The multi predecessor map to extract the paths from
+         * @param origin The origin, this is the vertex where all paths end
+         * @param file_name The name of the file to write
+         */
+        static void  WriteCSVMatlab(MultiPredecessorMap& map,
+                                    Vertex& origin,
+                                    const std::string& file_name);
+
+        /**
+         * Reads a CSV file.
+         * The first line of the CSV file is a header specifying the keys.
+         * The values are stored with their specified key into one map per line.
+         *
+         * @param values A vector of maps to store the key-value pairs into
+         * @param file_name The name of the file to read
+         * @param delimiter The value delimiter of the file
+         */
+        static void ReadCSV(ValueMapVector& values,
+                            const std::string& file_name,
+                            char delimiter = ',');
+
+        /**
+         * Reads a CSV file.
+         * The header specifies the keys.
+         * The values are stored with their specified key into one map per line.
+         *
+         * @param values A vector of maps to store the key-value pairs into
+         * @param header A string containing the keys separated by the delimiter
+         * @param file_name The name of the file to read
+         * @param delimiter The value delimiter of the file
+         */
+        static void ReadCSV(ValueMapVector& values,
+                            const std::string& header,
+                            const std::string& file_name,
+                            char delimiter = ',');
     };
 }
 

+ 112 - 0
util/Grid.cpp

@@ -0,0 +1,112 @@
+//
+// Created by wrede on 06.06.16.
+//
+
+#include "Grid.h"
+
+namespace util
+{
+    Grid::Grid(int width_count, int height_count, double width, double height)
+            : Grid(width_count, height_count, 1, width, height, 0.0)
+    {
+        /* EMPTY */
+    }
+
+    Grid::Grid(int width_count, int height_count, int depth_count,
+               double width, double height, double depth)
+            : width_count_(width_count),
+              height_count_(height_count),
+              depth_count_(depth_count),
+              width_(width),
+              height_(height),
+              depth_(depth),
+              cell_width_(width / width_count),
+              cell_height_(height / height_count),
+              cell_depth_(depth / depth_count)
+    {
+        for (int z = 0; z < depth_count; ++z)
+        {
+            values_.push_back(std::vector<std::vector<core::ObjectDataPtr>>());
+
+            for (int y = 0; y < height_count; ++y)
+            {
+                values_[z].push_back(std::vector<core::ObjectDataPtr>());
+
+                for (int x = 0; x < width_count; ++x)
+                {
+                    values_[z][y].push_back(core::ObjectDataPtr());
+                }
+            }
+        }
+    }
+
+    void Grid::PositionToIndex(double x, double y, double z,
+                               int& xi, int& yi, int& zi) const
+    {
+        xi = (int) (x / cell_width_);
+        yi = (int) (y / cell_height_);
+
+        if (depth_count_ > 1)
+        {
+            zi = (int) (z / cell_depth_);
+        }
+        else
+        {
+            zi = 0;
+        }
+    }
+
+    void Grid::SetValue(core::ObjectDataPtr value, int x, int y, int z)
+    {
+        values_[z][y][x] = value;
+    }
+
+    void Grid::SetValue(core::ObjectDataPtr value, double x, double y, double z)
+    {
+        int xi, yi, zi;
+        PositionToIndex(x, y, z, xi, yi, zi);
+        SetValue(value, xi, yi, zi);
+    }
+
+    core::ObjectDataPtr Grid::GetValue(int x, int y, int z) const
+    {
+        return values_[z][y][x];
+    }
+
+    core::ObjectDataPtr Grid::GetValue(double x, double y, double z) const
+    {
+        int xi, yi, zi;
+        PositionToIndex(x, y, z, xi, yi, zi);
+        return GetValue(xi, yi, zi);
+    }
+
+    int Grid::GetWidthCount() const
+    {
+        return width_count_;
+    }
+
+    int Grid::GetHeightCount() const
+    {
+        return height_count_;
+    }
+
+    int Grid::GetDepthCount() const
+    {
+        return depth_count_;
+    }
+
+    double Grid::GetWidth() const
+    {
+        return width_;
+    }
+
+    double Grid::GetHeight() const
+    {
+        return height_;
+    }
+
+    double Grid::GetDepth() const
+    {
+        return depth_;
+    }
+}

+ 179 - 0
util/Grid.h

@@ -0,0 +1,179 @@
+//
+// Created by wrede on 06.06.16.
+//
+
+#ifndef GBMOT_GRID_H
+#define GBMOT_GRID_H
+
+#include <vector>
+#include "../core/ObjectData.h"
+
+namespace util
+{
+    /**
+     * Class for storing values in a three dimensional grid.
+     * Can also be used for two dimensions but has a bit overhead.
+     */
+    class Grid
+    {
+    private:
+        /**
+         * The number of values on the x axis
+         */
+        const int width_count_;
+
+        /**
+         * The number of values on the y axis
+         */
+        const int height_count_;
+
+        /**
+         * The number of values on the z axis
+         */
+        const int depth_count_;
+
+        /**
+         * The size of the whole grid on the x axis
+         */
+        const double width_;
+
+        /**
+         * The size of the whole grid on the y axis
+         */
+        const double height_;
+
+        /**
+         * The size of the whole grid on the z axis
+         */
+        const double depth_;
+
+        /**
+         * The size of one grid cell on the x axis
+         */
+        const double cell_width_;
+
+        /**
+         * The size of one grid cell on the y axis
+         */
+        const double cell_height_;
+
+        /**
+         * The size of one grid cell on the z axis
+         */
+        const double cell_depth_;
+
+        /**
+         * The values stored in the grid cells
+         */
+        std::vector<std::vector<std::vector<core::ObjectDataPtr>>> values_;
+    public:
+        /**
+         * Creates a new two dimensional grid.
+         * @param width_count The number of elements on the x axis
+         * @param height_count The number of elements on the y axis
+         * @param width The size of the whole grid on the x axis
+         * @param height The size of the whole grid on the y axis
+         */
+        Grid(int width_count, int height_count, double width, double height);
+
+        /**
+         * Creates a new three dimensional grid.
+         * @param width_count The number of elements on the x axis
+         * @param height_count The number of elements on the y axis
+         * @param depth_count The number of elements on the z axis
+         * @param width The size of the whole grid on the x axis
+         * @param height The size of the whole grid on the y axis
+         * @param depth The size of the whole grid on the z axis
+         */
+        Grid(int width_count, int height_count, int depth_count,
+             double width, double height, double depth);
+
+        /**
+         * Sets a value in the grid cell with the given index.
+         * @param value The value to set
+         * @param x The x axis index
+         * @param y The y axis index
+         * @param z The z axis index
+         */
+        void SetValue(core::ObjectDataPtr value, int x, int y, int z = 0);
+
+        /**
+         * Sets a value in the grid cell at the given position.
+         * @param value The value to set
+         * @param x The x axis value
+         * @param y The y axis value
+         * @param z The z axis value
+         */
+        void SetValue(core::ObjectDataPtr value,
+                      double x, double y, double z = 0);
+
+        /**
+         * Gets the value in the grid cell with the given index.
+         * @param x The x axis index
+         * @param y The y axis index
+         * @param z The z axis index
+         * @return The value in the grid cell
+         */
+        core::ObjectDataPtr GetValue(int x, int y, int z = 0) const;
+
+        /**
+         * Gets the value in the grid cell at the given position.
+         * @param x The x axis value
+         * @param y The y axis value
+         * @param z The z axis value
+         * @return The value in the grid cell
+         */
+        core::ObjectDataPtr GetValue(double x, double y, double z = 0.0) const;
+
+        /**
+         * Gets the number of elements on the x axis.
+         * @return The number of elements on the x axis
+         */
+        int GetWidthCount() const;
+
+        /**
+         * Gets the number of elements on the y axis.
+         * @return The number of elements on the y axis
+         */
+        int GetHeightCount() const;
+
+        /**
+         * Gets the number of elements on the z axis.
+         * @return The number of elements on the z axis
+         */
+        int GetDepthCount() const;
+
+        /**
+         * Gets the size of the whole grid on the x axis.
+         * @return the size of the whole grid on the x axis
+         */
+        double GetWidth() const;
+
+        /**
+         * Gets the size of the whole grid on the y axis.
+         * @return the size of the whole grid on the y axis
+         */
+        double GetHeight() const;
+
+        /**
+         * Gets the size of the whole grid on the z axis.
+         * @return the size of the whole grid on the z axis
+         */
+        double GetDepth() const;
+
+        /**
+         * Converts a 3D position to an 3D index.
+         * @param x The x axis value
+         * @param y The y axis value
+         * @param z The z axis value
+         * @param xi The x axis index
+         * @param yi The y axis index
+         * @param zi The z axis index
+         */
+        void PositionToIndex(double x, double y, double z,
+                             int& xi, int& yi, int& zi) const;
+    };
+}
+
+
+#endif //GBMOT_GRID_H

+ 8 - 3
util/Logger.cpp

@@ -12,24 +12,29 @@ namespace util
         /* EMPTY */
     }
 
+    void Logger::LogMessage(const std::string& message)
+    {
+        std::cout << message;
+    }
+
     void Logger::LogInfo(const std::string& message)
     {
         if (Instance().info_)
         {
-            std::cout << "[Info] " << message << std::endl;
+            Instance().LogMessage("[Info] " + message + "\n");
         }
     }
 
     void Logger::LogError(const std::string& message)
     {
-        std::cout << "[Error] " << message << std::endl;
+        Instance().LogMessage("[Error] " + message + "\n");
     }
 
     void Logger::LogDebug(const std::string& message)
     {
         if (Instance().debug_)
         {
-            std::cout << "[Debug] " << message << std::endl;
+            Instance().LogMessage("[Debug] " + message + "\n");
         }
     }
 

+ 6 - 0
util/Logger.h

@@ -30,6 +30,12 @@ namespace util
          * True, if the debug messages should be logged
          */
         bool debug_;
+
+        /**
+         * Logs the given message.
+         * @param message The message to log
+         */
+        void LogMessage(const std::string& message);
     public:
         /**
          * -> Singleton

+ 14 - 0
util/MyMath.cpp

@@ -6,6 +6,8 @@
 
 namespace util
 {
+    const double MyMath::PI = 3.14159;
+
     double MyMath::Clamp(double min, double max, double value)
     {
         if (value < min)
@@ -39,6 +41,18 @@ namespace util
         double dz = b.z - a.z;
         return std::sqrt(dx * dx + dy * dy + dz * dz);
     }
+
+    double MyMath::EuclideanDistance(cv::Point2d a, cv::Point2d b)
+    {
+        double dx = b.x - a.x;
+        double dy = b.y - a.y;
+        return std::sqrt(dx * dx + dy * dy);
+    }
+
+    double MyMath::Radian(double degree)
+    {
+        return (degree * PI) / 180.0;
+    }
 }
 
 

+ 18 - 0
util/MyMath.h

@@ -17,6 +17,9 @@ namespace util
     class MyMath
     {
     public:
+
+        static const double PI;
+
         /**
          * Clamps the value between min and max, both inclusive.
          * @param min The minimum value
@@ -51,6 +54,21 @@ namespace util
          * @return The euclidean distance
          */
         static double EuclideanDistance(cv::Point3d a, cv::Point3d b);
+
+        /**
+         * Calculates the euclidean distance of the given points.
+         * @param a The first point in 2D space
+         * @param b The second point in 2D space
+         * @return The euclidean distance
+         */
+        static double EuclideanDistance(cv::Point2d a, cv::Point2d b);
+
+        /**
+         * Calculates the radian value of the given degree value.
+         * @param degree The arc value in degree
+         * @return The arc value in radian
+         */
+        static double Radian(double degree);
     };
 }
 

+ 117 - 40
util/Parser.cpp

@@ -6,9 +6,21 @@
 #include "MyMath.h"
 #include "Logger.h"
 #include "../core/ObjectDataAngular.h"
+#include "../core/ObjectDataBox.h"
 
 namespace util
 {
+    const std::string Parser::KEY_FRAME = "frame";
+    const std::string Parser::KEY_ID = "id";
+    const std::string Parser::KEY_SCORE = "score";
+    const std::string Parser::KEY_X = "x";
+    const std::string Parser::KEY_Y = "y";
+    const std::string Parser::KEY_Z = "z";
+    const std::string Parser::KEY_WIDTH = "width";
+    const std::string Parser::KEY_HEIGHT = "height";
+    const std::string Parser::KEY_DEPTH = "depth";
+    const std::string Parser::KEY_ANGLE = "angle";
+
     void Parser::ParseObjectDataMap(const std::vector<std::string>& keys,
                                     const Vector3d& values,
                                     core::DetectionSequence& sequence)
@@ -77,6 +89,15 @@ namespace util
 
     void Parser::ParseObjectDataAngular(const Vector3d& values,
                                         core::DetectionSequence& sequence)
+    {
+        ParseObjectDataAngular(values, sequence, 1.0, 1.0, 1.0);
+    }
+
+    void Parser::ParseObjectDataAngular(const Vector3d& values,
+                                        core::DetectionSequence& sequence,
+                                        double temporal_weight,
+                                        double spatial_weight,
+                                        double angular_weight)
     {
         util::Logger::LogInfo("Parsing ObjectDataAngular");
 
@@ -100,20 +121,28 @@ namespace util
             }
         }
 
+        util::Logger::LogDebug("min score " + std::to_string(min_score));
+        util::Logger::LogDebug("max score " + std::to_string(max_score));
+
         // Create objects
         for (size_t frame_i = 0; frame_i < values.size(); ++frame_i)
         {
             for (size_t object_i = 0; object_i < values[frame_i].size();
                  ++object_i)
             {
-                double angle = (values[frame_i][object_i][0] * 3.14159) / 180.0;
+                double angle = MyMath::Radian(values[frame_i][object_i][0]);
                 double score = values[frame_i][object_i][1];
                 double x = values[frame_i][object_i][2];
                 double y = values[frame_i][object_i][3];
-                double z = 0.0;
-                cv::Point3d point(x, y, z);
+                cv::Point2d point(x, y);
 
-                core::ObjectDataAngularPtr object(new core::ObjectDataAngular(frame_i, point, angle));
+                //util::Logger::LogDebug("score " + std::to_string(score));
+
+                core::ObjectDataAngularPtr object(
+                        new core::ObjectDataAngular(frame_i, point, angle,
+                                                    temporal_weight,
+                                                    spatial_weight,
+                                                    angular_weight));
 
                 object->SetDetectionScore(util::MyMath::InverseLerp(min_score, max_score, score));
 
@@ -122,58 +151,106 @@ namespace util
         }
     }
 
-    void Parser::ParseObjectDataAngular(const Vector3d& values,
-                                        core::DetectionSequence& sequence,
-                                        double temporal_weight,
-                                        double spatial_weight,
-                                        double angular_weight)
+    Grid Parser::ParseGrid(core::DetectionSequence& sequence,
+                           double min_x, double max_x, int res_x,
+                           double min_y, double max_y, int res_y)
     {
-        util::Logger::LogInfo("Parsing ObjectDataAngular");
+        int res_z = (int) sequence.GetFrameCount();
+        double width = max_x - min_x;
+        double height = max_y - min_y;
+        double depth = sequence.GetFrameCount();
+        Grid grid(res_x, res_y, res_z, width, height, depth);
 
-        // Calculate max and min score to normalize the score
-        double max_score = std::numeric_limits<double>::min();
-        double min_score = std::numeric_limits<double>::max();
-        for (size_t frame_i = 0; frame_i < values.size(); ++frame_i)
+        // Fill with elements with detection score of zero
+        for (int z = 0; z < grid.GetDepthCount(); ++z)
         {
-            for (size_t object_i = 0; object_i < values[frame_i].size();
-                 ++object_i)
+            for (int y = 0; y < grid.GetHeightCount(); ++y)
             {
-                double score = values[frame_i][object_i][1];
-                if (score > max_score)
+                for (int x = 0; x < grid.GetWidthCount(); ++x)
                 {
-                    max_score = score;
-                }
-                if (score < min_score)
-                {
-                    min_score = score;
+                    core::ObjectDataPtr value(new core::ObjectData((size_t)z));
+                    grid.SetValue(value, x, y, z);
                 }
             }
         }
 
-        // Create objects
-        for (size_t frame_i = 0; frame_i < values.size(); ++frame_i)
+        // Add the detections
+        for (size_t f = 0; f < sequence.GetFrameCount(); ++f)
         {
-            for (size_t object_i = 0; object_i < values[frame_i].size();
-                 ++object_i)
+            for (size_t i = 0; i < sequence.GetObjectCount(f); ++i)
             {
-                double angle = (values[frame_i][object_i][0] * 3.14159) / 180.0;
-                double score = values[frame_i][object_i][1];
-                double x = values[frame_i][object_i][2];
-                double y = values[frame_i][object_i][3];
-                double z = 0.0;
-                cv::Point3d point(x, y, z);
+                core::ObjectDataPtr original_value = sequence.GetObject(f, i);
+                core::ObjectData2DPtr value =
+                        std::static_pointer_cast<core::ObjectData2D>(original_value);
 
-                core::ObjectDataAngularPtr object(
-                        new core::ObjectDataAngular(frame_i, point, angle,
-                                                    temporal_weight,
-                                                    spatial_weight,
-                                                    angular_weight));
+                grid.SetValue(original_value,
+                              value->GetPosition().x,
+                              value->GetPosition().y,
+                              f);
+            }
+        }
 
-                object->SetDetectionScore(util::MyMath::InverseLerp(min_score, max_score, score));
+        return grid;
+    }
 
-                sequence.AddObject(object);
+    void Parser::ParseObjectDataBox(ValueMapVector& values,
+                                    core::DetectionSequence& sequence,
+                                    double image_width, double image_height,
+                                    double temporal_weight,
+                                    double spatial_weight)
+    {
+        util::Logger::LogInfo("Parsing ObjectDataBox detections");
+
+        // Calculate max and min score to normalize the score
+        double max_score = std::numeric_limits<double>::min();
+        double min_score = std::numeric_limits<double>::max();
+        for (size_t line_index = 0; line_index < values.size(); ++line_index)
+        {
+            double score = values[line_index][KEY_SCORE];
+            if (score > max_score)
+            {
+                max_score = score;
+            }
+            if (score < min_score)
+            {
+                min_score = score;
             }
         }
+
+        util::Logger::LogDebug("min score " + std::to_string(min_score));
+        util::Logger::LogDebug("max score " + std::to_string(max_score));
+
+        // Create objects
+        size_t obj_count = 0;
+        for (size_t line_index = 0; line_index < values.size(); ++line_index)
+        {
+            size_t frame = (size_t) fabs(values[line_index][KEY_FRAME]);
+            double x = values[line_index][KEY_X] / image_width;
+            double y = values[line_index][KEY_Y] / image_height;
+            double width = values[line_index][KEY_WIDTH] / image_width;
+            double height = values[line_index][KEY_HEIGHT] / image_height;
+            double score = values[line_index][KEY_SCORE];
+
+            cv::Point2d point(x, y);
+            cv::Point2d size(width, height);
+
+            core::ObjectDataBoxPtr object(new core::ObjectDataBox(frame,
+                                                                  point,
+                                                                  size));
+
+            object->SetTemporalWeight(temporal_weight);
+            object->SetSpatialWeight(spatial_weight);
+            object->SetDetectionScore(util::MyMath::InverseLerp(min_score,
+                                                                max_score,
+                                                                score));
+
+            sequence.AddObject(object);
+
+            obj_count++;
+        }
+
+        util::Logger::LogDebug("objects parsed " + std::to_string(obj_count));
+        util::Logger::LogDebug("frame count " + std::to_string(sequence.GetFrameCount()));
     }
 }
 

+ 39 - 1
util/Parser.h

@@ -9,6 +9,8 @@
 #include "../core/ObjectData.h"
 #include "../core/ObjectDataMap.h"
 #include "../core/ObjectData3D.h"
+#include "Grid.h"
+#include "FileIO.h"
 #include <opencv2/core/core.hpp>
 
 namespace util
@@ -22,7 +24,18 @@ namespace util
     class Parser
     {
     public:
-        //TODO define csv value order
+        static const std::string KEY_FRAME;
+        static const std::string KEY_ID;
+        static const std::string KEY_SCORE;
+        static const std::string KEY_X;
+        static const std::string KEY_Y;
+        static const std::string KEY_Z;
+        static const std::string KEY_WIDTH;
+        static const std::string KEY_HEIGHT;
+        static const std::string KEY_DEPTH;
+        static const std::string KEY_ANGLE;
+
+        //TODO rework old parsers
         /**
          * Parses the keys and values into a DetectionSequence of ObjectDataMap
          * objects.
@@ -65,6 +78,31 @@ namespace util
                                            double temporal_weight,
                                            double spatial_weight,
                                            double angular_weight);
+        /**
+         * Parses the given sequence into a grid.
+         * The sequence data need to be a ObjectData2D.
+         * The frame index is the depth of the grid.
+         * @param sequence The detection sequence to parse
+         * @param min_x The minimal x value
+         * @param max_x The maximal x value
+         * @param res_x The number of cells on the x axis
+         * @param min_y The minimal y value
+         * @param max_y The maximal y value
+         * @param res_y The number of cells on the y axis
+         * @return The grid with the detection values
+         */
+        static Grid ParseGrid(
+                core::DetectionSequence& sequence,
+                double min_x, double max_x, int res_x,
+                double min_y, double max_y, int res_y);
+
+        //TODO comment
+        static void ParseObjectDataBox(ValueMapVector& values,
+                                       core::DetectionSequence& sequence,
+                                       double image_width = 1.0,
+                                       double image_height = 1.0,
+                                       double temporal_weight = 1.0,
+                                       double spatial_weight = 1.0);
     };
 }
 

+ 15 - 6
visual/Visualizer.cpp → util/Visualizer.cpp

@@ -3,11 +3,11 @@
 //
 
 #include "Visualizer.h"
-#include "../util/Logger.h"
+#include "Logger.h"
 #include "../core/ObjectDataAngular.h"
-#include "../util/FileIO.h"
+#include "FileIO.h"
 
-namespace visual
+namespace util
 {
     void Visualizer::Display(core::DetectionSequence& sequence,
                              std::string image_folder,
@@ -119,6 +119,8 @@ namespace visual
                              std::string image_folder, std::string title,
                              size_t first_frame, int play_fps)
     {
+        util::Logger::LogInfo("Displaying data");
+
         size_t current_frame = first_frame;
 
         // Load images
@@ -132,7 +134,11 @@ namespace visual
         std::vector<cv::Scalar> colors;
         std::random_device rd;
         std::mt19937 gen(rd());
-        for (size_t i = 0; i < tracks.size(); ++i)
+        colors.push_back(cv::Scalar(0, 0, 255));
+        colors.push_back(cv::Scalar(0, 255, 0));
+        colors.push_back(cv::Scalar(255, 0, 0));
+        colors.push_back(cv::Scalar(0, 255, 255));
+        for (size_t i = 4; i < tracks.size(); ++i)
         {
             // BGR
             cv::Scalar color(std::generate_canonical<double, 10>(gen) * 255,
@@ -153,10 +159,13 @@ namespace visual
                                        + image_files[current_frame],
                                        1);
 
-            util::Logger::LogDebug("visualize frame " + std::to_string(current_frame));
+//            util::Logger::LogDebug("display frame " + std::to_string(current_frame));
             for (size_t i = 0; i < tracks.size(); ++i)
             {
-                tracks[i]->Visualize(image, colors[i], current_frame, 1, 1);
+//                util::Logger::LogDebug("display track #" + std::to_string(i));
+
+//                tracks[i]->Visualize(image, colors[i]);
+                tracks[i]->Visualize(image, colors[i], current_frame, 0, 0);
             }
 
             cv::imshow(title, image);

+ 1 - 1
visual/Visualizer.h → util/Visualizer.h

@@ -14,7 +14,7 @@
 #include <chrono>
 #include <random>
 
-namespace visual
+namespace util
 {
     /**
      * Utility class for visualizing detection sequences or tracks.

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott