evaluation/UAV-benchmark-MOTD_v1.0/utils/clearMOTMex.cpp (388 lines of code) (raw):

#include <matrix.h> #include "mex.h" #include <cmath> #include <omp.h> #include <set> #include <map> #include <vector> #include <algorithm> #include <iterator> #include <unordered_map> using namespace std; inline int index(int i, int j, int numRows) // 2D 0-indexed to C { return j*numRows + i; } inline double euclidean(double x1, double y1, double x2, double y2) { return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)); } double boxiou(double l1, double t1, double w1, double h1, double l2, double t2, double w2, double h2) { double area1 = w1 * h1; double area2 = w2 * h2; double x_overlap = max(0.0, min(l1 + w1, l2 + w2) - max(l1, l2)); double y_overlap = max(0.0, min(t1 + h1, t2 + h2) - max(t1, t2)); double intersectionArea = x_overlap*y_overlap; double unionArea = area1 + area2 - intersectionArea; double iou = intersectionArea / unionArea; return iou; } // Min cost bipartite matching via shortest augmenting paths // // Code from https://github.com/jaehyunp/ // // This is an O(n^3) implementation of a shortest augmenting path // algorithm for finding min cost perfect matchings in dense // graphs. In practice, it solves 1000x1000 problems in around 1 // second. // // cost[i][j] = cost for pairing left node i with right node j // Lmate[i] = index of right node that left node i pairs with // Rmate[j] = index of left node that right node j pairs with // // The values in cost[i][j] may be positive or negative. To perform // maximization, simply negate the cost[][] matrix. typedef vector<double> VD; typedef vector<VD> VVD; typedef vector<int> VI; double MinCostMatching(const VVD &cost, VI &Lmate, VI &Rmate) { int n = int(cost.size()); // construct dual feasible solution VD u(n); VD v(n); for (int i = 0; i < n; i++) { u[i] = cost[i][0]; for (int j = 1; j < n; j++) u[i] = min(u[i], cost[i][j]); } for (int j = 0; j < n; j++) { v[j] = cost[0][j] - u[0]; for (int i = 1; i < n; i++) v[j] = min(v[j], cost[i][j] - u[i]); } // construct primal solution satisfying complementary slackness Lmate = VI(n, -1); Rmate = VI(n, -1); int mated = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (Rmate[j] != -1) continue; if (fabs(cost[i][j] - u[i] - v[j]) < 1e-10) { Lmate[i] = j; Rmate[j] = i; mated++; break; } } } VD dist(n); VI dad(n); VI seen(n); // repeat until primal solution is feasible while (mated < n) { // find an unmatched left node int s = 0; while (Lmate[s] != -1) s++; // initialize Dijkstra fill(dad.begin(), dad.end(), -1); fill(seen.begin(), seen.end(), 0); for (int k = 0; k < n; k++) dist[k] = cost[s][k] - u[s] - v[k]; int j = 0; while (true) { // find closest j = -1; for (int k = 0; k < n; k++) { if (seen[k]) continue; if (j == -1 || dist[k] < dist[j]) j = k; } seen[j] = 1; // termination condition if (Rmate[j] == -1) break; // relax neighbors const int i = Rmate[j]; for (int k = 0; k < n; k++) { if (seen[k]) continue; const double new_dist = dist[j] + cost[i][k] - u[i] - v[k]; if (dist[k] > new_dist) { dist[k] = new_dist; dad[k] = j; } } } // update dual variables for (int k = 0; k < n; k++) { if (k == j || !seen[k]) continue; const int i = Rmate[k]; v[k] += dist[k] - dist[j]; u[i] -= dist[k] - dist[j]; } u[s] += dist[j]; // augment along path while (dad[j] >= 0) { const int d = dad[j]; Rmate[j] = Rmate[d]; Lmate[Rmate[j]] = j; j = d; } Rmate[j] = s; Lmate[s] = j; mated++; } double value = 0; for (int i = 0; i < n; i++) value += cost[i][Lmate[i]]; return value; } void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // gtMat and resMat should contain IDs in range [1,...,numIDs] // and frames in range [1, ..., numFrames] // data format: frame, ID, left, top, width, height, worldX, worldY double *gtMat = mxGetPr(prhs[0]); double *resMat = mxGetPr(prhs[1]); double threshold = (double)mxGetScalar(prhs[2]); bool world = (bool)mxGetScalar(prhs[3]); bool VERBOSE = (bool)mxGetScalar(prhs[4]); int *dimGT, *dimST; dimGT = (int *)mxGetDimensions(prhs[0]); dimST = (int *)mxGetDimensions(prhs[1]); int rowsGT = dimGT[0], colsGT = dimGT[1], rowsST = dimST[0], colsST = dimST[1]; int Fgt=0, Ngt = 0, Nst = 0; for (int i = 0; i < rowsGT; i++) { int frame = gtMat[index(i,0,rowsGT)]; int ID = gtMat[index(i,1,rowsGT)]; if (frame > Fgt) Fgt = frame; if (ID > Ngt) Ngt = ID; } for (int i = 0; i < rowsST; i++) { int frame = resMat[index(i, 0, rowsST)]; if (frame > Fgt) Fgt = frame; int ID = resMat[index(i, 1, rowsST)]; if (ID > Nst) Nst = ID; } plhs[0] = mxCreateDoubleMatrix(1, Fgt, mxREAL); plhs[1] = mxCreateDoubleMatrix(1, Fgt, mxREAL); plhs[2] = mxCreateDoubleMatrix(1, Fgt, mxREAL); plhs[3] = mxCreateDoubleMatrix(1, Fgt, mxREAL); plhs[4] = mxCreateDoubleMatrix(1, Fgt, mxREAL); plhs[5] = mxCreateDoubleMatrix(Fgt, Ngt, mxREAL); plhs[6] = mxCreateDoubleMatrix(Fgt, Ngt, mxREAL); plhs[7] = mxCreateDoubleMatrix(Fgt, Nst, mxREAL); double* mmeOut = mxGetPr(plhs[0]); double* cOut = mxGetPr(plhs[1]); double* fpOut = mxGetPr(plhs[2]); double* mOut = mxGetPr(plhs[3]); double* gOut = mxGetPr(plhs[4]); double* dOut = mxGetPr(plhs[5]); double* MOut = mxGetPr(plhs[6]); double* allfalseposOut = mxGetPr(plhs[7]); //double* MOut = mxGetPr(plhs[8]); double INF = 1e9; vector<unordered_map<int, int>> gtInd(Fgt); vector<unordered_map<int, int>> stInd(Fgt); vector<unordered_map<int,int>> M(Fgt); vector<int> mme(Fgt, 0); // ID Switchtes(mismatches) vector<int> c(Fgt, 0); // matches found vector<int> fp(Fgt, 0); // false positives vector<int> m(Fgt, 0); // misses = false negatives vector<int> g(Fgt, 0); // gt count for each frame vector<vector<double>> d(Fgt, vector<double>(Ngt, 0)); // all distances mapped to [0..1] vector<vector<int>> allfalsepos(Fgt, vector<int>(Nst, 0)); for (int i = 0; i < rowsGT; i++) { int frame = gtMat[index(i, 0, rowsGT)]-1; int ID = gtMat[index(i, 1, rowsGT)]-1; gtInd[frame][ID] = i; } for (int i = 0; i < rowsST; i++) { int frame = resMat[index(i, 0, rowsST)]-1; int ID = resMat[index(i, 1, rowsST)]-1; stInd[frame][ID] = i; } for (int i = 0; i < Fgt; i++) { for (unordered_map<int, int>::iterator it = gtInd[i].begin(); it != gtInd[i].end(); it++) g[i]++; } for (int t = 0; t < Fgt; t++) { //if ((t + 1) % 1000 == 0) mexEvalString("fprintf('.');"); // print every 1000th frame if (t > 0) { vector<int> mappings; for (unordered_map<int,int>::iterator it = M[t - 1].begin(); it != M[t - 1].end(); it++) mappings.push_back(it->first); sort(mappings.begin(), mappings.end()); for (int k = 0; k < mappings.size(); k++) { unordered_map<int, int>::const_iterator foundGtind = gtInd[t].find(mappings[k]); unordered_map<int, int>::const_iterator foundStind = stInd[t].find(M[t - 1][mappings[k]]); if (foundGtind != gtInd[t].end() && foundStind != stInd[t].end()) { bool matched = false; if (world) { double gtx, gty, stx, sty; int rowgt = gtInd[t][mappings[k]]; int rowres = stInd[t][M[t - 1][mappings[k]]]; gtx = gtMat[index(rowgt, 6, rowsGT)]; gty = gtMat[index(rowgt, 7, rowsGT)]; stx = resMat[index(rowres, 6, rowsST)]; sty = resMat[index(rowres, 7, rowsST)]; double dist = euclidean(gtx, gty, stx, sty); matched = (dist <= threshold); } else { double gtleft, gttop, gtwidth, gtheight, stleft, sttop, stwidth, stheight; int rowgt = gtInd[t][mappings[k]]; int rowres = stInd[t][M[t - 1][mappings[k]]]; gtleft = gtMat[index(rowgt, 2, rowsGT)]; gttop = gtMat[index(rowgt, 3, rowsGT)]; gtwidth = gtMat[index(rowgt, 4, rowsGT)]; gtheight = gtMat[index(rowgt, 5, rowsGT)]; stleft = resMat[index(rowres, 2, rowsST)]; sttop = resMat[index(rowres, 3, rowsST)]; stwidth = resMat[index(rowres, 4, rowsST)]; stheight = resMat[index(rowres, 5, rowsST)]; double dist = 1 - boxiou(gtleft, gttop, gtwidth, gtheight, stleft, sttop, stwidth, stheight); matched = (dist <= threshold); } if (matched) { M[t][mappings[k]] = M[t - 1][mappings[k]]; if (VERBOSE) printf("%d: preserve %d\n", t+1, mappings[k]+1); } } } } vector<int> unmappedGt, unmappedEs, stindt, findm; for (unordered_map<int,int>::iterator it = gtInd[t].begin(); it != gtInd[t].end(); it++) { unordered_map<int, int>::const_iterator found = M[t].find(it->first); if (found==M[t].end()) unmappedGt.push_back(it->first); } for (unordered_map<int,int>::iterator it = M[t].begin(); it != M[t].end(); it++) findm.push_back(it->second); for (unordered_map<int,int>::iterator it = stInd[t].begin(); it != stInd[t].end(); it++) stindt.push_back(it->first); sort(stindt.begin(), stindt.end()); sort(findm.begin(), findm.end()); set_difference(stindt.begin(), stindt.end(), findm.begin(), findm.end(), inserter(unmappedEs, unmappedEs.end())); sort(unmappedGt.begin(), unmappedGt.end()); int squareSize = max(unmappedGt.size(), unmappedEs.size()); vector<vector<double>> alldist(squareSize, vector<double>(squareSize, INF)); if (VERBOSE) { printf("%d: UnmappedGTs: ", t+1); for (int i = 0; i < unmappedGt.size(); i++) printf("%d, ", unmappedGt[i]+1); printf("\n%d: UnmappedEs: ", t+1); for (int i = 0; i < unmappedEs.size(); i++) printf("%d, ", unmappedEs[i]+1); printf("\n"); } int uid = 0; // Unique identifier for (int i = 0; i < unmappedGt.size(); i++) { for (int j = 0; j < unmappedEs.size(); j++) { int o = unmappedGt[i]; int e = unmappedEs[j]; if (world) { double gtx, gty, stx, sty; int rowgt = gtInd[t][o]; int rowres = stInd[t][e]; gtx = gtMat[index(rowgt, 6, rowsGT)]; gty = gtMat[index(rowgt, 7, rowsGT)]; stx = resMat[index(rowres, 6, rowsST)]; sty = resMat[index(rowres, 7, rowsST)]; double dist = euclidean(gtx, gty, stx, sty); if (dist <= threshold) { alldist[i][j] = dist; // Add unique identifier to break ties alldist[i][j] += 1e-9 * uid; uid++; } } else { double gtleft, gttop, gtwidth, gtheight, stleft, sttop, stwidth, stheight; int rowgt = gtInd[t][o]; int rowres = stInd[t][e]; gtleft = gtMat[index(rowgt, 2, rowsGT)]; gttop = gtMat[index(rowgt, 3, rowsGT)]; gtwidth = gtMat[index(rowgt, 4, rowsGT)]; gtheight = gtMat[index(rowgt, 5, rowsGT)]; stleft = resMat[index(rowres, 2, rowsST)]; sttop = resMat[index(rowres, 3, rowsST)]; stwidth = resMat[index(rowres, 4, rowsST)]; stheight = resMat[index(rowres, 5, rowsST)]; double dist = 1 - boxiou(gtleft, gttop, gtwidth, gtheight, stleft, sttop, stwidth, stheight); if (dist <= threshold) { alldist[i][j] = dist; // Add unique identifier to break ties alldist[i][j] += 1e-9 * uid; uid++; } } } } vector<int> Lmate, Rmate; MinCostMatching(alldist, Lmate, Rmate); for (int k = 0; k < Lmate.size(); k++) { if (alldist[k][Lmate[k]] == INF) continue; M[t][unmappedGt[k]] = unmappedEs[Lmate[k]]; if (VERBOSE) printf("%d: map %d with %d\n", t+1, unmappedGt[k]+1, unmappedEs[Lmate[k]]+1); } vector<int> curtracked, alltrackers, mappedtrackers, falsepositives, set1; for (unordered_map<int,int>::iterator it = M[t].begin(); it != M[t].end(); it++) { curtracked.push_back(it->first); set1.push_back(it->second); } for (unordered_map<int,int>::iterator it = stInd[t].begin(); it != stInd[t].end(); it++) alltrackers.push_back(it->first); sort(set1.begin(), set1.end()); sort(alltrackers.begin(), alltrackers.end()); set_intersection(set1.begin(), set1.end(), alltrackers.begin(), alltrackers.end(), inserter(mappedtrackers, mappedtrackers.begin())); set_difference(alltrackers.begin(), alltrackers.end(), mappedtrackers.begin(), mappedtrackers.end(), inserter(falsepositives, falsepositives.end())); for (int k = 0; k < falsepositives.size(); k++) allfalsepos[t][falsepositives[k]] = falsepositives[k]; // mismatch errors if (t > 0) { for (int k = 0; k < curtracked.size(); k++) { int ct = curtracked[k]; int lastnonempty = -1; for (int j = t - 1; j >= 0; j--) { if (M[j].find(ct) != M[j].end()) { lastnonempty = j; break; } } if (gtInd[t-1].find(ct)!=gtInd[t-1].end() && lastnonempty != -1) { int mtct = -1, mlastnonemptyct = -1; if (M[t].find(ct) != M[t].end()) mtct = M[t][ct]; if (M[lastnonempty].find(ct) != M[lastnonempty].end()) mlastnonemptyct = M[lastnonempty][ct]; if (mtct != mlastnonemptyct) mme[t]++; } } } c[t] = curtracked.size(); for (int k = 0; k < curtracked.size(); k++) { int ct = curtracked[k]; int eid = M[t][ct]; if (world) { double gtx, gty, stx, sty; int rowgt = gtInd[t][ct]; int rowres = stInd[t][eid]; gtx = gtMat[index(rowgt, 6, rowsGT)]; gty = gtMat[index(rowgt, 7, rowsGT)]; stx = resMat[index(rowres, 6, rowsST)]; sty = resMat[index(rowres, 7, rowsST)]; d[t][ct] = euclidean(gtx, gty, stx, sty); } else { double gtleft, gttop, gtwidth, gtheight, stleft, sttop, stwidth, stheight; int rowgt = gtInd[t][ct]; int rowres = stInd[t][eid]; gtleft = gtMat[index(rowgt, 2, rowsGT)]; gttop = gtMat[index(rowgt, 3, rowsGT)]; gtwidth = gtMat[index(rowgt, 4, rowsGT)]; gtheight = gtMat[index(rowgt, 5, rowsGT)]; stleft = resMat[index(rowres, 2, rowsST)]; sttop = resMat[index(rowres, 3, rowsST)]; stwidth = resMat[index(rowres, 4, rowsST)]; stheight = resMat[index(rowres, 5, rowsST)]; d[t][ct] = 1 - boxiou(gtleft, gttop, gtwidth, gtheight, stleft, sttop, stwidth, stheight); } } for (unordered_map<int,int>::iterator it = stInd[t].begin(); it != stInd[t].end(); it++) fp[t]++; fp[t] -= c[t]; m[t] = g[t] - c[t]; } // Copy back to matlab for (int k = 0; k < Fgt; k++) { mmeOut[k] = mme[k]; cOut[k] = c[k]; fpOut[k] = fp[k]; gOut[k] = g[k]; mOut[k] = m[k]; } for (int i = 0; i < Fgt; i++) { for (int j = 0; j < Ngt; j++) { dOut[index(i, j, Fgt)] = d[i][j]; dOut[index(i, j, Fgt)] = (d[i][j] == INF ? mxGetInf() : d[i][j]); } for (unordered_map<int, int>::iterator it = M[i].begin(); it != M[i].end(); it++) { int j = it->first; MOut[index(i, j, Fgt)] = M[i][j] + 1; // matlab indexed } for (int j = 0; j < Nst; j++) { allfalseposOut[index(i, j, Fgt)] = allfalsepos[i][j]; } } }