Адрес статьи: https://arxiv.org/pdf/2110.06864.pdf.
адрес git: https://github.com/ifzhang/ByteTrack
ByteTrack был публично выпущен в октябре 2021 года и получил награду ECCV 2022. Благодаря простой конструкции он победил все трекеры «магической модификации» того времени, впервые преодолев 80 MOTA на данных MOT17 и достигнув скорости вывода до 30 в одном V100. ФПС. Я резюмирую основные идеи ByteTrack следующим образом:
ByteTrack может эффективно устранять некоторые препятствия и поддерживать низкий уровень IDSwith. Достоверность обнаружения цели будет снижена, поскольку она закрыта, а когда она появится снова, достоверность увеличится. Вы можете себе представить:
Кроме того, следует тщательно рассматривать и устранять ложные срабатывания при обнаружении и кадры с низкой достоверностью без обнаружения цели.
DeepSort и ByteTrack часто сравнивают в Интернете. Что касается ByteTrack и DeepSort, у них есть свои ограничения. Мы должны выбрать подходящий алгоритм в соответствии с реальной ситуацией.
Чтобы по-настоящему понять и полностью понять, важно прочитать исходный код. Дело не в том, что вам нужно понимать исходный код для запуска проекта, но вы можете похвастаться после того, как поймете его. Дело не в том, что вам нужно хвастаться, по крайней мере, у вас будет чувство выполненного долга.
Без лишних слов, давайте сразу к делу! Этот раздел кода немного сложно объяснить подробно. Если вы не можете понять это в данный момент, вы можете поставить лайк и сначала сохранить его, а затем медленно прочитать позже. . .
Это легко понять. Вместо следования порядку кода анализ основан на порядке от начала до конца дорожки.
Только высокие (больше, чем high_thrash) ячейки уверенности могут начать новую траекторию. Порог, который различает кадры обнаружения с высокой и низкой достоверностью, равен track_thresh = 0,5. Но обычно значение, установленное high_thresh, больше, чем track_thresh. Например, high_thresh = 0,6. В новом треке состояние = Отслеживается, только первый кадр нового трека is_activated =True, в противном случае is_activated = false.
this->state = TrackState::Tracked;
if (frame_id == 1)
{
this->is_activated = true;
}
//this->is_activated = true;
this->frame_id = frame_id;
this->start_frame = frame_id;
Подвести итог:когда Первыйрамкачас,Сам трек - это пространство-время,Только уровень достоверности превышает high_thresh Когда появится новый стартовый трек состояние в это время = Tracked,is_activated = истинный. Впоследствии остаются только несовпадающие и уровень достоверности очень высок (более high_thresh ) — новый стартовый трек, состояние в это время = Tracked,is_activated = false。
Объединить is_activated = true с состоянием = потерянные треки. После слияния выполняется прогнозирование, которое следует за прогнозированием фильтра Калмана.
Каждая новая информация об обнаружении инициализирует STrack Объект, сможет ли этот объект начать новую траекторию, уточнялось ранее. в исходном коде tlbr 顺序Это ловушкаЗаказ неtop,left,bottom,верно. На самом деле осталось,top,right,нижний. я тоже сначала неправильно понял,Я до сих пор не понимаю, почему для назван в таком порядке.
if (objects.boxes.size() > 0)
{
for (int i = 0; i < objects.boxes.size(); i++)
{
std::vector<float> tlbr_; // x1,y1,x2,y2
tlbr_.resize(4);
tlbr_[0] = objects.boxes[i].x;
tlbr_[1] = objects.boxes[i].y;
tlbr_[2] = objects.boxes[i].x + objects.boxes[i].w;
tlbr_[3] = objects.boxes[i].y + objects.boxes[i].h;
float score = objects.boxes[i].score;
STrack strack(STrack::tlbr_to_tlwh(tlbr_), score);
if (score >= track_thresh)
{
detections.push_back(strack);
}
else
{
detections_low.push_back(strack);
}
}
}
tlbr_to_tlwh преобразует x1,y1,x2,y2 в x1,y1,w,h. При запуске нового трека tlwh_to_xyah в функции активации преобразует x1, y1, w, h в xCenter, yCenter, w/h, h. Затем поместите его в инициализацию фильтра Калмана, чтобы инициализировать его состояние и ковариацию.
void STrack::activate(byte_kalman::KalmanFilter &kalman_filter, int frame_id)
{
Опустить код здесь
auto mc = this->kalman_filter.initiate(xyah_box);
Опустить код здесь
}
На данный момент _motion_mat представляет собой матрицу 8*8. Соответствующее уравнение состояния движения представляет собой равномерную скорость.
box состояние meanдля:(xCenter,yCenter,w/h,h,Vx,Vy,Vr,Vh)。 предсказывать, предсказывать Получить новое состояние new_mean = _motion_mat * mean.T
void KalmanFilter::predict(KAL_MEAN &mean, KAL_COVA &covariance)
{
//revise the data;
DETECTBOX std_pos;
std_pos << _std_weight_position * mean(3),
_std_weight_position * mean(3),
1e-2,
_std_weight_position * mean(3);
DETECTBOX std_vel;
std_vel << _std_weight_velocity * mean(3),
_std_weight_velocity * mean(3),
1e-5,
_std_weight_velocity * mean(3);
KAL_MEAN tmp;
tmp.block<1, 4>(0, 0) = std_pos;
tmp.block<1, 4>(0, 4) = std_vel;
tmp = tmp.array().square();
KAL_COVA motion_cov = tmp.asDiagonal();
KAL_MEAN mean1 = this->_motion_mat * mean.transpose();
KAL_COVA covariance1 = this->_motion_mat * covariance *(_motion_mat.transpose());
covariance1 += motion_cov;
mean = mean1;
covariance = covariance1;
}
Обновить ковариацию covariance = _motion_mat * convariance *_motion_mat.T + motion_cov 。 montion_covдляматрица шума процесса。В целом может оставаться неизменным,Может быть установлен во время инициализации,Исходный кодсерединаSET для w/h связанная диагональная матрица.
Эта часть является изюминкой всей статьи, а также самой запутанной частью кода.
Блок предсказания первого совпадения и блок обнаружения с высокой степенью достоверности
Расчеты, использованные в этой статье iou Выполняется сопоставление, а также пересечение и сравнение между кадром предсказания и кадром обнаружения. когда совпадает поле предсказания, состояние в это время = Tracked,is_activated = true。 После сопоставления необходимо обновить ковариацию блока.
обновление в калмане:
KAL_DATA
KalmanFilter::update(
const KAL_MEAN &mean,
const KAL_COVA &covariance,
const DETECTBOX &measurement)
{
KAL_HDATA pa = project(mean, covariance);
KAL_HMEAN projected_mean = pa.first; // x,y,r,h
KAL_HCOVA projected_cov = pa.second; // _update_mat * covariance * (_update_mat.transpose()) + diag
Eigen::Matrix<float, 4, 8> B = (covariance * (_update_mat.transpose())).transpose();
Eigen::Matrix<float, 8, 4> kalman_gain = (projected_cov.llt().solve(B)).transpose(); // eg.8x4
Eigen::Matrix<float, 1, 4> innovation = measurement - projected_mean; //eg.1x4
auto tmp = innovation * (kalman_gain.transpose());
KAL_MEAN new_mean = (mean.array() + tmp.array()).matrix();
KAL_COVA new_covariance = covariance - kalman_gain * projected_cov*(kalman_gain.transpose());
return std::make_pair(new_mean, new_covariance);
}
Сначала введите функцию проекта и получите Projected_mean и Projected_con. Давайте сначала посмотрим, какие операции выполнял проект.
KAL_HDATA KalmanFilter::project(const KAL_MEAN &mean, const KAL_COVA &covariance)
{
DETECTBOX std;
std << _std_weight_position * mean(3), _std_weight_position * mean(3),
1e-1, _std_weight_position * mean(3);
KAL_HMEAN mean1 = _update_mat * mean.transpose();
KAL_HCOVA covariance1 = _update_mat * covariance * (_update_mat.transpose());
Eigen::Matrix<float, 4, 4> diag = std.asDiagonal();
diag = diag.array().square().matrix();
covariance1 += diag;
return std::make_pair(mean1, covariance1);
}
mean Матрица 1*8 (xCenter, yCenter, w/h, h, Vx, Vy, Vr, Vh) mean1 Эквивалентно извлечению mean первые четыре элемента. covariance1 Это сделано для облегчения последующих обновлений. covariance Промежуточная сумма. diag Для измерения ковариации шума настройки в этой статье аналогичны матрице шума процесса. kalman_gain Для выигрыша Калмана потребовалось бы projected_cov Обратная матрица , а затем B Его получают путем перемножения матриц. Здесь он получается непосредственно путем решения системы линейных уравнений, пропуская некоторые этапы вычислений. new_mean и new_covariance для нового box состояниеи Новая ковариация. После того, как кадр предсказания и кадр обнаружения с высокой степенью достоверности успешно сопоставлены, независимо от это время目标 state для гусеничного все еще Пропало, все надо обновить для гусеничногосостояние,иis_activated обновляются до истинный. И все нужно выполнить kalman середина update действовать. Как только цель будет достигнута:
(1) Состояние цели меняется на «Отслеживается».
(2) Значение is_activated цели становится истинным.
(3) Необходимо обновить среднюю ковариацию цели.
Кадр предсказания и кадр обнаружения, которые не совпадают в первый раз, дополнительно кэшируются. Удобное последующее действие.
второй матч Первый несовпадающий блок прогнозов и блок обнаружения с низкой достоверностью
Матчи по-прежнему засчитываются в счет ваших матчей. Аналогично обрабатываются совпадения в целевом первом матче. Несовпадающие цели будут отмечены, а состояние может быть изменено позже.
третий матч is_activated=false Блок отслеживания и первый не имеющий аналогов блок обнаружения с высокой степенью достоверности.
Если цель совпадает, то (1) укажите = Tracked(2)is_activated = true(3)mean и covariance все update。
Если цель не соответствует,в это времясостояниевстречастановиться При удалении эта цель будет удалена навсегда. Чтобы избежать случайного ложного срабатывания определенного кадра два раза подряд, необходимо обнаружить, по крайней мере, кадр с высокой достоверностью. confirm,有机встреча参и Последующие расчеты。
Перед публикацией результатов необходимо изменить значение переменной-члена класса BYTETrack.
this->lost_stracks = sub_stracks(this->lost_stracks, this->tracked_stracks);
this->lost_stracks = sub_stracks(this->lost_stracks, this->removed_stracks);
remove_duplicate_stracks(resa, resb, this->tracked_stracks, this->lost_stracks); // Удалять Повторить путь
При наличии повторяющихся путей количество кадров выживания одинаково и траектории аналогичны. Этот потерянный след также необходимо устранить. Результаты вывода: цель будет выводиться только в том случае, если is_activated = true, state = Tracked.
Если вы все еще не поняли после прочтения, я дам вам еще одну блок-схему, которую я составил.
Если вы действительно не можете понять исходный код и не хотите его понимать, вам просто нужно запустить его локально, чтобы увидеть эффект. Тогда смотрите прямо здесь.
Окружающая среда: компиляция Linux cmake
Набор данных: https://motchallenge.net/data/MOT17/
адрес git: https://github.com/ifzhang/ByteTrack
Первый clone Исходный код внизу. Ссылка была дана ранее. С++ Код находится в deploy папка, выбранная блоггером ncnn\cpp код в папке. Есть ниже include и src Это весь код.
В CMakeLists.txt отсутствуют ссылки.
Файл mian.cpp Основная идея состоит в том, чтобы прочитать файл det.txt и сохранить результаты обнаружения каждого кадра. Дайте мне примерный код
BYTETracker byteTrack = BYTETracker(10, 30);
for (int fi = 0; fi < maxFrame; fi++) { // maxFrame рамка
std::vector<ObjectTrack> trackResult;
byteTrack.update(detFrameData[fi], trackResult);
}
trackResult — это результат, определенный вами
Просто укажите файл BYTETracker.cpp и измените обновление на
void BYTETracker::update(const DetectInfo& objects, std::vector<ObjectTrack>& outTracks)
{
// в конце функции добавить код
for (auto i = 0; i < output_stracks.size(); i++)
{
outTracks.push_back({
static_cast<uint>(output_stracks[i].track_id),
static_cast<uint>(output_stracks[i].tlbr[0]),
static_cast<uint>(output_stracks[i].tlbr[1]),
static_cast<uint>(output_stracks[i].tlbr[2]),
static_cast<uint>(output_stracks[i].tlbr[3]),
output_stracks[i].score
});
}
}
На данный момент результаты получены. В дальнейшем вам останется только визуализировать соответствующие результаты на соответствующих картинках и все готово [Cheers.jpg]. Вы достаточно умны, чтобы принять меры.