【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=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

然后将框框展示出来。cv2.waitKey(100)这个部分100可以改成其他的这里可以调节视频的快慢。

	if key == ord("s"):
		# 选择一个区域,按s
		box = 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 cv2

ap = 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=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)

在这里面和上面一样同样也要同比例放大或者缩小每一帧图像。然后有一个重要操作,就是一定要将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 list
				idx = 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

	# 计算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()

后面这些就是一些退出的一些简单的操作了。

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

然后我们使用多线程进行改进程序:这里主函数就是要加上多线程。

if __name__ == '__main__':
	
	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(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":#过滤掉除了人以外所有的追踪目标
						continue
					box = 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和输出q
					iq = 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 = True
					p.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) & 0xFF
	
		if key == 27:
			break

		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()

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

如果觉得博主的文章还不错或者您用得到的话,可以免费的关注一下博主,如果三连收藏支持就更好啦!这就是给予我最大的支持!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python武器库开发-前端篇之Html基础语法(二十九)

前端篇之Html基础语法(二十九) HTML 元素 HTML元素指的是HTML文档中的标签和内容。标签用于定义元素的类型&#xff0c;而内容则是元素所包含的内容。HTML元素由开始标签和结束标签组成&#xff0c;也可以是自闭合标签。 例如&#xff0c;下面是一个叫做<p>的HTML元素…

laravel8安装多应用多模块(笔记三)

先安装laravel8 Laravel 安装&#xff08;笔记一&#xff09;-CSDN博客 一、进入项目根目录安装 laravel-modules composer require nwidart/laravel-modules 二、 大于laravel5需配置provider&#xff0c;自动生成配置文件 php artisan vendor:publish --provider"Nwid…

Apollo接入配置中心 -- 源码分析之如何获取配置

全文参考&#xff1a;https://mp.weixin.qq.com/s/G5BV5BIdOtB3LlxNsr4ZDQ https://blog.csdn.net/crystonesc/article/details/106630412 https://www.cnblogs.com/deepSleeping/p/14565774.html 背景&#xff1a;近期在接入行内配置中心&#xff0c;因此对配置的加载接入有了…

p12 63.删除无头结点无头指针的循环链表中所有值为x的结点 桂林电子科技大学2015年 (c语言代码实现)注释详解

本题代码如下 void delete(linklist* L, int x) {lnode* p *L, * q *L;while (p->next ! q)// 从第一个结点开始遍历链表&#xff0c;直到尾结点的前一个结点{if (p->next->data x)//判断是否等于x{lnode* r p->next;//将r指向x的位置p->next r->next;…

JoyT的科研之旅第一周——科研工具学习及论文阅读收获

CiteSpace概述 CiteSpace 是一个用于可视化和分析科学文献的工具&#xff0c;它专门针对研究者进行文献回顾和趋势分析。CiteSpace 的核心功能是创建文献引用网络&#xff0c;这些网络揭示了研究领域内各个文献之间的相互关系。使用 CiteSpace 可以为论文研究做出贡献的几种方…

Linux常用命令——bind命令

在线Linux命令查询工具 bind 显示或设置键盘按键与其相关的功能 补充说明 bind命令用于显示和设置命令行的键盘序列绑定功能。通过这一命令&#xff0c;可以提高命令行中操作效率。您可以利用bind命令了解有哪些按键组合与其功能&#xff0c;也可以自行指定要用哪些按键组合…

【Proteus仿真】【STM32单片机】智能垃圾桶设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用报警模块、LCD1602液晶模块、按键模块、人体红外传感器、HCSR04超声波、有害气体传感器、SG90舵机等。 主要功能&#xff1a; 系统运行后&…

python基础-numpy

numpy中shape (1,X) 和 &#xff08;X&#xff0c;&#xff09;的区别 参考 首先放结论&#xff1a;shape(x,)是一维数组&#xff0c;ndim1,[1,2,3,…x] ;shape(1,x)是二维&#xff1f;数组&#xff0c;ndim2,[[1,2,3,…n]] >>> import numpy as np >>> a…

常见树种(贵州省):016杜鹃、含笑、桃金娘、金丝桃、珍珠花、观光木

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、杜鹃 …

记录华为云服务器(Linux 可视化 宝塔面板)-- 安全组篇

文章目录 前言安全组说明安全组的特性安全组的应用场景 进入安全组添加基本规则添加自定义规则如有启发&#xff0c;可点赞收藏哟~ 前言 和windows防火墙类似&#xff0c;安全组是一种虚拟防火墙&#xff0c;具备状态检测和数据包过滤功能&#xff0c;可以对进出云服务器的流量…

5种主流API网关技术选型,yyds!

API网关是微服务项目的重要组成部分&#xff0c;今天来聊聊API网关的技术选型&#xff0c;有理论&#xff0c;有实战。 不 BB&#xff0c;上文章目录&#xff1a; 1 API网关基础 1.1 什么是API网关 API网关是一个服务器&#xff0c;是系统的唯一入口。 从面向对象设计的角度…

Linux加强篇002-部署Linux系统

目录 前言 1. shell语言 2. 执行命令的必备知识 3. 常用系统工作命令 4. 系统状态检测命令 5. 查找定位文件命令 6. 文本文件编辑命令 7. 文件目录管理命令 前言 悟已往之不谏&#xff0c;知来者之可追。实迷途其未远&#xff0c;觉今是而昨非。舟遥遥以轻飏&#xff…

测试用例的缝缝补补

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️山水速疾来去易&#xff0c;襄樊镇固永难开 ☁️定位页面的元素 参数:抽象类By里…

四、防火墙-NAT Server

学习防火墙之前&#xff0c;对路由交换应要有一定的认识 NAT Server1.1.基本原理1.2.多出口场景下的NAT Server1.3.源进源出 —————————————————————————————————————————————————— NAT Server 一般对用户提供一些可访问的…

apipost接口200状态码,浏览器控制台500状态码

后端 url 登录login方法 login(){this.$refs.loginForm.validate(async valid > {if (!valid) return// 由于data属性是一个json对象&#xff0c;需要进行解构赋值{data:result}&#xff0c;进行状态码判断const {data: result} await this.$http.post(/api/doLogin,this.…

普通程序员 VS 高级程序员!

见字如面&#xff0c;我是军哥&#xff01; 最近有读者朋友问我&#xff0c;普通程序员和高级程序员到底有什么区别&#xff1f;我说最关键的3点&#xff0c;你看看是否认同哈&#xff5e; 1、需求评审的能力 普通程序员&#xff0c;就是根据产品经理提的需求细节&#xff0c;开…

vue2:mixin混入的使用

前言 在使用vue2开发业务时,难免会遇到一些多组件公用的方法和基础的数值。 比如你的页面里面有很多相似的列表展示,分页器都是默认1页10行,都需要调用某个公共的接口,或者某一个操作函数很多页面都需要调用。 这个时候,就可以使用mixin和extend这两个api,将公共的数据和代码…

【鸿蒙应用ArkTS开发系列】- 云开发入门实战二 实现省市地区三级联动地址选择器组件(下)

文章目录 概述端云调用流程端侧集成AGC SDK端侧省市地区联动的地址选择器组件开发创建省市数据模型创建省市地区视图UI子组件创建页面UI视图Page文件 打包测试总结 概述 我们在前面的课程&#xff0c;对云开发的入门做了介绍&#xff0c;以及使用一个省市地区联动的地址选择器…

【点云surface】无序点云快速三角化

1 介绍 GreedyProjectionTriangulation 是一种基于局部二维投影的三维点贪婪三角剖分算法的实现。它假定局部表面光滑&#xff0c;不同点密度区域之间的过渡相对平滑。 GreedyProjectionTriangulation算法的基本思想是通过逐步投影点云数据到一个三角化网格上来进行重建。它首…

python-opencv轮廓检测(外轮廓检测和全部轮廓检测,计算轮廓面积和周长)

python-opencv轮廓检测&#xff08;外轮廓检测和全部轮廓检测&#xff0c;计算轮廓面积和周长&#xff09; 通过cv2.findContours&#xff0c;我们可以进行轮廓检测&#xff0c;当然也有很多检测模式&#xff0c;我们可以通过选择检测模式&#xff0c;进行外轮廓检测&#xff…