OpenCV从入门到精通实战(六)——多目标追踪

news2024/11/24 13:00:28

基于原生的追踪

使用OpenCV库实现基于视频的对象追踪。通过以下步骤和Python代码,您将能够选择不同的追踪器,并对视频中的对象进行实时追踪。

步骤 1: 导入必要的库

首先,我们需要导入一些必要的Python库,包括argparsetimecv2 (OpenCV) 和 numpy

import argparse
import time
import cv2
import numpy as np

步骤 2: 设置参数解析

使用argparse库来解析命令行参数。我们将指定输入视频文件的路径以及选择的追踪器类型。

ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", type=str, help="path to input video file")
ap.add_argument("-t", "--tracker", type=str, default="kcf", help="OpenCV object tracker type")
args = vars(ap.parse_args())

步骤 3: 定义支持的追踪器

在OpenCV中,有多种对象追踪器可用。我们将它们存储在一个字典中,便于后续使用。

OPENCV_OBJECT_TRACKERS = {
    "csrt": cv2.TrackerCSRT_create,
    "kcf": cv2.TrackerKCF_create,
    "boosting": cv2.TrackerBoosting_create,
    "mil": cv2.TrackerMIL_create,
    "tld": cv2.TrackerTLD_create,
    "medianflow": cv2.TrackerMedianFlow_create,
    "mosse": cv2.TrackerMOSSE_create
}

步骤 4: 初始化追踪器和视频流

我们初始化一个多对象追踪器并打开视频文件。

trackers = cv2.MultiTracker_create()
vs = cv2.VideoCapture(args["video"])

步骤 5: 处理视频帧

接下来,我们读取视频中的每一帧,并对其进行缩放处理,然后使用追踪器更新追踪状态,并绘制追踪的边框。

while True:
    frame = vs.read()
    frame = frame[1]
    if frame is None:
        break
    (h, w) = frame.shape[:2]
    width = 600
    r = width / float(w)
    dim = (width, int(h * r))
    frame = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)
    (success, boxes) = trackers.update(frame)
    for box in boxes:
        (x, y, w, h) = [int(v) for v in box]
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
    cv2.imshow("Frame", frame)
    key = cv2.waitKey(100) & 0xFF
    if key == ord("s"):
        box = cv2.selectROI("Frame", frame, fromCenter=False, showCrosshair=True)
        tracker = OPENCV_OBJECT_TRACKERS[args["tracker"]]()
        trackers.add(tracker, frame, box)
    elif key == 27:
        break
vs.release()
cv2.destroyAllWindows()

总结

import argparse
import time
import cv2
import numpy as np

# 配置参数
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", type=str,
	help="path to input video file")
ap.add_argument("-t", "--tracker", type=str, default="kcf",
	help="OpenCV object tracker type")
args = vars(ap.parse_args())

# opencv已经实现了的追踪算法

OPENCV_OBJECT_TRACKERS = {

	"csrt": cv2.TrackerCSRT_create,
	"kcf": cv2.TrackerKCF_create,
	"boosting": cv2.TrackerBoosting_create,
	"mil": cv2.TrackerMIL_create,
	"tld": cv2.TrackerTLD_create,
	"medianflow": cv2.TrackerMedianFlow_create,
	"mosse": cv2.TrackerMOSSE_create
}

# 实例化OpenCV's multi-object tracker
trackers = cv2.MultiTracker_create()
vs = cv2.VideoCapture(args["video"])

# 视频流
while True:
	# 取当前帧
	frame = vs.read()
	# (true, data)
	frame = frame[1]
	# 到头了就结束
	if frame is None:
		break

	# resize每一帧
	(h, w) = frame.shape[:2]
	width=600
	r = width / float(w)
	dim = (width, int(h * r))
	frame = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)

	# 追踪结果
	(success, boxes) = trackers.update(frame)

	# 绘制区域
	for box in boxes:
		(x, y, w, h) = [int(v) for v in box]
		cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

	# 显示
	cv2.imshow("Frame", frame)
	key = cv2.waitKey(100) & 0xFF

	if key == ord("s"):
		# 选择一个区域,按s
		box = cv2.selectROI("Frame", frame, fromCenter=False,
			showCrosshair=True)

		# 创建一个新的追踪器
		tracker = OPENCV_OBJECT_TRACKERS[args["tracker"]]()
		trackers.add(tracker, frame, box)

	# 退出
	elif key == 27:
		break
vs.release()
cv2.destroyAllWindows()

通过上述步骤和代码,可以实现一个简单的视频对象追踪应用,该应用支持多种追踪算法,并允许用户实时选择和追踪视频中的对象。这种技术在许多领域都有广泛的应用,包括安全监控、人机交互和自动驾驶车辆等。

检测模型的跟踪

检测模型 使用Python、OpenCV、dlib和多进程处理视频中的实时对象跟踪。以下是具体步骤及相关代码片段:

1. 设置和参数解析

  • 导入必要的库,并设置参数解析,处理输入如视频文件路径和模型配置。
from utils import FPS
import multiprocessing
import numpy as np
import argparse
import dlib
import cv2

2. 初始化深度学习模型

  • 加载预训练的Caffe模型进行对象检测。
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])

3. 视频流处理

  • 从指定的文件开始视频捕捉,并准备处理帧。
vs = cv2.VideoCapture(args["video"])

4. 帧处理

  • 调整帧大小并转换为RGB格式进行处理。
  • 如果检测到的对象置信度高于阈值,则初始化对象跟踪。
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

5. 对象检测和跟踪

  • 对初次检测到的对象创建跟踪器,并使用多进程处理。
p = multiprocessing.Process(target=start_tracker, args=(bb, label, rgb, iq, oq))
p.daemon = True
p.start()

6. 追踪器更新和结果输出

  • 每个跟踪器获取新的帧,更新位置并输出跟踪结果。
outputQueue.put((label, (startX, startY, endX, endY)))

7. 视频输出和显示

  • 如果指定了输出文件,将处理后的帧写入视频文件。
  • 显示处理后的帧并在用户按下ESC键时停止。
writer.write(frame)
key = cv2.waitKey(1) & 0xFF
if key == 27:
    break

8. 清理和资源释放

  • 停止FPS计时,释放视频文件和窗口资源。
fps.stop()
writer.release()
cv2.destroyAllWindows()
vs.release()

完整代码:
utils.py

import datetime

class FPS:
    def __init__(self):
        # store the start time, end time, and total number of frames
        # that were examined between the start and end intervals
        self._start = None
        self._end = None
        self._numFrames = 0

    def start(self):
        # start the timer
        self._start = datetime.datetime.now()
        return self

    def stop(self):
        # stop the timer
        self._end = datetime.datetime.now()

    def update(self):
        # increment the total number of frames examined during the
        # start and end intervals
        self._numFrames += 1

    def elapsed(self):
        # return the total number of seconds between the start and
        # end interval
        return (self._end - self._start).total_seconds()

    def fps(self):
        # compute the (approximate) frames per second
        return self._numFrames / self.elapsed()

multi_object_tracking_fast.py

import datetime

class FPS:
    def __init__(self):
        # store the start time, end time, and total number of frames
        # that were examined between the start and end intervals
        self._start = None
        self._end = None
        self._numFrames = 0

    def start(self):
        # start the timer
        self._start = datetime.datetime.now()
        return self

    def stop(self):
        # stop the timer
        self._end = datetime.datetime.now()

    def update(self):
        # increment the total number of frames examined during the
        # start and end intervals
        self._numFrames += 1

    def elapsed(self):
        # return the total number of seconds between the start and
        # end interval
        return (self._end - self._start).total_seconds()

    def fps(self):
        # compute the (approximate) frames per second
        return self._numFrames / self.elapsed()

multi_object_tracking_slow.py

#导入工具包
from utils import FPS
import numpy as np
import argparse
import dlib
import cv2
"""
--prototxt mobilenet_ssd/MobileNetSSD_deploy.prototxt 
--model mobilenet_ssd/MobileNetSSD_deploy.caffemodel 
--video race.mp4
"""
# 参数
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--prototxt", default="mobilenet_ssd/MobileNetSSD_deploy.prototxt",
	help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", default="mobilenet_ssd/MobileNetSSD_deploy.caffemodel",
	help="path to Caffe pre-trained model")
ap.add_argument("-v", "--video",default="race.mp4",
	help="path to input video file")
ap.add_argument("-o", "--output", type=str,
	help="path to optional output video file")
ap.add_argument("-c", "--confidence", type=float, default=0.2,
	help="minimum probability to filter weak detections")
args = vars(ap.parse_args())


# SSD标签
CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
	"bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
	"dog", "horse", "motorbike", "person", "pottedplant", "sheep",
	"sofa", "train", "tvmonitor"]

# 读取网络模型
print("[INFO] loading model...")
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])

# 初始化
print("[INFO] starting video stream...")
vs = cv2.VideoCapture(args["video"])
writer = None

# 一会要追踪多个目标
trackers = []
labels = []

# 计算FPS
fps = FPS().start()

while True:
	# 读取一帧
	(grabbed, frame) = vs.read()

	# 是否是最后了
	if frame is None:
		break

	# 预处理操作
	(h, w) = frame.shape[:2]
	width=600
	r = width / float(w)
	dim = (width, int(h * r))
	frame = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)
	rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

	# 如果要将结果保存的话
	if args["output"] is not None and writer is None:
		fourcc = cv2.VideoWriter_fourcc(*"MJPG")
		writer = cv2.VideoWriter(args["output"], fourcc, 30,
			(frame.shape[1], frame.shape[0]), True)

	# 先检测 再追踪
	if len(trackers) == 0:
		# 获取blob数据
		(h, w) = frame.shape[:2]
		blob = cv2.dnn.blobFromImage(frame, 0.007843, (w, h), 127.5)

		# 得到检测结果
		net.setInput(blob)
		detections = net.forward()

		# 遍历得到的检测结果
		for i in np.arange(0, detections.shape[2]):
			# 能检测到多个结果,只保留概率高的
			confidence = detections[0, 0, i, 2]

			# 过滤
			if confidence > args["confidence"]:
				# extract the index of the class label from the
				# detections list
				idx = int(detections[0, 0, i, 1])
				label = CLASSES[idx]

				# 只保留人的
				if CLASSES[idx] != "person":
					continue

				# 得到BBOX
				#print (detections[0, 0, i, 3:7])
				box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
				(startX, startY, endX, endY) = box.astype("int")

				# 使用dlib来进行目标追踪
				#http://dlib.net/python/index.html#dlib.correlation_tracker
				t = dlib.correlation_tracker()
				rect = dlib.rectangle(int(startX), int(startY), int(endX), int(endY))
				t.start_track(rgb, rect)

				# 保存结果
				labels.append(label)
				trackers.append(t)

				# 绘图
				cv2.rectangle(frame, (startX, startY), (endX, endY),
					(0, 255, 0), 2)
				cv2.putText(frame, label, (startX, startY - 15),
					cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 255, 0), 2)

	# 如果已经有了框,就可以直接追踪了
	else:
		# 每一个追踪器都要进行更新
		for (t, l) in zip(trackers, labels):
			t.update(rgb)
			pos = t.get_position()

			# 得到位置
			startX = int(pos.left())
			startY = int(pos.top())
			endX = int(pos.right())
			endY = int(pos.bottom())

			# 画出来
			cv2.rectangle(frame, (startX, startY), (endX, endY),
				(0, 255, 0), 2)
			cv2.putText(frame, l, (startX, startY - 15),
				cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 255, 0), 2)

	# 也可以把结果保存下来
	if writer is not None:
		writer.write(frame)

	# 显示
	cv2.imshow("Frame", frame)
	key = cv2.waitKey(1) & 0xFF

	# 退出
	if key == 27:
		break

	# 计算FPS
	fps.update()


fps.stop()
print("[INFO] elapsed time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))

if writer is not None:
	writer.release()

cv2.destroyAllWindows()
vs.release()

在这里插入图片描述
在这里插入图片描述

代码地址:多目标追踪

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

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

相关文章

Debian12 中重新安装MSSQL 并指定服务器、数据库、数据表字段的字符排序规则和默认语言等参数

在 Linux 上配置 SQL Server 设置 - SQL Server | Microsoft Learn 零、查看sql server 服务器支持的字符排序规则 SELECT Name from sys.fn_helpcollations() where name Like Chinese% go------ Chinese_PRC_CI_AI Chinese_PRC_CI_AI_WS Chinese_PRC_CI_AI_KS Chinese_PRC_…

读所罗门的密码笔记21_读后总结与感想兼导读

1. 基本信息 所罗门的密码:AI时代的价值、权力与信任 Solomons Code 奥拉夫格罗思 马克尼兹伯格 著 中信出版社,2022年5月出版 1.1. 读薄率 书籍总字数257千字,笔记总字数37780字。 读薄率37780257000≈14.7% 1.2. 读厚方向 千脑智能 脑机穿越 …

政安晨:【Keras机器学习示例演绎】(一)—— 利用类 U-Net 架构进行图像分割

目录 下载数据 准备输入图像的路径和目标分割掩码 一幅输入图像和相应的分割掩码是什么样子的? 准备数据集,以加载和矢量化成批数据 准备 U-Net Xception 风格模型 预留验证分割 训练模型 可视化预测 政安晨的个人主页:政安晨 欢迎 &…

SpringBoot整合零一万物模型API进行多轮对话

前期准备工作 零一万物官网:https://www.01.ai/cn 零一万物大模型开放平台:https://platform.lingyiwanwu.com/ 选择理由 性价比高很高,模型整体不错,新用户送60元,非常适合研究学习。 开发 只提供了http接口和p…

OpenHarmony UI动画-lottie

简介 lottie是一个适用于OpenHarmony的动画库,它可以解析Adobe After Effects软件通过Bodymovin插件导出的json格式的动画,并在移动设备上进行本地渲染。 下载安裝 ohpm install ohos/lottieOpenHarmony ohpm 环境配置等更多内容,请参考如何…

机器视觉【1】-机械臂视觉

文章目录 Eye-to-HandEye-in-Hand基于Eye-in-Hand型机械臂单目视觉定位单目相机标定针孔相机模型畸变标定方法机械臂手眼标定手眼标定求解图像预处理图像灰度化与二值化图像滤波图像特征匹配机械臂单目视觉定位目标物体图像深度信息目标物体中心定位参考文献根据机械臂与相机所…

python来实现nmap扫描

今天分享一个用python实现nmap扫描的方法,以下是实现步骤 代码如下: import subprocessmissing_ips {166.139.144.163, 31.47.8.35, 58.242.86.191, 212.178.135.62, 103.1.35.114} port "7" for missing_ip in missing_ips:# 构造nmap命令…

数学建模--蒙特卡罗法MATLAB代码保姆式解析

1.简单介绍 2.思想的实际运用 我们利用蒙特卡罗法的思想求解圆周率π的值,这里求得的肯定是近似值,我们是通过大量的模拟实验,利用概率求解的,但是这个值和我们的精确值之间还是有一定的误差的; 我们的思想就是在半径为…

智慧化赋能园区新未来:探讨智慧园区如何以科技创新为引擎,推动产业转型升级

随着科技的飞速发展,智慧化已成为推动园区产业升级和转型的重要引擎。智慧园区,以其高效、便捷、智能的特性,正逐步改变传统的产业园区模式,为产业发展注入新的活力。本文旨在探讨智慧园区如何以科技创新为引擎,推动产…

web自动化系列-selenium的3种等待方式(十一)

在ui自动化测试中,几乎出现问题最多的情况就是定位不到元素 ,当你的自动化在运行过程中 ,突然发现报错走不下去了 。很大概率就是因为找不到元素 ,而找不到元素的一个主要原因就是页面加载慢 ,代码运行速度快导致 。 …

vivado 使用 JTAG-to-AXI Master 调试核进行硬件系统通信

使用 JTAG-to-AXI Master 调试核进行硬件系统通信 JTAG-to-AXI Master 调试核为可自定义核 , 可在运行时生成 AXI 传输事务并驱动 FPGA 内部的 AXI 信号。该核支持所 有存储器映射型 AXI 接口和 AXI4-Lite 接口 , 并且可支持位宽为 32 或 64 …

Ubuntu 传输文件

scp [选项] 源文件 目标路径 以下是一些常用的 scp 命令选项: -r:递归复制目录和子目录。 -P:指定远程 SSH 服务器的端口号。 -i:指定用于身份验证的私钥文件。 -p:保留源文件的时间戳、权限和所有者。 -v&#x…

嵌入式面试-回答I2C

说明: 此文章是在阅读了一些列面试相关资料之后对于一些常见问题的整理,主要针对的是嵌入式软件面试中涉及到的问答,努力精准的抓住重点进行描述。若有不足非常欢迎指出,感谢!在总结过程中有些答案没标记参考来源&…

线性代数---行列式的性质

1. 行列式的行与列(按原顺序)互换

RabbitMQ学习记录

核心概念 Brocker:消息队列服务器实体 Exchange(消息交换机):它指定消息按什么规则,路由到哪个队列。 Queue(消息队列载体):每个消息都会被投入到一个或多个队列。 Binding(绑定):它的作用就是把exchange和queue按…

心学从0开始学习rust-十万个为什么篇章(持续更新篇章)

问答环节 1.const x 1;和let x 1有何区别呢,const申请的是全局变量所以会一直有效对吗? const 声明的常量具有全局作用域,但它们不能直接在函数内部声明。常量通常用于定义整个程序中使用的值,如配置常量或数学常量。 let 声明…

并发执行一定比串行执行快吗?

一、多线程的两个主要方向 并发:多线程之间各自执行各自的互不影响 并行:多线程之间互相竞争资源,进行读写的时候可能会产生相互覆盖 二、上下文切换 1.什么是上下文切换 在多线程编程中一般线程的个数都大于cpu的核心数,而一个cpu核心在任意时刻都只能被一个线…

ElasticSearch实战之项目搜索高亮

文章目录 1. 前情配置2、数据操作2.1 操作API2.2 数据入库 3. 高亮搜索3.1 方法封装3.2 高亮搜索 1. 前情配置 为满足ElasticSearch可在项目中实现搜索高亮&#xff0c;我们需要先做一些前情配置 导入ElasticSearch依赖 <dependency><groupId>org.springframewor…

怎么设置启用远程桌面? 如何让外网电脑远程本地内网?

如何远程控制电脑&#xff1f;最简单实用的方案是开启电脑系统自带的远程桌面功能&#xff0c;如果涉及跨网、内外网互通&#xff0c;可以同时用快解析内网映射外网。下面是方案的具体实施步骤&#xff0c;供大家参考。 怎么打开设置启用远程桌面&#xff1f; 1.在目标需要远…

【详细讲解CentOS常用的命令】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…