【opencv】计算机视觉:实时目标追踪

目录
前言
解析
深入探究
前言
目标追踪技术对于民生、社会的发展以及国家军事能力的壮大都具有重要的意义。它不仅仅可以应用到体育赛事当中目标的捕捉,还可以应用到交通上,比如实时监测车辆是否超速等!对于国家的军事也具有一定的意义,比如说导弹识别目标等方向。所以说实时目标追踪技术对于整个社会来说都是非常重要的!目前被应用的比较多的,而且效果较好的是YOLO系列,目前已经更新到了YOLO7。原作者更新到了YOLO3之后就不再更新YOLO这个系列了,因为被一些不法人员应用到了军事上,给民众要造成了一定的伤害!但是依旧没有阻挡住YOLO的发展。但是我们提出来的这个是基于计算机视觉的,那么为什么有了YOLO这么好的东西我们还要基于计算机视觉来做呢?因为YOLO训练的模型占用的内存一般不小,这就会影响了一些东西的使用,比如说摄像头!就没有办法有这么大的内存来存储,所以还需要一些不需要那么大内存的东西来去实时跟踪目标!

解析
首先我们来根据代码来讲解一下如何追踪实时物体!
首先我们导入库和配置参数,对于参数的配置。我们需要在参数框架上输入--video videos/nascar.mp4 --tracker kcf。表示的意思就是我们导入的视频是nascar.mp4,然后用kcf这个框架来干活。
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.legacy.TrackerCSRT_create,"kcf": cv2.legacy.TrackerKCF_create,"boosting": cv2.legacy.TrackerBoosting_create,"mil": cv2.legacy.TrackerMIL_create,"tld": cv2.legacy.TrackerTLD_create,"medianflow": cv2.legacy.TrackerMedianFlow_create,"mosse": cv2.legacy.TrackerMOSSE_create
}
这里注意一定要按照这个来写。其他的由于版本问题,可能会有问题。对于新老版本是不一样的。
然后我们建立多个追踪器。并且开始读入视频数据。这里的trackers就是我们需要建立的多目标追踪器。
trackers = cv2.legacy.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=600r = 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
然后将框框展示出来。cv2.waitKey(100)这个部分100可以改成其他的这里可以调节视频的快慢。
if key == ord("s"):# 选择一个区域,按sbox = cv2.selectROI("Frame", frame, fromCenter=False,showCrosshair=True)
如果我们按下S键,然后我们就可以手动的框出来ROI区域了。

tracker = OPENCV_OBJECT_TRACKERS[args["tracker"]]()#创建一个追踪器 添加追踪器trackers.add(tracker, frame, box)
这里创建出来追踪器,然后添加上。
elif key == 27:break
vs.release()
cv2.destroyAllWindows()
最后退出。

可以手动的任意追踪目标!!!完美!!!


追踪效果总体来说还是不错的!
深入探究
然后又继续做了一个多目标自动识别目标追踪。这里我们以运动员短跑为案例继续来讲解。
这里面我们导入库和第三方参数。
from utils import FPS
import numpy as np
import argparse
import dlib
import cv2ap = argparse.ArgumentParser()
ap.add_argument("-p", "--prototxt", required=True,help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", required=True,help="path to Caffe pre-trained model")
ap.add_argument("-v", "--video", required=True,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())
其中参数导入的话是这样:
--prototxt mobilenet_ssd/MobileNetSSD_deploy.prototxt --model mobilenet_ssd/MobileNetSSD_deploy.caffemodel --video race.mp4
--model mobilenet_ssd/MobileNetSSD_deploy.caffemodel
--video race.mp4
把这段代码直接复制粘贴到参数配置当中就好。
然后我们建立一些分类标签,看看计算机到时候框出来的很多很多框框都属于什么东西,然后我们进行过滤操作。
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"])
其中cv2.dnn.readNetFromCaffe(prototxt, model) 用于进行SSD网络的caffe框架的加载
参数说明:prototxt表示caffe网络的结构文本,model表示已经训练好的参数结果把视频读入进来。
print("[INFO] starting video stream...")
vs = cv2.VideoCapture(args["video"])
writer = None
trackers = []
labels = []
fps = FPS().start()
这里我们设置两个列表,等会来添加追踪器和标签信息。并且计算一下视频的fps数值。fps也就是一秒钟计算机可以处理多少帧图像。
while True:# 读取一帧(grabbed, frame) = vs.read()# 是否是最后了if frame is None:break# 预处理操作(h, w) = frame.shape[:2]width=600r = width / float(w)dim = (width, int(h * r))frame = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
在这里面和上面一样同样也要同比例放大或者缩小每一帧图像。然后有一个重要操作,就是一定要将BGR图像通道改成RGB通道顺序。
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)
这里是保存数据,如果output这个文件夹是空的并且writer也是空的,那么我们将实时视频保存下来。这个就涉及到了视频保存的代码,有需要的可以自行提取。
if len(trackers) == 0:# 获取blob数据(h, w) = frame.shape[:2]blob = cv2.dnn.blobFromImage(frame, 0.007843, (w, h), 127.5)
cv2.dnn.blobFromImage主要是对图像进行一个预处理,其中0.007843表示各通道数值的缩放比例。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 listidx = int(detections[0, 0, i, 1])label = CLASSES[idx]# 只保留人的if CLASSES[idx] != "person":continue
这里面在前向传播当中,我们得到一些概率值较大的,这里怎么定义较大呢,用args["confidence"]这个数值来定义,如果大于我们设定的概率数值,我们就把他的索引拿出来,然后取出来对应的标签,如果不是人的话我们就过滤除去,最后留下这一帧图像当中所有检测到的人。
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])(startX, startY, endX, endY) = box.astype("int")
这里面就是我们要得到这个框框,然后拿到这个框框的左上角和右下角坐标。
t = dlib.correlation_tracker()rect = dlib.rectangle(int(startX), int(startY), int(endX), int(endY))t.start_track(rgb, rect)
然后我们创建一个追踪器,然后得到检测到的框框,然后开始追踪,追踪的时候按照rgb,并且在第一帧图像的时候开始追踪。
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())
如果检测到框框了,那么就我们遍历一下追踪器和标签,然后更新追踪器,并且获得追踪器的位置。并且得到位置。
if writer is not None:writer.write(frame)# 显示cv2.imshow("Frame", frame)key = cv2.waitKey(1) & 0xFF# 退出if key == 27:break# 计算FPSfps.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()
后面这些就是一些退出的一些简单的操作了。



FPS就是表示一秒钟可以处理17帧图片。运行时间是大概有20秒。然后我们想法就是继续进行一下改进,让处理的快一些。那么我们想到的就是使用多线程进行操作。多线程是指从软件或者硬件上实现多个线程并发执行的技术。

然后我们使用多线程进行改进程序:这里主函数就是要加上多线程。
if __name__ == '__main__':while True:(grabbed, frame) = vs.read()if frame is None:break(h, w) = frame.shape[:2]width=600r = 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(inputQueues) == 0:(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]#置信度 这里我们可以理解为每一个模型对应CLASS的概率 然后选出来一个最高的if confidence > args["confidence"]:idx = int(detections[0, 0, i, 1])#表示CLASS的类别序号label = CLASSES[idx]#选出来if CLASSES[idx] != "person":#过滤掉除了人以外所有的追踪目标continuebox = detections[0, 0, i, 3:7] * np.array([w, h, w, h])#这里标记处框架 这里表示按照长宽背书来定义(startX, startY, endX, endY) = box.astype("int")bb = (startX, startY, endX, endY)# 创建输入q和输出qiq = multiprocessing.Queue()#定义多进程oq = multiprocessing.Queue()inputQueues.append(iq)outputQueues.append(oq)# 多核p = multiprocessing.Process(#八所有追踪器放进进程当中,本电脑为8核 12核会更快target=start_tracker,args=(bb, label, rgb, iq, oq))p.daemon = Truep.start()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 iq in inputQueues:iq.put(rgb)for oq in outputQueues:# 得到更新结果(label, (startX, startY, endX, endY)) = oq.get()# 绘图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)if writer is not None:writer.write(frame)cv2.imshow("Frame", frame)key = cv2.waitKey(1) & 0xFFif key == 27:breakfps.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()

这里就是5个线程一起跑。一秒钟可以处理24帧图像,运行时间14秒。大大的改进整体的进程。

如果觉得博主的文章还不错或者您用得到的话,可以免费的关注一下博主,如果三连收藏支持就更好啦!这就是给予我最大的支持!
相关文章:
【opencv】计算机视觉:实时目标追踪
目录 前言 解析 深入探究 前言 目标追踪技术对于民生、社会的发展以及国家军事能力的壮大都具有重要的意义。它不仅仅可以应用到体育赛事当中目标的捕捉,还可以应用到交通上,比如实时监测车辆是否超速等!对于国家的军事也具有一定的意义&a…...
生态对对碰|华为OceanStor闪存存储与OceanBase完成兼容性互认证!
近日,北京奥星贝斯科技有限公司 OceanBase 数据库与华为技术有限公司 OceanStor Dorado 全闪存存储系统、OceanStor 混合闪存存储系统完成兼容性互认证。 OceanBase 数据库挂载 OceanStor 闪存存储做为数据盘和日志盘,在 OceanStor 闪存存储系统卓越性能…...
微服务负载均衡器Ribbon
1.什么是Ribbon 目前主流的负载方案分为以下两种: 集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的(比如 F5),也有软件的(比如 Nginx)。 客户端根据…...
win10戴尔电脑安装操作系统遇到的问题MBR分区表只能安装GPT磁盘
首先按F2启动boot管理界面 调整启动盘的启动顺序,这里启动U盘为第一顺序。 第一步 选择安装程序的磁盘 第二步 转换磁盘为GPT磁盘 一般出现 磁盘0和1,说明存在两个盘 ,这里两个盘不是说的是C盘和D盘的问题,而是在物理上实际存在…...
阿里云服务器(vgn7i-vws) anaconda(py39)+pytorch1.12.0(cu113)
用xshell连接ip地址,端口号22,输入用户密码 安装anaconda 2022 10 py3.9 wget https://repo.anaconda.com/archive/Anaconda3-2022.10-Linux-x86_64.sh sha256sum Anaconda3-2022.10-Linux-x86_64.sh #校验数据完整性 chmod ux Anaconda3-2022.10-…...
使用 STM32F7 和 TensorFlow Lite 开发低功耗人脸识别设备
本文旨在介绍如何使用 STM32F7 和 TensorFlow Lite框架开发低功耗的人脸识别设备。首先,我们将简要介绍 STM32F7 的特点和能力。接下来,我们将讨论如何使用 TensorFlow Lite 在 STM32F7 上实现人脸识别算法。然后,我们将重点关注如何优化系统…...
【wireshark】基础学习
TOC 查询tcp tcp 查询tcp握手请求的代码 tcp.flags.ack 0 确定tcp握手成功的代码 tcp.flags.ack 1 确定tcp连接请求的代码 tcp.flags.ack 0 and tcp.flags.syn 1 3次握手后确定发送成功的查询 tcp.flags.fin 1 查询某IP对外发送的数据 ip.src_host 192.168.73.134 查询某…...
使用Java连接Hbase
我在网上试 了很多代码,但是大部分都不能实现,Java连接Hbase,一直报一个错 java.util.concurrent.ExecutionException: org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode NoNode for /hbase/hbaseid一直也不清楚为什…...
OCR是什么意思,有哪些好用的OCR识别软件?
1. 什么是OCR? OCR(Optical Character Recognition)是一种光学字符识别技术,它可以将印刷体文字转换为可编辑的电子文本。OCR技术通过扫描和分析图像中的文字,并将其转化为计算机可识别的文本格式,从而…...
Springmvc实现增删改差
一、包结构 二、各层代码 (1)数据User public class User {private Integer id;private String userName;private String note;public User() {super();}public User(Integer i, String userName, String note) {super();this.id i;this.userName userName;this.note note;…...
CentOS 7 使用cJSON 库
什么是JSON JSON是一种轻量级的数据交换格式,可读性强、编写简单。键值对组合编写规则,键名使用双引号包裹,冒号:分隔符后面紧跟着数值,有两种常用的数据类型是对象和数组。 对象:使用花括号{}包裹起来的…...
Linux——使用kill结束进程并恢复进程
目录 查看进程结束进程修复进程 查看进程 在linux中,关闭某进程之前先查看已经在运行的进程有哪些,使用下面命令查看: ps aux | grep -i apt 命令查看哪个进程正在使用 apt结束进程 结束某线程的命令为: sudo kill -9 PID 命令…...
【Linux虚拟内存的配置】
设置Linux虚拟内存 注意:在做项目时,电脑内存不够用,怎么办? 这里给大家提供了一种解决方案,用磁盘换内存,具体如下: 虚拟内存swap介绍 如果你的服务器的总是报告内存不足,并且时常因为内存不足而引发服务被强制kill的话,在不增加物理内…...
基于C#实现外排序
一、N 路归并排序 1.1、概序 我们知道算法中有一种叫做分治思想,一个大问题我们可以采取分而治之,各个突破,当子问题解决了,大问题也就 KO 了,还有一点我们知道内排序的归并排序是采用二路归并的,因为分治…...
HTML CSS登录网页设计
一、效果图: 二、HTML代码: <!DOCTYPE html> <!-- 定义HTML5文档 --> <html lang="en"> …...
dos 命令 判断路径中包含某字符并移动文件
SET GenFolder C:\Users\administered\Desktop\t2\old_file set path1C:\Users\administered\Desktop\t1\crontab_master set path2C:\Users\administered\Desktop\t2\old_file if not exist %GenFolder% ( echo %GenFolder%目录不存在,已创建该目录&#x…...
electron+vue3全家桶+vite项目搭建【26】electron本地安装Vue Devtool插件,安装浏览器扩展
文章目录 引入获取vue devtool导入插件排除插件的npm脚本最终效果 引入 demo项目地址 Vue Devtools插件是vue项目必备插件,它是安装在浏览器里的,而咱们的electron中实际就包含了一个浏览器,同理它也可以加载浏览器插件 获取vue devtool 直…...
Modbus TCP
Modbus (👆 百度百科,放心跳转) 起源 Modbus 由 Modicon 公司于 1979 年开发,是一种工业现场总线协议标准。 Modbus 通信协议具有多个变种,支持串口,以太网多个版本,其中最著名的…...
基于人工兔算法优化概率神经网络PNN的分类预测 - 附代码
基于人工兔算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于人工兔算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于人工兔优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要:针对PNN神经网络…...
微服务学习(十二):安装Minio
微服务学习(十二):安装Minio 一、简介 MinIO 是一款基于Go语言发开的高性能、分布式的对象存储系统。客户端支持Java,Net,Python,Javacript, Golang语言。MinIO系统,非常适合于存储大容量非结构化的数据,例如图片、视…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...
