You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
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:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
* text=auto
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user