├── images └── logo.png ├── .gitignore ├── sort ├── hungarian_test.cc ├── kalmantracker.hpp ├── sort.hpp ├── makefile ├── hungarian.hpp ├── kalmantracker.cc ├── sort.cc ├── runsorttracker.cc ├── hungarian.cc └── debug.hpp ├── readme.md └── cvmultitracker └── opencvmultitracker.cpp /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockkingjy/OpenMultiTracker/HEAD/images/logo.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | qrc_*.cpp 24 | ui_*.h 25 | Makefile* 26 | *-build-* 27 | 28 | # QtCreator 29 | 30 | *.autosave 31 | 32 | #QtCtreator Qml 33 | *.qmlproject.user 34 | *.qmlproject.user.* 35 | 36 | CMakeFiles/ 37 | *.cmake 38 | CMakeCache.txt 39 | Trackers 40 | build/ 41 | *.caffemodel 42 | *.bin 43 | .vscode/ 44 | .DS_Store 45 | *.aux 46 | *.bbl 47 | *.blg 48 | *.log 49 | *.out 50 | *.toc 51 | *.synctex.gz 52 | *~ 53 | -------------------------------------------------------------------------------- /sort/hungarian_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hungarian.hpp" 3 | 4 | using namespace sort; 5 | 6 | int main(void) 7 | { 8 | vector< vector > costMatrix = { { 10, 1.9, 8, 1.5, 0 }, 9 | { 1.0, 1.8, 7, 1.7, 0 }, 10 | { 1.3, 1.6, 9, 1.4, 0 }, 11 | { 1.2, 1.9, 0.8, 1.8, 0 } }; 12 | 13 | HungarianAlgorithm HungAlgo; 14 | vector assignment; 15 | 16 | double cost = HungAlgo.Solve(costMatrix, assignment); 17 | 18 | for (unsigned int x = 0; x < costMatrix.size(); x++) 19 | std::cout << x << ":" << assignment[x] << "\t"; 20 | 21 | std::cout << "\ncost: " << cost << std::endl; 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /sort/kalmantracker.hpp: -------------------------------------------------------------------------------- 1 | #ifndef KALMANTRACKER_HPP 2 | #define KALMANTRACKER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include "debug.hpp" 8 | 9 | using namespace std; 10 | 11 | namespace sort 12 | { 13 | class KalmanTracker 14 | { 15 | public: 16 | void init(cv::Rect2f bbox, int width, int height); 17 | void update(cv::Rect2f bbox); 18 | void predict(); 19 | cv::Rect2f get_state(); 20 | bool outofbound(); 21 | 22 | private: 23 | unsigned int type_ = CV_32F; 24 | int stateSize_ = 7; 25 | int measSize_ = 4; 26 | int contrSize_ = 0; 27 | cv::KalmanFilter kf_; 28 | cv::Mat state_; 29 | cv::Mat measure_; 30 | 31 | public: 32 | int image_width_ = 600; 33 | int image_height_ = 400; 34 | int time_since_update_ = 0; 35 | int hit_streak_ = 0; // how many continous updates. 36 | }; 37 | 38 | } // namespace sort 39 | 40 | #endif -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 |

5 | 6 | # What is OpenMultiTracker? 7 | OpenMultiTracker is a open sourced repository for Muliple Visual Tracking. It's written in C++, high speed, easy to use, and easy to be implemented in embedded system. 8 | 9 | 10 | 15 | 16 | For Single Object Visual Tracker, check: [OpenTracker](https://github.com/rockkingjy/OpenTracker). 17 | 18 | 19 | # References 20 | -------------------------------- 21 | (not complete, tell me if I forgot you) 22 | 23 | ## SORT 24 | Simple Online and Realtime Tracking 25 | Alex Bewley, Zongyuan Ge, Lionel Ott, Fabio Ramos, Ben Upcroft 26 | 27 | 28 | ## [MOT database](https://motchallenge.net/) 29 | 30 | 31 | 32 | ## Some code references 33 | 34 | SORT: https://github.com/abewley/sort 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /sort/sort.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SORT_HPP 2 | #define SORT_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "kalmantracker.hpp" 9 | #include "hungarian.hpp" 10 | 11 | using namespace std; 12 | 13 | namespace sort 14 | { 15 | class Sort 16 | { 17 | public: 18 | void init(int width, int height); 19 | void init(int max_age, int min_hits, int width, int height); 20 | void update(vector &bbox); 21 | void associate_detections_to_trackers(); 22 | float iou(cv::Rect2f bbox_gt, cv::Rect2f bb_test); 23 | void print_trackers(); 24 | void print_detections(); 25 | inline vector get_trackers() const { return trackers_; } 26 | 27 | private: 28 | int image_width_ = 600; 29 | int image_height_ = 400; 30 | int max_age_ = 1; 31 | int min_hits_ = 3; 32 | int frame_count_ = 0; 33 | float iou_threhold_ = 0.3; 34 | vector trackers_; 35 | vector detections_; 36 | vector assignment_; 37 | }; 38 | } // namespace sort 39 | 40 | #endif -------------------------------------------------------------------------------- /sort/makefile: -------------------------------------------------------------------------------- 1 | 2 | CC=gcc 3 | CXX=g++ 4 | 5 | LDFLAGS= `pkg-config --libs opencv` -lstdc++ -lm 6 | CXXFLAGS= -Wall `pkg-config --cflags opencv` -std=c++0x -lstdc++ -O3 -fPIC 7 | HEADERS = $(wildcard *.h) $(wildcard *.hpp) 8 | TARGET_LIB = libsorttracker.so 9 | OBJS = kalmantracker.o sort.o hungarian.o 10 | 11 | ALL = runsorttracker.bin $(TARGET_LIB) hungarian_test.bin 12 | 13 | all: $(ALL) 14 | 15 | runsorttracker.bin: $(OBJS) runsorttracker.o 16 | $(CC) -o $@ $^ $(LDFLAGS) 17 | 18 | hungarian_test.bin: hungarian.o hungarian_test.o 19 | $(CC) -o $@ $^ $(LDFLAGS) 20 | 21 | $(TARGET_LIB): $(OBJS) 22 | $(CC) ${LDFLAGS} -shared -o $@ $^ 23 | 24 | %.o: %.c $(HEADERS) 25 | $(CC) -c -o $@ $< $(CFLAGS) 26 | 27 | %.o: %.cpp $(HEADERS) 28 | $(CXX) -c -o $@ $< $(CXXFLAGS) 29 | 30 | 31 | .PHONY: clean 32 | 33 | clean: 34 | rm -rf *.o *.bin *.so 35 | 36 | .PHONY: install 37 | install: $(TARGET_LIB) 38 | mkdir -p /usr/local/include/opentracker 39 | mkdir -p /usr/local/include/opentracker/sort 40 | cp $(TARGET_LIB) /usr/local/lib 41 | mkdir -p /usr/local/include/opentracker/sort 42 | cp *.hpp /usr/local/include/opentracker/sort 43 | 44 | .PHONY: uninstall 45 | uninstall: $(TARGET_LIB) 46 | rm -f -r /usr/local/include/opentracker/sort 47 | rm -f /usr/local/lib/$(TARGET_LIB) -------------------------------------------------------------------------------- /sort/hungarian.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Hungarian.h: Header file for Class HungarianAlgorithm. 3 | // 4 | // This is a C++ wrapper with slight modification of a hungarian algorithm implementation by Markus Buehren. 5 | // The original implementation is a few mex-functions for use in MATLAB, found here: 6 | // http://www.mathworks.com/matlabcentral/fileexchange/6543-functions-for-the-rectangular-assignment-problem 7 | // 8 | // Both this code and the orignal code are published under the BSD license. 9 | // by Cong Ma, 2016 10 | // 11 | 12 | #ifndef HUNGARIAN_HPP 13 | #define HUNGARIAN_HPP 14 | 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | namespace sort 21 | { 22 | class HungarianAlgorithm 23 | { 24 | public: 25 | HungarianAlgorithm(); 26 | ~HungarianAlgorithm(); 27 | double Solve(vector> &DistMatrix, vector &Assignment); 28 | 29 | private: 30 | void assignmentoptimal(int *assignment, double *cost, double *distMatrix, int nOfRows, int nOfColumns); 31 | void buildassignmentvector(int *assignment, bool *starMatrix, int nOfRows, int nOfColumns); 32 | void computeassignmentcost(int *assignment, double *cost, double *distMatrix, int nOfRows); 33 | void step2a(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim); 34 | void step2b(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim); 35 | void step3(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim); 36 | void step4(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim, int row, int col); 37 | void step5(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim); 38 | }; 39 | 40 | } // namespace sort 41 | #endif -------------------------------------------------------------------------------- /sort/kalmantracker.cc: -------------------------------------------------------------------------------- 1 | #include "kalmantracker.hpp" 2 | 3 | namespace sort 4 | { 5 | 6 | void KalmanTracker::init(cv::Rect2f bbox, int width, int height) 7 | { 8 | image_width_ = width; 9 | image_height_ = height; 10 | time_since_update_ = 0; 11 | hit_streak_ = 0; 12 | 13 | kf_ = cv::KalmanFilter(stateSize_, measSize_, contrSize_, type_); 14 | state_ = cv::Mat(stateSize_, 1, type_); // [u,v,s,r,du,dv,ds] 15 | measure_ = cv::Mat(measSize_, 1, type_); // [u,v,s,r] 16 | 17 | // state 18 | state_.at(0) = bbox.x + bbox.width / 2.0f; 19 | state_.at(1) = bbox.y + bbox.height / 2.0f; 20 | state_.at(2) = (float)bbox.width * (float)bbox.height; 21 | state_.at(3) = (float)bbox.width / (float)bbox.height; 22 | state_.at(4) = 0.0f; 23 | state_.at(5) = 0.0f; 24 | state_.at(6) = 0.0f; 25 | 26 | // measure 27 | measure_.setTo(cv::Scalar(0)); 28 | 29 | // State Transition Matrix A 30 | // Note: set dT at each processing step! 31 | // [ 1 0 0 0 1 0 0 ] 32 | // [ 0 1 0 0 0 1 0 ] 33 | // [ 0 0 1 0 0 0 1 ] 34 | // [ 0 0 0 1 0 0 0 ] 35 | // [ 0 0 0 0 1 0 0 ] 36 | // [ 0 0 0 0 0 1 0 ] 37 | // [ 0 0 0 0 0 0 1 ] 38 | cv::setIdentity(kf_.transitionMatrix); 39 | kf_.transitionMatrix.at(4) = 1.0f; 40 | kf_.transitionMatrix.at(12) = 1.0f; 41 | kf_.transitionMatrix.at(20) = 1.0f; 42 | 43 | // Measure Matrix H 44 | // [ 1 0 0 0 0 0 0] 45 | // [ 0 1 0 0 0 0 0] 46 | // [ 0 0 1 0 0 0 0] 47 | // [ 0 0 0 1 0 0 0] 48 | kf_.measurementMatrix = cv::Mat::zeros(measSize_, stateSize_, type_); 49 | kf_.measurementMatrix.at(0) = 1.0f; 50 | kf_.measurementMatrix.at(8) = 1.0f; 51 | kf_.measurementMatrix.at(16) = 1.0f; 52 | kf_.measurementMatrix.at(24) = 1.0f; 53 | 54 | // Measures Noise Covariance Matrix R 55 | // [1 0 0 0] 56 | // [0 1 0 0] 57 | // [0 0 10 0] 58 | // [0 0 0 10] 59 | cv::setIdentity(kf_.measurementNoiseCov, cv::Scalar(1.0f)); 60 | kf_.measurementNoiseCov.at(10) = 10.0f; 61 | kf_.measurementNoiseCov.at(15) = 10.0f; 62 | 63 | // Posteriori error estimate covariance matrix (P(k)) 64 | kf_.errorCovPost.at(0) = 10.0f; 65 | kf_.errorCovPost.at(8) = 10.0f; 66 | kf_.errorCovPost.at(16) = 10.0f; 67 | kf_.errorCovPost.at(24) = 10.0f; 68 | kf_.errorCovPost.at(32) = 10000.0f; 69 | kf_.errorCovPost.at(40) = 10000.0f; 70 | kf_.errorCovPost.at(48) = 10000.0f; 71 | 72 | // Process Noise Covariance Matrix Q 73 | kf_.processNoiseCov.at(0) = 1.0f; 74 | kf_.processNoiseCov.at(8) = 1.0f; 75 | kf_.processNoiseCov.at(16) = 1.0f; 76 | kf_.processNoiseCov.at(24) = 1.0f; 77 | kf_.processNoiseCov.at(32) = 1e-2; 78 | kf_.processNoiseCov.at(40) = 1e-2; 79 | kf_.processNoiseCov.at(48) = 1e-4; 80 | 81 | kf_.statePost = state_; 82 | } 83 | 84 | void KalmanTracker::update(cv::Rect2f bbox) 85 | { 86 | time_since_update_ = 0; 87 | ++hit_streak_; 88 | measure_.at(0) = bbox.x + bbox.width / 2.0f; 89 | measure_.at(1) = bbox.y + bbox.height / 2.0f; 90 | measure_.at(2) = (float)bbox.width * (float)bbox.height; 91 | measure_.at(3) = (float)bbox.width / (float)bbox.height; 92 | 93 | kf_.correct(measure_); // Kalman Correction 94 | //cout << "Measure matrix:" << endl << measure_ << endl; 95 | } 96 | 97 | void KalmanTracker::predict() 98 | { 99 | if (time_since_update_ > 0) 100 | { 101 | hit_streak_ = 0; 102 | } 103 | ++time_since_update_; 104 | if (outofbound()) 105 | { 106 | state_.at(0) = 0.0f; 107 | state_.at(1) = 0.0f; 108 | state_.at(2) = 0.0f; 109 | state_.at(3) = 0.0f; 110 | state_.at(4) = 0.0f; 111 | state_.at(5) = 0.0f; 112 | state_.at(6) = 0.0f; 113 | } 114 | state_ = kf_.predict(); 115 | //cout << "State post:" << endl << state_ << endl; 116 | } 117 | 118 | cv::Rect2f KalmanTracker::get_state() 119 | { 120 | cv::Rect2f res; 121 | res.width = std::sqrt(state_.at(2) * state_.at(3)); 122 | res.height = state_.at(2) / res.width; 123 | res.x = state_.at(0) - res.width / 2.0f; 124 | res.y = state_.at(1) - res.height / 2.0f; 125 | return res; 126 | } 127 | 128 | bool KalmanTracker::outofbound() 129 | { 130 | cv::Rect2f res = get_state(); 131 | if (isnan(res.x) | isnan(res.y) | isnan(res.width) | isnan(res.height)) 132 | { 133 | return true; 134 | } 135 | if (res.x + res.width <= 0) 136 | { 137 | return true; 138 | } 139 | if (res.y + res.height <= 0) 140 | { 141 | return true; 142 | } 143 | if (res.x >= image_width_) 144 | { 145 | return true; 146 | } 147 | if (res.y >= image_height_) 148 | { 149 | return true; 150 | } 151 | if (res.width <= 0) 152 | { 153 | return true; 154 | } 155 | if (res.height <= 0) 156 | { 157 | return true; 158 | } 159 | return false; 160 | } 161 | 162 | } // namespace sort 163 | -------------------------------------------------------------------------------- /sort/sort.cc: -------------------------------------------------------------------------------- 1 | #include "sort.hpp" 2 | 3 | namespace sort 4 | { 5 | void Sort::init(int width, int height) 6 | { 7 | image_width_ = width; 8 | image_height_ = height; 9 | trackers_.clear(); 10 | frame_count_ = 0; 11 | } 12 | void Sort::init(int max_age, int min_hits, int width, int height) 13 | { 14 | image_width_ = width; 15 | image_height_ = height; 16 | max_age_ = max_age; 17 | min_hits_ = min_hits; 18 | trackers_.clear(); 19 | frame_count_ = 0; 20 | } 21 | // 22 | void Sort::update(vector &bbox) 23 | { 24 | ++frame_count_; 25 | // get the detections. 26 | detections_.clear(); 27 | for (unsigned int i = 0; i < bbox.size(); i++) 28 | { 29 | detections_.push_back(bbox[i]); 30 | } 31 | 32 | debug(); 33 | print_detections(); 34 | print_trackers(); 35 | // get the predicted locations from existing trackers. 36 | for (unsigned int i = 0; i < trackers_.size(); i++) 37 | { 38 | trackers_[i].predict(); 39 | //debug("inbound: %d", i); 40 | if (trackers_[i].outofbound()) 41 | { 42 | //debug("outbound: %d", i); 43 | trackers_.erase(trackers_.begin() + i); 44 | } 45 | } 46 | debug(); 47 | print_trackers(); 48 | 49 | // associate detections and trackers. 50 | if (!detections_.empty() & !trackers_.empty()) 51 | { 52 | associate_detections_to_trackers(); 53 | // update matched trackers with assigned detections. 54 | vector del; 55 | for (unsigned int i = 0; i < assignment_.size(); i++) 56 | { 57 | trackers_[i].update(detections_[assignment_[i]]); 58 | //debug("%d:%d", i, assignment_[i]); 59 | del.push_back(assignment_[i]); 60 | } 61 | /* for (unsigned int i = 0; i < del.size(); i++) 62 | { 63 | printf("%d ", del[i]); 64 | } 65 | debug();*/ 66 | std::sort(del.begin(), del.end(), std::greater()); 67 | for (unsigned int i = 0; i < del.size(); i++) 68 | { 69 | detections_.erase(detections_.begin() + del[i]); 70 | } 71 | } 72 | 73 | debug(); 74 | print_detections(); 75 | 76 | // create and initialise new trackers for unmatched detections. 77 | if (!detections_.empty()) 78 | { 79 | for (unsigned int i = 0; i < detections_.size(); i++) 80 | { 81 | KalmanTracker kalmantracker; 82 | kalmantracker.init(detections_[i], image_width_, image_height_); 83 | trackers_.push_back(kalmantracker); 84 | } 85 | } 86 | // remove aged tracker. 87 | for (unsigned int i = 0; i < trackers_.size(); i++) 88 | { 89 | // remove the tracker when not detected for long time. 90 | if (trackers_[i].time_since_update_ > max_age_) 91 | { 92 | trackers_.erase(trackers_.begin() + i); 93 | } 94 | } 95 | 96 | print_trackers(); 97 | } 98 | // row: trackers; col: detections. 99 | void Sort::associate_detections_to_trackers() 100 | { 101 | vector> iou_matrix, iou_matrix_inv; 102 | for (unsigned int i = 0; i < trackers_.size(); i++) 103 | { 104 | iou_matrix.push_back(vector()); 105 | for (unsigned int j = 0; j < detections_.size(); j++) 106 | { 107 | iou_matrix[i].push_back(iou(trackers_[i].get_state(), detections_[j])); 108 | } 109 | } 110 | // debug 111 | debug("%lu x %lu:", iou_matrix.size(), iou_matrix[0].size()); 112 | for (unsigned int i = 0; i < iou_matrix.size(); i++) 113 | { 114 | for (unsigned int j = 0; j < iou_matrix[i].size(); j++) 115 | { 116 | printf("%f ", iou_matrix[i][j]); 117 | } 118 | printf("\n"); 119 | } 120 | debug(); 121 | 122 | // find the max value, to make iou to be >= 0; 123 | double max = 0; 124 | for (unsigned int i = 0; i < iou_matrix.size(); i++) 125 | { 126 | for (unsigned int j = 0; j < iou_matrix[i].size(); j++) 127 | { 128 | if (iou_matrix[i][j] > max) 129 | { 130 | max = iou_matrix[i][j]; 131 | } 132 | } 133 | } 134 | 135 | // make matrix to be ready for hungraian minum assignment, make sure rows <= cols. 136 | for (unsigned int i = 0; i < iou_matrix.size(); i++) 137 | { 138 | iou_matrix_inv.push_back(vector()); 139 | for (unsigned int j = 0; j < iou_matrix[i].size(); j++) 140 | { 141 | iou_matrix_inv[i].push_back(max - iou_matrix[i][j]); 142 | } 143 | } 144 | if (iou_matrix.size() > iou_matrix[0].size()) 145 | { 146 | for (unsigned int i = iou_matrix[0].size(); i < iou_matrix.size(); i++) 147 | { 148 | for (unsigned int j = 0; j < iou_matrix.size(); j++) 149 | { 150 | iou_matrix_inv[j].push_back(0.0f); 151 | } 152 | } 153 | } 154 | 155 | // debug 156 | debug("%lu x %lu:", iou_matrix_inv.size(), iou_matrix_inv[0].size()); 157 | for (unsigned int i = 0; i < iou_matrix_inv.size(); i++) 158 | { 159 | for (unsigned int j = 0; j < iou_matrix_inv[i].size(); j++) 160 | { 161 | printf("%f ", iou_matrix_inv[i][j]); 162 | } 163 | printf("\n"); 164 | } 165 | debug(); 166 | 167 | // assign by hungarian algorithm. 168 | sort::HungarianAlgorithm hungarian; 169 | hungarian.Solve(iou_matrix_inv, assignment_); 170 | for (unsigned int i = 0; i < assignment_.size(); i++) 171 | { 172 | std::cout << i << ":" << assignment_[i] << "\t"; 173 | } 174 | cout << endl; 175 | debug(); 176 | 177 | // remove extra useless assignments when rows <= cols; 178 | if (iou_matrix.size() > iou_matrix[0].size()) 179 | { 180 | unsigned int n = assignment_.size(); 181 | for (unsigned int i = iou_matrix[0].size(); i < n; i++) 182 | { 183 | assignment_.erase(assignment_.end() - 1); 184 | /* 185 | // remove matched with low IOU. 186 | if (iou_matrix[i][assignment_[i]] < iou_threhold_) 187 | { 188 | assignment_.erase(assignment_.begin() + i); 189 | --i; 190 | } */ 191 | } 192 | } 193 | for (unsigned int i = 0; i < assignment_.size(); i++) 194 | { 195 | std::cout << i << ":" << assignment_[i] << "\t"; 196 | } 197 | cout << endl; 198 | debug(); 199 | } 200 | 201 | float Sort::iou(cv::Rect2f bbox_gt, cv::Rect2f bbox_test) 202 | { 203 | float x1 = (bbox_gt.x > bbox_test.x) ? bbox_gt.x : bbox_test.x; 204 | float y1 = (bbox_gt.y > bbox_test.y) ? bbox_gt.y : bbox_test.y; 205 | float x2 = (bbox_gt.x + bbox_gt.width) > (bbox_test.x + bbox_test.width) ? (bbox_test.x + bbox_test.width) : (bbox_gt.x + bbox_gt.width); 206 | float y2 = (bbox_gt.y + bbox_gt.height) > (bbox_test.y + bbox_test.height) ? (bbox_test.y + bbox_test.height) : (bbox_gt.y + bbox_gt.height); 207 | float w = x2 - x1 > 0 ? x2 - x1 : 0; 208 | float h = y2 - y1 > 0 ? y2 - y1 : 0; 209 | float iou = w * h / ((bbox_gt.area() + bbox_test.area()) - w * h); 210 | return iou; 211 | } 212 | 213 | void Sort::print_trackers() 214 | { 215 | debug("%lu Trackers:", trackers_.size()); 216 | for (unsigned int i = 0; i < trackers_.size(); i++) 217 | { 218 | cv::Rect2f rec = trackers_[i].get_state(); 219 | debug("%f, %f, %f, %f", rec.x, rec.y, rec.width, rec.height); 220 | } 221 | debug("-------------------------------"); 222 | } 223 | void Sort::print_detections() 224 | { 225 | debug("%lu detections:", detections_.size()); 226 | for (unsigned int i = 0; i < detections_.size(); i++) 227 | { 228 | debug("%f, %f, %f, %f", detections_[i].x, detections_[i].y, detections_[i].width, detections_[i].height); 229 | } 230 | debug("-------------------------------"); 231 | } 232 | 233 | } // namespace sort 234 | -------------------------------------------------------------------------------- /sort/runsorttracker.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "debug.hpp" 8 | #include "kalmantracker.hpp" 9 | #include "sort.hpp" 10 | 11 | using namespace std; 12 | using namespace cv; 13 | using namespace sort; 14 | 15 | int main(int argc, char **argv) 16 | { 17 | // Database settings 18 | string databaseTypes[3] = {"Demo", "MOT16", "2D_MOT_2015"}; 19 | string databaseType = databaseTypes[2]; 20 | // Read from the images ==================================================== 21 | int f = 0, fileNow = 1; 22 | float x, y, w, h, confidence, confidenceThreshhold = 0; 23 | vector bboxGroundtruth; 24 | 25 | std::string s; 26 | std::string path; 27 | ifstream *groundtruth = NULL; 28 | ostringstream osfile; 29 | 30 | if (databaseType == "Demo") 31 | { 32 | path = "../sequences/Crossing"; 33 | // some of the dataset has '\t' as the delimiter, change it to ','. 34 | fstream gt(path + "/groundtruth_rect.txt"); 35 | string tmp; 36 | size_t index = 1; 37 | while (gt >> tmp) 38 | { 39 | if (tmp.find(',') < 10) 40 | { 41 | break; 42 | } 43 | if (index % 4 == 0) 44 | { 45 | } 46 | else 47 | { 48 | gt << ","; 49 | } 50 | index++; 51 | } 52 | gt.close(); 53 | // Read the groundtruth bbox 54 | groundtruth = new ifstream(path + "/groundtruth_rect.txt"); 55 | f = 1; 56 | getline(*groundtruth, s, ','); 57 | x = atof(s.c_str()); 58 | getline(*groundtruth, s, ','); 59 | y = atof(s.c_str()); 60 | getline(*groundtruth, s, ','); 61 | w = atof(s.c_str()); 62 | getline(*groundtruth, s); 63 | h = atof(s.c_str()); 64 | f = 1; 65 | bboxGroundtruth.push_back(Rect2f(x, y, w, h)); 66 | cout << f << " " << x << " " << y << " " << w << " " << h << " " << endl; 67 | // Read images in a folder 68 | osfile << path << "/img/" << setw(4) << setfill('0') << f << ".jpg"; 69 | cout << osfile.str() << endl; 70 | } 71 | else if (databaseType == "MOT16") 72 | { 73 | string folderMOT = "MOT16-01"; 74 | path = "/media/elab/sdd/data/MOT16/test/" + folderMOT; 75 | groundtruth = new ifstream(path + "/det/det.txt"); 76 | getline(*groundtruth, s, ','); 77 | f = atof(s.c_str()); 78 | while (f == fileNow) 79 | { 80 | getline(*groundtruth, s, ','); 81 | getline(*groundtruth, s, ','); 82 | x = atof(s.c_str()); 83 | getline(*groundtruth, s, ','); 84 | y = atof(s.c_str()); 85 | getline(*groundtruth, s, ','); 86 | w = atof(s.c_str()); 87 | getline(*groundtruth, s, ','); 88 | h = atof(s.c_str()); 89 | getline(*groundtruth, s, ','); 90 | confidence = atof(s.c_str()); 91 | //cout << f << " " << x << " " << y << " " << w << " " << h << " " << endl; 92 | if (confidence > confidenceThreshhold) 93 | { 94 | bboxGroundtruth.push_back(Rect2f(x, y, w, h)); 95 | } 96 | getline(*groundtruth, s); 97 | getline(*groundtruth, s, ','); 98 | f = atof(s.c_str()); 99 | } 100 | // Read images in a folder 101 | osfile << path << "/img1/" << setw(6) << setfill('0') << fileNow << ".jpg"; 102 | cout << osfile.str() << endl; 103 | } 104 | else if (databaseType == "2D_MOT_2015") 105 | { 106 | string folderMOT = "PETS09-S2L1"; 107 | path = "/media/elab/sdd/mycodes/tracker/sort/mot_benchmark/train/" + folderMOT; 108 | //groundtruth = new ifstream(path + "/det/det.txt"); 109 | groundtruth = new ifstream("/media/elab/sdd/mycodes/tracker/sort/data/PETS09-S2L1/det.txt"); 110 | getline(*groundtruth, s, ','); 111 | f = atof(s.c_str()); 112 | while (f == fileNow) 113 | { 114 | getline(*groundtruth, s, ','); 115 | getline(*groundtruth, s, ','); 116 | x = atof(s.c_str()); 117 | getline(*groundtruth, s, ','); 118 | y = atof(s.c_str()); 119 | getline(*groundtruth, s, ','); 120 | w = atof(s.c_str()); 121 | getline(*groundtruth, s, ','); 122 | h = atof(s.c_str()); 123 | getline(*groundtruth, s, ','); 124 | confidence = atof(s.c_str()); 125 | //cout << f << " " << x << " " << y << " " << w << " " << h << " " << endl; 126 | if (confidence > confidenceThreshhold) 127 | { 128 | bboxGroundtruth.push_back(Rect2f(x, y, w, h)); 129 | } 130 | getline(*groundtruth, s); 131 | getline(*groundtruth, s, ','); 132 | f = atof(s.c_str()); 133 | } 134 | // Read images in a folder 135 | osfile << path << "/img1/" << setw(6) << setfill('0') << fileNow << ".jpg"; 136 | cout << osfile.str() << endl; 137 | } 138 | 139 | cv::Mat frame = cv::imread(osfile.str().c_str(), CV_LOAD_IMAGE_UNCHANGED); 140 | if (!frame.data) 141 | { 142 | cout << "Could not open or find the image" << std::endl; 143 | return -1; 144 | } 145 | cv::Mat frameDraw; 146 | frame.copyTo(frameDraw); 147 | // Draw gt; 148 | if (databaseType == "MOT16" || databaseType == "2D_MOT_2015") 149 | { 150 | for (unsigned int i = 0; i < bboxGroundtruth.size(); i++) 151 | { 152 | cout << bboxGroundtruth[i].x << " " << bboxGroundtruth[i].y << " " << bboxGroundtruth[i].width << " " << bboxGroundtruth[i].height << endl; 153 | rectangle(frameDraw, bboxGroundtruth[i], Scalar(0, 0, 0), 2, 1); 154 | } 155 | } 156 | 157 | imshow("OpenTracker", frameDraw); 158 | //waitKey(0); 159 | /* 160 | // Create KalmanTracker 161 | cv::Rect2f kalmanbbox; 162 | KalmanTracker kalmantracker; 163 | kalmantracker.init(bboxGroundtruth[0], frame.cols, frame.rows); 164 | */ 165 | // Create sort multi tracker; 166 | Sort sorttracker; 167 | sorttracker.init(frame.cols, frame.rows); 168 | 169 | while (frame.data) 170 | { 171 | /* 172 | // KalmanTracker 173 | kalmantracker.predict(); 174 | kalmanbbox = kalmantracker.get_state(); 175 | debug("bbox: %f, %f, %f, %f", kalmanbbox.x, kalmanbbox.y, kalmanbbox.width, kalmanbbox.height); 176 | rectangle(frameDraw, kalmanbbox, Scalar(0, 255, 0), 2, 1); 177 | */ 178 | 179 | // update sort tracker 180 | sorttracker.update(bboxGroundtruth); 181 | //sorttracker.print_trackers(); 182 | vector result = sorttracker.get_trackers(); 183 | for (unsigned int i = 0; i < result.size(); i++) 184 | { 185 | rectangle(frameDraw, result[i].get_state(), Scalar(0, 255, 0), 2, 1); 186 | } 187 | 188 | // Show the image 189 | imshow("OpenTracker", frameDraw); 190 | 191 | int c = cvWaitKey(1); 192 | if (c != -1) 193 | c = c % 256; 194 | if (c == 27) 195 | { 196 | cvDestroyWindow("OpenTracker"); 197 | return 0; 198 | } 199 | waitKey(1); 200 | // Read next image====================================================== 201 | fileNow++; 202 | osfile.str(""); 203 | if (databaseType == "Demo") 204 | { 205 | bboxGroundtruth.clear(); 206 | getline(*groundtruth, s, ','); 207 | x = atof(s.c_str()); 208 | getline(*groundtruth, s, ','); 209 | y = atof(s.c_str()); 210 | getline(*groundtruth, s, ','); 211 | w = atof(s.c_str()); 212 | getline(*groundtruth, s); 213 | h = atof(s.c_str()); 214 | //cout << f << " " << x << " " << y << " " << w << " " << h << " " << isLost << endl; 215 | // Read images in a folder 216 | f++; 217 | bboxGroundtruth.push_back(Rect2f(x, y, w, h)); 218 | osfile << path << "/img/" << setw(4) << setfill('0') << f << ".jpg"; 219 | //cout << osfile.str() << endl; 220 | } 221 | else if (databaseType == "MOT16" || databaseType == "2D_MOT_2015") 222 | { 223 | bboxGroundtruth.clear(); 224 | while (f == fileNow) 225 | { 226 | getline(*groundtruth, s, ','); 227 | getline(*groundtruth, s, ','); 228 | x = atof(s.c_str()); 229 | getline(*groundtruth, s, ','); 230 | y = atof(s.c_str()); 231 | getline(*groundtruth, s, ','); 232 | w = atof(s.c_str()); 233 | getline(*groundtruth, s, ','); 234 | h = atof(s.c_str()); 235 | getline(*groundtruth, s, ','); 236 | confidence = atof(s.c_str()); 237 | //cout << f << " " << x << " " << y << " " << w << " " << h << " " << endl; 238 | if (confidence > confidenceThreshhold) 239 | { 240 | bboxGroundtruth.push_back(Rect2f(x, y, w, h)); 241 | } 242 | getline(*groundtruth, s); 243 | getline(*groundtruth, s, ','); 244 | f = atof(s.c_str()); 245 | } 246 | // Read images in a folder 247 | osfile << path << "/img1/" << setw(6) << setfill('0') << fileNow << ".jpg"; 248 | cout << osfile.str() << "=======================" << endl; 249 | } 250 | 251 | frame = cv::imread(osfile.str().c_str(), CV_LOAD_IMAGE_UNCHANGED); 252 | if (!frame.data) 253 | { 254 | cout << "Could not open or find the image" << std::endl; 255 | return -1; 256 | } 257 | frame.copyTo(frameDraw); 258 | // Draw gt; 259 | if (databaseType == "Demo" || databaseType == "MOT16" || databaseType == "2D_MOT_2015") 260 | { 261 | for (unsigned int i = 0; i < bboxGroundtruth.size(); i++) 262 | { 263 | cout << bboxGroundtruth[i].x << " " << bboxGroundtruth[i].y << " " << bboxGroundtruth[i].width << " " << bboxGroundtruth[i].height << endl; 264 | rectangle(frameDraw, bboxGroundtruth[i], Scalar(0, 0, 0), 2, 1); 265 | } 266 | } 267 | 268 | // KalmanTracker update 269 | // kalmantracker.update(bboxGroundtruth[0]); 270 | } 271 | return 0; 272 | } -------------------------------------------------------------------------------- /sort/hungarian.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Hungarian.cpp: Implementation file for Class HungarianAlgorithm. 3 | // 4 | // This is a C++ wrapper with slight modification of a hungarian algorithm implementation by Markus Buehren. 5 | // The original implementation is a few mex-functions for use in MATLAB, found here: 6 | // http://www.mathworks.com/matlabcentral/fileexchange/6543-functions-for-the-rectangular-assignment-problem 7 | // 8 | // Both this code and the orignal code are published under the BSD license. 9 | // by Cong Ma, 2016 10 | // 11 | 12 | #include 13 | #include // for DBL_MAX 14 | #include // for fabs() 15 | #include "hungarian.hpp" 16 | 17 | namespace sort 18 | { 19 | HungarianAlgorithm::HungarianAlgorithm() {} 20 | HungarianAlgorithm::~HungarianAlgorithm() {} 21 | 22 | //********************************************************// 23 | // A single function wrapper for solving assignment problem. 24 | //********************************************************// 25 | double HungarianAlgorithm::Solve(vector> &DistMatrix, vector &Assignment) 26 | { 27 | unsigned int nRows = DistMatrix.size(); 28 | unsigned int nCols = DistMatrix[0].size(); 29 | 30 | double *distMatrixIn = new double[nRows * nCols]; 31 | int *assignment = new int[nRows]; 32 | double cost = 0.0; 33 | 34 | // Fill in the distMatrixIn. Mind the index is "i + nRows * j". 35 | // Here the cost matrix of size MxN is defined as a double precision array of N*M elements. 36 | // In the solving functions matrices are seen to be saved MATLAB-internally in row-order. 37 | // (i.e. the matrix [1 2; 3 4] will be stored as a vector [1 3 2 4], NOT [1 2 3 4]). 38 | for (unsigned int i = 0; i < nRows; i++) 39 | for (unsigned int j = 0; j < nCols; j++) 40 | distMatrixIn[i + nRows * j] = DistMatrix[i][j]; 41 | 42 | // call solving function 43 | assignmentoptimal(assignment, &cost, distMatrixIn, nRows, nCols); 44 | 45 | Assignment.clear(); 46 | for (unsigned int r = 0; r < nRows; r++) 47 | Assignment.push_back(assignment[r]); 48 | 49 | delete[] distMatrixIn; 50 | delete[] assignment; 51 | return cost; 52 | } 53 | 54 | //********************************************************// 55 | // Solve optimal solution for assignment problem using Munkres algorithm, also known as Hungarian Algorithm. 56 | //********************************************************// 57 | void HungarianAlgorithm::assignmentoptimal(int *assignment, double *cost, double *distMatrixIn, int nOfRows, int nOfColumns) 58 | { 59 | double *distMatrix, *distMatrixTemp, *distMatrixEnd, *columnEnd, value, minValue; 60 | bool *coveredColumns, *coveredRows, *starMatrix, *newStarMatrix, *primeMatrix; 61 | int nOfElements, minDim, row, col; 62 | 63 | /* initialization */ 64 | *cost = 0; 65 | for (row = 0; row < nOfRows; row++) 66 | assignment[row] = -1; 67 | 68 | /* generate working copy of distance Matrix */ 69 | /* check if all matrix elements are positive */ 70 | nOfElements = nOfRows * nOfColumns; 71 | distMatrix = (double *)malloc(nOfElements * sizeof(double)); 72 | distMatrixEnd = distMatrix + nOfElements; 73 | 74 | for (row = 0; row < nOfElements; row++) 75 | { 76 | value = distMatrixIn[row]; 77 | if (value < 0) 78 | cerr << "All matrix elements have to be non-negative." << endl; 79 | distMatrix[row] = value; 80 | } 81 | 82 | /* memory allocation */ 83 | coveredColumns = (bool *)calloc(nOfColumns, sizeof(bool)); 84 | coveredRows = (bool *)calloc(nOfRows, sizeof(bool)); 85 | starMatrix = (bool *)calloc(nOfElements, sizeof(bool)); 86 | primeMatrix = (bool *)calloc(nOfElements, sizeof(bool)); 87 | newStarMatrix = (bool *)calloc(nOfElements, sizeof(bool)); /* used in step4 */ 88 | 89 | /* preliminary steps */ 90 | if (nOfRows <= nOfColumns) 91 | { 92 | minDim = nOfRows; 93 | 94 | for (row = 0; row < nOfRows; row++) 95 | { 96 | /* find the smallest element in the row */ 97 | distMatrixTemp = distMatrix + row; 98 | minValue = *distMatrixTemp; 99 | distMatrixTemp += nOfRows; 100 | while (distMatrixTemp < distMatrixEnd) 101 | { 102 | value = *distMatrixTemp; 103 | if (value < minValue) 104 | minValue = value; 105 | distMatrixTemp += nOfRows; 106 | } 107 | 108 | /* subtract the smallest element from each element of the row */ 109 | distMatrixTemp = distMatrix + row; 110 | while (distMatrixTemp < distMatrixEnd) 111 | { 112 | *distMatrixTemp -= minValue; 113 | distMatrixTemp += nOfRows; 114 | } 115 | } 116 | 117 | /* Steps 1 and 2a */ 118 | for (row = 0; row < nOfRows; row++) 119 | for (col = 0; col < nOfColumns; col++) 120 | if (fabs(distMatrix[row + nOfRows * col]) < DBL_EPSILON) 121 | if (!coveredColumns[col]) 122 | { 123 | starMatrix[row + nOfRows * col] = true; 124 | coveredColumns[col] = true; 125 | break; 126 | } 127 | } 128 | else /* if(nOfRows > nOfColumns) */ 129 | { 130 | minDim = nOfColumns; 131 | 132 | for (col = 0; col < nOfColumns; col++) 133 | { 134 | /* find the smallest element in the column */ 135 | distMatrixTemp = distMatrix + nOfRows * col; 136 | columnEnd = distMatrixTemp + nOfRows; 137 | 138 | minValue = *distMatrixTemp++; 139 | while (distMatrixTemp < columnEnd) 140 | { 141 | value = *distMatrixTemp++; 142 | if (value < minValue) 143 | minValue = value; 144 | } 145 | 146 | /* subtract the smallest element from each element of the column */ 147 | distMatrixTemp = distMatrix + nOfRows * col; 148 | while (distMatrixTemp < columnEnd) 149 | *distMatrixTemp++ -= minValue; 150 | } 151 | 152 | /* Steps 1 and 2a */ 153 | for (col = 0; col < nOfColumns; col++) 154 | for (row = 0; row < nOfRows; row++) 155 | if (fabs(distMatrix[row + nOfRows * col]) < DBL_EPSILON) 156 | if (!coveredRows[row]) 157 | { 158 | starMatrix[row + nOfRows * col] = true; 159 | coveredColumns[col] = true; 160 | coveredRows[row] = true; 161 | break; 162 | } 163 | for (row = 0; row < nOfRows; row++) 164 | coveredRows[row] = false; 165 | } 166 | 167 | /* move to step 2b */ 168 | step2b(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim); 169 | 170 | /* compute cost and remove invalid assignments */ 171 | computeassignmentcost(assignment, cost, distMatrixIn, nOfRows); 172 | 173 | /* free allocated memory */ 174 | free(distMatrix); 175 | free(coveredColumns); 176 | free(coveredRows); 177 | free(starMatrix); 178 | free(primeMatrix); 179 | free(newStarMatrix); 180 | 181 | return; 182 | } 183 | 184 | /********************************************************/ 185 | void HungarianAlgorithm::buildassignmentvector(int *assignment, bool *starMatrix, int nOfRows, int nOfColumns) 186 | { 187 | int row, col; 188 | 189 | for (row = 0; row < nOfRows; row++) 190 | for (col = 0; col < nOfColumns; col++) 191 | if (starMatrix[row + nOfRows * col]) 192 | { 193 | #ifdef ONE_INDEXING 194 | assignment[row] = col + 1; /* MATLAB-Indexing */ 195 | #else 196 | assignment[row] = col; 197 | #endif 198 | break; 199 | } 200 | } 201 | 202 | /********************************************************/ 203 | void HungarianAlgorithm::computeassignmentcost(int *assignment, double *cost, double *distMatrix, int nOfRows) 204 | { 205 | int row, col; 206 | 207 | for (row = 0; row < nOfRows; row++) 208 | { 209 | col = assignment[row]; 210 | if (col >= 0) 211 | *cost += distMatrix[row + nOfRows * col]; 212 | } 213 | } 214 | 215 | /********************************************************/ 216 | void HungarianAlgorithm::step2a(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim) 217 | { 218 | bool *starMatrixTemp, *columnEnd; 219 | int col; 220 | 221 | /* cover every column containing a starred zero */ 222 | for (col = 0; col < nOfColumns; col++) 223 | { 224 | starMatrixTemp = starMatrix + nOfRows * col; 225 | columnEnd = starMatrixTemp + nOfRows; 226 | while (starMatrixTemp < columnEnd) 227 | { 228 | if (*starMatrixTemp++) 229 | { 230 | coveredColumns[col] = true; 231 | break; 232 | } 233 | } 234 | } 235 | 236 | /* move to step 3 */ 237 | step2b(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim); 238 | } 239 | 240 | /********************************************************/ 241 | void HungarianAlgorithm::step2b(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim) 242 | { 243 | int col, nOfCoveredColumns; 244 | 245 | /* count covered columns */ 246 | nOfCoveredColumns = 0; 247 | for (col = 0; col < nOfColumns; col++) 248 | if (coveredColumns[col]) 249 | nOfCoveredColumns++; 250 | 251 | if (nOfCoveredColumns == minDim) 252 | { 253 | /* algorithm finished */ 254 | buildassignmentvector(assignment, starMatrix, nOfRows, nOfColumns); 255 | } 256 | else 257 | { 258 | /* move to step 3 */ 259 | step3(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim); 260 | } 261 | } 262 | 263 | /********************************************************/ 264 | void HungarianAlgorithm::step3(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim) 265 | { 266 | bool zerosFound; 267 | int row, col, starCol; 268 | 269 | zerosFound = true; 270 | while (zerosFound) 271 | { 272 | zerosFound = false; 273 | for (col = 0; col < nOfColumns; col++) 274 | if (!coveredColumns[col]) 275 | for (row = 0; row < nOfRows; row++) 276 | if ((!coveredRows[row]) && (fabs(distMatrix[row + nOfRows * col]) < DBL_EPSILON)) 277 | { 278 | /* prime zero */ 279 | primeMatrix[row + nOfRows * col] = true; 280 | 281 | /* find starred zero in current row */ 282 | for (starCol = 0; starCol < nOfColumns; starCol++) 283 | if (starMatrix[row + nOfRows * starCol]) 284 | break; 285 | 286 | if (starCol == nOfColumns) /* no starred zero found */ 287 | { 288 | /* move to step 4 */ 289 | step4(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim, row, col); 290 | return; 291 | } 292 | else 293 | { 294 | coveredRows[row] = true; 295 | coveredColumns[starCol] = false; 296 | zerosFound = true; 297 | break; 298 | } 299 | } 300 | } 301 | 302 | /* move to step 5 */ 303 | step5(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim); 304 | } 305 | 306 | /********************************************************/ 307 | void HungarianAlgorithm::step4(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim, int row, int col) 308 | { 309 | int n, starRow, starCol, primeRow, primeCol; 310 | int nOfElements = nOfRows * nOfColumns; 311 | 312 | /* generate temporary copy of starMatrix */ 313 | for (n = 0; n < nOfElements; n++) 314 | newStarMatrix[n] = starMatrix[n]; 315 | 316 | /* star current zero */ 317 | newStarMatrix[row + nOfRows * col] = true; 318 | 319 | /* find starred zero in current column */ 320 | starCol = col; 321 | for (starRow = 0; starRow < nOfRows; starRow++) 322 | if (starMatrix[starRow + nOfRows * starCol]) 323 | break; 324 | 325 | while (starRow < nOfRows) 326 | { 327 | /* unstar the starred zero */ 328 | newStarMatrix[starRow + nOfRows * starCol] = false; 329 | 330 | /* find primed zero in current row */ 331 | primeRow = starRow; 332 | for (primeCol = 0; primeCol < nOfColumns; primeCol++) 333 | if (primeMatrix[primeRow + nOfRows * primeCol]) 334 | break; 335 | 336 | /* star the primed zero */ 337 | newStarMatrix[primeRow + nOfRows * primeCol] = true; 338 | 339 | /* find starred zero in current column */ 340 | starCol = primeCol; 341 | for (starRow = 0; starRow < nOfRows; starRow++) 342 | if (starMatrix[starRow + nOfRows * starCol]) 343 | break; 344 | } 345 | 346 | /* use temporary copy as new starMatrix */ 347 | /* delete all primes, uncover all rows */ 348 | for (n = 0; n < nOfElements; n++) 349 | { 350 | primeMatrix[n] = false; 351 | starMatrix[n] = newStarMatrix[n]; 352 | } 353 | for (n = 0; n < nOfRows; n++) 354 | coveredRows[n] = false; 355 | 356 | /* move to step 2a */ 357 | step2a(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim); 358 | } 359 | 360 | /********************************************************/ 361 | void HungarianAlgorithm::step5(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim) 362 | { 363 | double h, value; 364 | int row, col; 365 | 366 | /* find smallest uncovered element h */ 367 | h = DBL_MAX; 368 | for (row = 0; row < nOfRows; row++) 369 | if (!coveredRows[row]) 370 | for (col = 0; col < nOfColumns; col++) 371 | if (!coveredColumns[col]) 372 | { 373 | value = distMatrix[row + nOfRows * col]; 374 | if (value < h) 375 | h = value; 376 | } 377 | 378 | /* add h to each covered row */ 379 | for (row = 0; row < nOfRows; row++) 380 | if (coveredRows[row]) 381 | for (col = 0; col < nOfColumns; col++) 382 | distMatrix[row + nOfRows * col] += h; 383 | 384 | /* subtract h from each uncovered column */ 385 | for (col = 0; col < nOfColumns; col++) 386 | if (!coveredColumns[col]) 387 | for (row = 0; row < nOfRows; row++) 388 | distMatrix[row + nOfRows * col] -= h; 389 | 390 | /* move to step 3 */ 391 | step3(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim); 392 | } 393 | 394 | } // namespace sort -------------------------------------------------------------------------------- /sort/debug.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_HPP 2 | #define DEBUG_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | namespace sort 17 | { 18 | #define debug(a, args...) printf("%s(%s:%d) " a "\n", __func__, __FILE__, __LINE__, ##args) 19 | #define ddebug(a, args...) //printf("%s(%s:%d) " a "\n", __func__, __FILE__, __LINE__, ##args) 20 | 21 | using namespace std; 22 | 23 | void timerExample(); 24 | inline void timerExample() 25 | { 26 | std::clock_t start; 27 | double duration; 28 | 29 | start = std::clock(); 30 | 31 | /* Your algorithm here */ 32 | 33 | duration = (std::clock() - start) / (double)CLOCKS_PER_SEC; 34 | std::cout << "time: " << duration << '\n'; 35 | } 36 | 37 | void timerExampleCV(); 38 | inline void timerExampleCV() 39 | { 40 | double timer = (double)cv::getTickCount(); 41 | float timedft = 0; 42 | 43 | // your test code here 44 | 45 | timedft = ((double)cv::getTickCount() - timer) / cv::getTickFrequency(); 46 | debug("time: %f", timedft); 47 | } 48 | 49 | // Show the type of a Mat 50 | // Using like this: 51 | // string ty = type2str( im.type() ); 52 | // printf("im: %s %d x %d \n", ty.c_str(), im.cols, im.rows ); 53 | void printMat(cv::Mat mat); 54 | inline void printMat(cv::Mat mat) 55 | { 56 | int type = mat.type(); 57 | string r; 58 | 59 | uchar depth = type & CV_MAT_DEPTH_MASK; 60 | uchar chans = 1 + (type >> CV_CN_SHIFT); 61 | 62 | switch (depth) 63 | { 64 | case CV_8U: 65 | r = "8U"; 66 | break; 67 | case CV_8S: 68 | r = "8S"; 69 | break; 70 | case CV_16U: 71 | r = "16U"; 72 | break; 73 | case CV_16S: 74 | r = "16S"; 75 | break; 76 | case CV_32S: 77 | r = "32S"; 78 | break; 79 | case CV_32F: 80 | r = "32F"; 81 | break; 82 | case CV_64F: 83 | r = "64F"; 84 | break; 85 | default: 86 | r = "User"; 87 | break; 88 | } 89 | 90 | r += "C"; 91 | r += (chans + '0'); 92 | 93 | debug("%s %d x %d", r.c_str(), mat.rows, mat.cols); 94 | //return r; 95 | } 96 | 97 | void printVector_Mat(std::vector a); 98 | inline void printVector_Mat(std::vector a) 99 | { 100 | printMat(a[0]); 101 | for (size_t i = 0; i < a.size(); i++) 102 | { 103 | debug("%lu, %lu, %d x %d", i, a.size(), a[i].rows, a[i].cols); 104 | } 105 | } 106 | 107 | void printMaxmin(); 108 | inline void printMaxmin(cv::Mat mat) 109 | { 110 | cv::Point p; 111 | double maxValue = -1, minValue = 256; 112 | cv::minMaxLoc(mat, &minValue, &maxValue, NULL, &p); 113 | printf("mat: min: %lf max: %lf loc: %d %d \n", minValue, maxValue, p.x, p.y); 114 | } 115 | 116 | void showmat1channels(cv::Mat mat, int type); 117 | inline void showmat1channels(cv::Mat mat, int type) 118 | { 119 | for (int i = 0; i < mat.rows; i++) 120 | { 121 | for (int j = 0; j < mat.cols; j++) 122 | { 123 | if (type == 0) 124 | { // char 125 | printf("%d ", mat.at(i, j)); 126 | } 127 | else if (type == 1) 128 | { // int 129 | printf("%d ", mat.at(i, j)); 130 | } 131 | else if (type == 2) 132 | { //float 133 | printf("%f ", mat.at(i, j)); 134 | } 135 | else if (type == 3) 136 | { //double 137 | printf("%lf ", mat.at(i, j)); 138 | } 139 | } 140 | printf("\n"); 141 | } 142 | printf("-------------------------End of 1 channel mat\n"); 143 | } 144 | 145 | void showmat2channels(cv::Mat mat, int type); 146 | 147 | inline void showmat2channels(cv::Mat mat, int type) 148 | { 149 | for (int k = 0; k < mat.channels(); k++) 150 | { 151 | printf("\n"); 152 | for (int i = 0; i < mat.rows; i++) 153 | { 154 | for (int j = 0; j < mat.cols; j++) 155 | { 156 | if (type == 0) 157 | { // char 158 | printf("%d ", mat.at(i, j)[k]); 159 | } 160 | else if (type == 1) 161 | { // int 162 | printf("%d ", mat.at(i, j)[k]); 163 | } 164 | else if (type == 2) 165 | { //float 166 | printf("%f ", mat.at(i, j)[k]); 167 | } 168 | else if (type == 3) 169 | { //float 170 | printf("%lf ", mat.at(i, j)[k]); 171 | } 172 | } 173 | printf("\n"); 174 | } 175 | printf("-------------------------"); 176 | } 177 | printf("End of 2 channels mat\n"); 178 | } 179 | 180 | void showmat3channels(cv::Mat mat, int type); 181 | 182 | inline void showmat3channels(cv::Mat mat, int type) 183 | { 184 | for (int k = 0; k < mat.channels(); k++) 185 | { 186 | for (int i = 0; i < mat.rows; i++) 187 | { 188 | for (int j = 0; j < mat.cols; j++) 189 | { 190 | if (type == 0) 191 | { // char 192 | printf("%d ", mat.at(i, j)[k]); 193 | } 194 | else if (type == 1) 195 | { // int 196 | printf("%d ", mat.at(i, j)[k]); 197 | } 198 | else if (type == 2) 199 | { //float 200 | printf("%f ", mat.at(i, j)[k]); 201 | } 202 | else if (type == 3) 203 | { //float 204 | printf("%lf ", mat.at(i, j)[k]); 205 | } 206 | } 207 | printf("\n"); 208 | } 209 | printf("\n\n"); 210 | break; 211 | } 212 | printf("End of 3 channel mat\n"); 213 | } 214 | 215 | void showmat1ch(cv::Mat mat, int type); 216 | inline void showmat1ch(cv::Mat mat, int type) 217 | { 218 | printf("\nFirst row: \n"); 219 | for (int j = 0; j < mat.cols; j++) 220 | { 221 | if (type == 1) 222 | { // int 223 | printf("%d ", mat.at(0, j)); 224 | } 225 | else if (type == 2) 226 | { //float 227 | printf("%f ", mat.at(0, j)); 228 | } 229 | else if (type == 3) 230 | { // first row 231 | printf("%lf ", mat.at(0, j)); 232 | } 233 | } 234 | printf("\nrow %d: \n", mat.cols - 1); 235 | for (int j = 0; j < mat.cols; j++) 236 | { 237 | if (type == 1) 238 | { // last row 239 | printf("%d ", mat.at(mat.cols - 1, j)); 240 | } 241 | else if (type == 2) 242 | { // last row 243 | printf("%f ", mat.at(mat.cols - 1, j)); 244 | } 245 | else if (type == 3) 246 | { // last row 247 | printf("%lf ", mat.at(mat.cols - 1, j)); 248 | } 249 | } 250 | printf("\nFirst col: \n"); 251 | for (int i = 0; i < mat.rows; i++) 252 | { 253 | if (type == 1) 254 | { // first col 255 | printf("%d ", mat.at(i, 0)); 256 | } 257 | else if (type == 2) 258 | { // first col 259 | printf("%f ", mat.at(i, 0)); 260 | } 261 | else if (type == 3) 262 | { // first col 263 | printf("%lf ", mat.at(i, 0)); 264 | } 265 | } 266 | printf("\ncol %d: \n", mat.rows - 1); 267 | for (int i = 0; i < mat.rows; i++) 268 | { 269 | if (type == 1) 270 | { // last col 271 | printf("%d ", mat.at(i, mat.rows - 1)); 272 | } 273 | else if (type == 2) 274 | { // last col 275 | printf("%f ", mat.at(i, mat.rows - 1)); 276 | } 277 | else if (type == 3) 278 | { // last col 279 | printf("%lf ", mat.at(i, mat.rows - 1)); 280 | } 281 | } 282 | printf("\nEnd of 2 channel mat\n"); 283 | } 284 | 285 | void showmat2ch(cv::Mat mat, int type); 286 | inline void showmat2ch(cv::Mat mat, int type) 287 | { 288 | printf("First row: \n"); 289 | for (int k = 0; k < mat.channels(); k++) 290 | { 291 | for (int j = 0; j < mat.cols; j++) 292 | { 293 | if (type == 3) 294 | { // first row 295 | printf("%lf ", mat.at(0, j)[k]); 296 | } 297 | } 298 | printf("\n\n"); 299 | } 300 | printf("\n"); 301 | printf("row %d: \n", mat.cols - 1); 302 | for (int k = 0; k < mat.channels(); k++) 303 | { 304 | for (int j = 0; j < mat.cols; j++) 305 | { 306 | if (type == 3) 307 | { // last row 308 | printf("%lf ", mat.at(mat.cols - 1, j)[k]); 309 | } 310 | } 311 | printf("\n\n"); 312 | } 313 | printf("\n"); 314 | printf("First col: \n"); 315 | for (int k = 0; k < mat.channels(); k++) 316 | { 317 | for (int i = 0; i < mat.rows; i++) 318 | { 319 | if (type == 3) 320 | { // first col 321 | printf("%lf ", mat.at(i, 0)[k]); 322 | } 323 | } 324 | printf("\n\n"); 325 | } 326 | printf("\n"); 327 | printf("col %d: \n", mat.rows - 1); 328 | for (int k = 0; k < mat.channels(); k++) 329 | { 330 | for (int i = 0; i < mat.rows; i++) 331 | { 332 | if (type == 3) 333 | { // last col 334 | printf("%lf ", mat.at(i, mat.rows - 1)[k]); 335 | } 336 | } 337 | printf("\n\n"); 338 | } 339 | printf("End of 2 channel mat\n"); 340 | } 341 | 342 | // Attention!!!! opencv/caffe: BGR, matlab: RGB, different order!!! 343 | void showmat3ch(cv::Mat mat, int type); 344 | inline void showmat3ch(cv::Mat mat, int type) 345 | { 346 | std::vector splitmat; 347 | cv::split(mat, splitmat); 348 | 349 | debug("channels: %lu", splitmat.size()); 350 | 351 | printf("First row of channel 0: \n"); 352 | for (int j = 0; j < mat.cols; j += 1) 353 | { 354 | if (type == 0) 355 | { // 2: means Red, 0 means first row 356 | printf("%d ", splitmat[2].at(0, j)); 357 | } 358 | else if (type == 1) 359 | { 360 | printf("%d ", splitmat[2].at(0, j)); 361 | } 362 | else if (type == 2) 363 | { 364 | printf("%f ", splitmat[2].at(0, j)); 365 | } 366 | else if (type == 3) 367 | { 368 | printf("%lf ", splitmat[2].at(0, j)); 369 | } 370 | } 371 | printf("\n\n"); 372 | 373 | printf("\n"); 374 | printf("First col of channel 0: \n"); 375 | for (int i = 0; i < mat.rows; i += 1) 376 | { 377 | if (type == 0) 378 | { 379 | printf("%d ", splitmat[2].at(i, 0)); 380 | } 381 | else if (type == 1) 382 | { 383 | printf("%d ", splitmat[2].at(i, 0)); 384 | } 385 | else if (type == 2) 386 | { 387 | printf("%f ", splitmat[2].at(i, 0)); 388 | } 389 | else if (type == 3) 390 | { 391 | printf("%lf ", splitmat[2].at(i, 0)); 392 | } 393 | } 394 | printf("\n\n"); 395 | 396 | printf("End of feature mat\n"); 397 | } 398 | 399 | void showmatNch(cv::Mat mat, int type); 400 | inline void showmatNch(cv::Mat mat, int type) 401 | { 402 | std::vector splitmat; 403 | cv::split(mat, splitmat); 404 | 405 | debug("channels: %lu", splitmat.size()); 406 | printf("1th row of channel 0: \n"); 407 | for (int j = 0; j < mat.cols; j += 1) 408 | { 409 | if (type == 0) 410 | { 411 | printf("%d ", splitmat[0].at(1, j)); 412 | } 413 | else if (type == 1) 414 | { // first row 415 | printf("%d ", splitmat[0].at(1, j)); 416 | } 417 | else if (type == 2) 418 | { // first row 419 | printf("%f ", splitmat[0].at(1, j)); 420 | } 421 | else if (type == 3) 422 | { // first row 423 | printf("%lf ", splitmat[0].at(1, j)); 424 | } 425 | } 426 | printf("\n"); 427 | printf("1th col of channel 0: \n"); 428 | for (int i = 0; i < mat.rows; i += 1) 429 | { 430 | if (type == 0) 431 | { // first row 432 | printf("%d ", splitmat[0].at(i, 1)); 433 | } 434 | else if (type == 1) 435 | { // first row 436 | printf("%d ", splitmat[0].at(i, 1)); 437 | } 438 | else if (type == 2) 439 | { // first row 440 | printf("%f ", splitmat[0].at(i, 1)); 441 | } 442 | else if (type == 3) 443 | { // first col 444 | printf("%lf ", splitmat[0].at(i, 1)); 445 | } 446 | } 447 | printf("\n"); 448 | printf("10th row of channel 0: \n"); 449 | for (int j = 0; j < mat.cols; j += 1) 450 | { 451 | if (type == 0) 452 | { 453 | printf("%d ", splitmat[0].at(10, j)); 454 | } 455 | else if (type == 1) 456 | { // first row 457 | printf("%d ", splitmat[0].at(10, j)); 458 | } 459 | else if (type == 2) 460 | { // first row 461 | printf("%f ", splitmat[0].at(10, j)); 462 | } 463 | else if (type == 3) 464 | { // first row 465 | printf("%lf ", splitmat[0].at(10, j)); 466 | } 467 | } 468 | printf("\n"); 469 | printf("20th col of channel 0: \n"); 470 | for (int i = 0; i < mat.rows; i += 1) 471 | { 472 | if (type == 0) 473 | { // first row 474 | printf("%d ", splitmat[0].at(i, 20)); 475 | } 476 | else if (type == 1) 477 | { // first row 478 | printf("%d ", splitmat[0].at(i, 20)); 479 | } 480 | else if (type == 2) 481 | { // first row 482 | printf("%f ", splitmat[0].at(i, 20)); 483 | } 484 | else if (type == 3) 485 | { // first col 486 | printf("%lf ", splitmat[0].at(i, 20)); 487 | } 488 | } 489 | printf("\n"); 490 | printf("24th row of channel -1: \n"); 491 | for (int j = 0; j < mat.cols; j += 1) 492 | { 493 | if (type == 0) 494 | { 495 | printf("%d ", splitmat[splitmat.size()-1].at(24, j)); 496 | } 497 | else if (type == 1) 498 | { // first row 499 | printf("%d ", splitmat[splitmat.size()-1].at(24, j)); 500 | } 501 | else if (type == 2) 502 | { // first row 503 | printf("%f ", splitmat[splitmat.size()-1].at(24, j)); 504 | } 505 | else if (type == 3) 506 | { // first row 507 | printf("%lf ", splitmat[splitmat.size()-1].at(24, j)); 508 | } 509 | } 510 | printf("\n\n"); 511 | printf("End of feature mat\n"); 512 | } 513 | 514 | //TEST========================================================================== 515 | // Simple test of the structure of mat in opencv; channel->x->y; 516 | void opencvTest(); 517 | inline void opencvTest() 518 | { 519 | printf("opencvTest begin=======================================\n"); 520 | float *newdata = (float *)malloc(sizeof(float) * (2 * 3 * 4)); 521 | 522 | for (int i = 0; i < 2 * 3 * 4; i++) 523 | { 524 | newdata[i] = i; 525 | } 526 | 527 | cv::Mat mat = cv::Mat(cv::Size(3, 4), CV_32FC(2), newdata); 528 | 529 | printf("\nInfo of original mat:"); 530 | printMat(mat); 531 | for (int i = 0; i < 2 * 3 * 4; i++) 532 | { 533 | printf("%f ", mat.at(0, i)); 534 | } 535 | printf("\n"); 536 | 537 | std::vector splitmat; 538 | cv::split(mat, splitmat); 539 | 540 | printf("\nInfo of splited mat:"); 541 | printMat(splitmat[0]); 542 | 543 | printf("channel 0:\n"); 544 | for (int j = 0; j < mat.rows; j++) 545 | { 546 | for (int i = 0; i < mat.cols; i++) 547 | { 548 | printf("%f ", splitmat[0].at(j, i)); 549 | } 550 | printf("\n"); 551 | } 552 | printf("\n"); 553 | printf("channel 1:\n"); 554 | for (int j = 0; j < mat.rows; j++) 555 | { 556 | for (int i = 0; i < mat.cols; i++) 557 | { 558 | printf("%f ", splitmat[1].at(j, i)); 559 | } 560 | printf("\n"); 561 | } 562 | printf("\n"); 563 | printf("%p, %p, %p, %p, %p\n", newdata, 564 | &mat.at(0, 0)[0], 565 | &mat.at(0, 0)[1], 566 | &mat.at(0, 1)[0], 567 | &mat.at(1, 0)[0] 568 | ); 569 | 570 | free(newdata); 571 | printf("opencvTest end=======================================\n"); 572 | } 573 | 574 | void absTest(); 575 | inline void absTest() 576 | { 577 | printf("absTest begin=======================================\n"); 578 | std::vector v{0.1, 0.2}; 579 | //sometimes this works: 580 | //``` 581 | //float abs = abs(1.23f); 582 | //``` 583 | //but it use a different liberay from eigen, cause error 584 | //so remember to add `std::` before! 585 | float abs = std::abs(1.23f); 586 | debug("False abs:%f", abs); 587 | 588 | abs = std::abs(1.23f); 589 | debug("True abs:%f", abs); 590 | printf("absTest end=======================================\n"); 591 | } 592 | 593 | void accumulateTest(); 594 | inline void accumulateTest() 595 | { 596 | printf("accumulateTest begin=======================================\n"); 597 | std::vector v{0.1, 0.2}; 598 | float sum = std::accumulate(v.begin(), v.end(), 0); 599 | debug("False sum:%f", sum); 600 | 601 | sum = std::accumulate(v.begin(), v.end(), 0.0f); 602 | debug("True sum:%f", sum); 603 | printf("accumulateTest end=======================================\n"); 604 | } 605 | /* Compare the differences of function copyTo() and clone(): 606 | [0, 0, 0, 0, 0] 607 | [0, 0, 0, 0, 0] 608 | [0, 0, 0, 0, 0] 609 | [1, 1, 1, 1, 1] 610 | */ 611 | void copyTo_clone_Difference(); 612 | inline void copyTo_clone_Difference() 613 | { 614 | // copyTo will not change the address of the destination matrix. 615 | cv::Mat mat1 = cv::Mat::ones(1, 5, CV_32F); 616 | cv::Mat mat2 = mat1; 617 | cv::Mat mat3 = cv::Mat::zeros(1, 5, CV_32F); 618 | mat3.copyTo(mat1); 619 | std::cout << mat1 << std::endl; // it has a old address with new value 620 | std::cout << mat2 << std::endl; // it has a old address with new value 621 | // clone will always allocate a new address for the destination matrix. 622 | mat1 = cv::Mat::ones(1, 5, CV_32F); 623 | mat2 = mat1; 624 | mat3 = cv::Mat::zeros(1, 5, CV_32F); 625 | mat1 = mat3.clone(); 626 | std::cout << mat1 << std::endl; // it has a new address with new value 627 | std::cout << mat2 << std::endl; // it has a old address with old value 628 | } 629 | 630 | void matReferenceTest(); 631 | inline void matReferenceTest() 632 | { 633 | cv::Mat mat; 634 | mat.release(); 635 | debug("%p, %d", mat.data, mat.data==NULL); 636 | mat.create(cv::Size(10, 10), CV_32FC2); 637 | debug("%p, %d", mat.data, mat.data==NULL); 638 | mat.release(); 639 | debug("%p, %d", mat.data, mat.data==NULL); 640 | } 641 | 642 | } 643 | #endif -------------------------------------------------------------------------------- /cvmultitracker/opencvmultitracker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | using namespace cv; 12 | 13 | cv::Ptr createTrackerByName(cv::String name) 14 | { 15 | cv::Ptr tracker; 16 | 17 | if (name == "KCF") 18 | tracker = cv::TrackerKCF::create(); 19 | else if (name == "TLD") 20 | tracker = cv::TrackerTLD::create(); 21 | else if (name == "BOOSTING") 22 | tracker = cv::TrackerBoosting::create(); 23 | else if (name == "MEDIAN_FLOW") 24 | tracker = cv::TrackerMedianFlow::create(); 25 | else if (name == "MIL") 26 | tracker = cv::TrackerMIL::create(); 27 | else if (name == "GOTURN") 28 | tracker = cv::TrackerGOTURN::create(); 29 | else if (name == "MOSSE") 30 | tracker = cv::TrackerMOSSE::create(); 31 | else if (name == "CSRT") 32 | tracker = cv::TrackerCSRT::create(); 33 | else 34 | CV_Error(cv::Error::StsBadArg, "Invalid tracking algorithm name\n"); 35 | 36 | return tracker; 37 | } 38 | 39 | int main(int argc, char **argv) 40 | { 41 | // Database settings 42 | string databaseTypes[5] = {"Demo","VOT-2017", "TB-2015", "TLP", "UAV123"}; 43 | string databaseType = databaseTypes[0];//4]; 44 | // Read from the images ==================================================== 45 | int f, isLost; 46 | float x, y, w, h; 47 | float x1, y1, x2, y2, x3, y3, x4, y4; //gt for vot 48 | std::string s; 49 | std::string path; 50 | ifstream *groundtruth; 51 | ostringstream osfile; 52 | if (databaseType == "Demo") 53 | { 54 | path = "../sequences/Crossing"; 55 | // some of the dataset has '\t' as the delimiter, change it to ','. 56 | fstream gt(path + "/groundtruth_rect.txt"); 57 | string tmp; 58 | size_t index = 1; 59 | while (gt >> tmp) 60 | { 61 | if(tmp.find(',')<10) 62 | { 63 | break; 64 | } 65 | if (index%4 == 0) 66 | { 67 | } 68 | else 69 | { 70 | gt << ","; 71 | } 72 | index++; 73 | } 74 | gt.close(); 75 | // Read the groundtruth bbox 76 | groundtruth = new ifstream(path + "/groundtruth_rect.txt"); 77 | f = 1; 78 | getline(*groundtruth, s, ','); 79 | x = atof(s.c_str()); 80 | getline(*groundtruth, s, ','); 81 | y = atof(s.c_str()); 82 | getline(*groundtruth, s, ','); 83 | w = atof(s.c_str()); 84 | getline(*groundtruth, s); 85 | h = atof(s.c_str()); 86 | cout << f << " " << x << " " << y << " " << w << " " << h << " " << endl; 87 | // Read images in a folder 88 | osfile << path << "/img/" << setw(4) << setfill('0') << f << ".jpg"; 89 | cout << osfile.str() << endl; 90 | } 91 | else if (databaseType == "VOT-2017") 92 | { 93 | string folderVOT = "girl"; //"iceskater1";//"road";//"drone1";//"iceskater1";//"girl"; //"road";//"bag";////"helicopter"; 94 | path = "/media/elab/sdd/data/VOT/vot2017/" + folderVOT; 95 | // Read the groundtruth bbox 96 | groundtruth = new ifstream("/media/elab/sdd/data/VOT/vot2017/" + folderVOT + "/groundtruth.txt"); 97 | f = 1; 98 | getline(*groundtruth, s, ','); 99 | x1 = atof(s.c_str()); 100 | getline(*groundtruth, s, ','); 101 | y1 = atof(s.c_str()); 102 | getline(*groundtruth, s, ','); 103 | x2 = atof(s.c_str()); 104 | getline(*groundtruth, s, ','); 105 | y2 = atof(s.c_str()); 106 | getline(*groundtruth, s, ','); 107 | x3 = atof(s.c_str()); 108 | getline(*groundtruth, s, ','); 109 | y3 = atof(s.c_str()); 110 | getline(*groundtruth, s, ','); 111 | x4 = atof(s.c_str()); 112 | getline(*groundtruth, s); 113 | y4 = atof(s.c_str()); 114 | x = std::min(x1, x4); 115 | y = std::min(y1, y2); 116 | w = std::max(x2, x3) - x; 117 | h = std::max(y3, y4) - y; 118 | cout << x << " " << y << " " << w << " " << h << endl; 119 | // Read images in a folder 120 | osfile << path << "/" << setw(8) << setfill('0') << f << ".jpg"; 121 | cout << osfile.str() << endl; 122 | } 123 | else if (databaseType == "TB-2015") 124 | { 125 | path = "/media/elab/sdd/data/TB-2015/Crossing"; //Coke"; ///Bird1";//BlurFace"; 126 | // some of the dataset has '\t' as the delimiter, so first change it to ','. 127 | fstream gt(path + "/groundtruth_rect.txt"); 128 | string tmp; 129 | size_t index = 1; 130 | while (gt >> tmp) 131 | { 132 | if(tmp.find(',')<10) 133 | { 134 | break; 135 | } 136 | if (index%4 == 0) 137 | { 138 | } 139 | else 140 | { 141 | gt << ","; 142 | } 143 | index++; 144 | } 145 | gt.close(); 146 | // Read the groundtruth bbox 147 | groundtruth = new ifstream(path + "/groundtruth_rect.txt"); 148 | f = 1; 149 | getline(*groundtruth, s, ','); 150 | x = atof(s.c_str()); 151 | getline(*groundtruth, s, ','); 152 | y = atof(s.c_str()); 153 | getline(*groundtruth, s, ','); 154 | w = atof(s.c_str()); 155 | getline(*groundtruth, s); 156 | h = atof(s.c_str()); 157 | cout << f << " " << x << " " << y << " " << w << " " << h << " " << endl; 158 | // Read images in a folder 159 | osfile << path << "/img/" << setw(4) << setfill('0') << f << ".jpg"; 160 | cout << osfile.str() << endl; 161 | } 162 | else if (databaseType == "TLP") 163 | { 164 | path = "/media/elab/sdd/data/TLP/Drone1";//Sam";//Drone2"; //Bike";//Alladin";//IceSkating";// 165 | // Read the groundtruth bbox 166 | groundtruth = new ifstream(path + "/groundtruth_rect.txt"); 167 | getline(*groundtruth, s, ','); 168 | f = atof(s.c_str()); 169 | getline(*groundtruth, s, ','); 170 | x = atof(s.c_str()); 171 | getline(*groundtruth, s, ','); 172 | y = atof(s.c_str()); 173 | getline(*groundtruth, s, ','); 174 | w = atof(s.c_str()); 175 | getline(*groundtruth, s, ','); 176 | h = atof(s.c_str()); 177 | getline(*groundtruth, s); 178 | isLost = atof(s.c_str()); 179 | cout << f << " " << x << " " << y << " " << w << " " << h << " " << isLost << endl; 180 | // Read images in a folder 181 | osfile << path << "/img/" << setw(5) << setfill('0') << f << ".jpg"; 182 | cout << osfile.str() << endl; 183 | } 184 | else if (databaseType == "UAV123") 185 | { 186 | string folderUAV = "bike1"; //"person23";//"building1";//"wakeboard2"; //"person3";// 187 | path = "/media/elab/sdd/data/UAV123/data_seq/UAV123/" + folderUAV; 188 | // Read the groundtruth bbox 189 | groundtruth = new ifstream("/media/elab/sdd/data/UAV123/anno/UAV123/" + folderUAV + ".txt"); 190 | f = 1; 191 | getline(*groundtruth, s, ','); 192 | x = atof(s.c_str()); 193 | getline(*groundtruth, s, ','); 194 | y = atof(s.c_str()); 195 | getline(*groundtruth, s, ','); 196 | w = atof(s.c_str()); 197 | getline(*groundtruth, s); 198 | h = atof(s.c_str()); 199 | cout << x << " " << y << " " << w << " " << h << endl; 200 | // Read images in a folder 201 | osfile << path << "/" << setw(6) << setfill('0') << f << ".jpg"; 202 | cout << osfile.str() << endl; 203 | } 204 | 205 | Rect2f bboxGroundtruth(x, y, w, h); 206 | 207 | cv::Mat frame = cv::imread(osfile.str().c_str(), CV_LOAD_IMAGE_UNCHANGED); 208 | cv::Mat frameDraw; 209 | frame.copyTo(frameDraw); 210 | if (!frame.data) 211 | { 212 | cout << "Could not open or find the image" << std::endl; 213 | return -1; 214 | } 215 | // Draw gt; 216 | if (databaseType == "Demo") 217 | { 218 | rectangle(frameDraw, bboxGroundtruth, Scalar(0, 0, 0), 2, 1); 219 | } 220 | else if (databaseType == "TLP") 221 | { 222 | rectangle(frameDraw, bboxGroundtruth, Scalar(0, 0, 0), 2, 1); 223 | } 224 | else if (databaseType == "TB-2015") 225 | { 226 | rectangle(frameDraw, bboxGroundtruth, Scalar(0, 0, 0), 2, 1); 227 | } 228 | else if (databaseType == "UAV123") 229 | { 230 | rectangle(frameDraw, bboxGroundtruth, Scalar(0, 0, 0), 2, 1); 231 | } 232 | else if (databaseType == "VOT-2017") 233 | { 234 | line(frameDraw, cv::Point(x1, y1), cv::Point(x2, y2), Scalar(0, 0, 0), 2, 1); 235 | line(frameDraw, cv::Point(x2, y2), cv::Point(x3, y3), Scalar(0, 0, 0), 2, 1); 236 | line(frameDraw, cv::Point(x3, y3), cv::Point(x4, y4), Scalar(0, 0, 0), 2, 1); 237 | line(frameDraw, cv::Point(x4, y4), cv::Point(x1, y1), Scalar(0, 0, 0), 2, 1); 238 | } 239 | 240 | std::string trackingAlg = "KCF"; 241 | // one tracker 242 | Ptr tracker = createTrackerByName(trackingAlg); 243 | Rect2d bbox(x, y, w, h); 244 | tracker->init(frame, bboxGroundtruth); 245 | 246 | // multitracker 247 | MultiTracker trackers; 248 | vector objects; 249 | vector ROIs; 250 | selectROIs("tracker",frame,ROIs); 251 | std::vector > algorithms; 252 | for (size_t i = 0; i < ROIs.size(); i++) 253 | { 254 | algorithms.push_back(createTrackerByName(trackingAlg)); 255 | objects.push_back(ROIs[i]); 256 | } 257 | trackers.add(algorithms,frame,objects); 258 | 259 | 260 | 261 | while (frame.data) 262 | { 263 | frame.copyTo(frameDraw); 264 | 265 | double timer = (double)getTickCount(); 266 | bool ok = tracker->update(frame, bbox); 267 | float fpsone = getTickFrequency() / ((double)getTickCount() - timer); 268 | 269 | timer = (double)getTickCount(); 270 | trackers.update(frame); 271 | float fpsmulti = getTickFrequency() / ((double)getTickCount() - timer); 272 | 273 | if (ok) 274 | { 275 | rectangle(frameDraw, bbox, Scalar(255, 0, 255), 2, 1); //blue 276 | } 277 | else 278 | { 279 | putText(frameDraw, "ECO tracking failure detected", cv::Point(100, 80), FONT_HERSHEY_SIMPLEX, 280 | 0.75, Scalar(255, 0, 255), 2); 281 | } 282 | for(unsigned i=0;i