Normalize repo to LF (Unix) line-endings, enforce (#654)

- A top-level .gitattributes sets the attribute 'text=auto' for all
  files in the repo, enabling line-ending normalization
- A `git add --renormalize` run converted any existing CRLF files
  to the canonical LF format.
- 'text=auto' permits Git on Windows to convert files to CRLF
  automatically on checkout, for convenience. Any commits
  added will be converted back to the repo format for checkin.
This commit is contained in:
Frank Dana
2021-04-13 12:19:50 +00:00
committed by GitHub
parent 8cefd49abf
commit fbc8a9b47b
7 changed files with 941 additions and 939 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
* text=auto

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,34 @@
///////////////////////////////////////////////////////////////////////////////
// Hungarian.h: Header file for Class HungarianAlgorithm.
//
// This is a C++ wrapper with slight modification of a hungarian algorithm implementation by Markus Buehren.
// The original implementation is a few mex-functions for use in MATLAB, found here:
// http://www.mathworks.com/matlabcentral/fileexchange/6543-functions-for-the-rectangular-assignment-problem
//
// Both this code and the orignal code are published under the BSD license.
// by Cong Ma, 2016
//
#include <iostream>
#include <vector>
#include <cstdlib>
#include <cfloat>
#include <math.h>
class HungarianAlgorithm
{
public:
HungarianAlgorithm();
~HungarianAlgorithm();
double Solve(std::vector<std::vector<double>> &DistMatrix, std::vector<int> &Assignment);
private:
void assignmentoptimal(int *assignment, double *cost, double *distMatrix, int nOfRows, int nOfColumns);
void buildassignmentvector(int *assignment, bool *starMatrix, int nOfRows, int nOfColumns);
void computeassignmentcost(int *assignment, double *cost, double *distMatrix, int nOfRows);
void step2a(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
void step2b(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
void step3(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
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);
void step5(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
};
///////////////////////////////////////////////////////////////////////////////
// Hungarian.h: Header file for Class HungarianAlgorithm.
//
// This is a C++ wrapper with slight modification of a hungarian algorithm implementation by Markus Buehren.
// The original implementation is a few mex-functions for use in MATLAB, found here:
// http://www.mathworks.com/matlabcentral/fileexchange/6543-functions-for-the-rectangular-assignment-problem
//
// Both this code and the orignal code are published under the BSD license.
// by Cong Ma, 2016
//
#include <iostream>
#include <vector>
#include <cstdlib>
#include <cfloat>
#include <math.h>
class HungarianAlgorithm
{
public:
HungarianAlgorithm();
~HungarianAlgorithm();
double Solve(std::vector<std::vector<double>> &DistMatrix, std::vector<int> &Assignment);
private:
void assignmentoptimal(int *assignment, double *cost, double *distMatrix, int nOfRows, int nOfColumns);
void buildassignmentvector(int *assignment, bool *starMatrix, int nOfRows, int nOfColumns);
void computeassignmentcost(int *assignment, double *cost, double *distMatrix, int nOfRows);
void step2a(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
void step2b(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
void step3(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
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);
void step5(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
};

View File

@@ -1,118 +1,118 @@
///////////////////////////////////////////////////////////////////////////////
// KalmanTracker.cpp: KalmanTracker Class Implementation Declaration
#include "KalmanTracker.h"
#include <ctime>
using namespace std;
using namespace cv;
int KalmanTracker::kf_count = 0;
// initialize Kalman filter
void KalmanTracker::init_kf(
StateType stateMat)
{
int stateNum = 7;
int measureNum = 4;
kf = KalmanFilter(stateNum, measureNum, 0);
measurement = Mat::zeros(measureNum, 1, CV_32F);
kf.transitionMatrix = (Mat_<float>(7, 7) << 1, 0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 1,
0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 1);
setIdentity(kf.measurementMatrix);
setIdentity(kf.processNoiseCov, Scalar::all(1e-1));
setIdentity(kf.measurementNoiseCov, Scalar::all(1e-4));
setIdentity(kf.errorCovPost, Scalar::all(1e-2));
// initialize state vector with bounding box in [cx,cy,s,r] style
kf.statePost.at<float>(0, 0) = stateMat.x + stateMat.width / 2;
kf.statePost.at<float>(1, 0) = stateMat.y + stateMat.height / 2;
kf.statePost.at<float>(2, 0) = stateMat.area();
kf.statePost.at<float>(3, 0) = stateMat.width / stateMat.height;
}
// Predict the estimated bounding box.
StateType KalmanTracker::predict()
{
// predict
Mat p = kf.predict();
m_age += 1;
if (m_time_since_update > 0)
m_hit_streak = 0;
m_time_since_update += 1;
StateType predictBox = get_rect_xysr(p.at<float>(0, 0), p.at<float>(1, 0), p.at<float>(2, 0), p.at<float>(3, 0));
m_history.push_back(predictBox);
return m_history.back();
}
StateType KalmanTracker::predict2()
{
// predict
Mat p = kf.predict();
StateType predictBox = get_rect_xysr(p.at<float>(0, 0), p.at<float>(1, 0), p.at<float>(2, 0), p.at<float>(3, 0));
return predictBox;
}
// Update the state vector with observed bounding box.
void KalmanTracker::update(
StateType stateMat)
{
m_time_since_update = 0;
m_history.clear();
m_hits += 1;
m_hit_streak += 1;
// measurement
measurement.at<float>(0, 0) = stateMat.x + stateMat.width / 2;
measurement.at<float>(1, 0) = stateMat.y + stateMat.height / 2;
measurement.at<float>(2, 0) = stateMat.area();
measurement.at<float>(3, 0) = stateMat.width / stateMat.height;
// update
kf.correct(measurement);
// time_t now = time(0);
// convert now to string form
// detect_times.push_back(dt);
}
// Return the current state vector
StateType KalmanTracker::get_state()
{
Mat s = kf.statePost;
return get_rect_xysr(s.at<float>(0, 0), s.at<float>(1, 0), s.at<float>(2, 0), s.at<float>(3, 0));
}
// Convert bounding box from [cx,cy,s,r] to [x,y,w,h] style.
StateType KalmanTracker::get_rect_xysr(
float cx,
float cy,
float s,
float r)
{
float w = sqrt(s * r);
float h = s / w;
float x = (cx - w / 2);
float y = (cy - h / 2);
if (x < 0 && cx > 0)
x = 0;
if (y < 0 && cy > 0)
y = 0;
return StateType(x, y, w, h);
}
///////////////////////////////////////////////////////////////////////////////
// KalmanTracker.cpp: KalmanTracker Class Implementation Declaration
#include "KalmanTracker.h"
#include <ctime>
using namespace std;
using namespace cv;
int KalmanTracker::kf_count = 0;
// initialize Kalman filter
void KalmanTracker::init_kf(
StateType stateMat)
{
int stateNum = 7;
int measureNum = 4;
kf = KalmanFilter(stateNum, measureNum, 0);
measurement = Mat::zeros(measureNum, 1, CV_32F);
kf.transitionMatrix = (Mat_<float>(7, 7) << 1, 0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 1,
0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 1);
setIdentity(kf.measurementMatrix);
setIdentity(kf.processNoiseCov, Scalar::all(1e-1));
setIdentity(kf.measurementNoiseCov, Scalar::all(1e-4));
setIdentity(kf.errorCovPost, Scalar::all(1e-2));
// initialize state vector with bounding box in [cx,cy,s,r] style
kf.statePost.at<float>(0, 0) = stateMat.x + stateMat.width / 2;
kf.statePost.at<float>(1, 0) = stateMat.y + stateMat.height / 2;
kf.statePost.at<float>(2, 0) = stateMat.area();
kf.statePost.at<float>(3, 0) = stateMat.width / stateMat.height;
}
// Predict the estimated bounding box.
StateType KalmanTracker::predict()
{
// predict
Mat p = kf.predict();
m_age += 1;
if (m_time_since_update > 0)
m_hit_streak = 0;
m_time_since_update += 1;
StateType predictBox = get_rect_xysr(p.at<float>(0, 0), p.at<float>(1, 0), p.at<float>(2, 0), p.at<float>(3, 0));
m_history.push_back(predictBox);
return m_history.back();
}
StateType KalmanTracker::predict2()
{
// predict
Mat p = kf.predict();
StateType predictBox = get_rect_xysr(p.at<float>(0, 0), p.at<float>(1, 0), p.at<float>(2, 0), p.at<float>(3, 0));
return predictBox;
}
// Update the state vector with observed bounding box.
void KalmanTracker::update(
StateType stateMat)
{
m_time_since_update = 0;
m_history.clear();
m_hits += 1;
m_hit_streak += 1;
// measurement
measurement.at<float>(0, 0) = stateMat.x + stateMat.width / 2;
measurement.at<float>(1, 0) = stateMat.y + stateMat.height / 2;
measurement.at<float>(2, 0) = stateMat.area();
measurement.at<float>(3, 0) = stateMat.width / stateMat.height;
// update
kf.correct(measurement);
// time_t now = time(0);
// convert now to string form
// detect_times.push_back(dt);
}
// Return the current state vector
StateType KalmanTracker::get_state()
{
Mat s = kf.statePost;
return get_rect_xysr(s.at<float>(0, 0), s.at<float>(1, 0), s.at<float>(2, 0), s.at<float>(3, 0));
}
// Convert bounding box from [cx,cy,s,r] to [x,y,w,h] style.
StateType KalmanTracker::get_rect_xysr(
float cx,
float cy,
float s,
float r)
{
float w = sqrt(s * r);
float h = s / w;
float x = (cx - w / 2);
float y = (cy - h / 2);
if (x < 0 && cx > 0)
x = 0;
if (y < 0 && cy > 0)
y = 0;
return StateType(x, y, w, h);
}

View File

@@ -1,12 +1,12 @@
///////////////////////////////////////////////////////////////////////////////
// KalmanTracker.h: KalmanTracker Class Declaration
#ifndef KALMAN_H
#define KALMAN_H 2
#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
///////////////////////////////////////////////////////////////////////////////
// KalmanTracker.h: KalmanTracker Class Declaration
#ifndef KALMAN_H
#define KALMAN_H 2
#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
#define StateType cv::Rect_<float>
@@ -14,56 +14,56 @@
class KalmanTracker
{
public:
KalmanTracker()
{
init_kf(StateType());
m_time_since_update = 0;
m_hits = 0;
m_hit_streak = 0;
m_age = 0;
m_id = kf_count;
//kf_count++;
}
KalmanTracker(StateType initRect, float confidence, int classId) : confidence(confidence), classId(classId)
{
init_kf(initRect);
m_time_since_update = 0;
m_hits = 0;
m_hit_streak = 0;
m_age = 0;
m_id = kf_count;
kf_count++;
}
~KalmanTracker()
{
m_history.clear();
}
StateType predict();
StateType predict2();
void update(StateType stateMat);
StateType get_state();
StateType get_rect_xysr(float cx, float cy, float s, float r);
static int kf_count;
int m_time_since_update;
int m_hits;
int m_hit_streak;
int m_age;
int m_id;
float confidence;
int classId;
private:
void init_kf(StateType stateMat);
cv::KalmanFilter kf;
cv::Mat measurement;
std::vector<StateType> m_history;
};
KalmanTracker()
{
init_kf(StateType());
m_time_since_update = 0;
m_hits = 0;
m_hit_streak = 0;
m_age = 0;
m_id = kf_count;
//kf_count++;
}
KalmanTracker(StateType initRect, float confidence, int classId) : confidence(confidence), classId(classId)
{
init_kf(initRect);
m_time_since_update = 0;
m_hits = 0;
m_hit_streak = 0;
m_age = 0;
m_id = kf_count;
kf_count++;
}
~KalmanTracker()
{
m_history.clear();
}
StateType predict();
StateType predict2();
void update(StateType stateMat);
StateType get_state();
StateType get_rect_xysr(float cx, float cy, float s, float r);
static int kf_count;
int m_time_since_update;
int m_hits;
int m_hit_streak;
int m_age;
int m_id;
float confidence;
int classId;
private:
void init_kf(StateType stateMat);
cv::KalmanFilter kf;
cv::Mat measurement;
std::vector<StateType> m_history;
};
#endif

View File

@@ -1,211 +1,211 @@
#include "sort.hpp"
using namespace std;
// Constructor
SortTracker::SortTracker(int max_age, int min_hits)
{
_min_hits = min_hits;
_max_age = max_age;
alive_tracker = true;
}
// Computes IOU between two bounding boxes
double SortTracker::GetIOU(cv::Rect_<float> bb_test, cv::Rect_<float> bb_gt)
{
float in = (bb_test & bb_gt).area();
float un = bb_test.area() + bb_gt.area() - in;
if (un < DBL_EPSILON)
return 0;
return (double)(in / un);
}
// Computes centroid distance between two bounding boxes
double SortTracker::GetCentroidsDistance(
cv::Rect_<float> bb_test,
cv::Rect_<float> bb_gt)
{
float bb_test_centroid_x = (bb_test.x + bb_test.width / 2);
float bb_test_centroid_y = (bb_test.y + bb_test.height / 2);
float bb_gt_centroid_x = (bb_gt.x + bb_gt.width / 2);
float bb_gt_centroid_y = (bb_gt.y + bb_gt.height / 2);
double distance = (double)sqrt(pow(bb_gt_centroid_x - bb_test_centroid_x, 2) + pow(bb_gt_centroid_y - bb_test_centroid_y, 2));
return distance;
}
void SortTracker::update(vector<cv::Rect> detections_cv, int frame_count, double image_diagonal, std::vector<float> confidences, std::vector<int> classIds)
{
vector<TrackingBox> detections;
if (trackers.size() == 0) // the first frame met
{
alive_tracker = false;
// initialize kalman trackers using first detections.
for (unsigned int i = 0; i < detections_cv.size(); i++)
{
TrackingBox tb;
tb.box = cv::Rect_<float>(detections_cv[i]);
tb.classId = classIds[i];
tb.confidence = confidences[i];
detections.push_back(tb);
KalmanTracker trk = KalmanTracker(detections[i].box, detections[i].confidence, detections[i].classId);
trackers.push_back(trk);
}
return;
}
else
{
for (unsigned int i = 0; i < detections_cv.size(); i++)
{
TrackingBox tb;
tb.box = cv::Rect_<float>(detections_cv[i]);
tb.classId = classIds[i];
tb.confidence = confidences[i];
detections.push_back(tb);
}
for (auto it = frameTrackingResult.begin(); it != frameTrackingResult.end(); it++)
{
int frame_age = frame_count - it->frame;
if (frame_age >= _max_age || frame_age < 0)
{
dead_trackers_id.push_back(it->id);
}
}
}
///////////////////////////////////////
// 3.1. get predicted locations from existing trackers.
predictedBoxes.clear();
for (unsigned int i = 0; i < trackers.size();)
{
cv::Rect_<float> pBox = trackers[i].predict();
if (pBox.x >= 0 && pBox.y >= 0)
{
predictedBoxes.push_back(pBox);
i++;
continue;
}
trackers.erase(trackers.begin() + i);
}
trkNum = predictedBoxes.size();
detNum = detections.size();
centroid_dist_matrix.clear();
centroid_dist_matrix.resize(trkNum, vector<double>(detNum, 0));
for (unsigned int i = 0; i < trkNum; i++) // compute iou matrix as a distance matrix
{
for (unsigned int j = 0; j < detNum; j++)
{
// use 1-iou because the hungarian algorithm computes a minimum-cost assignment.
double distance = SortTracker::GetCentroidsDistance(predictedBoxes[i], detections[j].box) / image_diagonal;
centroid_dist_matrix[i][j] = distance;
}
}
HungarianAlgorithm HungAlgo;
assignment.clear();
HungAlgo.Solve(centroid_dist_matrix, assignment);
// find matches, unmatched_detections and unmatched_predictions
unmatchedTrajectories.clear();
unmatchedDetections.clear();
allItems.clear();
matchedItems.clear();
if (detNum > trkNum) // there are unmatched detections
{
for (unsigned int n = 0; n < detNum; n++)
allItems.insert(n);
for (unsigned int i = 0; i < trkNum; ++i)
matchedItems.insert(assignment[i]);
set_difference(allItems.begin(), allItems.end(),
matchedItems.begin(), matchedItems.end(),
insert_iterator<set<int>>(unmatchedDetections, unmatchedDetections.begin()));
}
else if (detNum < trkNum) // there are unmatched trajectory/predictions
{
for (unsigned int i = 0; i < trkNum; ++i)
if (assignment[i] == -1) // unassigned label will be set as -1 in the assignment algorithm
unmatchedTrajectories.insert(i);
}
else
;
// filter out matched with low IOU
matchedPairs.clear();
for (unsigned int i = 0; i < trkNum; ++i)
{
if (assignment[i] == -1) // pass over invalid values
continue;
if (centroid_dist_matrix[i][assignment[i]] > max_centroid_dist_norm)
{
unmatchedTrajectories.insert(i);
unmatchedDetections.insert(assignment[i]);
}
else
matchedPairs.push_back(cv::Point(i, assignment[i]));
}
for (unsigned int i = 0; i < matchedPairs.size(); i++)
{
int trkIdx = matchedPairs[i].x;
int detIdx = matchedPairs[i].y;
trackers[trkIdx].update(detections[detIdx].box);
trackers[trkIdx].classId = detections[detIdx].classId;
trackers[trkIdx].confidence = detections[detIdx].confidence;
}
// create and initialise new trackers for unmatched detections
for (auto umd : unmatchedDetections)
{
KalmanTracker tracker = KalmanTracker(detections[umd].box, detections[umd].confidence, detections[umd].classId);
trackers.push_back(tracker);
}
for (auto it2 = dead_trackers_id.begin(); it2 != dead_trackers_id.end(); it2++)
{
for (unsigned int i = 0; i < trackers.size();)
{
if (trackers[i].m_id == (*it2))
{
trackers.erase(trackers.begin() + i);
continue;
}
i++;
}
}
// get trackers' output
frameTrackingResult.clear();
for (unsigned int i = 0; i < trackers.size();)
{
if ((trackers[i].m_time_since_update < 1 && trackers[i].m_hit_streak >= _min_hits) || frame_count <= _min_hits)
{
alive_tracker = true;
TrackingBox res;
res.box = trackers[i].get_state();
res.id = trackers[i].m_id;
res.frame = frame_count;
res.classId = trackers[i].classId;
res.confidence = trackers[i].confidence;
frameTrackingResult.push_back(res);
}
// remove dead tracklet
if (trackers[i].m_time_since_update >= _max_age)
{
trackers.erase(trackers.begin() + i);
continue;
}
i++;
}
}
#include "sort.hpp"
using namespace std;
// Constructor
SortTracker::SortTracker(int max_age, int min_hits)
{
_min_hits = min_hits;
_max_age = max_age;
alive_tracker = true;
}
// Computes IOU between two bounding boxes
double SortTracker::GetIOU(cv::Rect_<float> bb_test, cv::Rect_<float> bb_gt)
{
float in = (bb_test & bb_gt).area();
float un = bb_test.area() + bb_gt.area() - in;
if (un < DBL_EPSILON)
return 0;
return (double)(in / un);
}
// Computes centroid distance between two bounding boxes
double SortTracker::GetCentroidsDistance(
cv::Rect_<float> bb_test,
cv::Rect_<float> bb_gt)
{
float bb_test_centroid_x = (bb_test.x + bb_test.width / 2);
float bb_test_centroid_y = (bb_test.y + bb_test.height / 2);
float bb_gt_centroid_x = (bb_gt.x + bb_gt.width / 2);
float bb_gt_centroid_y = (bb_gt.y + bb_gt.height / 2);
double distance = (double)sqrt(pow(bb_gt_centroid_x - bb_test_centroid_x, 2) + pow(bb_gt_centroid_y - bb_test_centroid_y, 2));
return distance;
}
void SortTracker::update(vector<cv::Rect> detections_cv, int frame_count, double image_diagonal, std::vector<float> confidences, std::vector<int> classIds)
{
vector<TrackingBox> detections;
if (trackers.size() == 0) // the first frame met
{
alive_tracker = false;
// initialize kalman trackers using first detections.
for (unsigned int i = 0; i < detections_cv.size(); i++)
{
TrackingBox tb;
tb.box = cv::Rect_<float>(detections_cv[i]);
tb.classId = classIds[i];
tb.confidence = confidences[i];
detections.push_back(tb);
KalmanTracker trk = KalmanTracker(detections[i].box, detections[i].confidence, detections[i].classId);
trackers.push_back(trk);
}
return;
}
else
{
for (unsigned int i = 0; i < detections_cv.size(); i++)
{
TrackingBox tb;
tb.box = cv::Rect_<float>(detections_cv[i]);
tb.classId = classIds[i];
tb.confidence = confidences[i];
detections.push_back(tb);
}
for (auto it = frameTrackingResult.begin(); it != frameTrackingResult.end(); it++)
{
int frame_age = frame_count - it->frame;
if (frame_age >= _max_age || frame_age < 0)
{
dead_trackers_id.push_back(it->id);
}
}
}
///////////////////////////////////////
// 3.1. get predicted locations from existing trackers.
predictedBoxes.clear();
for (unsigned int i = 0; i < trackers.size();)
{
cv::Rect_<float> pBox = trackers[i].predict();
if (pBox.x >= 0 && pBox.y >= 0)
{
predictedBoxes.push_back(pBox);
i++;
continue;
}
trackers.erase(trackers.begin() + i);
}
trkNum = predictedBoxes.size();
detNum = detections.size();
centroid_dist_matrix.clear();
centroid_dist_matrix.resize(trkNum, vector<double>(detNum, 0));
for (unsigned int i = 0; i < trkNum; i++) // compute iou matrix as a distance matrix
{
for (unsigned int j = 0; j < detNum; j++)
{
// use 1-iou because the hungarian algorithm computes a minimum-cost assignment.
double distance = SortTracker::GetCentroidsDistance(predictedBoxes[i], detections[j].box) / image_diagonal;
centroid_dist_matrix[i][j] = distance;
}
}
HungarianAlgorithm HungAlgo;
assignment.clear();
HungAlgo.Solve(centroid_dist_matrix, assignment);
// find matches, unmatched_detections and unmatched_predictions
unmatchedTrajectories.clear();
unmatchedDetections.clear();
allItems.clear();
matchedItems.clear();
if (detNum > trkNum) // there are unmatched detections
{
for (unsigned int n = 0; n < detNum; n++)
allItems.insert(n);
for (unsigned int i = 0; i < trkNum; ++i)
matchedItems.insert(assignment[i]);
set_difference(allItems.begin(), allItems.end(),
matchedItems.begin(), matchedItems.end(),
insert_iterator<set<int>>(unmatchedDetections, unmatchedDetections.begin()));
}
else if (detNum < trkNum) // there are unmatched trajectory/predictions
{
for (unsigned int i = 0; i < trkNum; ++i)
if (assignment[i] == -1) // unassigned label will be set as -1 in the assignment algorithm
unmatchedTrajectories.insert(i);
}
else
;
// filter out matched with low IOU
matchedPairs.clear();
for (unsigned int i = 0; i < trkNum; ++i)
{
if (assignment[i] == -1) // pass over invalid values
continue;
if (centroid_dist_matrix[i][assignment[i]] > max_centroid_dist_norm)
{
unmatchedTrajectories.insert(i);
unmatchedDetections.insert(assignment[i]);
}
else
matchedPairs.push_back(cv::Point(i, assignment[i]));
}
for (unsigned int i = 0; i < matchedPairs.size(); i++)
{
int trkIdx = matchedPairs[i].x;
int detIdx = matchedPairs[i].y;
trackers[trkIdx].update(detections[detIdx].box);
trackers[trkIdx].classId = detections[detIdx].classId;
trackers[trkIdx].confidence = detections[detIdx].confidence;
}
// create and initialise new trackers for unmatched detections
for (auto umd : unmatchedDetections)
{
KalmanTracker tracker = KalmanTracker(detections[umd].box, detections[umd].confidence, detections[umd].classId);
trackers.push_back(tracker);
}
for (auto it2 = dead_trackers_id.begin(); it2 != dead_trackers_id.end(); it2++)
{
for (unsigned int i = 0; i < trackers.size();)
{
if (trackers[i].m_id == (*it2))
{
trackers.erase(trackers.begin() + i);
continue;
}
i++;
}
}
// get trackers' output
frameTrackingResult.clear();
for (unsigned int i = 0; i < trackers.size();)
{
if ((trackers[i].m_time_since_update < 1 && trackers[i].m_hit_streak >= _min_hits) || frame_count <= _min_hits)
{
alive_tracker = true;
TrackingBox res;
res.box = trackers[i].get_state();
res.id = trackers[i].m_id;
res.frame = frame_count;
res.classId = trackers[i].classId;
res.confidence = trackers[i].confidence;
frameTrackingResult.push_back(res);
}
// remove dead tracklet
if (trackers[i].m_time_since_update >= _max_age)
{
trackers.erase(trackers.begin() + i);
continue;
}
i++;
}
}

View File

@@ -1,61 +1,61 @@
#include "KalmanTracker.h"
#include "Hungarian.h"
#include <iostream>
#include <fstream>
#include <iomanip> // to format image names using setw() and setfill()
#include <set>
#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
#ifndef _OPENCV_KCFTRACKER_HPP_
#define _OPENCV_KCFTRACKER_HPP_
#endif
#pragma once
typedef struct TrackingBox
{
int frame = 0;
float confidence = 0;
int classId = 0;
int id = 0;
cv::Rect_<float> box = cv::Rect_<float>(0.0, 0.0, 0.0, 0.0);
TrackingBox() {}
TrackingBox(int _frame, float _confidence, int _classId, int _id) : frame(_frame), confidence(_confidence), classId(_classId), id(_id) {}
} TrackingBox;
class SortTracker
{
public:
// Constructor
SortTracker(int max_age = 7, int min_hits = 2);
// Initialize tracker
// Update position based on the new frame
void update(std::vector<cv::Rect> detection, int frame_count, double image_diagonal, std::vector<float> confidences, std::vector<int> classIds);
double GetIOU(cv::Rect_<float> bb_test, cv::Rect_<float> bb_gt);
double GetCentroidsDistance(cv::Rect_<float> bb_test, cv::Rect_<float> bb_gt);
std::vector<KalmanTracker> trackers;
double max_centroid_dist_norm = 0.15;
std::vector<cv::Rect_<float>> predictedBoxes;
std::vector<std::vector<double>> centroid_dist_matrix;
std::vector<int> assignment;
std::set<int> unmatchedDetections;
std::set<int> unmatchedTrajectories;
std::set<int> allItems;
std::set<int> matchedItems;
std::vector<cv::Point> matchedPairs;
std::vector<TrackingBox> frameTrackingResult;
std::vector<int> dead_trackers_id;
unsigned int trkNum = 0;
unsigned int detNum = 0;
int _min_hits;
int _max_age;
bool alive_tracker;
};
#include "KalmanTracker.h"
#include "Hungarian.h"
#include <iostream>
#include <fstream>
#include <iomanip> // to format image names using setw() and setfill()
#include <set>
#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
#ifndef _OPENCV_KCFTRACKER_HPP_
#define _OPENCV_KCFTRACKER_HPP_
#endif
#pragma once
typedef struct TrackingBox
{
int frame = 0;
float confidence = 0;
int classId = 0;
int id = 0;
cv::Rect_<float> box = cv::Rect_<float>(0.0, 0.0, 0.0, 0.0);
TrackingBox() {}
TrackingBox(int _frame, float _confidence, int _classId, int _id) : frame(_frame), confidence(_confidence), classId(_classId), id(_id) {}
} TrackingBox;
class SortTracker
{
public:
// Constructor
SortTracker(int max_age = 7, int min_hits = 2);
// Initialize tracker
// Update position based on the new frame
void update(std::vector<cv::Rect> detection, int frame_count, double image_diagonal, std::vector<float> confidences, std::vector<int> classIds);
double GetIOU(cv::Rect_<float> bb_test, cv::Rect_<float> bb_gt);
double GetCentroidsDistance(cv::Rect_<float> bb_test, cv::Rect_<float> bb_gt);
std::vector<KalmanTracker> trackers;
double max_centroid_dist_norm = 0.15;
std::vector<cv::Rect_<float>> predictedBoxes;
std::vector<std::vector<double>> centroid_dist_matrix;
std::vector<int> assignment;
std::set<int> unmatchedDetections;
std::set<int> unmatchedTrajectories;
std::set<int> allItems;
std::set<int> matchedItems;
std::vector<cv::Point> matchedPairs;
std::vector<TrackingBox> frameTrackingResult;
std::vector<int> dead_trackers_id;
unsigned int trkNum = 0;
unsigned int detNum = 0;
int _min_hits;
int _max_age;
bool alive_tracker;
};