基于 PyTorch 的目标检测和跟踪(无敌版)

article/2025/8/20 10:27:00

一个不知名大学生,江湖人称菜狗
original author: jacky Li
Email : 3435673055@qq.com

 Time of completion:2023.2.1
Last edited: 2023.2.1

目录

图像中的目标检测

视频中的目标跟踪

作者有言


在文章《基于 PyTorch 的图像分类器》中,介绍了如何在 PyTorch 中使用您自己的图像来训练图像分类器,然后使用它来进行图像识别。本篇文章中,我将向您展示如何使用预训练的分类器检测图像中的多个对象,然后在视频中跟踪它们。

图像分类(识别)和目标检测分类之间有什么区别?在分类中,识别图像中的主要对象,然后通过单个类对整个图像进行分类。在检测中,在图像中识别多个对象,并对其进行分类,同时确定一个位置

图像中的目标检测

目标检测有几种算法,其中 YOLO 和 SSD 是最流行的。对于本篇文章,我们将尝试使用 YOLOv3。

这里的 YOLO 检测代码是基于 Erik Lindernoren 对 Joseph Redmon 和 Ali Farhadi 论文(论文链接:https://pjreddie.com/media/files/papers/YOLOv3.pdf)的实现。我们首先导入所需的模块:


from models import *
from utils import *import os, sys, time, datetime, random
import torch
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
from torch.autograd import Variableimport matplotlib.pyplot as plt
import matplotlib.patches as patches
from PIL import Image

然后我们加载预训练模型的配置参数和权重,以及训练 Darknet 模型的 COCO 数据集的类名。和在 PyTorch 中一样,不要忘记在加载后将模型设置为 eval 模式。


config_path='config/yolov3.cfg'
weights_path='config/yolov3.weights'
class_path='config/coco.names'
img_size=416
conf_thres=0.8
nms_thres=0.4# Load model and weights
model = Darknet(config_path, img_size=img_size)
model.load_weights(weights_path)
model.cuda()
model.eval()
classes = utils.load_classes(class_path)
Tensor = torch.cuda.FloatTensor

上面还有一些预定义的值:图像尺寸(416px) ,Confidenc 阈值和 NMS 阈值。

下面的基本函数将返回对指定图像的检测。请注意,它需要一个 Pillow 读取的图像作为输入。大多数代码处理图像大小调整到416 * 416 大小的正方形,同时保持它的长宽比和填充。实际的检测是在最后4行。


def detect_image(img):# scale and pad imageratio = min(img_size/img.size[0], img_size/img.size[1])imw = round(img.size[0] * ratio)imh = round(img.size[1] * ratio)img_transforms=transforms.Compose([transforms.Resize((imh,imw)),transforms.Pad((max(int((imh-imw)/2),0),max(int((imw-imh)/2),0), max(int((imh-imw)/2),0),max(int((imw-imh)/2),0)), (128,128,128)),transforms.ToTensor(),])# convert image to Tensorimage_tensor = img_transforms(img).float()image_tensor = image_tensor.unsqueeze_(0)input_img = Variable(image_tensor.type(Tensor))# run inference on the model and get detectionswith torch.no_grad():detections = model(input_img)detections = utils.non_max_suppression(detections, 80,conf_thres, nms_thres)return detections[0]

最后,让我们通过加载一个图像,获得检测值,然后在检测到的对象周围显示它与边框一起。同样,这里的大多数代码处理缩放和填充图像,以及为每个检测到的类获取不同的颜色。

# load image and get detections
img_path = "images/blueangels.jpg"
prev_time = time.time()
img = Image.open(img_path)
detections = detect_image(img)
inference_time = datetime.timedelta(seconds=time.time() - prev_time)
print ('Inference Time: %s' % (inference_time))# Get bounding-box colors
cmap = plt.get_cmap('tab20b')
colors = [cmap(i) for i in np.linspace(0, 1, 20)]img = np.array(img)
plt.figure()
fig, ax = plt.subplots(1, figsize=(12,9))
ax.imshow(img)pad_x = max(img.shape[0] - img.shape[1], 0) * (img_size / max(img.shape))
pad_y = max(img.shape[1] - img.shape[0], 0) * (img_size / max(img.shape))
unpad_h = img_size - pad_y
unpad_w = img_size - pad_xif detections is not None:unique_labels = detections[:, -1].cpu().unique()n_cls_preds = len(unique_labels)bbox_colors = random.sample(colors, n_cls_preds)# browse detections and draw bounding boxesfor x1, y1, x2, y2, conf, cls_conf, cls_pred in detections:box_h = ((y2 - y1) / unpad_h) * img.shape[0]box_w = ((x2 - x1) / unpad_w) * img.shape[1]y1 = ((y1 - pad_y // 2) / unpad_h) * img.shape[0]x1 = ((x1 - pad_x // 2) / unpad_w) * img.shape[1]color = bbox_colors[int(np.where(unique_labels == int(cls_pred))[0])]bbox = patches.Rectangle((x1, y1), box_w, box_h,linewidth=2, edgecolor=color, facecolor='none')ax.add_patch(bbox)plt.text(x1, y1, s=classes[int(cls_pred)],color='white', verticalalignment='top',bbox={'color': color, 'pad': 0})
plt.axis('off')
# save image
plt.savefig(img_path.replace(".jpg", "-det.jpg"),        bbox_inches='tight', pad_inches=0.0)
plt.show()

视频中的目标跟踪

现在你已经知道如何检测图像中的不同物体了。当你在一个视频中一帧一帧地做这个动作时,你会看到那些跟踪框在移动,这样的可视化效果可能会非常酷。但是,如果这些视频帧中有多个对象,你怎么知道一帧中的对象是否与前一帧中的对象相同呢?这就是所谓的目标跟踪,并使用多个检测,以确定一个特定的对象随着时间的推移。

有几个算法可以做到这一点,我决定使用 SORT,这是非常容易使用并且速度相当快。SORT(Simple Online and Realtime Tracking)是2017年由 Alex Bewley,Zongyuan Ge,Lionel Ott,Fabio Ramos,Ben Upcroft 发表的一篇论文,该论文建议使用 Kalman 过滤器来预测先前确定的物体的轨迹,并将它们与新的检测结果进行匹配。作者 Alex Bewley 还编写了一个多功能的 Python 实现,我将在本文中使用它。

现在说到代码,前3个代码段将与单幅图像检测中的代码段相同,因为它们处理的是在单帧上获得 YOLO 检测。区别在于最后一部分,对于每个检测,我们调用 Sort 对象的 Update 函数,以获得对图像中对象的引用。因此,与前面示例中的常规检测(包括边界框的坐标和类预测)不同,我们将获得跟踪的对象,除了上面的参数,还包括一个对象 ID。然后我们以几乎相同的方式显示,但添加 ID 并使用不同的颜色,这样你就可以很容易地在视频帧中看到对象。

我还使用 OpenCV 来读取视频并显示视频帧。注意,Jupyter 处理视频的速度相当慢。您可以使用它进行测试和简单的可视化,但是我还提供了一个独立的 Python 脚本,它将读取源视频,并用跟踪的对象输出一个副本。在笔记本上播放 OpenCV 视频并不容易,所以你可以保留这段代码用于其他实验。

videopath = 'video/intersection.mp4'%pylab inline
import cv2
from IPython.display import clear_outputcmap = plt.get_cmap('tab20b')
colors = [cmap(i)[:3] for i in np.linspace(0, 1, 20)]# initialize Sort object and video capture
from sort import *
vid = cv2.VideoCapture(videopath)
mot_tracker = Sort()#while(True):
for ii in range(40):ret, frame = vid.read()frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)pilimg = Image.fromarray(frame)detections = detect_image(pilimg)    img = np.array(pilimg)pad_x = max(img.shape[0] - img.shape[1], 0) *(img_size / max(img.shape))pad_y = max(img.shape[1] - img.shape[0], 0) *(img_size / max(img.shape))unpad_h = img_size - pad_yunpad_w = img_size - pad_xif detections is not None:tracked_objects = mot_tracker.update(detections.cpu())        unique_labels = detections[:, -1].cpu().unique()n_cls_preds = len(unique_labels)for x1, y1, x2, y2, obj_id, cls_pred in tracked_objects:box_h = int(((y2 - y1) / unpad_h) * img.shape[0])box_w = int(((x2 - x1) / unpad_w) * img.shape[1])y1 = int(((y1 - pad_y // 2) / unpad_h) * img.shape[0])x1 = int(((x1 - pad_x // 2) / unpad_w) * img.shape[1])            color = colors[int(obj_id) % len(colors)]color = [i * 255 for i in color]cls = classes[int(cls_pred)]cv2.rectangle(frame, (x1, y1), (x1+box_w, y1+box_h),color, 4)cv2.rectangle(frame, (x1, y1-35), (x1+len(cls)*19+60,y1), color, -1)cv2.putText(frame, cls + "-" + str(int(obj_id)),(x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX,1, (255,255,255), 3)    fig=figure(figsize=(12, 8))title("Video Stream")imshow(frame)show()clear_output(wait=True)

您可以使用常规的 Python 脚本进行实时处理(您可以从摄像机获取输入)和保存视频。下面是我用这个程序生成的视频样本。

视频链接:https://youtu.be/1BY2CxiMYvQ

结果如视频所示,你现在可以尝试自己检测图像中的多个对象,并通过视频帧跟踪这些对象。

作者有言

如果需要代码,请私聊博主,博主看见回。
如果感觉博主讲的对您有用,请点个关注支持一下吧,将会对此类问题持续更新……


http://chatgpt.dhexx.cn/article/IQD8sTme.shtml

相关文章

CMSIS-RTOS是什么?

关注星标公众号,不错过精彩内容 作者 | strongerHuang 微信公众号 | strongerHuang CMSIS:Cortex Microcontroller Software Interface Standard,Cortex微控制器软件接口标准。它包含的内容比较多: CMSIS-RTOS:主要用于…

RAM Sequential

前段时间,在公众号上偶然看到一篇很不错的技术分享文章:《南湖处理器DFT设计范例》。文中详细介绍了中科院计算所的RISC-V处理器实施的DFT设计。 去年,也基于一款处理器应用过Share Test Bus技术,但在memory界面fault测试的问题&a…

monoSLAM

单目相机的优点(和双目相机相比):双目相机测得的深度距离收到基线长度的限制,单目相机就可以解决这个问题。 参考博客:http://blog.csdn.net/heyijia0327/article/details/50758944 (一定要看&#xff0c…

Linux一键实现ramos打造自己的livecd

软件名:remastersys作者:nerun个人亲测可用,kali和ubuntu下都成功了,直接一键将当前使用的系统打包成iso,启动测试如下:1:iso直接加载启动成功进入ramos2:iso解压文件到根目录&#…

RAMOS系统简介及制作

同步发布在个人博客上:https://www.zhyong.cn ,可通过搜索文章名称找到该文章! RAMOS系统简介 内存操作系统(RAMOS)是全内存运行,启动后不依赖硬盘的Windows系统。它的原理是利用特殊的软件把多余的内存虚拟为内存盘,然…

如何打造内存操作系统RAMOS?

如何打造内存操作系统RAMOS?添加链接描述 把系统放进内存里 自己打造高速RAMOS 所谓内存操作系统就是全内存运行,系统将不再依赖硬盘。如今科技这么发达,电脑内存也越来越大,如果我们可以利用剩余内存来制作虚拟磁盘&#xff0c…

RAMOS(全内存操作系统)初识----仅供测试

内存操作系统(RAMOS)是全内存运行,启动后不依赖硬盘的Windows系统。它的原理是利用特殊的软件把多余的内存虚拟为内存盘,然后将制作好的操作系统镜像释放到这个虚拟内存盘中运行,让Windows操作系统和应用软件完全工作于内存之中,从…

英语拼读规则

前言: 想学英语就要用英语的思维去学。不能用某国某人指定的方法。误人子弟呀!! 一、就英语就要像学汉语一样要学会拼音,拼音会了汉字自然就会读了。 第一步:26个字母的【音标】要记牢。不只会写字母 也要会写字母对应…

英语名词复数s的发音规则

目录 1. 英语名词复数s的发音规则 1. 在清辅音后发/s/,[p], [t], [k], [h]; [f], [x], [s], [𝛉], [ꭍ]; [ts], [tr], [tꭍ]。记忆顺口溜:婆婆有位特殊的客户 ,她叫福西施,t前缀 2. 在浊辅音和元音后发/z/音&#x…

英语口语中的音变现象及读音规则

英语口语中的音变现象是指再说英语的过程中出于“省力” 的原因,在读英语的时候唇舌处于放松的状态,可以让我们更轻松地说英语。音变现象包括:连读,弱读,缩读,浊化,异化。这五大音变现象最具有代…

英语语法---读音规则

一、48个音标(音素)简表(18大语音语变现象) 单元音又分为前元音、中元音和后元音,其区分点在于发音时舌身是在口腔的前部、中部还是后部 音素发音链接:https://en-yinbiao.xiao84.com/ 18大语音语变现象&…

链表之头指针、头结点、首元结点、空链表

链表之头指针、头结点、首元结点、空链表 文章目录 链表之头指针、头结点、首元结点、空链表前言疑问整理头指针,头结点,首元结点定义首元结点定义头指针定义头结点定义 疑问回答 前言 最近在用力扣刷链表的题,总是写不出来,对这…

求二叉树指定结点到根结点的路径c++ 非常详细。

看了很多 没有看见完整的代码 我喜欢喂饭喂到嘴边。 部分代码参考16 二叉树:以x为根的子树的深度_DHU杨骅麟(紫外线过敏)的博客-CSDN博客 面试经典(16)--二叉树根节点到指定节点的路径_nginux的博客-CSDN博客_二叉树根节点到目标节点路径 运…

二叉树的结点数

二叉树的结点数(*) (10分) 已知二叉树的结点结构定义如下: typedef struct _NODE_ {char data;struct _NODE_ *lch, *rch; } NODE; 说明:data 为数据域,均为英文大写字母。lch 和 rch 分别为指示左、右孩子的指针。 请编写函数,求二叉树的结点个数。 函数原型 // 结点…

求一个结点x在在二叉树中的双亲结点算法

1、算法思想 使用先序递归遍历思想完成算法设计。首先判断节点的左右孩子是否存在,若存在,并且左右孩子中有一个符合查找要求,则返回元素!否则,继续递归查找,直到成功或者找不到符合要求的结点&#xff01…

计算二叉树中结点的个数

思想: 递归实现 图示为举例二叉树进行思路解释 二叉树中结点的个数:只要能计算出A左子树的个数A右子树的个数1 左子树个数:以B为结点的左子树个数右子树个数1 右子树个数:以C为结点的左子树个数右子树个数1 . . . .&#xff0…

(图解)单链表删除结点值为x的结点算法

目录 一、非递归的算法 第一种算法思路如下: 第二种算法思路如下: 二、递归的算法 一、非递归的算法 第一种算法思路如下: 先判断链表L是否为空,空链表退出程序;用p利用while循环从头到尾扫描单链表,p…

单链表的基本操作-插入结点、删除结点、新建链表、查找结点位置

** C语言新手小白的学习笔记-------------目前持续更新中 ** 本人90后电气工程及其自动化大学生,大二开始接触C语言,写过前端,Python,但是都不精通,通过许多认识后明白了自身的许多不足,因此,…