Merge remote-tracking branch 'origin/develop' into effect-parenting

This commit is contained in:
Brenno
2021-04-13 12:43:55 -03:00
7 changed files with 935 additions and 933 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,116 +1,116 @@
///////////////////////////////////////////////////////////////////////////////
// KalmanTracker.cpp: KalmanTracker Class Implementation Declaration
#include "KalmanTracker.h"
#include <ctime>
using namespace std;
using namespace cv;
// 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;
// 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,52 +14,52 @@
class KalmanTracker
{
public:
KalmanTracker()
{
init_kf(StateType());
m_time_since_update = 0;
m_hits = 0;
m_hit_streak = 0;
m_age = 0;
m_id = 0;
}
KalmanTracker(StateType initRect, float confidence, int classId, int objectId) : confidence(confidence), classId(classId)
{
init_kf(initRect);
m_time_since_update = 0;
m_hits = 0;
m_hit_streak = 0;
m_age = 0;
m_id = objectId;
}
~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);
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 = 0;
}
KalmanTracker(StateType initRect, float confidence, int classId, int objectId) : confidence(confidence), classId(classId)
{
init_kf(initRect);
m_time_since_update = 0;
m_hits = 0;
m_hit_streak = 0;
m_age = 0;
m_id = objectId;
}
~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);
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, i);
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, umd);
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, i);
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, umd);
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.05;
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.05;
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;
};