Browse Source

finished the ksp implementation

Helge Wrede 9 years ago
parent
commit
7e00a64b56
10 changed files with 577 additions and 244 deletions
  1. 32 35
      algo/Berclaz.cpp
  2. 284 72
      algo/KShortestPaths5.cpp
  3. 5 1
      algo/KShortestPaths5.h
  4. 37 33
      algo/NStage.cpp
  5. 8 11
      algo/NStage.h
  6. 169 78
      main/main.cpp
  7. 7 2
      util/Logger.cpp
  8. 6 0
      util/Logger.h
  9. 27 10
      util/Visualizer.cpp
  10. 2 2
      util/Visualizer.h

+ 32 - 35
algo/Berclaz.cpp

@@ -10,6 +10,7 @@
 #include "KShortestPaths2.h"
 #include "KShortestPaths2.h"
 #include "KShortestPaths3.h"
 #include "KShortestPaths3.h"
 #include "KShortestPaths4.h"
 #include "KShortestPaths4.h"
+#include "KShortestPaths5.h"
 
 
 namespace algo
 namespace algo
 {
 {
@@ -36,15 +37,12 @@ namespace algo
             }
             }
         }
         }
 
 
-        util::Logger::LogDebug("vertex count " + std::to_string(boost::num_vertices(graph)));
-        util::Logger::LogDebug("edge count " + std::to_string(boost::num_edges(graph)));
-
         // Add source and sink vertex
         // Add source and sink vertex
         source = boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()), graph);
         source = boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()), graph);
         sink = boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()), graph);
         sink = boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()), graph);
 
 
-        util::Logger::LogDebug("source index: " + std::to_string(source));
-        util::Logger::LogDebug("sink index: " + std::to_string(sink));
+//        util::Logger::LogDebug("source index: " + std::to_string(source));
+//        util::Logger::LogDebug("sink index: " + std::to_string(sink));
         util::Logger::LogDebug("add edges");
         util::Logger::LogDebug("add edges");
 
 
         // Iterate all vertices but source and sink
         // Iterate all vertices but source and sink
@@ -109,19 +107,19 @@ namespace algo
         }
         }
 
 
         util::Logger::LogDebug("vertex count " + std::to_string(boost::num_vertices(graph)));
         util::Logger::LogDebug("vertex count " + std::to_string(boost::num_vertices(graph)));
-        util::Logger::LogDebug("calculated vertex count " + std::to_string(
-           grid.GetWidthCount() * grid.GetHeightCount() * grid.GetDepthCount() + 2
-        ));
+//        util::Logger::LogDebug("calculated vertex count " + std::to_string(
+//           grid.GetWidthCount() * grid.GetHeightCount() * grid.GetDepthCount() + 2
+//        ));
         util::Logger::LogDebug("edge count " + std::to_string(boost::num_edges(graph)));
         util::Logger::LogDebug("edge count " + std::to_string(boost::num_edges(graph)));
-        util::Logger::LogDebug("width count " + std::to_string(grid.GetWidthCount()));
-        util::Logger::LogDebug("height count " + std::to_string(grid.GetHeightCount()));
-        util::Logger::LogDebug("depth count " + std::to_string(grid.GetDepthCount()));
-        util::Logger::LogDebug("calculated edge count " + std::to_string(
-           grid.GetWidthCount() * grid.GetHeightCount() * (grid.GetDepthCount() - 1) * 11 +
-           grid.GetWidthCount() * grid.GetHeightCount() * 2 -
-           (grid.GetWidthCount() + grid.GetHeightCount()) * 2 * 3 * (grid.GetDepthCount() - 1) +
-           4 * (grid.GetDepthCount() - 1)
-        ));
+//        util::Logger::LogDebug("width count " + std::to_string(grid.GetWidthCount()));
+//        util::Logger::LogDebug("height count " + std::to_string(grid.GetHeightCount()));
+//        util::Logger::LogDebug("depth count " + std::to_string(grid.GetDepthCount()));
+//        util::Logger::LogDebug("calculated edge count " + std::to_string(
+//           grid.GetWidthCount() * grid.GetHeightCount() * (grid.GetDepthCount() - 1) * 11 +
+//           grid.GetWidthCount() * grid.GetHeightCount() * 2 -
+//           (grid.GetWidthCount() + grid.GetHeightCount()) * 2 * 3 * (grid.GetDepthCount() - 1) +
+//           4 * (grid.GetDepthCount() - 1)
+//        ));
     }
     }
 
 
     void Berclaz::ExtractTracks(DirectedGraph& graph, MultiPredecessorMap& map, Vertex origin,
     void Berclaz::ExtractTracks(DirectedGraph& graph, MultiPredecessorMap& map, Vertex origin,
@@ -162,26 +160,25 @@ namespace algo
             Vertex source, sink;
             Vertex source, sink;
             CreateGraph(graph, source, sink, grid);
             CreateGraph(graph, source, sink, grid);
 
 
-            util::Logger::LogDebug("run suurballe");
-//            KShortestPaths3 ksp;
-//            MultiPredecessorMap ksp_result = ksp.Run(graph, source, sink, max_track_count);
-            KShortestPaths4 suurballe(graph, source, sink, max_track_count);
-            suurballe.Run();
+            util::Logger::LogDebug("run ksp");
+            KShortestPaths5 ksp(graph, source, sink);
+            ksp.Run(max_track_count);
+
+            util::Logger::LogDebug("get paths");
+            std::vector<std::vector<Vertex>> paths;
+            ksp.GetPaths(paths);
 
 
             util::Logger::LogDebug("extract tracks");
             util::Logger::LogDebug("extract tracks");
-            suurballe.GetTracks(tracks);
-
-//            size_t l = 0;
-//            for (std::vector<Vertex> path : suurballe.GetPaths())
-//            {
-//                l++;
-//                std::cout << "P" << l << "{ ";
-//                for (Vertex v : path)
-//                {
-//                    std::cout << v << " ";
-//                }
-//                std::cout << "}\n";
-//            }
+            VertexValueMap values = boost::get(boost::vertex_name, graph);
+            for (auto path : paths)
+            {
+                core::TrackletPtr tlt(new core::Tracklet());
+                for (auto v : path)
+                {
+                    tlt->AddPathObject(values[v]);
+                }
+                tracks.push_back(tlt);
+            }
         }
         }
 
 
         // Only connect tracks if the sequence was split
         // Only connect tracks if the sequence was split

+ 284 - 72
algo/KShortestPaths5.cpp

@@ -6,8 +6,9 @@
 #include <boost/graph/dijkstra_shortest_paths.hpp>
 #include <boost/graph/dijkstra_shortest_paths.hpp>
 #include <boost/graph/copy.hpp>
 #include <boost/graph/copy.hpp>
 #include <boost/graph/bellman_ford_shortest_paths.hpp>
 #include <boost/graph/bellman_ford_shortest_paths.hpp>
+#include <iomanip>
 #include "KShortestPaths5.h"
 #include "KShortestPaths5.h"
-#define DEBUG
+#include "../util/Logger.h"
 
 
 namespace algo
 namespace algo
 {
 {
@@ -36,16 +37,21 @@ namespace algo
                 break;
                 break;
             default:
             default:
                 FindPaths(max_path_count);
                 FindPaths(max_path_count);
+                break;
         }
         }
+
+        util::Logger::LogDebug(std::to_string(sink_neighbors_.size()) + " paths have been found");
     }
     }
 
 
-    void KShortestPaths5::FindPath(DirectedGraph& graph, Vertex& source, Vertex& sink,
-                                   VertexPredecessorMap& predecessors)
+    bool KShortestPaths5::FindPath(DirectedGraph& graph, Vertex& source, Vertex& sink,
+                                   VertexPredecessorMap& predecessors, VertexDistanceMap& distances)
     {
     {
         // The predecessors and the distances
         // The predecessors and the distances
         std::vector<Vertex> p(boost::num_vertices(graph));
         std::vector<Vertex> p(boost::num_vertices(graph));
         std::vector<Weight> d(boost::num_vertices(graph));
         std::vector<Weight> d(boost::num_vertices(graph));
 
 
+        util::Logger::LogDebug("scan the graph for negative edge weights");
+
         // Scan the graph for negative edge weights to use the proper algorithm
         // Scan the graph for negative edge weights to use the proper algorithm
         bool negative_edges = false;
         bool negative_edges = false;
         EdgeIter ei, ei_end;
         EdgeIter ei, ei_end;
@@ -58,11 +64,12 @@ namespace algo
             }
             }
         }
         }
 
 
-#ifdef DEBUG
-        std::cout << "the specified graph has "
-                  << (negative_edges ? "negative" : "only positive")
-                  << " edge weights" << std::endl;
-#endif
+        if (negative_edges)
+            util::Logger::LogDebug("the graph contains negative edges");
+        else
+            util::Logger::LogDebug("the graph contains only positive edges");
+
+        util::Logger::LogDebug("run a single-source shortest paths algorithm");
 
 
         if (negative_edges)
         if (negative_edges)
         {
         {
@@ -94,50 +101,41 @@ namespace algo
                                             boost::get(boost::vertex_index, graph))));
                                             boost::get(boost::vertex_index, graph))));
         }
         }
 
 
-#ifdef DEBUG
-        {
-            std::cout << "distances and parents:" << std::endl;
-            VertexIter vi, vend;
-            for (boost::tie(vi, vend) = vertices(graph); vi != vend; ++vi)
-            {
-                std::cout << "distance(" << *vi << ") = " << d[*vi] << ", ";
-                std::cout << "parent(" << *vi << ") = " << p[*vi] << std::endl;
-            }
-            std::cout << std::endl;
-        }
-#endif
+        util::Logger::LogDebug("prepare a map of visited vertices to detect negative cycles");
 
 
-#ifdef DEBUG
-        std::cout << "path: ";
-        std::cout << sink;
-#endif
-        // Record the vertices already visited to detect negative cycles
+        // Record the vertices already visited to detect negative cycles (and store the distances)
         std::unordered_map<Vertex, bool> visited_vertices;
         std::unordered_map<Vertex, bool> visited_vertices;
         VertexIter vi, vi_end;
         VertexIter vi, vi_end;
         for (boost::tie(vi, vi_end) = boost::vertices(graph); vi != vi_end; ++vi)
         for (boost::tie(vi, vi_end) = boost::vertices(graph); vi != vi_end; ++vi)
         {
         {
             visited_vertices[*vi] = false;
             visited_vertices[*vi] = false;
+
+            distances[*vi] = d[*vi];
         }
         }
 
 
+        util::Logger::LogDebug("insert the path into the output map (and detect negative cycles)");
+
         // Insert the path from the specified source to target into the specified map
         // Insert the path from the specified source to target into the specified map
         for (auto u = sink, v = p[u]; u != source; u = v, v = p[u])
         for (auto u = sink, v = p[u]; u != source; u = v, v = p[u])
         {
         {
             if (visited_vertices[u])
             if (visited_vertices[u])
             {
             {
-                std::cerr << "error: negative cycles are not allowed" << std::endl;
-                break;
+                util::Logger::LogError("negative cycle at vertex " + std::to_string(u));
+                return false;
             }
             }
 
 
             predecessors[u] = v;
             predecessors[u] = v;
             visited_vertices[u] = true;
             visited_vertices[u] = true;
-#ifdef DEBUG
-            std::cout << "<" << v;
-#endif
         }
         }
 
 
-#ifdef DEBUG
-        std::cout << std::endl;
-#endif
+        return true;
+    }
+
+    bool KShortestPaths5::FindPath(DirectedGraph& graph, Vertex& source, Vertex& sink,
+                                   VertexPredecessorMap& predecessors)
+    {
+        VertexDistanceMap d;
+        return FindPath(graph, source, sink, predecessors, d);
     }
     }
 
 
     void KShortestPaths5::FindPathPair()
     void KShortestPaths5::FindPathPair()
@@ -145,6 +143,8 @@ namespace algo
         VertexIter vi, vi_end;
         VertexIter vi, vi_end;
         EdgeIter ei, ei_end;
         EdgeIter ei, ei_end;
 
 
+        util::Logger::LogDebug("find the first path (in the original graph)");
+
         // Find the first path
         // Find the first path
         VertexPredecessorMap orig_first_path;
         VertexPredecessorMap orig_first_path;
         FindPath(orig_graph_, source_, sink_, orig_first_path);
         FindPath(orig_graph_, source_, sink_, orig_first_path);
@@ -154,6 +154,8 @@ namespace algo
         // every edge pointing on the path should end in the newly created vertex in the splitting
         // every edge pointing on the path should end in the newly created vertex in the splitting
         // process
         // process
 
 
+        util::Logger::LogDebug("copy the original graph");
+
         // Create the graph to transform and create the map to map from vertices in the transformed
         // Create the graph to transform and create the map to map from vertices in the transformed
         // graph to vertices in the original graph, at first every vertex is mapped to itself
         // graph to vertices in the original graph, at first every vertex is mapped to itself
         DirectedGraph trans_graph;
         DirectedGraph trans_graph;
@@ -165,6 +167,8 @@ namespace algo
         // Transform the first path by inverting edges (and weights) and splitting nodes along the
         // Transform the first path by inverting edges (and weights) and splitting nodes along the
         // path
         // path
 
 
+        util::Logger::LogDebug("reverse the first path");
+
         // Reverse the first path
         // Reverse the first path
         VertexPredecessorMap trans_first_path;
         VertexPredecessorMap trans_first_path;
         for (auto u = sink_, v = orig_first_path[u]; u != source_; u = v, v = orig_first_path[u])
         for (auto u = sink_, v = orig_first_path[u]; u != source_; u = v, v = orig_first_path[u])
@@ -172,6 +176,8 @@ namespace algo
             trans_first_path[v] = u;
             trans_first_path[v] = u;
         }
         }
 
 
+        util::Logger::LogDebug("invert the edges along the first path");
+
         // Invert edges
         // Invert edges
         for (auto u = sink_, v = orig_first_path[u]; u != source_; u = v, v = orig_first_path[u])
         for (auto u = sink_, v = orig_first_path[u]; u != source_; u = v, v = orig_first_path[u])
         {
         {
@@ -186,21 +192,12 @@ namespace algo
             }
             }
             else
             else
             {
             {
-                std::cerr << "error: edge not found " << v << " -> " << u << std::endl;
+                util::Logger::LogError("edge not found " + std::to_string(v) + " -> " +
+                                       std::to_string(u));
             }
             }
         }
         }
 
 
-#ifdef DEBUG
-        std::cout << "inverted edges: " << std::endl;
-        for (boost::tie(ei, ei_end) = boost::edges(trans_graph); ei != ei_end; ++ei)
-        {
-            std::cout << boost::source(*ei, trans_graph)
-                      << " > " << boost::target(*ei, trans_graph)
-                      << " | " << boost::get(boost::edge_weight, trans_graph, *ei)
-                      << std::endl;
-        }
-        std::cout << std::endl;
-#endif
+        util::Logger::LogDebug("split the nodes along the first path");
 
 
         // Split nodes
         // Split nodes
         VertexPredecessorMap old_to_new;
         VertexPredecessorMap old_to_new;
@@ -221,17 +218,20 @@ namespace algo
             boost::tie(edge, e_found) = boost::edge(v, u, orig_graph_);
             boost::tie(edge, e_found) = boost::edge(v, u, orig_graph_);
             if (e_found)
             if (e_found)
             {
             {
-                w = boost::get(boost::edge_weight, trans_graph, edge);
+                w = boost::get(boost::edge_weight, orig_graph_, edge);
             }
             }
             else
             else
             {
             {
-                std::cerr << "error: edge not found " << v << " -> " << u << std::endl;
+                util::Logger::LogError("edge not found " + std::to_string(v) + " -> " +
+                                       std::to_string(u));
             }
             }
 
 
             // Create the edge from the concomitant vertex to the path predecessor
             // Create the edge from the concomitant vertex to the path predecessor
             boost::add_edge(new_u, v, -w, trans_graph);
             boost::add_edge(new_u, v, -w, trans_graph);
         }
         }
 
 
+        util::Logger::LogDebug("extend the copied graph with the remaining edges");
+
         // Add all remaining edges
         // Add all remaining edges
         for (boost::tie(ei, ei_end) = boost::edges(orig_graph_); ei != ei_end; ++ei)
         for (boost::tie(ei, ei_end) = boost::edges(orig_graph_); ei != ei_end; ++ei)
         {
         {
@@ -262,32 +262,13 @@ namespace algo
             boost::add_edge(source, target, weight, trans_graph);
             boost::add_edge(source, target, weight, trans_graph);
         }
         }
 
 
-#ifdef DEBUG
-        std::cout << "transformed graph: " << std::endl;
-        for (boost::tie(ei, ei_end) = boost::edges(trans_graph); ei != ei_end; ++ei)
-        {
-            std::cout << boost::source(*ei, trans_graph)
-                      << " > " << boost::target(*ei, trans_graph)
-                      << " | " << boost::get(boost::edge_weight, trans_graph, *ei)
-                      << std::endl;
-        }
-        std::cout << std::endl;
-#endif
+        util::Logger::LogDebug("find the second path (in the copied and transformed graph)");
 
 
         // Find the second path in the transformed graph
         // Find the second path in the transformed graph
         VertexPredecessorMap trans_second_path;
         VertexPredecessorMap trans_second_path;
         FindPath(trans_graph, source_, sink_, trans_second_path);
         FindPath(trans_graph, source_, sink_, trans_second_path);
 
 
-        // Check if the two paths have vertices (except source and sink) in common
-        bool vertex_disjoint = true;
-        for (auto u = trans_first_path[sink_]; u != source_; u = trans_first_path[u])
-        {
-            if (trans_second_path.count(u) > 0)
-            {
-                vertex_disjoint = false;
-                break;
-            }
-        }
+        util::Logger::LogDebug("map the second path into the original graph");
 
 
         // Map the second path from the transformed graph into the original graph
         // Map the second path from the transformed graph into the original graph
         VertexPredecessorMap orig_second_path;
         VertexPredecessorMap orig_second_path;
@@ -300,20 +281,38 @@ namespace algo
             orig_second_path[orig_u] = orig_v;
             orig_second_path[orig_u] = orig_v;
         }
         }
 
 
+        util::Logger::LogDebug("check if the two paths are already vertex disjoint");
+
+        // Check if the two paths have vertices (except source and sink) in common
+        bool vertex_disjoint = true;
+        for (auto u = orig_first_path[sink_]; u != source_; u = orig_first_path[u])
+        {
+            if (orig_second_path.count(u) > 0)
+            {
+                vertex_disjoint = false;
+                break;
+            }
+        }
+
         // If the paths are not vertex disjoint, we need to remove the edges common to both paths
         // If the paths are not vertex disjoint, we need to remove the edges common to both paths
         if (!vertex_disjoint)
         if (!vertex_disjoint)
         {
         {
+            util::Logger::LogDebug("remove edges used by both paths to guarantee vertex disjointness");
+
             for (auto u = sink_, v = orig_first_path[u];
             for (auto u = sink_, v = orig_first_path[u];
                  u != source_;
                  u != source_;
                  u = v, v = orig_first_path[u])
                  u = v, v = orig_first_path[u])
             {
             {
                 if (orig_second_path.count(v) > 0 && orig_second_path[v] == u)
                 if (orig_second_path.count(v) > 0 && orig_second_path[v] == u)
                 {
                 {
+                    orig_first_path.erase(u);
                     orig_second_path.erase(v);
                     orig_second_path.erase(v);
                 }
                 }
             }
             }
         }
         }
 
 
+        util::Logger::LogDebug("add the first and second path to the map of all paths");
+
         // Store the paths
         // Store the paths
         AddPath(orig_first_path);
         AddPath(orig_first_path);
         AddPath(orig_second_path);
         AddPath(orig_second_path);
@@ -321,17 +320,230 @@ namespace algo
 
 
     void KShortestPaths5::AddPath(VertexPredecessorMap& path)
     void KShortestPaths5::AddPath(VertexPredecessorMap& path)
     {
     {
-        for (auto u = path[sink_], v = path[u]; u != source_; u = v, v = path[u])
+        for (auto edge : path)
         {
         {
-            paths_[u] = v;
+            if (edge.first == edge.second)
+                continue;
+
+            if (edge.first == sink_)
+                sink_neighbors_.push_back(edge.second);
+            else
+                paths_[edge.first] = edge.second;
         }
         }
+    }
 
 
-        sink_neighbors_.push_back(path[sink_]);
+    void KShortestPaths5::AddPath(VertexPredecessorMap& in, MultiPredecessorMap& out)
+    {
+        for (auto edge : in)
+        {
+            if (edge.first != edge.second)
+                out[edge.first].insert(edge.second);
+        }
+    }
+
+    void KShortestPaths5::AddPaths(MultiPredecessorMap& paths)
+    {
+        for (auto pair : paths)
+        {
+            Vertex t = pair.first;
+            for (auto s : pair.second)
+            {
+                if (t == sink_)
+                    sink_neighbors_.push_back(s);
+                else
+                    paths_[t] = s;
+            }
+        }
     }
     }
 
 
     void KShortestPaths5::FindPaths(size_t count)
     void KShortestPaths5::FindPaths(size_t count)
     {
     {
-        //TODO
+        VertexIter vi, vi_end;
+        EdgeIter ei, ei_end;
+
+        // The edge weights of the original graph
+        EdgeWeightMap orig_weights = boost::get(boost::edge_weight, orig_graph_);
+
+        // All found paths
+        MultiPredecessorMap k_orig_paths;
+
+        // Find the first path (only path found in the original graph)
+        VertexDistanceMap orig_distances;
+        VertexPredecessorMap orig_first_path;
+        if (!FindPath(orig_graph_, source_, sink_, orig_first_path, orig_distances))
+        {
+            util::Logger::LogInfo("Not even a single path could have been found!");
+            return;
+        }
+        AddPath(orig_first_path, k_orig_paths);
+
+        // Transform the original edge weights
+        for (boost::tie(ei, ei_end) = boost::edges(orig_graph_); ei != ei_end; ++ei)
+        {
+            Vertex source = boost::source(*ei, orig_graph_);
+            Vertex target = boost::target(*ei, orig_graph_);
+
+            orig_weights[*ei] = orig_distances[source] + orig_weights[*ei] - orig_distances[target];
+        }
+
+        // Find the specified amount of paths iteratively
+        for (size_t i = 1; i < count; ++i)
+        {
+            util::Logger::LogDebug("copy the original graph");
+
+            // Create a graph used for transformations and start by copying the vertices
+            DirectedGraph trans_graph;
+            for (boost::tie(vi, vi_end) = boost::vertices(orig_graph_); vi != vi_end; ++vi)
+            {
+                boost::add_vertex(trans_graph);
+            }
+
+            util::Logger::LogDebug("invert the edges along all previous found paths");
+
+            // Invert edges for all previous paths (also invert their weight)
+            std::vector<EdgeIter> edge_queue;
+            for (boost::tie(ei, ei_end) = boost::edges(orig_graph_); ei != ei_end; ++ei)
+            {
+                Vertex source = boost::source(*ei, orig_graph_);
+                Vertex target = boost::target(*ei, orig_graph_);
+
+                if (k_orig_paths.count(target) > 0 && k_orig_paths[target].count(source) > 0)
+                {
+                    Weight weight = orig_weights[*ei];
+
+                    boost::add_edge(target, source, -weight, trans_graph);
+                }
+                else
+                {
+                    edge_queue.push_back(ei);
+                }
+            }
+
+            util::Logger::LogDebug("split the nodes along all previous found path");
+
+            // Split nodes
+            VertexPredecessorMap old_to_new;
+            VertexPredecessorMap new_to_old;
+            for (auto orig_edge : k_orig_paths)
+            {
+                Vertex source = *orig_edge.second.begin();
+                Vertex target = orig_edge.first;
+
+                // Create the concomitant vertex
+                Vertex new_target = boost::add_vertex(trans_graph);
+                old_to_new[target] = new_target;
+                new_to_old[new_target] = target;
+
+                // Retrieve the weight from the original path in the original graph
+                Weight weight = 0.0;
+                Edge edge;
+                bool e_found;
+                boost::tie(edge, e_found) = boost::edge(source, target, orig_graph_);
+                if (e_found)
+                {
+                    weight = orig_weights[edge];
+                }
+                else
+                {
+                    util::Logger::LogError("error: edge not found " + std::to_string(source) +
+                                           " -> " + std::to_string(target));
+                }
+
+                // Create the edge from the concomitant vertex to the path predecessor
+                boost::add_edge(new_target, source, -weight, trans_graph);
+
+                //TODO experimental testing
+                if (weight < 0)
+                    std::cout << "NEGATIVE AUXILIARY EDGE" << std::endl;
+            }
+
+            util::Logger::LogDebug("extend the copied graph with the remaining edges");
+
+            // Add all remaining edges
+            for (auto e : edge_queue)
+            {
+                Vertex source = boost::source(*e, orig_graph_);
+                Vertex target = boost::target(*e, orig_graph_);
+                Weight weight = orig_weights[*e];
+
+                // If the edge points to source or sink add the edge unchanged
+                if (target == source_ || target == sink_)
+                {
+                    boost::add_edge(source, target, weight, trans_graph);
+                    continue;
+                }
+
+                // If the edge points to split vertices (vertices on the path except source and
+                // sink), point the edge towards the concomitant vertex
+                if (k_orig_paths.count(target) > 0 && old_to_new.count(target) > 0)
+                {
+                    boost::add_edge(source, old_to_new[target], weight, trans_graph);
+                    continue;
+                }
+
+                // Add every other edge unchanged
+                boost::add_edge(source, target, weight, trans_graph);
+            }
+
+            util::Logger::LogDebug("find the second path (in the copied and transformed graph)");
+
+            // Find the next path in the transformed graph
+            VertexPredecessorMap trans_next_path;
+            if (!FindPath(trans_graph, source_, sink_, trans_next_path))
+            {
+                util::Logger::LogInfo("No more paths may be found!");
+                return;
+            }
+
+            util::Logger::LogDebug("map the second path into the original graph");
+
+            // Map the second path from the transformed graph into the original graph
+            VertexPredecessorMap orig_next_path;
+            for (auto u = sink_, v = trans_next_path[u]; u != source_; u = v, v = trans_next_path[u])
+            {
+                Vertex orig_u = new_to_old.count(u) > 0 ? new_to_old[u] : u;
+                Vertex orig_v = new_to_old.count(v) > 0 ? new_to_old[v] : v;
+
+                orig_next_path[orig_u] = orig_v;
+            }
+
+            AddPath(orig_next_path, k_orig_paths);
+
+            util::Logger::LogDebug("remove edges used by multiple paths to guarantee vertex disjointness");
+
+            // Remove edges used by multiple paths
+            for (auto pair : k_orig_paths)
+            {
+                Vertex target = pair.first;
+                for (auto source : pair.second)
+                {
+                    if (k_orig_paths.count(source) > 0 && k_orig_paths[source].count(target) > 0)
+                    {
+                        k_orig_paths[source].erase(target);
+                        k_orig_paths[target].erase(source);
+                    }
+                }
+            }
+
+            util::Logger::LogDebug("remove vertices with no edges from the path");
+
+            // Remove empty vertices from the paths
+            for (auto iter = k_orig_paths.begin(); iter != k_orig_paths.end(); )
+            {
+                auto pair = *iter;
+                if (pair.second.empty())
+                {
+                    iter = k_orig_paths.erase(iter);
+                }
+                else
+                {
+                    ++iter;
+                }
+            }
+        }
+
+        // Store the paths
+        AddPaths(k_orig_paths);
     }
     }
 
 
     void KShortestPaths5::GetPaths(std::vector<std::vector<Vertex>>& paths)
     void KShortestPaths5::GetPaths(std::vector<std::vector<Vertex>>& paths)

+ 5 - 1
algo/KShortestPaths5.h

@@ -18,12 +18,16 @@ namespace algo
         VertexPredecessorMap paths_;
         VertexPredecessorMap paths_;
         std::vector<Vertex> sink_neighbors_;
         std::vector<Vertex> sink_neighbors_;
 
 
-        void FindPath(DirectedGraph& graph, Vertex& source, Vertex& sink,
+        bool FindPath(DirectedGraph& graph, Vertex& source, Vertex& sink,
+                      VertexPredecessorMap& predecessors, VertexDistanceMap& distances);
+        bool FindPath(DirectedGraph& graph, Vertex& source, Vertex& sink,
                       VertexPredecessorMap& predecessors);
                       VertexPredecessorMap& predecessors);
         void FindPathPair();
         void FindPathPair();
         void FindPaths(size_t count);
         void FindPaths(size_t count);
 
 
         void AddPath(VertexPredecessorMap& path);
         void AddPath(VertexPredecessorMap& path);
+        void AddPath(VertexPredecessorMap& in, MultiPredecessorMap& out);
+        void AddPaths(MultiPredecessorMap& paths);
     public:
     public:
         KShortestPaths5(DirectedGraph input_graph, Vertex source, Vertex sink);
         KShortestPaths5(DirectedGraph input_graph, Vertex source, Vertex sink);
         void Run(size_t max_path_count);
         void Run(size_t max_path_count);

+ 37 - 33
algo/NStage.cpp

@@ -8,18 +8,17 @@
 
 
 namespace algo
 namespace algo
 {
 {
-    NStage::NStage(size_t max_frame_skip,
-                       std::vector<double> penalty_value,
-                       std::vector<size_t> max_tracklet_count)
+    NStage::NStage(std::vector<size_t> max_frame_skip,
+                   std::vector<double> penalty_value,
+                   std::vector<size_t> max_tracklet_count)
     {
     {
-        max_frame_skip_ = max_frame_skip;
+        max_frame_skips_ = max_frame_skip;
         penalty_values_ = penalty_value;
         penalty_values_ = penalty_value;
         max_tracklet_counts_ = max_tracklet_count;
         max_tracklet_counts_ = max_tracklet_count;
         iterations_ = std::min(max_tracklet_count.size(), penalty_value.size());
         iterations_ = std::min(max_tracklet_count.size(), penalty_value.size());
     }
     }
 
 
-    void NStage::CreateObjectGraph(DirectedGraph& graph,
-                                     const core::DetectionSequence& detections)
+    void NStage::CreateObjectGraph(DirectedGraph& graph, const core::DetectionSequence& detections)
     {
     {
         util::Logger::LogInfo("Creating object graph");
         util::Logger::LogInfo("Creating object graph");
 
 
@@ -37,8 +36,7 @@ namespace algo
 
 
             for (size_t j = 0; j < detections.GetObjectCount(i); ++j)
             for (size_t j = 0; j < detections.GetObjectCount(i); ++j)
             {
             {
-                Vertex v = boost::add_vertex(detections.GetObject(i, j),
-                                             graph);
+                Vertex v = boost::add_vertex(detections.GetObject(i, j), graph);
 
 
                 layer.push_back(v);
                 layer.push_back(v);
             }
             }
@@ -61,9 +59,7 @@ namespace algo
                 Vertex u = layers[i][j];
                 Vertex u = layers[i][j];
 
 
                 // For each next frame/layer until maxFrameSkip or end
                 // For each next frame/layer until maxFrameSkip or end
-                for (size_t k = 1;
-                     k != (max_frame_skip_ + 1) && i + k < layers.size();
-                     ++k)
+                for (size_t k = 1; k <= max_frame_skips_[0] && i + k < layers.size(); ++k)
                 {
                 {
                     // To every edge in the next frame/layer
                     // To every edge in the next frame/layer
                     for (size_t l = 0; l < layers[i + k].size(); ++l)
                     for (size_t l = 0; l < layers[i + k].size(); ++l)
@@ -91,10 +87,8 @@ namespace algo
         util::Logger::LogDebug("edge count " + std::to_string(boost::num_edges(graph)));
         util::Logger::LogDebug("edge count " + std::to_string(boost::num_edges(graph)));
     }
     }
 
 
-    void NStage::CreateTrackletGraph(DirectedGraph& obj_graph,
-                                       DirectedGraph& tlt_graph,
-                                       size_t frame_count,
-                                       size_t iteration)
+    void NStage::CreateTrackletGraph(DirectedGraph& obj_graph, DirectedGraph& tlt_graph,
+                                     size_t frame_count, size_t iteration)
     {
     {
         util::Logger::LogInfo("Creating tracklet graph");
         util::Logger::LogInfo("Creating tracklet graph");
 
 
@@ -115,6 +109,9 @@ namespace algo
         Vertex obj_src = obj_indices[0];
         Vertex obj_src = obj_indices[0];
         Vertex obj_snk = obj_indices[obj_graph_size - 1];
         Vertex obj_snk = obj_indices[obj_graph_size - 1];
 
 
+        //TODO experimental
+        EdgeWeightMap weight_map = boost::get(boost::edge_weight, obj_graph);
+
         // Iteratively run dijkstra to extract tracklets
         // Iteratively run dijkstra to extract tracklets
         for (size_t i = 0; i != max_tracklet_counts_[iteration]; ++i)
         for (size_t i = 0; i != max_tracklet_counts_[iteration]; ++i)
         {
         {
@@ -132,26 +129,34 @@ namespace algo
 
 
             // Create the tracklet
             // Create the tracklet
             core::TrackletPtr tracklet(new core::Tracklet);
             core::TrackletPtr tracklet(new core::Tracklet);
-            for (Vertex u = obj_pred_map[obj_snk], v = obj_snk;
-                 u != v;
-                 v = u, u = obj_pred_map[v])
+            for (Vertex u = obj_pred_map[obj_snk], v = obj_snk; u != v; v = u, u = obj_pred_map[v])
             {
             {
                 tracklet->AddPathObject(obj_values[u]);
                 tracklet->AddPathObject(obj_values[u]);
 
 
                 // Leave source and sink untouched
                 // Leave source and sink untouched
                 if (!obj_values[u]->IsVirtual())
                 if (!obj_values[u]->IsVirtual())
                 {
                 {
+                    //TODO original
                     // Remove the path by setting all used edges to a weight of
                     // Remove the path by setting all used edges to a weight of
                     // infinity
                     // infinity
-                    std::pair<DirectedGraph::out_edge_iterator,
-                              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;
-                         ++iter)
+//                    std::pair<DirectedGraph::out_edge_iterator,
+//                              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;
+//                         ++iter)
+//                    {
+//                        boost::get(boost::edge_weight, obj_graph, *iter)
+//                                = std::numeric_limits<double>::infinity();
+//                    }
+
+                    //TODO experimental
+                    OutEdgeIter oei, oei_end;
+                    for (boost::tie(oei, oei_end) = boost::out_edges(u, obj_graph);
+                         oei != oei_end;
+                         ++oei)
                     {
                     {
-                        boost::get(boost::edge_weight, obj_graph, *iter)
-                                = std::numeric_limits<double>::infinity();
+                        weight_map[*oei] = std::numeric_limits<double>::infinity();
                     }
                     }
                 }
                 }
             }
             }
@@ -162,8 +167,7 @@ namespace algo
         }
         }
 
 
         // Add sink to tracklet graph
         // Add sink to tracklet graph
-        Vertex tlt_snk =
-                boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()),
+        Vertex tlt_snk = boost::add_vertex(core::ObjectDataPtr(new core::ObjectData()),
                                   tlt_graph);
                                   tlt_graph);
 
 
         util::Logger::LogDebug("adding edges");
         util::Logger::LogDebug("adding edges");
@@ -177,8 +181,7 @@ namespace algo
         for (size_t i = 1; i < tlt_graph_size - 1; ++i)
         for (size_t i = 1; i < tlt_graph_size - 1; ++i)
         {
         {
             Vertex u = tlt_indices[i];
             Vertex u = tlt_indices[i];
-            core::TrackletPtr u_ptr =
-                    std::static_pointer_cast<core::Tracklet>(tlt_values[u]);
+            core::TrackletPtr u_ptr = std::static_pointer_cast<core::Tracklet>(tlt_values[u]);
             size_t u_first_frame = u_ptr->GetFirstFrameIndex();
             size_t u_first_frame = u_ptr->GetFirstFrameIndex();
             size_t u_last_frame = u_ptr->GetLastFrameIndex();
             size_t u_last_frame = u_ptr->GetLastFrameIndex();
 
 
@@ -193,7 +196,8 @@ namespace algo
                     size_t v_first_frame = v_ptr->GetFirstFrameIndex();
                     size_t v_first_frame = v_ptr->GetFirstFrameIndex();
 
 
                     // Link only tracklets that are in temporal order
                     // Link only tracklets that are in temporal order
-                    if (u_last_frame < v_first_frame)
+                    if (u_last_frame < v_first_frame &&
+                            (v_first_frame - u_last_frame < max_frame_skips_[iteration]))
                     {
                     {
                         boost::add_edge(u, v,
                         boost::add_edge(u, v,
                                         tlt_values[u]->CompareTo(tlt_values[v]),
                                         tlt_values[u]->CompareTo(tlt_values[v]),
@@ -218,7 +222,7 @@ namespace algo
     }
     }
 
 
     void NStage::ExtractTracks(DirectedGraph& tlt_graph, size_t depth,
     void NStage::ExtractTracks(DirectedGraph& tlt_graph, size_t depth,
-                                 std::vector<core::TrackletPtr>& tracks)
+                               std::vector<core::TrackletPtr>& tracks)
     {
     {
         util::Logger::LogInfo("Extracting tracks");
         util::Logger::LogInfo("Extracting tracks");
 
 
@@ -243,7 +247,7 @@ namespace algo
     }
     }
 
 
     void NStage::Run(const core::DetectionSequence& sequence,
     void NStage::Run(const core::DetectionSequence& sequence,
-                       std::vector<core::TrackletPtr>& tracks)
+                     std::vector<core::TrackletPtr>& tracks)
     {
     {
         // Running the two stage graph algorithm
         // Running the two stage graph algorithm
         DirectedGraph obj_graph;
         DirectedGraph obj_graph;

+ 8 - 11
algo/NStage.h

@@ -21,7 +21,7 @@ namespace algo
         /**
         /**
          * Maximum edge length to link object
          * Maximum edge length to link object
          */
          */
-        size_t max_frame_skip_;
+        std::vector<size_t> max_frame_skips_;
 
 
         /**
         /**
          * Edge value to link to source and sink
          * Edge value to link to source and sink
@@ -43,8 +43,7 @@ namespace algo
          * @param graph The graph to write into
          * @param graph The graph to write into
          * @param detections The objects to use for the graph
          * @param detections The objects to use for the graph
          */
          */
-        void CreateObjectGraph(DirectedGraph& graph,
-                               const core::DetectionSequence& detections);
+        void CreateObjectGraph(DirectedGraph& graph, const core::DetectionSequence& detections);
 
 
         /**
         /**
          * Reduces the object graph into linked tracklets.
          * Reduces the object graph into linked tracklets.
@@ -53,10 +52,8 @@ namespace algo
          * @param frame_count The frame count of the object graph
          * @param frame_count The frame count of the object graph
          * @param iteration The current iteration
          * @param iteration The current iteration
          */
          */
-        void CreateTrackletGraph(DirectedGraph& obj_graph,
-                                 DirectedGraph& tlt_graph,
-                                 size_t frame_count,
-                                 size_t iteration);
+        void CreateTrackletGraph(DirectedGraph& obj_graph, DirectedGraph& tlt_graph,
+                                 size_t frame_count, size_t iteration);
 
 
         /**
         /**
          * Extracts the finished tracks from the given tracklet graph.
          * Extracts the finished tracks from the given tracklet graph.
@@ -64,8 +61,7 @@ namespace algo
          * @param depth The depth to flatten the tracklets to
          * @param depth The depth to flatten the tracklets to
          * @param tracks The vector to write the extracted tracks in
          * @param tracks The vector to write the extracted tracks in
          */
          */
-        void ExtractTracks(DirectedGraph& tlt_graph,
-                           size_t depth,
+        void ExtractTracks(DirectedGraph& tlt_graph, size_t depth,
                            std::vector<core::TrackletPtr>& tracks);
                            std::vector<core::TrackletPtr>& tracks);
     public:
     public:
         /**
         /**
@@ -76,8 +72,9 @@ namespace algo
          * @param penalty_value The edge value to link to source and sink
          * @param penalty_value The edge value to link to source and sink
          * @param max_tracklet_count The maximum number of tracklets to create
          * @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);
+        NStage(std::vector<size_t> max_frame_skip,
+               std::vector<double> penalty_value,
+               std::vector<size_t> max_tracklet_count);
 
 
         void Run(const core::DetectionSequence& sequence,
         void Run(const core::DetectionSequence& sequence,
                  std::vector<core::TrackletPtr>& tracks);
                  std::vector<core::TrackletPtr>& tracks);

+ 169 - 78
main/main.cpp

@@ -17,10 +17,11 @@
 #include <boost/program_options.hpp>
 #include <boost/program_options.hpp>
 #include <boost/graph/named_function_params.hpp>
 #include <boost/graph/named_function_params.hpp>
 #include <boost/graph/bellman_ford_shortest_paths.hpp>
 #include <boost/graph/bellman_ford_shortest_paths.hpp>
+#include <iomanip>
 
 
 struct
 struct
 {
 {
-    size_t max_frame_skip;
+    std::string max_frame_skip;
     std::string max_tracklet_count;
     std::string max_tracklet_count;
     std::string penalty_value;
     std::string penalty_value;
 } n_stage_params;
 } n_stage_params;
@@ -30,13 +31,14 @@ void RunNStage(core::DetectionSequence& sequence,
 {
 {
     util::Logger::LogInfo("Running n-stage");
     util::Logger::LogInfo("Running n-stage");
 
 
+    std::vector<size_t> max_frame_skips;
     std::vector<double> penalty_values;
     std::vector<double> penalty_values;
     std::vector<size_t> max_tracklet_counts;
     std::vector<size_t> max_tracklet_counts;
 
 
     // Parse strings to vectors
     // Parse strings to vectors
     size_t d_index;
     size_t d_index;
     std::string str, part;
     std::string str, part;
-    str = n_stage_params.max_tracklet_count;
+    str = n_stage_params.max_frame_skip;
     do
     do
     {
     {
         d_index = str.find(",");
         d_index = str.find(",");
@@ -45,7 +47,7 @@ void RunNStage(core::DetectionSequence& sequence,
 
 
         if (part.size() > 0)
         if (part.size() > 0)
         {
         {
-            max_tracklet_counts.push_back((unsigned long&&) atoi(part.c_str()));
+            max_frame_skips.push_back((unsigned long&&) atoi(part.c_str()));
         }
         }
 
 
         str = str.substr(d_index + 1);
         str = str.substr(d_index + 1);
@@ -66,10 +68,24 @@ void RunNStage(core::DetectionSequence& sequence,
         str = str.substr(d_index + 1);
         str = str.substr(d_index + 1);
     }
     }
     while (d_index != std::string::npos);
     while (d_index != std::string::npos);
+    str = n_stage_params.max_tracklet_count;
+    do
+    {
+        d_index = str.find(",");
+
+        part = str.substr(0, d_index);
+
+        if (part.size() > 0)
+        {
+            max_tracklet_counts.push_back((unsigned long&&) atoi(part.c_str()));
+        }
+
+        str = str.substr(d_index + 1);
+    }
+    while (d_index != std::string::npos);
 
 
     // Init n stage
     // Init n stage
-    algo::NStage n_stage(n_stage_params.max_frame_skip,
-                         penalty_values, max_tracklet_counts);
+    algo::NStage n_stage(max_frame_skips, penalty_values, max_tracklet_counts);
 
 
     n_stage.Run(sequence, tracks);
     n_stage.Run(sequence, tracks);
 
 
@@ -118,8 +134,8 @@ void RunBerclaz(core::DetectionSequence& sequence,
 void Run(int argc, char** argv)
 void Run(int argc, char** argv)
 {
 {
     // Algorithm independent values
     // Algorithm independent values
-    std::string input_file, output_file, images_folder, algorithm, config_path, header, input_format;
-    bool info, debug, display;
+    std::string input_file, output_path, images_folder, algorithm, config_path, header, input_format;
+    bool info, debug, display, output;
     char input_delimiter, output_delimiter;
     char input_delimiter, output_delimiter;
     double temporal_weight, spatial_weight, angular_weight, image_width, image_height;
     double temporal_weight, spatial_weight, angular_weight, image_width, image_height;
 
 
@@ -139,14 +155,18 @@ void Run(int argc, char** argv)
              boost::program_options::value<bool>(&display)
              boost::program_options::value<bool>(&display)
                      ->default_value(false),
                      ->default_value(false),
              "if a window with the images and the detected tracks should be opened")
              "if a window with the images and the detected tracks should be opened")
+            ("output",
+             boost::program_options::value<bool>(&output)
+                     ->default_value(false),
+             "if the results should be written into the specified output folder")
             ("config",
             ("config",
              boost::program_options::value<std::string>(&config_path),
              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")
              "the path to the config file, if no path is given the command line arguments are read")
             ("input-file",
             ("input-file",
              boost::program_options::value<std::string>(&input_file),
              boost::program_options::value<std::string>(&input_file),
              "set detections file path")
              "set detections file path")
-            ("output-file",
-             boost::program_options::value<std::string>(&output_file),
+            ("output-path",
+             boost::program_options::value<std::string>(&output_path),
              "set the output file path")
              "set the output file path")
             ("output-delimiter",
             ("output-delimiter",
              boost::program_options::value<char>(&output_delimiter)
              boost::program_options::value<char>(&output_delimiter)
@@ -180,8 +200,8 @@ void Run(int argc, char** argv)
              boost::program_options::value<std::string>(&algorithm),
              boost::program_options::value<std::string>(&algorithm),
              "set the algorithm to use, current viable options: n-stage berclaz")
              "set the algorithm to use, current viable options: n-stage berclaz")
             ("max-frame-skip",
             ("max-frame-skip",
-             boost::program_options::value<size_t>(&n_stage_params.max_frame_skip)
-                     ->default_value(1),
+             boost::program_options::value<std::string>(&n_stage_params.max_frame_skip)
+                     ->default_value("1,1"),
              "(n stage) set the maximum number of frames a track can skip between two detections,"
              "(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")
                      " if set to less or equal than zero all frames are linked")
             ("max-tracklet-count",
             ("max-tracklet-count",
@@ -263,7 +283,7 @@ void Run(int argc, char** argv)
     }
     }
     else if (opt_var_map.count("input-file") == 0 ||
     else if (opt_var_map.count("input-file") == 0 ||
              opt_var_map.count("input-format") == 0 ||
              opt_var_map.count("input-format") == 0 ||
-             opt_var_map.count("output-file") == 0)
+                (opt_var_map.count("output-path") == 0 && output))
     {
     {
         std::cout << opts << std::endl;
         std::cout << opts << std::endl;
         exit(0);
         exit(0);
@@ -368,7 +388,10 @@ void Run(int argc, char** argv)
                           + " minutes");
                           + " minutes");
 
 
     // Write the output file
     // Write the output file
-    util::FileIO::WriteTracks(tracks, output_file, output_delimiter);
+    if (output)
+    {
+        util::FileIO::WriteTracks(tracks, output_path + "/tracks.csv", output_delimiter);
+    }
 
 
     // Display the tracking data
     // Display the tracking data
     if (display)
     if (display)
@@ -376,10 +399,10 @@ void Run(int argc, char** argv)
         util::Visualizer vis;
         util::Visualizer vis;
 
 
         if (algorithm == "berclaz")
         if (algorithm == "berclaz")
-            vis.Display(tracks, images_folder, "Visualizer",
+            vis.Display(tracks, images_folder, output, output_path, "Visualizer",
                         0, 24, berclaz_params.h_res, berclaz_params.v_res);
                         0, 24, berclaz_params.h_res, berclaz_params.v_res);
         else
         else
-            vis.Display(tracks, images_folder);
+            vis.Display(tracks, images_folder, output, output_path);
     }
     }
 }
 }
 
 
@@ -726,34 +749,33 @@ void CreateBerclazGraph(DirectedGraph& graph, Vertex& source, Vertex& sink)
                 {
                 {
                     // Iterate all nearby cells in the next frame
                     // Iterate all nearby cells in the next frame
                     for (int ny = std::max(0, y - vicinity_size);
                     for (int ny = std::max(0, y - vicinity_size);
-                         ny <
-                         std::min(grid.GetHeightCount(), y + vicinity_size + 1);
+                         ny < std::min(grid.GetHeightCount(), y + vicinity_size + 1);
                          ++ny)
                          ++ny)
                     {
                     {
                         for (int nx = std::max(0, x - vicinity_size);
                         for (int nx = std::max(0, x - vicinity_size);
-                             nx < std::min(grid.GetWidthCount(),
-                                           x + vicinity_size + 1);
+                             nx < std::min(grid.GetWidthCount(), x + vicinity_size + 1);
                              ++nx)
                              ++nx)
                         {
                         {
                             // Second vertex index
                             // Second vertex index
-                            int vj = nx + ny * grid.GetHeightCount() +
-                                     (z + 1) * layer_size;
+                            int vj = nx + ny * grid.GetHeightCount() + (z + 1) * layer_size;
 
 
                             // Connect to nearby cells
                             // Connect to nearby cells
-                            boost::add_edge(vertices[vi], vertices[vj],
-                                            weight, graph);
+                            boost::add_edge(vertices[vi], vertices[vj], weight, graph);
                         }
                         }
                     }
                     }
 
 
-                    boost::add_edge(vertices[vi], sink, 0.0, graph);
+//                    boost::add_edge(vertices[vi], sink, 0.0, graph);
                 }
                 }
                 else
                 else
                 {
                 {
                     boost::add_edge(vertices[vi], sink, weight, graph);
                     boost::add_edge(vertices[vi], sink, weight, graph);
                 }
                 }
 
 
-                // Connect with source and sink
-                boost::add_edge(source, vertices[vi], 0.0, graph);
+                if (z < 1)
+                {
+                    // Connect with source
+                    boost::add_edge(source, vertices[vi], 0.0, graph);
+                }
             }
             }
         }
         }
     }
     }
@@ -762,58 +784,75 @@ void CreateBerclazGraph(DirectedGraph& graph, Vertex& source, Vertex& sink)
     util::Logger::LogDebug("edge count " + std::to_string(boost::num_edges(graph)));
     util::Logger::LogDebug("edge count " + std::to_string(boost::num_edges(graph)));
 }
 }
 
 
-void CreatePresentationGraph(DirectedGraph& graph, Vertex& source, Vertex& sink)
+void CreatePresentationGraph(DirectedGraph& graph, Vertex& source, Vertex& sink, bool two_paths)
 {
 {
     std::vector<Vertex> vertices;
     std::vector<Vertex> vertices;
-    for (size_t i = 0; i < 10; ++i)
-    {
-        vertices.push_back(boost::add_vertex(core::ObjectDataPtr(new core::ObjectData(i)), graph));
-    }
 
 
-    source = vertices[0];
-    sink = vertices[9];
+    if (two_paths)
+    {
+        for (size_t i = 0; i < 10; ++i)
+        {
+            vertices.push_back(
+                    boost::add_vertex(core::ObjectDataPtr(new core::ObjectData(i)), graph));
+        }
 
 
-    boost::add_edge(vertices[0], vertices[1], 1.0, graph);
-    boost::add_edge(vertices[0], vertices[2], 1.0, graph);
-    boost::add_edge(vertices[1], vertices[3], 12.0, graph);
-    boost::add_edge(vertices[1], vertices[4], 15.0, graph);
-    boost::add_edge(vertices[2], vertices[3], 15.0, graph);
-    boost::add_edge(vertices[2], vertices[4], 10.0, graph);
-    boost::add_edge(vertices[3], vertices[5], 15.0, graph);
-    boost::add_edge(vertices[3], vertices[6], 12.0, graph);
-    boost::add_edge(vertices[4], vertices[5], 12.0, graph);
-    boost::add_edge(vertices[4], vertices[6], 11.0, graph);
-    boost::add_edge(vertices[5], vertices[7], 12.0, graph);
-    boost::add_edge(vertices[5], vertices[8], 12.0, graph);
-    boost::add_edge(vertices[6], vertices[7], 11.0, graph);
-    boost::add_edge(vertices[6], vertices[8], 10.0, graph);
-    boost::add_edge(vertices[7], vertices[9], 1.0, graph);
-    boost::add_edge(vertices[8], vertices[9], 1.0, graph);
-
-    // add a negative cycle
-//    boost::add_edge(vertices[4], vertices[6], -1.0, graph);
-//    boost::add_edge(vertices[5], vertices[4], -1.0, graph);
-//    boost::add_edge(vertices[6], vertices[5], -1.0, graph);
-
-    // add a unreachable vertex
-//    boost::add_vertex(core::ObjectDataPtr(new core::ObjectData(10)), graph);
+        source = vertices[0];
+        sink = vertices[9];
+
+        boost::add_edge(vertices[0], vertices[1], 1.0, graph);
+        boost::add_edge(vertices[0], vertices[2], 1.0, graph);
+        boost::add_edge(vertices[1], vertices[3], 12.0, graph);
+        boost::add_edge(vertices[1], vertices[4], 15.0, graph);
+        boost::add_edge(vertices[2], vertices[3], 15.0, graph);
+        boost::add_edge(vertices[2], vertices[4], 10.0, graph);
+        boost::add_edge(vertices[3], vertices[5], 15.0, graph);
+        boost::add_edge(vertices[3], vertices[6], 12.0, graph);
+        boost::add_edge(vertices[4], vertices[5], 12.0, graph);
+        boost::add_edge(vertices[4], vertices[6], 11.0, graph);
+        boost::add_edge(vertices[5], vertices[7], 12.0, graph);
+        boost::add_edge(vertices[5], vertices[8], 12.0, graph);
+        boost::add_edge(vertices[6], vertices[7], 11.0, graph);
+        boost::add_edge(vertices[6], vertices[8], 10.0, graph);
+        boost::add_edge(vertices[7], vertices[9], 1.0, graph);
+        boost::add_edge(vertices[8], vertices[9], 1.0, graph);
+    }
+    else
+    {
+        for (size_t i = 0; i < 14; ++i)
+        {
+            vertices.push_back(
+                    boost::add_vertex(core::ObjectDataPtr(new core::ObjectData(i)), graph));
+        }
 
 
-//    boost::add_edge(vertices[0], vertices[1], 0.0, graph);
-//    boost::add_edge(vertices[0], vertices[2], 0.0, graph);
-//    boost::add_edge(vertices[1], vertices[3], 12.0, graph);
-//    boost::add_edge(vertices[1], vertices[4], 15.0, graph);
-//    boost::add_edge(vertices[2], vertices[3], 15.0, graph);
-//    boost::add_edge(vertices[2], vertices[4], 10.0, graph);
-//    boost::add_edge(vertices[3], vertices[5], 12.0, graph);
-//    boost::add_edge(vertices[3], vertices[6], 12.0, graph);
-//    boost::add_edge(vertices[4], vertices[5], 11.0, graph);
-//    boost::add_edge(vertices[4], vertices[6], 10.0, graph);
-//    boost::add_edge(vertices[5], vertices[7], 15.0, graph);
-//    boost::add_edge(vertices[5], vertices[8], 12.0, graph);
-//    boost::add_edge(vertices[6], vertices[7], 12.0, graph);
-//    boost::add_edge(vertices[6], vertices[8], 11.0, graph);
-//    boost::add_edge(vertices[7], vertices[9], 0.0, graph);
-//    boost::add_edge(vertices[8], vertices[9], 0.0, graph);
+        source = vertices[0];
+        sink = vertices[9];
+
+        boost::add_edge(vertices[0], vertices[1], 1.0, graph);
+        boost::add_edge(vertices[0], vertices[2], 1.0, graph);
+        boost::add_edge(vertices[1], vertices[3], 12.0, graph);
+        boost::add_edge(vertices[1], vertices[4], 15.0, graph);
+        boost::add_edge(vertices[2], vertices[3], 15.0, graph);
+        boost::add_edge(vertices[2], vertices[4], 10.0, graph);
+        boost::add_edge(vertices[3], vertices[5], 15.0, graph);
+        boost::add_edge(vertices[3], vertices[6], 12.0, graph);
+        boost::add_edge(vertices[4], vertices[5], 12.0, graph);
+        boost::add_edge(vertices[4], vertices[6], 11.0, graph);
+        boost::add_edge(vertices[5], vertices[7], 12.0, graph);
+        boost::add_edge(vertices[5], vertices[8], 12.0, graph);
+        boost::add_edge(vertices[6], vertices[7], 11.0, graph);
+        boost::add_edge(vertices[6], vertices[8], 10.0, graph);
+        boost::add_edge(vertices[7], vertices[9], 1.0, graph);
+        boost::add_edge(vertices[8], vertices[9], 1.0, graph);
+
+        boost::add_edge(vertices[0], vertices[10], 20.0, graph);
+        boost::add_edge(vertices[10], vertices[11], 20.0, graph);
+        boost::add_edge(vertices[10], vertices[3], 20.0, graph);
+        boost::add_edge(vertices[10], vertices[4], 20.0, graph);
+        boost::add_edge(vertices[11], vertices[12], 20.0, graph);
+        boost::add_edge(vertices[11], vertices[5], 20.0, graph);
+        boost::add_edge(vertices[12], vertices[6], 20.0, graph);
+        boost::add_edge(vertices[13], vertices[9], 20.0, graph);
+    }
 }
 }
 
 
 void TestSuurballe()
 void TestSuurballe()
@@ -879,14 +918,66 @@ void TestSuurballe()
     std::cout << "Total paths length: " << suurballe.GetTotalPathsLength() << std::endl;
     std::cout << "Total paths length: " << suurballe.GetTotalPathsLength() << std::endl;
 }
 }
 
 
+void CreateSuurballeGraph(DirectedGraph& graph, Vertex& source, Vertex& sink, bool first)
+{
+    std::vector<Vertex> vertices;
+
+    if (first)
+    {
+        // First example graph
+        for (int i = 0; i < 7; ++i)
+        {
+            vertices.push_back(boost::add_vertex(graph));
+        }
+
+        source = vertices[0];
+        sink = vertices[6];
+
+        boost::add_edge(vertices[0], vertices[1], 5.0, graph);
+        boost::add_edge(vertices[0], vertices[4], 2.0, graph);
+        boost::add_edge(vertices[1], vertices[2], 1.0, graph);
+        boost::add_edge(vertices[1], vertices[4], 1.0, graph);
+        boost::add_edge(vertices[2], vertices[6], 1.0, graph);
+        boost::add_edge(vertices[3], vertices[2], 1.0, graph);
+        boost::add_edge(vertices[4], vertices[3], 2.0, graph);
+        boost::add_edge(vertices[4], vertices[5], 1.0, graph);
+        boost::add_edge(vertices[5], vertices[2], 1.0, graph);
+        boost::add_edge(vertices[5], vertices[6], 1.0, graph);
+    }
+    else
+    {
+        // Second example graph
+        for (int i = 0; i < 8; ++i)
+        {
+            vertices.push_back(boost::add_vertex(graph));
+        }
+        source = vertices[0];
+        sink = vertices[7];
+        boost::add_edge(vertices[0], vertices[1], 1.0, graph);
+        boost::add_edge(vertices[0], vertices[4], 8.0, graph);
+        boost::add_edge(vertices[0], vertices[5], 1.0, graph);
+        boost::add_edge(vertices[1], vertices[2], 1.0, graph);
+        boost::add_edge(vertices[1], vertices[7], 8.0, graph);
+        boost::add_edge(vertices[2], vertices[3], 1.0, graph);
+        boost::add_edge(vertices[3], vertices[4], 1.0, graph);
+        boost::add_edge(vertices[3], vertices[6], 2.0, graph);
+        boost::add_edge(vertices[4], vertices[7], 1.0, graph);
+        boost::add_edge(vertices[5], vertices[2], 2.0, graph);
+        boost::add_edge(vertices[5], vertices[6], 6.0, graph);
+        boost::add_edge(vertices[6], vertices[7], 1.0, graph);
+    }
+}
+
 void TestYAOKSP()
 void TestYAOKSP()
 {
 {
     Vertex source, sink;
     Vertex source, sink;
     DirectedGraph graph;
     DirectedGraph graph;
-    CreatePresentationGraph(graph, source, sink);
+//    CreatePresentationGraph(graph, source, sink, true);
+    CreateSuurballeGraph(graph, source, sink, false);
+//    CreateBerclazGraph(graph, source, sink);
     algo::KShortestPaths5 ksp(graph, source, sink);
     algo::KShortestPaths5 ksp(graph, source, sink);
 
 
-    ksp.Run(2);
+    ksp.Run(3);
 
 
     std::vector<std::vector<Vertex>> paths;
     std::vector<std::vector<Vertex>> paths;
     ksp.GetPaths(paths);
     ksp.GetPaths(paths);
@@ -895,7 +986,7 @@ void TestYAOKSP()
         std::cout << "path: ";
         std::cout << "path: ";
         for (auto v : path)
         for (auto v : path)
         {
         {
-            std::cout << v << " ";
+            std::cout << std::setw(2) << v << " ";
         }
         }
         std::cout << std::endl;
         std::cout << std::endl;
     }
     }
@@ -905,7 +996,7 @@ int main(int argc, char** argv)
 {
 {
     //TODO load with frame offset
     //TODO load with frame offset
 
 
-//    Run(argc, argv);
+    Run(argc, argv);
 
 
 //    TestTracklet();
 //    TestTracklet();
 
 
@@ -939,7 +1030,7 @@ int main(int argc, char** argv)
 
 
 //    TestSuurballe();
 //    TestSuurballe();
 
 
-    TestYAOKSP();
+//    TestYAOKSP();
 
 
     return 0;
     return 0;
 }
 }

+ 7 - 2
util/Logger.cpp

@@ -17,17 +17,22 @@ namespace util
         std::cout << message;
         std::cout << message;
     }
     }
 
 
+    void Logger::LogErrorMessage(const std::string& message)
+    {
+        std::cerr << message;
+    }
+
     void Logger::LogInfo(const std::string& message)
     void Logger::LogInfo(const std::string& message)
     {
     {
         if (Instance().info_)
         if (Instance().info_)
         {
         {
-            Instance().LogMessage("[Info] " + message + "\n");
+            Instance().LogMessage("[Info ] " + message + "\n");
         }
         }
     }
     }
 
 
     void Logger::LogError(const std::string& message)
     void Logger::LogError(const std::string& message)
     {
     {
-        Instance().LogMessage("[Error] " + message + "\n");
+        Instance().LogErrorMessage("[Error] " + message + "\n");
     }
     }
 
 
     void Logger::LogDebug(const std::string& message)
     void Logger::LogDebug(const std::string& message)

+ 6 - 0
util/Logger.h

@@ -36,6 +36,12 @@ namespace util
          * @param message The message to log
          * @param message The message to log
          */
          */
         void LogMessage(const std::string& message);
         void LogMessage(const std::string& message);
+
+        /**
+         * Logs the given error message.
+         * @param message The error message to log
+         */
+        void LogErrorMessage(const std::string& message);
     public:
     public:
         /**
         /**
          * -> Singleton
          * -> Singleton

+ 27 - 10
util/Visualizer.cpp

@@ -10,7 +10,7 @@
 namespace util
 namespace util
 {
 {
     void Visualizer::Display(core::DetectionSequence& sequence,
     void Visualizer::Display(core::DetectionSequence& sequence,
-                             std::string image_folder,
+                             std::string image_folder, bool output, std::string output_path,
                              std::string title, size_t first_frame,
                              std::string title, size_t first_frame,
                              int play_fps)
                              int play_fps)
     {
     {
@@ -116,8 +116,9 @@ namespace util
     }
     }
 
 
     void Visualizer::Display(std::vector<core::TrackletPtr>& tracks,
     void Visualizer::Display(std::vector<core::TrackletPtr>& tracks,
-                             std::string image_folder, std::string title,
-                             size_t first_frame, int play_fps, int grid_width, int grid_height)
+                             std::string image_folder, bool output, std::string output_path,
+                             std::string title, size_t first_frame, int play_fps, int grid_width,
+                             int grid_height)
     {
     {
         util::Logger::LogInfo("Displaying data");
         util::Logger::LogInfo("Displaying data");
 
 
@@ -127,9 +128,6 @@ namespace util
         std::vector<std::string> image_files;
         std::vector<std::string> image_files;
         util::FileIO::ListFiles(image_folder, image_files);
         util::FileIO::ListFiles(image_folder, image_files);
 
 
-        // Create window
-        cv::namedWindow(title, CV_WINDOW_AUTOSIZE);
-
         // Generate a random color for each individual track
         // Generate a random color for each individual track
         std::vector<cv::Scalar> colors;
         std::vector<cv::Scalar> colors;
         std::random_device rd;
         std::random_device rd;
@@ -147,6 +145,26 @@ namespace util
             colors.push_back(color);
             colors.push_back(color);
         }
         }
 
 
+        //TODO move to extra class
+        //TODO create necessary directories
+        if (output)
+        {
+            util::Logger::LogInfo("Start writing output images");
+            for (size_t i = 0; i < image_files.size(); ++i)
+            {
+                cv::Mat image = cv::imread(image_folder + "/" + image_files[i], 1);
+                for (size_t j = 0; j < tracks.size(); ++j)
+                {
+                    tracks[j]->Visualize(image, colors[j], i, 0, 0);
+                }
+                cv::imwrite(output_path + "/images/" + image_files[i], image);
+            }
+            util::Logger::LogInfo("Finished writing output images");
+        }
+
+        // Create window
+        cv::namedWindow(title, CV_WINDOW_AUTOSIZE);
+
         // Display frames and data
         // Display frames and data
         int target_delay = 1000 / play_fps;
         int target_delay = 1000 / play_fps;
         int last_frame_time = GetTime();
         int last_frame_time = GetTime();
@@ -155,11 +173,9 @@ namespace util
         while (true)
         while (true)
         {
         {
             // Display image
             // Display image
-            cv::Mat image = cv::imread(image_folder + "/"
-                                       + image_files[current_frame],
-                                       1);
+            cv::Mat image = cv::imread(image_folder + "/" + image_files[current_frame], 1);
 
 
-            //TODO draw grid (experimental)
+            // Draw grid
             if (grid_width > 0 && grid_height > 0)
             if (grid_width > 0 && grid_height > 0)
             {
             {
                 cv::Scalar gridColor(255, 255, 255);
                 cv::Scalar gridColor(255, 255, 255);
@@ -177,6 +193,7 @@ namespace util
                 }
                 }
             }
             }
 
 
+            //Visualize the tracklets
             for (size_t i = 0; i < tracks.size(); ++i)
             for (size_t i = 0; i < tracks.size(); ++i)
             {
             {
                 tracks[i]->Visualize(image, colors[i], current_frame, 0, 0);
                 tracks[i]->Visualize(image, colors[i], current_frame, 0, 0);

+ 2 - 2
util/Visualizer.h

@@ -38,7 +38,7 @@ namespace util
          * @param play_fps The FPS to use when auto play is activated.
          * @param play_fps The FPS to use when auto play is activated.
          */
          */
         void Display(core::DetectionSequence& sequence,
         void Display(core::DetectionSequence& sequence,
-                     std::string image_folder,
+                     std::string image_folder, bool output, std::string output_path,
                      std::string title = "Visualizer", size_t first_frame = 0,
                      std::string title = "Visualizer", size_t first_frame = 0,
                      int play_fps = 24);
                      int play_fps = 24);
 
 
@@ -57,7 +57,7 @@ namespace util
          * @param grid_height The number of cells in a column
          * @param grid_height The number of cells in a column
          */
          */
         void Display(std::vector<core::TrackletPtr>& tracks,
         void Display(std::vector<core::TrackletPtr>& tracks,
-                     std::string image_folder,
+                     std::string image_folder, bool output, std::string output_path,
                      std::string title = "Visualizer", size_t first_frame = 0,
                      std::string title = "Visualizer", size_t first_frame = 0,
                      int play_fps = 24, int grid_width = 0, int grid_height = 0);
                      int play_fps = 24, int grid_width = 0, int grid_height = 0);
     };
     };