基于点之间距离的多目标跟踪

news2024/9/22 19:39:28

1. 动机

        目标跟踪是计算机视觉领域一种常用的算法,用于将前后帧中的同一个目标关联起来,从而可以针对某一个特定目标进行分析,如对状态进行投票平滑获取更为稳健的结果。

        然而,目前流行的跟踪算法大多是基于检测的bbox之间的IOU来匹配的,这对于某些小目标或者点的检测,IOU通常不是一个好的选择,因为目标太小,很容易使得相邻两帧之间的IOU为0。

        为了解决这个问题,本文提出了一种基于点之间距离的跟踪方法:将目标建模为一个点,通过计算前后帧点之间的距离,利用匈牙利匹配来进行跟踪。

2. 方法

        直接上代码,里面给出了跟踪方法的定义以及一个使用示例:

"""
Test for multi-target tracker
"""

import numpy as np
from scipy.optimize import linear_sum_assignment


# 定义目标类
class Target:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.id = None
        self.miss_num = 0
        self.lost = False  # 添加一个标记来表示目标是否丢失


# 定义跟踪器类
class Tracker:
    def __init__(self, max_age=1, thres_dist=100):
        self.max_age = max_age
        self.thres_dist = thres_dist
        self.tracked_targets = []
        self.last_id = 0

    # 在下一帧中更新目标位置并使用匈牙利算法进行匹配
    def update(self, targets):
        # print([[t.x, t.y] for t in targets])
        # print([[t.x, t.y] for t in self.tracked_targets])
        # 计算每个跟踪器与目标之间的相似度(这里使用欧氏距离作为相似度指标)
        distances = []
        for target in targets:
            dist_list = []
            for tracked_target in self.tracked_targets:
                if not tracked_target.lost:  # 只考虑未丢失的目标
                    dist = np.sqrt((target[0] - tracked_target.x) ** 2 + (target[1] - tracked_target.y) ** 2)
                    dist_list.append(dist)
                else:
                    dist_list.append(np.inf)  # 将丢失的目标设置为无穷大距离,避免被匹配
            distances.append(dist_list)
        distances = np.asarray(distances)
        # 使用匈牙利算法进行匹配
        row_ind, col_ind = linear_sum_assignment(distances)
        # print(row_ind, col_ind, distances)
        # 更新匹配成功的目标位置
        # print(len(self.tracked_targets))
        for i, j in zip(row_ind, col_ind):
            if not self.tracked_targets[j].lost and distances[i][j] < self.thres_dist:  # 只更新未丢失的目标位置
                self.tracked_targets[j].x = targets[i][0]
                self.tracked_targets[j].y = targets[i][1]
            else:
                # 如果目标丢失,继续标记为丢失状态,不进行位置更新,同时累计丢失次数
                self.tracked_targets[j].miss_num += 1
                if self.tracked_targets[j].miss_num >= self.max_age:
                    # print("lost", self.tracked_targets[j].id)
                    self.tracked_targets[j].lost = True
        # 添加新的目标到跟踪列表
        for j in range(len(targets)):
            if j not in col_ind:
                self.create_target(targets[j][0], targets[j][1])
        # 检测丢失的目标,如果目标丢失超过一定帧数,将其从跟踪列表中删除
        lost_targets = []
        for target in self.tracked_targets:
            if target.lost:
                lost_targets.append(target)
        for target in lost_targets:
            self.tracked_targets.remove(target)

    def create_target(self, x, y):
        tar = Target(x, y)
        tar.id = self.last_id
        self.tracked_targets.append(tar)
        self.last_id += 1


def get_color_by_id(id):
    colors = [
        (255, 0, 0),
        (255, 255, 0),
        (255, 0, 255),
        (30, 140, 100),
        (0, 255, 0),
        (0, 50, 200),
        (100, 0, 30),
        (100, 100, 0),
        (20, 10, 200),
        (20, 250, 100),
        (145, 0, 90),
        (15, 10, 190),
        (15, 100, 100),
    ]
    index = id % len(colors)
    return colors[index]


if __name__ == '__main__':
    import cv2
    from PIL import Image
    import copy

    img = np.ones([500, 500, 3]).astype(np.uint8)
    pil_imgs = [Image.fromarray(img)]

    # 初始化目标列表
    preds = [[1, 1], [1, 499], [499, 1], [499, 499]]

    # 初始化跟踪器
    tracker = Tracker()

    # 模拟多帧跟踪过程
    for i in range(100):
        # 在每一帧中,随机移动每个目标的位置
        delta = 10
        if i in [10, 11, 12, 13]:
            delta = 30

        # print([[t.x, t.y] for t in tracker.tracked_targets])
        preds[0][0] += np.random.randint(0, delta)
        preds[0][1] += np.random.randint(0, delta)
        preds[1][0] += np.random.randint(0, delta)
        preds[1][1] -= np.random.randint(0, delta)
        preds[2][0] -= np.random.randint(0, delta)
        preds[2][1] += np.random.randint(0, delta)
        preds[3][0] -= np.random.randint(0, delta)
        preds[3][1] -= np.random.randint(0, delta)
        # print([[t.x, t.y] for t in tracker.tracked_targets])

        # 更新跟踪器的目标列表
        tracker.update(copy.deepcopy(preds))
        # 打印当前帧中每个跟踪到的目标位置
        # print("frame: {}".format(i))
        points, ids = [], []
        for target in tracker.tracked_targets:
            print("Target {}: ({}, {}); lost: {}".format(target.id, target.x, target.y, target.lost))
            points.append([target.x, target.y])
            ids.append(target.id)
            # cv2.circle(img, [target.x, target.y], point_size, point_color, thickness)
            cv2.putText(img, str(target.id), [target.x, target.y], cv2.FONT_HERSHEY_SIMPLEX, 0.4,
                        get_color_by_id(target.id), thickness=1, lineType=cv2.LINE_AA)

        pil_imgs.append(Image.fromarray(img))
        cv2.imshow('img', img)
        if cv2.waitKey(30) == ord('q'):
            break

    # 创建并保存GIF文件
    image_0 = pil_imgs[0]
    image_0.save('track_result.gif', save_all=True, append_images=pil_imgs[1:], duration=30, loop=0)

运行上述代码后,会保存一个GIF文件,展示了多个目标的跟踪结果,如下图:

基于点的多目标跟踪结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1237690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pyqt5实现串口工具

使用pyqt5做一个串口工具 一、设计界面二、功能代码实现 一、设计界面 界面使用qtdesigner设计&#xff0c;然后在转成Python代码&#xff0c;以下是转好后的代码 untitled_serial.py # -*- coding: utf-8 -*-# Form implementation generated from reading ui file untitle…

【HarmonyOS】获取备案需要的公钥和MD5签名问题

【关键字】 HarmonyOS、公钥、MD5签名 【问题描述】 有cp反馈Harmony App如何获取备案需要的公钥和MD5签名。 【解决方案】 1、获取备案需要的公钥&#xff1a; 1&#xff09;用记事本打开签名对应.cer文件 2&#xff09;里面的内容粘贴到一个可以查看证书的网站上面&…

【广州华锐互动】VR防溺水安全内容体验提高群众防溺水意识

在全球各地&#xff0c;溺水是导致儿童和青少年死亡的主要原因之一。据世界卫生组织的统计&#xff0c;全球每年有超过36万人因溺水而死亡&#xff0c;其中大部分是儿童和青少年。因此&#xff0c;提供有效的防溺水教育和培训至关重要。随着科技的发展&#xff0c;虚拟现实&…

C++_String增删查改模拟实现

C_String增删查改模拟实现 前言一、string默认构造、析构函数、拷贝构造、赋值重载1.1 默认构造1.2 析构函数1.3 拷贝构造1.4 赋值重载 二、迭代器和范围for三、元素相关&#xff1a;operator[ ]四、容量相关&#xff1a;size、resize、capacity、reserve4.1 size、capacity4.2…

【Redis篇】简述Redis | 详解Redis命令

文章目录 &#x1f38d;什么是Redis&#x1f38d;Redis特点&#x1f38d;Redis应用场景&#x1f354;Windows安装Redis⭐启动Redis &#x1f33a;Redis数据类型&#x1f33a;Redis常用命令⭐字符串string操作命令⭐哈希hash操作命令⭐列表list操作命令⭐集合set操作命令⭐有序集…

在Ubuntu18.04安装适合jdk8的eclipse

直接在Ubuntu软件那里下载的eclipse不能用&#xff0c;下载后启动会报错&#xff1a;Eclipse An error has occurred. See the log file/home/hadoop/.eclipse/ org.eclipse.platform_3.8_155965261/ configuration/1700567835954.log 上网搜索方法&#xff0c;按教程说的修改e…

华为认证 | HCIE考证流程详解!

HCIE&#xff08;Huawei Certified ICT Expert&#xff0c;华为认证ICT专家&#xff09;是华为认证体系中最高级别的ICT技术认证&#xff0c;旨在打造高含金量的专家级认证&#xff0c;为技术融合背景下的ICT产业提供新的能力标准&#xff0c;以实现华为认证引领ICT行业技术认证…

斯坦福NLP课程来了

生成式AI&#xff0c;尤其是以ChatGPT为首的大语言模型正在改变人们的生活方式&#xff0c;我想一定有小伙伴想加入NLP这个行列。 微软重磅发布4个适合初学者的机器学习资料 我在前一篇文章中分享了微软人工智能初学者课程&#xff0c;其中的【生成式AI】非常适合初学者&…

系列六、ThreadLocal内存泄漏案例

一、内存泄漏 vs 内存溢出 内存泄漏&#xff1a;内存泄漏是指程序中已经动态分配的堆内存由于某种原因程序未释放或者无法释放&#xff0c;造成系统内存的浪费&#xff0c;导致程序运行速度减慢甚至导致系统崩溃等严重后果&#xff0c;内存泄漏最终 会导致内…

2023年中国高压驱动芯片分类、市场规模及发展趋势分析[图]

高压驱动芯片是一种能在高压环境下工作的集成电路&#xff0c;主要用于控制和驱动各种功率器件&#xff0c;如继电器、电磁阀、电机、变频器等。高压驱动芯片根据其输出电流的大小和形式可分为两类恒流型和开关型。 高压驱动芯片分类 资料来源&#xff1a;共研产业咨询&#x…

CorelDRAW2024有哪些新功能?如何下载

作为一个广告设计者怎么能不会一两款专业设计软件&#xff0c;Adobe公司的PS、AI和Corel公司的CorelDRAW都是常用的图片处理软件&#xff0c;也是市场上同类设计软件中的翘楚。针对不同的设计任务选择不同的设计软件&#xff0c;才能提高工作效率&#xff0c;事半功倍。 Corel…

七个步骤 从零到servlet第一个hello

目录 Tomcat安装 Servlet 1.引入项目 2.引入依赖 3.创建目录 1.创建 webapp 目录 2.创建 web.xml 3.编写 web.xml 4.编写代码 5.打包程序 6.部署程序 7.验证程序 Smart Tomcat Tomcat安装 在动漫世界&#xff0c;我们有汤姆猫 在Java世界&#xff0c;同样也有一个…

精彩预告 | OpenHarmony即将亮相MTSC 2023

MTSC 2023 第12届中国互联网测试开发大会&#xff08;深圳站&#xff09;即将于2023年11月25日&#xff0c;在深圳登喜路国际大酒店举办&#xff0c;大会将以“1个主会场4个平行分会场”的形式呈现&#xff0c;聚集一众顶尖技术专家和行业领袖&#xff0c;围绕如今备受关注的行…

redis之主从复制和哨兵模式

&#xff08;一&#xff09;redis的性能管理 1、redis的数据缓存在内存中 2、查看redis的性能&#xff1a;info memory&#xff08;重点&#xff09; used_memory:904192&#xff08;单位字节&#xff09; redis中数据占用的内存 used_memory_rss:10522624 redis向操作系统…

锯木棍

题目描述 有一根粗细均匀长度为 L 的木棍&#xff0c;先用红颜色刻度线将它 m 等分&#xff0c;再用蓝色刻度线将 其 n 等分&#xff08; m>n &#xff09;&#xff0c;然后按所有刻度线将该木棍锯成小段&#xff0c;计算并输出长度最长的木棍的长度和根数。 输入格式…

(内部资料)收下这几个人工智能学习秘籍!

秘籍一&#xff1a;练好基本功 学习基础知识&#xff1a;人工智能涉及多个学科领域&#xff0c;包括数学、计算机科学、统计学等。因此&#xff0c;学习基础知识是非常重要的。您可以通过学习线性代数、概率论和微积分等数学基础知识&#xff0c;以及掌握Python编程语言和常用…

Linux学习笔记-Ubuntu下使用Crontab设置定时任务

文章目录 一、概述二、基于crontab的设置2.1 基本命令说明2.2 使用-e指令编辑命令2.2.1 进入编辑模式2.2.2 指令信息格式2.2.4 开启日志1) 修改rsyslog配置文件2) 重启rsyslog3) 查看日志 2.2.3 设置后之后重启服务 三、示例3.1 每隔一分钟往文件中日期3.2 使用-l查看任务列表3…

微软重磅发布4个适合初学者的机器学习资料

自媒体火起来后&#xff0c;很多科技大佬都开始写博客&#xff0c;录视频了&#xff0c;大佬一入行&#xff0c;整个行业卷上天&#xff0c;像我这样的也只能走资源整合之路了&#xff0c;不过这样也好&#xff0c;科技进步&#xff0c;人类发展需要他们。 除了个人&#xff0…

深度学习常见激活函数:ReLU,sigmoid,Tanh,softmax,Leaky ReLU,PReLU,ELU整理集合,应用场景

文章目录 1、ReLU 函数&#xff08;隐藏层中是一个常用的默认选择&#xff09;1.1 优点1.2 缺点 2、sigmoid 函数2.1 优点2.2 缺点 3、Tanh 函数3.1 优点3.2 缺点 4、softmax 函数&#xff08;多分类任务最后一层都会使用&#xff09;5、Leaky ReLU 函数5.1 优点5.2 缺点 6、PR…

KDE 项目发布了 KDE Gear 23.08.3

导读KDE 项目发布了 KDE Gear 23.08.3&#xff0c;作为最新的 KDE Gear 23.08 开源集合的第三次维护更新&#xff0c;该集合包含了用于 KDE Plasma 桌面环境和其他平台的 KDE 应用程序。 KDE Gear 23.08.3 是在 KDE Gear 23.08.2 大约一个月之后发布的&#xff0c;包含了更多对…