preview.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * markerAssociationDP.cpp
  3. *
  4. * Created on: Feb 6, 2013
  5. * Author: koerner
  6. */
  7. #include <boost/config.hpp>
  8. #include <boost/graph/adjacency_list.hpp>
  9. #include <boost/graph/dijkstra_shortest_paths.hpp>
  10. #include <boost/graph/graph_traits.hpp>
  11. #include <boost/graph/iteration_macros.hpp>
  12. #include <boost/graph/properties.hpp>
  13. #include <boost/property_map/property_map.hpp>
  14. #include <boost/program_options.hpp>
  15. #include <boost/format.hpp>
  16. #include <opencv2/opencv.hpp>
  17. #include <limits>
  18. #include <iostream>
  19. #include <fstream>
  20. #include <utility>
  21. #include <vector>
  22. // command line parameters
  23. struct Params {
  24. // filename of 3d point filen
  25. std::string strPointClouds;
  26. // file in which the results are saved
  27. std::string outputFilename;
  28. // max link distance
  29. double maxLinkDistance;
  30. // max angular distance
  31. double maxAngularDistance;
  32. // number of tracklets to be extracted
  33. size_t trackletCount;
  34. // number of allowed frames which can be skipped within one tracklet
  35. size_t allowedFrameSkip;
  36. };
  37. // each node contains this struct to provide information about the 3d point
  38. struct NodeInfo {
  39. // creates virtual marker
  40. NodeInfo() {
  41. this->position = cv::Point3d(0, 0, 0);
  42. this->frame = std::numeric_limits<size_t>::max();
  43. }
  44. // create normal marker info
  45. NodeInfo(const cv::Point3d &_position, const size_t &_frame) {
  46. this->position = _position;
  47. this->frame = _frame;
  48. }
  49. //
  50. bool isVirtual() {
  51. return (this->frame == std::numeric_limits<size_t>::max());
  52. }
  53. //
  54. cv::Point3d position;
  55. size_t frame;
  56. };
  57. // get command line parameters
  58. bool evalCmdLine(int argc, char **argv, Params &p) {
  59. // define parameters
  60. boost::program_options::options_description desc("Allowed options");
  61. desc.add_options()
  62. ("help", "produce help message")
  63. ("pointFile,p",
  64. boost::program_options::value< std::string >(),
  65. "3d point clouds file containing the detections for each frame")
  66. ("outputFile,o",
  67. boost::program_options::value< std::string >(),
  68. "output file for the generated tracklets")
  69. ("trackletCount,c",
  70. boost::program_options::value< size_t >()->default_value(1),
  71. "number of tracklets to be extracted")
  72. ("maxLinkDistance,d",
  73. boost::program_options::value< double >()->default_value(1.0),
  74. "maximum Euclidean distance (in px) allowed for two detections to get linked")
  75. ("maxAngularDistance,a",
  76. boost::program_options::value< double >()->default_value(20.0),
  77. "maximum angular distance (in deg) allowed for two detections to get linked")
  78. ("allowedFrameSkip,s",
  79. boost::program_options::value< size_t >()->default_value(1),
  80. "number of allowed frames which can be skipped within one tracklet (>= 1)")
  81. ;
  82. // parse parameters
  83. boost::program_options::variables_map vm;
  84. boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
  85. boost::program_options::notify(vm);
  86. if (vm.count("help")) {
  87. std::cout << desc << std::endl;
  88. exit(EXIT_SUCCESS);
  89. }
  90. // check parameters
  91. if (vm.count("pointFile")) {
  92. p.strPointClouds = vm["pointFile"].as< std::string >();
  93. } else {
  94. std::cerr << "No points file passed!" << std::endl;
  95. std::cout << desc << std::endl;
  96. exit(EXIT_SUCCESS);
  97. }
  98. if (vm.count("outputFile")) {
  99. p.outputFilename = vm["outputFile"].as< std::string >();
  100. } else {
  101. std::cerr << "No output file passed!" << std::endl;
  102. std::cout << desc << std::endl;
  103. exit(EXIT_SUCCESS);
  104. }
  105. p.maxLinkDistance = vm["maxLinkDistance"].as< double >();
  106. p.maxAngularDistance = vm["maxAngularDistance"].as< double >();
  107. p.trackletCount = vm["trackletCount"].as< size_t >();
  108. p.allowedFrameSkip = vm["allowedFrameSkip"].as< size_t >();
  109. return true;
  110. }
  111. void readPoints3d(const std::string &filename,
  112. std::vector< std::vector< cv::Point3d > > &clouds) {
  113. std::cout << "Reading points from file " << filename << std::endl;
  114. std::ifstream pointFile(filename.c_str(), std::ios_base::in);
  115. if (!pointFile.is_open()) {
  116. std::cerr << "Could not open file " << std::endl;
  117. return;
  118. }
  119. uint frame = 0;
  120. uint detections = 0;
  121. std::string line;
  122. while (std::getline(pointFile, line)) {
  123. std::cerr << "\rReading points of frame " << frame + 1 << "... ";
  124. std::vector< cv::Point3d > cloud;
  125. std::stringstream split(line + " ");
  126. double tmpValue;
  127. int tmpDim = 0;
  128. cv::Point3d tmpPoint;
  129. while ((split >> tmpValue).good()) {
  130. switch (tmpDim) {
  131. case 0:
  132. tmpPoint.x = tmpValue;
  133. break;
  134. case 1:
  135. tmpPoint.y = tmpValue;
  136. break;
  137. case 2:
  138. tmpPoint.z = tmpValue;
  139. cloud.push_back(tmpPoint);
  140. //std::cout << cv::Mat(tmpPoint) << std::endl;
  141. detections++;
  142. break;
  143. }
  144. tmpDim = (tmpDim + 1) % 3;
  145. }
  146. clouds.push_back(cloud);
  147. std::cout << cloud.size() << std::flush;
  148. frame++;
  149. }
  150. uint nFrames = clouds.size();
  151. std::cerr << std::endl << "Read " << nFrames << " frames (" << detections << " detections)" << std::endl;
  152. }
  153. void createTracklets(const std::vector< std::vector< cv::Point3d > > &clouds, const Params &params) {
  154. typedef double Weight;
  155. typedef boost::property< boost::edge_weight_t, Weight > WeightProperty;
  156. // typedef boost::property< boost::vertex_name_t, std::string > NameProperty;
  157. typedef boost::property< boost::vertex_name_t, NodeInfo > NameProperty;
  158. typedef boost::adjacency_list<
  159. boost::listS,
  160. boost::vecS,
  161. boost::directedS,
  162. NameProperty,
  163. WeightProperty > Graph;
  164. typedef boost::graph_traits< Graph >::vertex_descriptor Vertex;
  165. typedef boost::property_map< Graph, boost::vertex_index_t >::type IndexMap;
  166. typedef boost::property_map< Graph, boost::vertex_name_t >::type NameMap;
  167. typedef boost::iterator_property_map< Vertex*, IndexMap, Vertex, Vertex& > PredecessorMap;
  168. typedef boost::iterator_property_map< Weight*, IndexMap, Weight, Weight& > DistanceMap;
  169. // Create a graph
  170. Graph g;
  171. std::vector< std::vector< Vertex > > vertices;
  172. size_t frameStart = 0;
  173. size_t frameMax = clouds.size();
  174. // frameMax = 900;
  175. // adding vertices
  176. for (size_t frame = frameStart; frame < frameMax; ++frame) {
  177. std::cout << "\rAdding layer for frame " << frame + 1; // << std::flush;
  178. std::vector< cv::Point3d > p = clouds[frame];
  179. std::vector< Vertex > layer;
  180. for (size_t marker = 0; marker < p.size(); ++marker) {
  181. Vertex v = boost::add_vertex(NodeInfo(p[marker], frame), g);
  182. layer.push_back(v);
  183. }
  184. vertices.push_back(layer);
  185. std::cout << ": " << p.size() << ", " << layer.size() << ", " << vertices.rbegin()->size() << std::flush;
  186. }
  187. // virtual source and sink
  188. Vertex vSource = boost::add_vertex(NodeInfo(), g);
  189. Vertex vSink = boost::add_vertex(NodeInfo(), g);
  190. NameMap nameMap = boost::get(boost::vertex_name, g);
  191. std::cout << std::endl;
  192. // adding edges (layer eq frame)
  193. for (size_t iLayers = 0; iLayers < vertices.size(); ++iLayers) {
  194. // all points of frame "iLayers"
  195. std::vector< Vertex > p = vertices[iLayers];
  196. // for each point of layer "iLayers"
  197. for (size_t iP = 0; iP < p.size(); ++iP) {
  198. Vertex vP = p[iP];
  199. // create edges to source and sink
  200. std::cout << "\rAdding edges " << iLayers << "-> vSink" << std::flush;
  201. if (iLayers <= 100)
  202. boost::add_edge(vSource, vP, (iLayers + 1) * (params.maxLinkDistance + params.maxAngularDistance), g);
  203. if (iLayers + 100 >= vertices.size())
  204. boost::add_edge(vP, vSink, (vertices.size() - iLayers) * (params.maxLinkDistance + params.maxAngularDistance), g);
  205. // create shortcuts to next-next layers
  206. for (size_t iOffset = 1; iOffset <= params.allowedFrameSkip; ++iOffset) {
  207. if (iLayers + iOffset < vertices.size() - 1) {
  208. std::cout << "\rAdding edges for frames " << iLayers << "->" << (iLayers + iOffset) << std::flush;
  209. // all points of frame "iLayers" + "iOffset"
  210. std::vector< Vertex > q = vertices[iLayers + iOffset];
  211. // for each node of neighboring layers (in time)
  212. for (size_t iQ = 0; iQ < q.size(); ++iQ) {
  213. Vertex vQ = q[iQ];
  214. // euclidean distance between iP and iQ
  215. cv::Point3d ptP = nameMap[vP].position;
  216. cv::Point3d ptQ = nameMap[vQ].position;
  217. double dx = ptP.x - ptQ.x;
  218. double dy = ptP.y - ptQ.y;
  219. double dz = ptP.z - ptQ.z;
  220. Weight distPosition = sqrt(dx * dx + dy * dy);
  221. Weight distAngular = std::max(0.0, abs(dz) - 5.0);
  222. // edge weight
  223. //std::cout << " x" << params.maxLinkDistance << "," << params.maxAngularDistance << "; " << distPosition << "," << distAngular << "," << iOffset << " = " << 0.1 * (distPosition + 0.5 * distAngular) * double(iOffset) << std::endl;
  224. if (distPosition < params.maxLinkDistance && distAngular < params.maxAngularDistance) {
  225. // if we discard one layer, the edge weight should be higher!
  226. boost::add_edge(vP, vQ, 0.1 * (distPosition + 0.5 * distAngular) * double(iOffset), g);
  227. //boost::add_edge(vP, vQ, 0.001 * Weight((1.0 + 0.33 * distPosition) * (1.0 + distAngular) * Weight(1.0 + iOffset)), g);
  228. //std::cout << "x" << params.maxAngularDistance << "," << distPosition << "," << distAngular << "," << iOffset << std::endl;
  229. //boost::add_edge(vP, vQ, Weight(dist * Weight(1 + 0.5 * iOffset)), g);
  230. // boost::add_edge(vP, vQ, Weight(dist), g);
  231. }
  232. }
  233. }
  234. }
  235. }
  236. }
  237. std::cout << std::endl;
  238. // Create things for Dijkstra
  239. std::vector< Vertex > predecessors(boost::num_vertices(g)); // To store parents
  240. std::vector< Weight > distances(boost::num_vertices(g)); // To store distances
  241. IndexMap indexMap = boost::get(boost::vertex_index, g);
  242. PredecessorMap predecessorMap(&predecessors[0], indexMap);
  243. DistanceMap distanceMap(&distances[0], indexMap);
  244. // output file
  245. std::ofstream f(params.outputFilename.c_str());
  246. // Compute shortest paths from input layer vertices to the sink
  247. for (size_t tracklet = 0; tracklet < params.trackletCount; ++tracklet) {
  248. boost::dijkstra_shortest_paths(g, // the graph
  249. vSource, // the source vertex
  250. boost::distance_map(distanceMap).predecessor_map(predecessorMap));
  251. // Output results
  252. // std::cout << "distances and parents:" << std::endl;
  253. // NameMap nameMap = boost::get(boost::vertex_name, g);
  254. // BGL_FORALL_VERTICES(v, g, Graph) {
  255. // for (size_t i = 0; i < vertices.size(); ++i) {
  256. // for (size_t j = 0; j < vertices[i].size(); ++j) {
  257. // Vertex *v = &vertices[i][j];
  258. // std::cout << "distance(" << nameMap[vSink] << ", " << nameMap[*v] << ") = " << distanceMap[*v] << ", ";
  259. // std::cout << "predecessor(" << nameMap[*v] << ") = " << nameMap[predecessorMap[*v]] << std::endl;
  260. // }
  261. // }
  262. //
  263. // std::cout << std::endl;
  264. // Extract the shortest path
  265. typedef std::vector< Graph::edge_descriptor > PathType;
  266. PathType path;
  267. Vertex v = vSink; // We want to start at the sink and work our way back to the source
  268. for (Vertex u = predecessorMap[v]; u != v; v = u, u = predecessorMap[v]) {
  269. std::pair< Graph::edge_descriptor, bool > edgePair = boost::edge(u, v, g);
  270. Graph::edge_descriptor edge = edgePair.first;
  271. path.push_back(edge);
  272. }
  273. // Write shortest path
  274. //int c = 0;
  275. bool vFirst = true;
  276. //std::cout << "Shortest path from vSource to vSink: " << std::endl;
  277. for (PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator != path.rend(); ++pathIterator) {
  278. // print all non-virtual nodes of this path
  279. if (!nameMap[boost::source(*pathIterator, g)].isVirtual()) {
  280. //std::cout << nameMap[boost::source(*pathIterator, g)].position << " -> " << nameMap[boost::target(*pathIterator, g)].position
  281. // << " = "
  282. // << boost::get(boost::edge_weight, g, *pathIterator) << std::endl;
  283. f << nameMap[boost::source(*pathIterator, g)].position.x << " "
  284. << nameMap[boost::source(*pathIterator, g)].position.y << " "
  285. << nameMap[boost::source(*pathIterator, g)].position.z << " "
  286. << nameMap[boost::source(*pathIterator, g)].frame << " ";
  287. }
  288. // for each node of the path, set the weights of all outgoing edges to Inf (for Dijkstra equivalent to deletion of the node)
  289. if (!vFirst) {
  290. std::pair<Graph::out_edge_iterator, Graph::out_edge_iterator> edgeIts = boost::out_edges(boost::source(*pathIterator, g), g);
  291. //size_t nEdges = 0;
  292. for (Graph::out_edge_iterator edgeIt = edgeIts.first; edgeIt != edgeIts.second; edgeIt++) {
  293. boost::get(boost::edge_weight, g, *edgeIt) = std::numeric_limits<Weight>::infinity();
  294. //std::cout << "w = " << boost::get(boost::edge_weight, g, *edgeIt) << std::endl;
  295. //nEdges++;
  296. }
  297. //std::cout << "Found " << nEdges << " out edges for this node" << std::endl;
  298. //getchar();
  299. }
  300. vFirst = false;
  301. }
  302. f << "\n";
  303. std::cout << "Found tracklet #" << tracklet + 1 << "/" << params.trackletCount << ": " << path.size() << " nodes, distance: " << distanceMap[vSink] << std::endl;
  304. }
  305. f.close();
  306. }
  307. int main(int argc, char** argv) {
  308. // get command line parameters
  309. Params p;
  310. if (!evalCmdLine(argc, argv, p)) {
  311. std::cerr << "Error while parsing arguments!" << std::endl;
  312. return 1;
  313. }
  314. std::vector< std::vector< cv::Point3d > > points3dLists;
  315. if (!p.strPointClouds.empty()) {
  316. readPoints3d(p.strPointClouds, points3dLists);
  317. }
  318. createTracklets(points3dLists, p);
  319. return EXIT_SUCCESS;
  320. }