123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- /*
- * markerAssociationDP.cpp
- *
- * Created on: Feb 6, 2013
- * Author: koerner
- */
- #include <boost/config.hpp>
- #include <boost/graph/adjacency_list.hpp>
- #include <boost/graph/dijkstra_shortest_paths.hpp>
- #include <boost/graph/graph_traits.hpp>
- #include <boost/graph/graphviz.hpp>
- #include <boost/graph/iteration_macros.hpp>
- #include <boost/graph/properties.hpp>
- #include <boost/property_map/property_map.hpp>
- #include <boost/program_options.hpp>
- #include <boost/format.hpp>
- #include <opencv2/opencv.hpp>
- #include <limits>
- #include <iostream>
- #include <fstream>
- #include <utility>
- #include <vector>
- /**
- * command line parameters
- */
- // command line parameters
- struct Params {
- // filename of 3d point filen
- std::string strTracklets;
- // output filename
- std::string outputFilename;
- // number of tracklets to be extracted
- size_t trackCount;
- // maximum temporal distance (in frames) for two tracklets to get linked
- size_t maxTemporalDist;
- // maximum spatial distance (in mm) for two tracklets to get linked
- double maxSpatialDist;
- // minimum length of tracks to be selected
- double minTrackLength;
- };
- // get command line parameters
- bool evalCmdLine(int argc, char **argv, Params &p) {
- // define parameters
- boost::program_options::options_description desc("Allowed options");
- desc.add_options()
- ("help", "produce help message")
- ("trackletFile,t", boost::program_options::value< std::string >(), "tracklet input file (as generated by \"graphBasedTracklets\")")
- ("outputFile,o", boost::program_options::value< std::string >(), "output file")
- ("trackCount,c", boost::program_options::value< size_t >()->default_value(1), "number of tracks to be extracted")
- ("maxSpatialDist,d",
- boost::program_options::value< double >()->default_value(1.5),
- "maximum spatial distance (in mm) for two tracklets to get linked")
- ("maxTemporalDist,s",
- boost::program_options::value< size_t >()->default_value(150),
- "maximum temporal distance (in frames) for two tracklets to get linked")
- ("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)")
- ;
- // parse parameters
- boost::program_options::variables_map vm;
- boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
- boost::program_options::notify(vm);
- if (vm.count("help") || vm.empty()) {
- std::cout << desc << std::endl;
- exit(EXIT_SUCCESS);
- }
- // default parameters
- if (vm.count("trackletFile")) {
- p.strTracklets = vm["trackletFile"].as< std::string >();
- } else {
- std::cerr << "No tracklet input file passed!\n";
- std::cout << desc << std::endl;
- exit(EXIT_SUCCESS);
- }
- if (vm.count("outputFile")) {
- p.outputFilename = vm["outputFile"].as< std::string >();
- } else {
- std::cerr << "No output file passed!" << std::endl;
- std::cout << desc << std::endl;
- exit(EXIT_SUCCESS);
- }
- p.trackCount = vm["trackCount"].as< size_t >();
- p.maxTemporalDist = vm["maxTemporalDist"].as< size_t >();
- p.maxSpatialDist = vm["maxSpatialDist"].as< double >();
- p.minTrackLength = vm["minTrackLength"].as< double >();
- return true;
- }
- /**
- * helper functions
- */
- double mean(const std::vector< double > &values) {
- if (values.size() == 0) {
- return 0.0;
- }
- double sum = 0.0;
- for (size_t k = 0; k < values.size(); k++) {
- sum += values[k];
- }
- return sum / double(values.size());
- }
- /**
- * tracklet handling
- */
- // tracklet class
- class Tracklet {
- public:
- // constructors
- Tracklet() {
- this->rawPoints.clear();
- this->ids.clear();
- }
- Tracklet(const Tracklet &tracklet) {
- this->rawPoints = tracklet.rawPoints;
- this->ids = tracklet.ids;
- }
- Tracklet& operator=(const Tracklet &tracklet) {
- this->rawPoints = tracklet.rawPoints;
- this->ids = tracklet.ids;
- return *this;
- }
- // getters/setters
- bool isVirtual() const {
- return this->rawPoints.empty();
- }
- std::string getIdString() const {
- std::stringstream ss;
- for (size_t k = 0; k < this->ids.size(); k++) {
- if (k > 0) {
- ss << ",";
- }
- ss << ids[k];
- }
- return ss.str();
- }
- std::vector< size_t > &getIds() {
- return this->ids;
- }
- const std::vector< size_t > &getIds() const {
- return this->ids;
- }
- void appendId(size_t _id) {
- this->ids.push_back(_id);
- }
- void appendIds(std::vector< size_t > _ids) {
- this->ids.insert(this->ids.end(), _ids.begin(), _ids.end());
- }
- size_t getFirstFrame() const {
- //return this->firstFrame;
- return this->rawPoints.begin()->first;
- }
- size_t getLastFrame() const {
- return this->rawPoints.rbegin()->first;
- }
- size_t getRange() const {
- return this->getLastFrame() - this->getFirstFrame() + 1;
- }
- const cv::Point3d &getFirstPoint() const {
- return this->rawPoints.begin()->second;
- }
- const cv::Point3d &getLastPoint() const {
- return this->rawPoints.rbegin()->second;
- }
- void printDebugInfo() const {
- std::cout << "=== DEBUG ===" << std::endl;
- std::cout << "IDs: " << this->getIdString() << std::endl;
- std::cout << "frames: (" << this->getFirstFrame() << "," << this->getLastFrame() << ")" << std::endl;
- std::cout << "raw point count: " << this->pRawPoints()->size() << std::endl;
- std::cout << "first point: " << this->rawPoints.begin()->second << std::endl;
- }
- void interpolatePoints(void) {
- for (std::map< size_t, cv::Point3d >::iterator it = this->rawPoints.begin();
- it != this->rawPoints.end(); ++it) {
- cv::Point3d p = it->second;
- // std::cout << it->first << p;
- std::map< size_t, cv::Point3d >::iterator itNext = it;
- std::advance(itNext, 1);
- if (itNext != this->rawPoints.end()) {
- size_t dT = itNext->first - it->first;
- cv::Point3d q = itNext->second;
- cv::Point3d v = (q - p) * (1.0 / (double)(dT));
- if (dT > 0) {
- for (size_t i = 1; i < dT; ++i) {
- // std::cout << " -> " << it->first + i << (p + v * (double)i);
- this->rawPoints.insert(std::make_pair(it->first + i, p + v * (double)i));
- }
- }
- }
- //std::cout << std::endl;
- }
- }
- const double getMatchingScore(const Tracklet &tracklet) {
- size_t tStart = std::max(this->getFirstFrame(), tracklet.getFirstFrame());
- size_t tEnd = std::min(this->getLastFrame(), tracklet.getLastFrame());
- int tDiff = tEnd - tStart;
- double tRatio = 2.0 * (double)tDiff / (double)(this->pRawPoints()->size() + tracklet.pRawPoints()->size() - 2);
- if (tRatio > 0.0) {
- const std::map< size_t, cv::Point3d >* p = this->pRawPoints();
- const std::map< size_t, cv::Point3d >* q = tracklet.pRawPoints();
- double dist = 0.0f;
- for (size_t i = tStart; i <= tEnd; ++i) {
- dist += cv::norm(p->at(i) - q->at(i));
- }
- dist /= (double)tDiff;
- return dist;
- } else {
- return std::numeric_limits< double >::max();
- }
- }
- const std::map< size_t, cv::Point3d >* pRawPoints() const {
- return &this->rawPoints;
- }
- void addPoint(size_t _frame, cv::Point3d &_point) {
- this->rawPoints[_frame] = _point;
- }
- void append(Tracklet &tracklet) {
- this->rawPoints.insert(tracklet.pRawPoints()->begin(), tracklet.pRawPoints()->end());
- this->appendIds(tracklet.getIds());
- }
- void getVelocities(std::vector< double > &velocities) {
- // clear object to be returned
- velocities = std::vector< double >(0);
- // need at least two points
- if (this->rawPoints.size() <= 1) {
- return;
- }
- // for consecutive points (in time), calculate magnitude of difference (a.k.a. velocity)
- for (std::map< size_t, cv::Point3d >::iterator it = this->rawPoints.begin(); it != this->rawPoints.end(); it++) {
- std::map< size_t, cv::Point3d >::iterator it2 = it;
- it2++;
- if (it2 != this->rawPoints.end()) {
- double dx = it->second.x - it2->second.x;
- double dy = it->second.y - it2->second.y;
- double v = sqrt(dx * dx + dy * dy);
- velocities.push_back(v);
- }
- }
- }
- // linking cost to another tracklet (assuming "this" comes before "target" in time)
- double linkingCost(Tracklet &target, const Params ¶ms) {
- // temporal distance (if "target" does not start after "this" ends, linking is not possible)
- int dTemporal = int(target.getFirstFrame()) - this->getLastFrame();
- if ((dTemporal <= 0) || (dTemporal > int(params.maxTemporalDist))) {
- return std::numeric_limits< double >::infinity();
- }
- // distance between nearest end-points
- double dx = target.getFirstPoint().x - this->getLastPoint().x;
- double dy = target.getFirstPoint().y - this->getLastPoint().y;
- double dSpatial = sqrt(dx * dx + dy * dy);
- if (dSpatial > params.maxSpatialDist) {
- return std::numeric_limits< double >::infinity();
- }
- // angular distance between nearest end-points
- double dz = target.getFirstPoint().z - this->getLastPoint().z;
- double dAngular = std::max(0.0, abs(dz) - 5.0);
- if (dAngular > 25) {
- return std::numeric_limits< double >::infinity();
- }
- // difference between mean velocities
- std::vector< double > velocitiesThis, velocitiesTarget;
- this->getVelocities(velocitiesThis);
- target.getVelocities(velocitiesTarget);
- double dMeanVelocities = std::abs(mean(velocitiesThis) - mean(velocitiesTarget));
- //
- // final cost
- return 0.1 * double(dTemporal) * (dAngular + dSpatial + dMeanVelocities);
- }
- protected:
- std::map< size_t, cv::Point3d > rawPoints;
- std::vector< size_t > ids;
- };
- void mergeDuplicates(std::vector< Tracklet > &tracklets, const double maxScore = 2.0) {
- // iterate over all tracklets
- for (std::vector< Tracklet >::iterator it1 = tracklets.begin(); it1 != tracklets.end(); ++it1) {
- // get maximum time span
- size_t tMin = it1->getFirstFrame();
- size_t tMax = it1->getLastFrame();
- // collect tracklets to be merged
- std::vector< std::vector< Tracklet >::iterator > toBeMerged;
- // first one by default
- toBeMerged.push_back(it1);
- // iterate over all succeeding tracklets
- for (std::vector< Tracklet >::iterator it2 = it1 + 1; it2 != tracklets.end(); ++it2) {
- double match = it1->getMatchingScore(*it2);
- if (match < maxScore) {
- /*
- std::cout
- << std::distance(tracklets.begin(), it1) << " " << it1->getIdString() << " -> "
- << std::distance(tracklets.begin(), it2) << " " << it2->getIdString() << ": "
- << match << std::endl;
- */
- // update time span
- tMin = std::min(tMin, it2->getFirstFrame());
- tMax = std::max(tMax, it2->getLastFrame());
- // add to merge candidates
- toBeMerged.push_back(it2);
- }
- }
- if (toBeMerged.size() > 1) {
- std::cout << "Merging " << toBeMerged.size() << " tracks!" << std::endl;
- //std::cout << "tMin: " << tMin << ", tMax: " << tMax << std::endl;
- // our new tracklet
- Tracklet mergedTracklet;
- // iterate over complete time span
- for (size_t t = tMin; t <= tMax; ++t) {
- cv::Point3d p;
- size_t nP = 0;
- // get point for current time step of each merging candidate
- for (size_t i = 0; i < toBeMerged.size(); ++i) {
- std::map< size_t, cv::Point3d >::const_iterator itT = toBeMerged[i]->pRawPoints()->find(t);
- if (itT != toBeMerged[i]->pRawPoints()->end()) {
- p = p + itT->second;
- ++nP;
- }
- }
- // result is the average of all candidate points
- p *= 1.0 / (double)nP;
- // add to new tracklet
- mergedTracklet.addPoint(t, p);
- }
- // delete merged tracks
- for (int i = toBeMerged.size() - 1; i >= 0; --i) {
- mergedTracklet.appendIds(toBeMerged[i]->getIds());
- if (i > 0) {
- tracklets.erase(toBeMerged[i]);
- }
- }
- // replace first tracklet by the merged one
- *it1 = mergedTracklet;
- }
- }
- }
- void readTracklets(const std::string &filename,
- std::vector< Tracklet > &tracklets,
- size_t &nFrames) {
- // open file
- std::cout << "Reading tracklets from file " << filename << std::endl;
- std::ifstream pointFile(filename.c_str(), std::ios_base::in);
- if (!pointFile.is_open()) {
- std::cerr << "Could not open file " << std::endl;
- return;
- }
- // result object
- tracklets.clear();
- // read in all 3d points
- std::string line;
- // for each line...
- nFrames = 0;
- size_t id = 0;
- while (std::getline(pointFile, line)) {
- // print current frame number
- //std::cerr << "\rReading points... " << std::flush;
- // points of the current frame
- std::vector< cv::Point3d > tracklet;
- // read 3d points for each camera
- Tracklet tmpTracklet;
- tmpTracklet.appendId(id++);
- std::stringstream split(line);
- cv::Point3d tmpPoint;
- size_t frame = 0;
- // for each point...
- while (split.good()) {
- // read all points of this line
- if ((split >> tmpPoint.x >> tmpPoint.y >> tmpPoint.z >> frame).good()) {
- tmpTracklet.addPoint(frame, tmpPoint);
- // update global frame count
- nFrames = std::max(nFrames, tmpTracklet.getLastFrame() + 1);
- }
- }
- // add tracklet to list
- tmpTracklet.interpolatePoints();
- tracklets.push_back(tmpTracklet);
- }
- uint nTracklets = tracklets.size();
- std::cerr << std::endl << "Read " << nTracklets << " tracklets" << std::endl;
- // merge duplicate tracklets
- mergeDuplicates(tracklets);
- nTracklets = tracklets.size();
- std::cerr << std::endl << "Merged to " << nTracklets << " tracklets" << std::endl;
- }
- /**
- * graph-based typedefs
- */
- typedef double Weight;
- typedef boost::property< boost::edge_weight_t, Weight > WeightProperty;
- typedef boost::property< boost::vertex_name_t, Tracklet > NameProperty;
- typedef boost::adjacency_list<
- boost::listS,
- boost::vecS,
- boost::directedS,
- NameProperty,
- WeightProperty > Graph;
- typedef boost::graph_traits< Graph >::vertex_descriptor Vertex;
- typedef boost::property_map< Graph, boost::vertex_index_t >::type IndexMap;
- typedef boost::property_map< Graph, boost::vertex_name_t >::type NameMap;
- typedef boost::iterator_property_map< Vertex*, IndexMap, Vertex, Vertex& > PredecessorMap;
- typedef boost::iterator_property_map< Weight*, IndexMap, Weight, Weight& > DistanceMap;
- //
- template< class G >
- class VertexWriter {
- public:
- VertexWriter(G _g) :
- g(_g) {
- this->nameMap = boost::get(boost::vertex_name, g);
- }
- template< class VertexOrEdge >
- void operator()(std::ostream& out, const VertexOrEdge& v) const {
- if (nameMap[v].isVirtual()) {
- out << "[label=\"" << nameMap[v].getIdString() << "\",shape=\"circle\"]";
- } else {
- out << "[label=\"" << nameMap[v].getIdString() << ":\\n(" << nameMap[v].getFirstFrame() << ","
- << nameMap[v].getLastFrame() << ")\",shape=\"box\"]";
- }
- //
- }
- private:
- G g;
- NameMap nameMap;
- };
- //
- template< class G >
- class EdgeWriter {
- public:
- EdgeWriter(G _g) :
- g(_g) {
- }
- template< class VertexOrEdge >
- void operator()(std::ostream& out, const VertexOrEdge& v) const {
- out << "[label=\"" << boost::get(boost::edge_weight, g, v) << "\"]";
- }
- private:
- G g;
- };
- // tracklet graph to dot file
- void trackletsToDot(std::string filename, const Graph &g) {
- std::cout << "Writing graph to file \"" << filename << "\"" << std::endl;
- std::ofstream graphFile(filename.c_str());
- if (!graphFile.is_open()) {
- std::cerr << "Could not open file \"" << filename << "\"" << std::endl;
- return;
- }
- VertexWriter< Graph > vertexWriter(g);
- EdgeWriter< Graph > edgeWriter(g);
- boost::write_graphviz(graphFile, g, vertexWriter, edgeWriter);
- graphFile.close();
- }
- /**
- * main tracking functions
- */
- // nFrames: global frame count (needed to calculated weights to vSink)
- // return tracks
- void createTracksFromTracklets(const std::vector< Tracklet > &tracklets,
- const Params ¶ms,
- const size_t nFrames,
- std::vector< Tracklet > &tracks) {
- //
- // build graph
- //
- Graph g;
- std::vector< Vertex > vertices;
- size_t trackletStart = 0;
- size_t trackletMax = tracklets.size();
- // adding vertices
- for (size_t iTracklet = trackletStart; iTracklet < trackletMax; ++iTracklet) {
- std::cout << "\rAdding node for tracklet " << iTracklet + 1 << std::flush;
- Vertex v = boost::add_vertex(tracklets[iTracklet], g);
- vertices.push_back(v);
- }
- // virtual source and sink
- Vertex vSource = boost::add_vertex(Tracklet(), g);
- Vertex vSink = boost::add_vertex(Tracklet(), g);
- // debug
- ///boost::add_edge(vSource, vSink, 0, g);
- NameMap nameMap = boost::get(boost::vertex_name, g);
- std::cout << std::endl;
- // adding edges (layer eq tracklets)
- for (size_t iTracklet = 0; iTracklet < vertices.size(); ++iTracklet) {
- // all points of frame "iLayers"
- Vertex tracklet1 = vertices[iTracklet];
- // create edges to source and sink
- std::cout << "\rAdding edges vSource -> " << iTracklet + 1 << " -> vSink" << std::flush;
- boost::add_edge(vSource, tracklet1, (nameMap[tracklet1].getFirstFrame() + 1) * 1, g);
- boost::add_edge(tracklet1, vSink, (nFrames - nameMap[tracklet1].getLastFrame()) * 1, g);
- for (size_t jTracklet = 0; jTracklet < vertices.size(); ++jTracklet) {
- // get second tracklet for linking
- Vertex tracklet2 = vertices[jTracklet];
- // this is where the magic happens... the cost function!
- double ijCost = nameMap[tracklet1].linkingCost(nameMap[tracklet2], params);
- // create edge between both nodes
- if (ijCost < std::numeric_limits< double >::infinity()) {
- boost::add_edge(tracklet1, tracklet2, ijCost, g);
- }
- }
- }
- std::cout << std::endl;
- //
- // find tracks (shortest paths in tracklet graph)
- //
- // Create things for Dijkstra
- std::vector< Vertex > predecessors(boost::num_vertices(g)); // To store parents
- std::vector< Weight > distances(boost::num_vertices(g)); // To store distances
- IndexMap indexMap = boost::get(boost::vertex_index, g);
- PredecessorMap predecessorMap(&predecessors[0], indexMap);
- DistanceMap distanceMap(&distances[0], indexMap);
- // export graph to graphviz dot file
- //trackletsToDot("tmp2.dot", g);
- // each track consists of merged tracklets (which in turn is again a tracklet)
- tracks.clear();
- // Compute shortest paths from input layer vertices to the sink
- for (size_t tracklet = 0; tracklet < params.trackCount; ++tracklet) {
- // preparations for Dijkstra
- boost::dijkstra_shortest_paths(g, // the graph
- vSource, // the source vertex
- boost::distance_map(distanceMap).predecessor_map(predecessorMap));
- // stop if no more tracks can be found
- if (distanceMap[vSink] == std::numeric_limits<double>::max()) {
- std::cout << "No more tracks can be found" << std::endl;
- break;
- }
- // Extract the shortest path
- typedef std::vector< Graph::edge_descriptor > PathType;
- PathType path;
- Vertex v = vSink; // We want to start at the sink and work our way back to the source
- for (Vertex u = predecessorMap[v]; u != v; v = u, u = predecessorMap[v]) {
- std::pair< Graph::edge_descriptor, bool > edgePair = boost::edge(u, v, g);
- Graph::edge_descriptor edge = edgePair.first;
- path.push_back(edge);
- }
- // traverse shortest path (actually: traverse reverse path in a reverse direction)
- Tracklet currentTrack;
- bool vFirst = true;
- for (PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator != path.rend(); ++pathIterator) {
- // append non-virtual tracklets to this path
- if (!nameMap[boost::source(*pathIterator, g)].isVirtual()) {
- currentTrack.append(nameMap[boost::source(*pathIterator, g)]);
- }
- // 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)
- if (!vFirst) {
- std::pair< Graph::out_edge_iterator, Graph::out_edge_iterator > edgeIts = boost::out_edges(boost::source(*pathIterator,
- g),
- g);
- for (Graph::out_edge_iterator edgeIt = edgeIts.first; edgeIt != edgeIts.second; edgeIt++) {
- boost::get(boost::edge_weight, g, *edgeIt) = std::numeric_limits< Weight >::infinity();
- }
- }
- vFirst = false;
- }
- // interpolate
- currentTrack.interpolatePoints();
- tracks.push_back(currentTrack);
- std::cout << "Found track #" << tracklet + 1 << "/" << params.trackCount << ": " << path.size() - 1 << " tracklet(s), cost: "
- << distanceMap[vSink] << std::endl;
- }
- // merge duplicate tracks
- mergeDuplicates(tracks);
- std::cerr << std::endl << "Merged to " << tracks.size() << " tracks" << std::endl;
- }
- void writeTracks(std::string filename, std::vector< Tracklet > &tracks, size_t nFrames, double minTrackLength) {
- // open file
- std::ofstream f(filename.c_str());
- // get minimum track length
- size_t minLength;
- if (minTrackLength <= 1.0) {
- minLength = std::min(size_t(minTrackLength * double(nFrames)), nFrames);
- } else {
- minLength = std::min(size_t(minTrackLength), nFrames);
- }
- // print each track
- size_t finalCount = 0;
- for (size_t track = 0; track < tracks.size(); ++track) {
- if (tracks[track].getRange() >= minLength) {
- const std::map< size_t, cv::Point3d > *p = tracks[track].pRawPoints();
- for (std::map< size_t, cv::Point3d >::const_iterator it = p->begin(); it != p->end(); it++) {
- f << it->second.x << " " << it->second.y << " " << it->second.z << " " << it->first << " ";
- }
- //f << tracks[track].getIdString()
- f << std::endl;
- finalCount++;
- }
- }
- f.close();
- std::cout << finalCount << " tracks with length >= " << minLength << " were found" << std::endl;
- }
- int main(int argc, char** argv) {
- // get command line parameters
- Params p;
- if (!evalCmdLine(argc, argv, p)) {
- std::cerr << "Error while parsing arguments!" << std::endl;
- return 1;
- }
- size_t nFrames;
- std::vector< Tracklet > tracklets, tracks;
- readTracklets(p.strTracklets, tracklets, nFrames);
- createTracksFromTracklets(tracklets, p, nFrames, tracks);
- writeTracks(p.outputFilename, tracks, nFrames, p.minTrackLength);
- return EXIT_SUCCESS;
- }
|