preview2.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  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/graphviz.hpp>
  12. #include <boost/graph/iteration_macros.hpp>
  13. #include <boost/graph/properties.hpp>
  14. #include <boost/property_map/property_map.hpp>
  15. #include <boost/program_options.hpp>
  16. #include <boost/format.hpp>
  17. #include <opencv2/opencv.hpp>
  18. #include <limits>
  19. #include <iostream>
  20. #include <fstream>
  21. #include <utility>
  22. #include <vector>
  23. /**
  24. * command line parameters
  25. */
  26. // command line parameters
  27. struct Params {
  28. // filename of 3d point filen
  29. std::string strTracklets;
  30. // output filename
  31. std::string outputFilename;
  32. // number of tracklets to be extracted
  33. size_t trackCount;
  34. // maximum temporal distance (in frames) for two tracklets to get linked
  35. size_t maxTemporalDist;
  36. // maximum spatial distance (in mm) for two tracklets to get linked
  37. double maxSpatialDist;
  38. // minimum length of tracks to be selected
  39. double minTrackLength;
  40. };
  41. // get command line parameters
  42. bool evalCmdLine(int argc, char **argv, Params &p) {
  43. // define parameters
  44. boost::program_options::options_description desc("Allowed options");
  45. desc.add_options()
  46. ("help", "produce help message")
  47. ("trackletFile,t", boost::program_options::value< std::string >(), "tracklet input file (as generated by \"graphBasedTracklets\")")
  48. ("outputFile,o", boost::program_options::value< std::string >(), "output file")
  49. ("trackCount,c", boost::program_options::value< size_t >()->default_value(1), "number of tracks to be extracted")
  50. ("maxSpatialDist,d",
  51. boost::program_options::value< double >()->default_value(1.5),
  52. "maximum spatial distance (in mm) for two tracklets to get linked")
  53. ("maxTemporalDist,s",
  54. boost::program_options::value< size_t >()->default_value(150),
  55. "maximum temporal distance (in frames) for two tracklets to get linked")
  56. ("minTrackLength,l", boost::program_options::value< double >()->default_value(0.85), "minimum length of tracks to be selected (if value is <= 1, it is interpreted as fraction of the sequence length)")
  57. ;
  58. // parse parameters
  59. boost::program_options::variables_map vm;
  60. boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
  61. boost::program_options::notify(vm);
  62. if (vm.count("help") || vm.empty()) {
  63. std::cout << desc << std::endl;
  64. exit(EXIT_SUCCESS);
  65. }
  66. // default parameters
  67. if (vm.count("trackletFile")) {
  68. p.strTracklets = vm["trackletFile"].as< std::string >();
  69. } else {
  70. std::cerr << "No tracklet input file passed!\n";
  71. std::cout << desc << std::endl;
  72. exit(EXIT_SUCCESS);
  73. }
  74. if (vm.count("outputFile")) {
  75. p.outputFilename = vm["outputFile"].as< std::string >();
  76. } else {
  77. std::cerr << "No output file passed!" << std::endl;
  78. std::cout << desc << std::endl;
  79. exit(EXIT_SUCCESS);
  80. }
  81. p.trackCount = vm["trackCount"].as< size_t >();
  82. p.maxTemporalDist = vm["maxTemporalDist"].as< size_t >();
  83. p.maxSpatialDist = vm["maxSpatialDist"].as< double >();
  84. p.minTrackLength = vm["minTrackLength"].as< double >();
  85. return true;
  86. }
  87. /**
  88. * helper functions
  89. */
  90. double mean(const std::vector< double > &values) {
  91. if (values.size() == 0) {
  92. return 0.0;
  93. }
  94. double sum = 0.0;
  95. for (size_t k = 0; k < values.size(); k++) {
  96. sum += values[k];
  97. }
  98. return sum / double(values.size());
  99. }
  100. /**
  101. * tracklet handling
  102. */
  103. // tracklet class
  104. class Tracklet {
  105. public:
  106. // constructors
  107. Tracklet() {
  108. this->rawPoints.clear();
  109. this->ids.clear();
  110. }
  111. Tracklet(const Tracklet &tracklet) {
  112. this->rawPoints = tracklet.rawPoints;
  113. this->ids = tracklet.ids;
  114. }
  115. Tracklet& operator=(const Tracklet &tracklet) {
  116. this->rawPoints = tracklet.rawPoints;
  117. this->ids = tracklet.ids;
  118. return *this;
  119. }
  120. // getters/setters
  121. bool isVirtual() const {
  122. return this->rawPoints.empty();
  123. }
  124. std::string getIdString() const {
  125. std::stringstream ss;
  126. for (size_t k = 0; k < this->ids.size(); k++) {
  127. if (k > 0) {
  128. ss << ",";
  129. }
  130. ss << ids[k];
  131. }
  132. return ss.str();
  133. }
  134. std::vector< size_t > &getIds() {
  135. return this->ids;
  136. }
  137. const std::vector< size_t > &getIds() const {
  138. return this->ids;
  139. }
  140. void appendId(size_t _id) {
  141. this->ids.push_back(_id);
  142. }
  143. void appendIds(std::vector< size_t > _ids) {
  144. this->ids.insert(this->ids.end(), _ids.begin(), _ids.end());
  145. }
  146. size_t getFirstFrame() const {
  147. //return this->firstFrame;
  148. return this->rawPoints.begin()->first;
  149. }
  150. size_t getLastFrame() const {
  151. return this->rawPoints.rbegin()->first;
  152. }
  153. size_t getRange() const {
  154. return this->getLastFrame() - this->getFirstFrame() + 1;
  155. }
  156. const cv::Point3d &getFirstPoint() const {
  157. return this->rawPoints.begin()->second;
  158. }
  159. const cv::Point3d &getLastPoint() const {
  160. return this->rawPoints.rbegin()->second;
  161. }
  162. void printDebugInfo() const {
  163. std::cout << "=== DEBUG ===" << std::endl;
  164. std::cout << "IDs: " << this->getIdString() << std::endl;
  165. std::cout << "frames: (" << this->getFirstFrame() << "," << this->getLastFrame() << ")" << std::endl;
  166. std::cout << "raw point count: " << this->pRawPoints()->size() << std::endl;
  167. std::cout << "first point: " << this->rawPoints.begin()->second << std::endl;
  168. }
  169. void interpolatePoints(void) {
  170. for (std::map< size_t, cv::Point3d >::iterator it = this->rawPoints.begin();
  171. it != this->rawPoints.end(); ++it) {
  172. cv::Point3d p = it->second;
  173. // std::cout << it->first << p;
  174. std::map< size_t, cv::Point3d >::iterator itNext = it;
  175. std::advance(itNext, 1);
  176. if (itNext != this->rawPoints.end()) {
  177. size_t dT = itNext->first - it->first;
  178. cv::Point3d q = itNext->second;
  179. cv::Point3d v = (q - p) * (1.0 / (double)(dT));
  180. if (dT > 0) {
  181. for (size_t i = 1; i < dT; ++i) {
  182. // std::cout << " -> " << it->first + i << (p + v * (double)i);
  183. this->rawPoints.insert(std::make_pair(it->first + i, p + v * (double)i));
  184. }
  185. }
  186. }
  187. //std::cout << std::endl;
  188. }
  189. }
  190. const double getMatchingScore(const Tracklet &tracklet) {
  191. size_t tStart = std::max(this->getFirstFrame(), tracklet.getFirstFrame());
  192. size_t tEnd = std::min(this->getLastFrame(), tracklet.getLastFrame());
  193. int tDiff = tEnd - tStart;
  194. double tRatio = 2.0 * (double)tDiff / (double)(this->pRawPoints()->size() + tracklet.pRawPoints()->size() - 2);
  195. if (tRatio > 0.0) {
  196. const std::map< size_t, cv::Point3d >* p = this->pRawPoints();
  197. const std::map< size_t, cv::Point3d >* q = tracklet.pRawPoints();
  198. double dist = 0.0f;
  199. for (size_t i = tStart; i <= tEnd; ++i) {
  200. dist += cv::norm(p->at(i) - q->at(i));
  201. }
  202. dist /= (double)tDiff;
  203. return dist;
  204. } else {
  205. return std::numeric_limits< double >::max();
  206. }
  207. }
  208. const std::map< size_t, cv::Point3d >* pRawPoints() const {
  209. return &this->rawPoints;
  210. }
  211. void addPoint(size_t _frame, cv::Point3d &_point) {
  212. this->rawPoints[_frame] = _point;
  213. }
  214. void append(Tracklet &tracklet) {
  215. this->rawPoints.insert(tracklet.pRawPoints()->begin(), tracklet.pRawPoints()->end());
  216. this->appendIds(tracklet.getIds());
  217. }
  218. void getVelocities(std::vector< double > &velocities) {
  219. // clear object to be returned
  220. velocities = std::vector< double >(0);
  221. // need at least two points
  222. if (this->rawPoints.size() <= 1) {
  223. return;
  224. }
  225. // for consecutive points (in time), calculate magnitude of difference (a.k.a. velocity)
  226. for (std::map< size_t, cv::Point3d >::iterator it = this->rawPoints.begin(); it != this->rawPoints.end(); it++) {
  227. std::map< size_t, cv::Point3d >::iterator it2 = it;
  228. it2++;
  229. if (it2 != this->rawPoints.end()) {
  230. double dx = it->second.x - it2->second.x;
  231. double dy = it->second.y - it2->second.y;
  232. double v = sqrt(dx * dx + dy * dy);
  233. velocities.push_back(v);
  234. }
  235. }
  236. }
  237. // linking cost to another tracklet (assuming "this" comes before "target" in time)
  238. double linkingCost(Tracklet &target, const Params &params) {
  239. // temporal distance (if "target" does not start after "this" ends, linking is not possible)
  240. int dTemporal = int(target.getFirstFrame()) - this->getLastFrame();
  241. if ((dTemporal <= 0) || (dTemporal > int(params.maxTemporalDist))) {
  242. return std::numeric_limits< double >::infinity();
  243. }
  244. // distance between nearest end-points
  245. double dx = target.getFirstPoint().x - this->getLastPoint().x;
  246. double dy = target.getFirstPoint().y - this->getLastPoint().y;
  247. double dSpatial = sqrt(dx * dx + dy * dy);
  248. if (dSpatial > params.maxSpatialDist) {
  249. return std::numeric_limits< double >::infinity();
  250. }
  251. // angular distance between nearest end-points
  252. double dz = target.getFirstPoint().z - this->getLastPoint().z;
  253. double dAngular = std::max(0.0, abs(dz) - 5.0);
  254. if (dAngular > 25) {
  255. return std::numeric_limits< double >::infinity();
  256. }
  257. // difference between mean velocities
  258. std::vector< double > velocitiesThis, velocitiesTarget;
  259. this->getVelocities(velocitiesThis);
  260. target.getVelocities(velocitiesTarget);
  261. double dMeanVelocities = std::abs(mean(velocitiesThis) - mean(velocitiesTarget));
  262. //
  263. // final cost
  264. return 0.1 * double(dTemporal) * (dAngular + dSpatial + dMeanVelocities);
  265. }
  266. protected:
  267. std::map< size_t, cv::Point3d > rawPoints;
  268. std::vector< size_t > ids;
  269. };
  270. void mergeDuplicates(std::vector< Tracklet > &tracklets, const double maxScore = 2.0) {
  271. // iterate over all tracklets
  272. for (std::vector< Tracklet >::iterator it1 = tracklets.begin(); it1 != tracklets.end(); ++it1) {
  273. // get maximum time span
  274. size_t tMin = it1->getFirstFrame();
  275. size_t tMax = it1->getLastFrame();
  276. // collect tracklets to be merged
  277. std::vector< std::vector< Tracklet >::iterator > toBeMerged;
  278. // first one by default
  279. toBeMerged.push_back(it1);
  280. // iterate over all succeeding tracklets
  281. for (std::vector< Tracklet >::iterator it2 = it1 + 1; it2 != tracklets.end(); ++it2) {
  282. double match = it1->getMatchingScore(*it2);
  283. if (match < maxScore) {
  284. /*
  285. std::cout
  286. << std::distance(tracklets.begin(), it1) << " " << it1->getIdString() << " -> "
  287. << std::distance(tracklets.begin(), it2) << " " << it2->getIdString() << ": "
  288. << match << std::endl;
  289. */
  290. // update time span
  291. tMin = std::min(tMin, it2->getFirstFrame());
  292. tMax = std::max(tMax, it2->getLastFrame());
  293. // add to merge candidates
  294. toBeMerged.push_back(it2);
  295. }
  296. }
  297. if (toBeMerged.size() > 1) {
  298. std::cout << "Merging " << toBeMerged.size() << " tracks!" << std::endl;
  299. //std::cout << "tMin: " << tMin << ", tMax: " << tMax << std::endl;
  300. // our new tracklet
  301. Tracklet mergedTracklet;
  302. // iterate over complete time span
  303. for (size_t t = tMin; t <= tMax; ++t) {
  304. cv::Point3d p;
  305. size_t nP = 0;
  306. // get point for current time step of each merging candidate
  307. for (size_t i = 0; i < toBeMerged.size(); ++i) {
  308. std::map< size_t, cv::Point3d >::const_iterator itT = toBeMerged[i]->pRawPoints()->find(t);
  309. if (itT != toBeMerged[i]->pRawPoints()->end()) {
  310. p = p + itT->second;
  311. ++nP;
  312. }
  313. }
  314. // result is the average of all candidate points
  315. p *= 1.0 / (double)nP;
  316. // add to new tracklet
  317. mergedTracklet.addPoint(t, p);
  318. }
  319. // delete merged tracks
  320. for (int i = toBeMerged.size() - 1; i >= 0; --i) {
  321. mergedTracklet.appendIds(toBeMerged[i]->getIds());
  322. if (i > 0) {
  323. tracklets.erase(toBeMerged[i]);
  324. }
  325. }
  326. // replace first tracklet by the merged one
  327. *it1 = mergedTracklet;
  328. }
  329. }
  330. }
  331. void readTracklets(const std::string &filename,
  332. std::vector< Tracklet > &tracklets,
  333. size_t &nFrames) {
  334. // open file
  335. std::cout << "Reading tracklets from file " << filename << std::endl;
  336. std::ifstream pointFile(filename.c_str(), std::ios_base::in);
  337. if (!pointFile.is_open()) {
  338. std::cerr << "Could not open file " << std::endl;
  339. return;
  340. }
  341. // result object
  342. tracklets.clear();
  343. // read in all 3d points
  344. std::string line;
  345. // for each line...
  346. nFrames = 0;
  347. size_t id = 0;
  348. while (std::getline(pointFile, line)) {
  349. // print current frame number
  350. //std::cerr << "\rReading points... " << std::flush;
  351. // points of the current frame
  352. std::vector< cv::Point3d > tracklet;
  353. // read 3d points for each camera
  354. Tracklet tmpTracklet;
  355. tmpTracklet.appendId(id++);
  356. std::stringstream split(line);
  357. cv::Point3d tmpPoint;
  358. size_t frame = 0;
  359. // for each point...
  360. while (split.good()) {
  361. // read all points of this line
  362. if ((split >> tmpPoint.x >> tmpPoint.y >> tmpPoint.z >> frame).good()) {
  363. tmpTracklet.addPoint(frame, tmpPoint);
  364. // update global frame count
  365. nFrames = std::max(nFrames, tmpTracklet.getLastFrame() + 1);
  366. }
  367. }
  368. // add tracklet to list
  369. tmpTracklet.interpolatePoints();
  370. tracklets.push_back(tmpTracklet);
  371. }
  372. uint nTracklets = tracklets.size();
  373. std::cerr << std::endl << "Read " << nTracklets << " tracklets" << std::endl;
  374. // merge duplicate tracklets
  375. mergeDuplicates(tracklets);
  376. nTracklets = tracklets.size();
  377. std::cerr << std::endl << "Merged to " << nTracklets << " tracklets" << std::endl;
  378. }
  379. /**
  380. * graph-based typedefs
  381. */
  382. typedef double Weight;
  383. typedef boost::property< boost::edge_weight_t, Weight > WeightProperty;
  384. typedef boost::property< boost::vertex_name_t, Tracklet > NameProperty;
  385. typedef boost::adjacency_list<
  386. boost::listS,
  387. boost::vecS,
  388. boost::directedS,
  389. NameProperty,
  390. WeightProperty > Graph;
  391. typedef boost::graph_traits< Graph >::vertex_descriptor Vertex;
  392. typedef boost::property_map< Graph, boost::vertex_index_t >::type IndexMap;
  393. typedef boost::property_map< Graph, boost::vertex_name_t >::type NameMap;
  394. typedef boost::iterator_property_map< Vertex*, IndexMap, Vertex, Vertex& > PredecessorMap;
  395. typedef boost::iterator_property_map< Weight*, IndexMap, Weight, Weight& > DistanceMap;
  396. //
  397. template< class G >
  398. class VertexWriter {
  399. public:
  400. VertexWriter(G _g) :
  401. g(_g) {
  402. this->nameMap = boost::get(boost::vertex_name, g);
  403. }
  404. template< class VertexOrEdge >
  405. void operator()(std::ostream& out, const VertexOrEdge& v) const {
  406. if (nameMap[v].isVirtual()) {
  407. out << "[label=\"" << nameMap[v].getIdString() << "\",shape=\"circle\"]";
  408. } else {
  409. out << "[label=\"" << nameMap[v].getIdString() << ":\\n(" << nameMap[v].getFirstFrame() << ","
  410. << nameMap[v].getLastFrame() << ")\",shape=\"box\"]";
  411. }
  412. //
  413. }
  414. private:
  415. G g;
  416. NameMap nameMap;
  417. };
  418. //
  419. template< class G >
  420. class EdgeWriter {
  421. public:
  422. EdgeWriter(G _g) :
  423. g(_g) {
  424. }
  425. template< class VertexOrEdge >
  426. void operator()(std::ostream& out, const VertexOrEdge& v) const {
  427. out << "[label=\"" << boost::get(boost::edge_weight, g, v) << "\"]";
  428. }
  429. private:
  430. G g;
  431. };
  432. // tracklet graph to dot file
  433. void trackletsToDot(std::string filename, const Graph &g) {
  434. std::cout << "Writing graph to file \"" << filename << "\"" << std::endl;
  435. std::ofstream graphFile(filename.c_str());
  436. if (!graphFile.is_open()) {
  437. std::cerr << "Could not open file \"" << filename << "\"" << std::endl;
  438. return;
  439. }
  440. VertexWriter< Graph > vertexWriter(g);
  441. EdgeWriter< Graph > edgeWriter(g);
  442. boost::write_graphviz(graphFile, g, vertexWriter, edgeWriter);
  443. graphFile.close();
  444. }
  445. /**
  446. * main tracking functions
  447. */
  448. // nFrames: global frame count (needed to calculated weights to vSink)
  449. // return tracks
  450. void createTracksFromTracklets(const std::vector< Tracklet > &tracklets,
  451. const Params &params,
  452. const size_t nFrames,
  453. std::vector< Tracklet > &tracks) {
  454. //
  455. // build graph
  456. //
  457. Graph g;
  458. std::vector< Vertex > vertices;
  459. size_t trackletStart = 0;
  460. size_t trackletMax = tracklets.size();
  461. // adding vertices
  462. for (size_t iTracklet = trackletStart; iTracklet < trackletMax; ++iTracklet) {
  463. std::cout << "\rAdding node for tracklet " << iTracklet + 1 << std::flush;
  464. Vertex v = boost::add_vertex(tracklets[iTracklet], g);
  465. vertices.push_back(v);
  466. }
  467. // virtual source and sink
  468. Vertex vSource = boost::add_vertex(Tracklet(), g);
  469. Vertex vSink = boost::add_vertex(Tracklet(), g);
  470. // debug
  471. ///boost::add_edge(vSource, vSink, 0, g);
  472. NameMap nameMap = boost::get(boost::vertex_name, g);
  473. std::cout << std::endl;
  474. // adding edges (layer eq tracklets)
  475. for (size_t iTracklet = 0; iTracklet < vertices.size(); ++iTracklet) {
  476. // all points of frame "iLayers"
  477. Vertex tracklet1 = vertices[iTracklet];
  478. // create edges to source and sink
  479. std::cout << "\rAdding edges vSource -> " << iTracklet + 1 << " -> vSink" << std::flush;
  480. boost::add_edge(vSource, tracklet1, (nameMap[tracklet1].getFirstFrame() + 1) * 1, g);
  481. boost::add_edge(tracklet1, vSink, (nFrames - nameMap[tracklet1].getLastFrame()) * 1, g);
  482. for (size_t jTracklet = 0; jTracklet < vertices.size(); ++jTracklet) {
  483. // get second tracklet for linking
  484. Vertex tracklet2 = vertices[jTracklet];
  485. // this is where the magic happens... the cost function!
  486. double ijCost = nameMap[tracklet1].linkingCost(nameMap[tracklet2], params);
  487. // create edge between both nodes
  488. if (ijCost < std::numeric_limits< double >::infinity()) {
  489. boost::add_edge(tracklet1, tracklet2, ijCost, g);
  490. }
  491. }
  492. }
  493. std::cout << std::endl;
  494. //
  495. // find tracks (shortest paths in tracklet graph)
  496. //
  497. // Create things for Dijkstra
  498. std::vector< Vertex > predecessors(boost::num_vertices(g)); // To store parents
  499. std::vector< Weight > distances(boost::num_vertices(g)); // To store distances
  500. IndexMap indexMap = boost::get(boost::vertex_index, g);
  501. PredecessorMap predecessorMap(&predecessors[0], indexMap);
  502. DistanceMap distanceMap(&distances[0], indexMap);
  503. // export graph to graphviz dot file
  504. //trackletsToDot("tmp2.dot", g);
  505. // each track consists of merged tracklets (which in turn is again a tracklet)
  506. tracks.clear();
  507. // Compute shortest paths from input layer vertices to the sink
  508. for (size_t tracklet = 0; tracklet < params.trackCount; ++tracklet) {
  509. // preparations for Dijkstra
  510. boost::dijkstra_shortest_paths(g, // the graph
  511. vSource, // the source vertex
  512. boost::distance_map(distanceMap).predecessor_map(predecessorMap));
  513. // stop if no more tracks can be found
  514. if (distanceMap[vSink] == std::numeric_limits<double>::max()) {
  515. std::cout << "No more tracks can be found" << std::endl;
  516. break;
  517. }
  518. // Extract the shortest path
  519. typedef std::vector< Graph::edge_descriptor > PathType;
  520. PathType path;
  521. Vertex v = vSink; // We want to start at the sink and work our way back to the source
  522. for (Vertex u = predecessorMap[v]; u != v; v = u, u = predecessorMap[v]) {
  523. std::pair< Graph::edge_descriptor, bool > edgePair = boost::edge(u, v, g);
  524. Graph::edge_descriptor edge = edgePair.first;
  525. path.push_back(edge);
  526. }
  527. // traverse shortest path (actually: traverse reverse path in a reverse direction)
  528. Tracklet currentTrack;
  529. bool vFirst = true;
  530. for (PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator != path.rend(); ++pathIterator) {
  531. // append non-virtual tracklets to this path
  532. if (!nameMap[boost::source(*pathIterator, g)].isVirtual()) {
  533. currentTrack.append(nameMap[boost::source(*pathIterator, g)]);
  534. }
  535. // for each node of the path (but not the first, i.e. vSource), set the weights of all outgoing edges to Inf (for Dijkstra equivalent to deletion of the node)
  536. if (!vFirst) {
  537. std::pair< Graph::out_edge_iterator, Graph::out_edge_iterator > edgeIts = boost::out_edges(boost::source(*pathIterator,
  538. g),
  539. g);
  540. for (Graph::out_edge_iterator edgeIt = edgeIts.first; edgeIt != edgeIts.second; edgeIt++) {
  541. boost::get(boost::edge_weight, g, *edgeIt) = std::numeric_limits< Weight >::infinity();
  542. }
  543. }
  544. vFirst = false;
  545. }
  546. // interpolate
  547. currentTrack.interpolatePoints();
  548. tracks.push_back(currentTrack);
  549. std::cout << "Found track #" << tracklet + 1 << "/" << params.trackCount << ": " << path.size() - 1 << " tracklet(s), cost: "
  550. << distanceMap[vSink] << std::endl;
  551. }
  552. // merge duplicate tracks
  553. mergeDuplicates(tracks);
  554. std::cerr << std::endl << "Merged to " << tracks.size() << " tracks" << std::endl;
  555. }
  556. void writeTracks(std::string filename, std::vector< Tracklet > &tracks, size_t nFrames, double minTrackLength) {
  557. // open file
  558. std::ofstream f(filename.c_str());
  559. // get minimum track length
  560. size_t minLength;
  561. if (minTrackLength <= 1.0) {
  562. minLength = std::min(size_t(minTrackLength * double(nFrames)), nFrames);
  563. } else {
  564. minLength = std::min(size_t(minTrackLength), nFrames);
  565. }
  566. // print each track
  567. size_t finalCount = 0;
  568. for (size_t track = 0; track < tracks.size(); ++track) {
  569. if (tracks[track].getRange() >= minLength) {
  570. const std::map< size_t, cv::Point3d > *p = tracks[track].pRawPoints();
  571. for (std::map< size_t, cv::Point3d >::const_iterator it = p->begin(); it != p->end(); it++) {
  572. f << it->second.x << " " << it->second.y << " " << it->second.z << " " << it->first << " ";
  573. }
  574. //f << tracks[track].getIdString()
  575. f << std::endl;
  576. finalCount++;
  577. }
  578. }
  579. f.close();
  580. std::cout << finalCount << " tracks with length >= " << minLength << " were found" << std::endl;
  581. }
  582. int main(int argc, char** argv) {
  583. // get command line parameters
  584. Params p;
  585. if (!evalCmdLine(argc, argv, p)) {
  586. std::cerr << "Error while parsing arguments!" << std::endl;
  587. return 1;
  588. }
  589. size_t nFrames;
  590. std::vector< Tracklet > tracklets, tracks;
  591. readTracklets(p.strTracklets, tracklets, nFrames);
  592. createTracksFromTracklets(tracklets, p, nFrames, tracks);
  593. writeTracks(p.outputFilename, tracks, nFrames, p.minTrackLength);
  594. return EXIT_SUCCESS;
  595. }