OpenCV 实时对象跟踪(质心跟踪)

发布时间:2024-12-10 15:13

使用相机的运动跟踪对焦,可以追踪移动对象保持清晰 #生活技巧# #数码产品使用技巧# #相机调焦方法#

本文章先介绍对象跟踪过程,考虑对象跟踪的特点决定使用:质心跟踪算法,然后会一步一步说明质心跟踪算法的实现;最后是如何用python代码实现。

实验效果如下:

对象跟踪过程 进行一组初始的对象检测(如:边界框坐标的输入集)为每个初始检测创建唯一的ID(每个独立对象有唯一的ID)然后跟踪每个对象在视频中的帧中移动时的情况,并保持唯一ID的分配

补充第二点:对象跟踪允许我们将唯一的ID应用于每个被跟踪的对象,从而使我们能够对视频中的唯一对象进行计数。

好了下一步我们应该考虑对象跟踪算法的特点。

对象跟踪算法的特点(理想下) 仅要求对象检测阶段一次(即,最初检测到对象时)将是非常快- 多比实际运行的物体探测器本身更快能够处理被跟踪对象何时“消失”或移动到视频帧的边界之外遮挡力强能够拾取帧之间“丢失”的对象

不妨使用OpenCV实现质心跟踪,OpenCV是一种易于理解但非常有效的跟踪算法。

质心跟踪依赖于

(1)现有对象质心(即检测出对象,然后计算对象的质心)

(2)实时图像数据连续帧之间,新对象质心之间的欧氏距离(EUCLIDEAN DISTAN)  

备注:如果对欧氏距离不了解的可以到文章底部看看。

质心跟踪算法实现

步骤1:接受边界框坐标并计算质心

图1:要使用质心跟踪构建简单的对象跟踪算法,第一步是接受来自对象检测器的边界框坐标,然后使用它们来计算质心。

质心追踪算法假定我们传递一组边界框的(X,Y)坐标-对于每个检测到的对象的每一个帧

1)这些边界框可以由大家想要的任何类型的对象检测器生成(颜色阈值+轮廓提取,Haar级联,HOG +线性SVM,SSD,Faster R-CNN等),前提是要针对帧中的每一帧进行计算视频。

2)有了边界框坐标后,我们必须计算“质心”或更简单地计算边界框的中心(x,y)坐标。 上面的图1演示了接受一组边界框坐标并计算质心。

3)由于这些是提供给我们算法的边界框的第一组初始集合,因此我们将为其分配唯一的ID。

步骤2:计算新边界框与现有对象之间的欧氏距离(EUCLIDEAN DISTAN)

图2:此图像中存在三个对象,用于使用Python和OpenCV进行简单的对象跟踪。我们需要计算每对原始质心(紫色)和新质心(黄色)之间的欧氏距离(EUCLIDEAN DISTAN)。

可能你会疑惑,为什么下面说一共检测到了三个对象,图中就有5个质心了?

答:本来是有两个对象(其质心为紫色),当下一帧数据时,这两个对象移动了,原来的质心位置自然也会改变的,会产生新的质心(黄色的);于是在原来两个紫色质心,由于原对象移动,产生两个新质心(黄色),再加上一个新对象的质心,就变成了3个黄色质心+2个紫色质心。

对于视频流中的每个后续帧,我们应用计算对象质心的步骤#1但是,我们首先需要确定是否可以将新的对象质心(黄色)与旧的对象质心(紫色)相关联,而不是为每个检测到的对象分配新的唯一ID(这会破坏对象跟踪的目的)。为了完成此过程,我们计算了每对现有对象质心和输入对象质心之间的欧氏距离(EUCLIDEAN DISTAN)(用绿色箭头突出显示)。

图2中可以看到,这次我们在图像中检测到三个对象。靠近的两对是两个现有对象。

其实这里简单来说,通过计算原始质心(黄色)和新质心(紫色)之间的欧氏距离(EUCLIDEAN DISTAN)后,计算出最小值的(箭头最短),是指向原来的对象;步骤3会进一步将的。

步骤#3:更新(x,y) -现有对象的坐标

图3:我们的简单质心对象跟踪方法将关联的对象的对象距离最小化。但是,我们该如何处理左下角的对象呢?

质心跟踪算法的主要假设是一个给定的对象将潜在地移动在后续的帧之间,但距离为帧中的质心之间和将小比对象之间的所有其它距离。

因此,如果我们选择将质心与后续帧之间的最小距离相关联,则可以构建对象跟踪器。

图3中,大家可以看到我们的质心跟踪器算法如何选择将最小化其欧氏距离(EUCLIDEAN DISTAN)的质心关联起来。

但是左下角的孤独点呢?

它没有任何关联-我们如何处理它?

步骤4:注册新对象

图4:在使用Python和OpenCV进行对象跟踪的示例中,我们有一个与现有对象不匹配的新对象,因此将其注册为对象ID#3。

如果输入检测的数量多于被跟踪的现有对象,则我们需要注册新对象。“注册”仅表示通过以下方式将新对象添加到跟踪对象列表中:

给它分配一个新的对象ID存储该对象的边界框坐标的质心

然后,我们可以返回到步骤2,并为视频流中的每个帧重复步骤流水线。

图4演示了使用最小欧氏距离(EUCLIDEAN DISTAN)关联现有对象ID,然后注册新对象的过程。

步骤5:注销旧对象

任何合理的对象跟踪算法都必须能够处理对象丢失,消失或离开视野时的情况。

实际情况下,您如何处理这些情况实际上取决于对象跟踪器的部署位置,但是对于此实现,我们将在旧对象无法与任何现有对象匹配的情况下(总共N个后续帧)注销旧对象。

质心跟踪代码实现:centroidtracker.py

from scipy.spatial import distance as dist

from collections import OrderedDict

import numpy as np

class CentroidTracker():

def __init__(self, maxDisappeared=50):

self.nextObjectID = 0

self.objects = OrderedDict()

self.disappeared = OrderedDict()

self.maxDisappeared = maxDisappeared

def register(self, centroid):

self.objects[self.nextObjectID] = centroid

self.disappeared[self.nextObjectID] = 0

self.nextObjectID += 1

def deregister(self, objectID):

del self.objects[objectID]

del self.disappeared[objectID]

def update(self, rects):

if len(rects) == 0:

for objectID in list(self.disappeared.keys()):

self.disappeared[objectID] += 1

if self.disappeared[objectID] > self.maxDisappeared:

self.deregister(objectID)

return self.objects

inputCentroids = np.zeros((len(rects), 2), dtype="int")

for (i, (startX, startY, endX, endY)) in enumerate(rects):

cX = int((startX + endX) / 2.0)

cY = int((startY + endY) / 2.0)

inputCentroids[i] = (cX, cY)

if len(self.objects) == 0:

for i in range(0, len(inputCentroids)):

self.register(inputCentroids[i])

else:

objectIDs = list(self.objects.keys())

objectCentroids = list(self.objects.values())

D = dist.cdist(np.array(objectCentroids), inputCentroids)

rows = D.min(axis=1).argsort()

cols = D.argmin(axis=1)[rows]

usedRows = set()

usedCols = set()

for (row, col) in zip(rows, cols):

if row in usedRows or col in usedCols:

continue

objectID = objectIDs[row]

self.objects[objectID] = inputCentroids[col]

self.disappeared[objectID] = 0

usedRows.add(row)

usedCols.add(col)

unusedRows = set(range(0, D.shape[0])).difference(usedRows)

unusedCols = set(range(0, D.shape[1])).difference(usedCols)

if D.shape[0] >= D.shape[1]:

for row in unusedRows:

objectID = objectIDs[row]

self.disappeared[objectID] += 1

if self.disappeared[objectID] > self.maxDisappeared:

self.deregister(objectID)

else:

for col in unusedCols:

self.register(inputCentroids[col])

return self.objects

主函数代码实验:object_tracker.py

from centroidtracker import CentroidTracker

from imutils.video import VideoStream

import numpy as np

import argparse

import imutils

import time

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("-c", "--confidence", type=float, default=0.5,help="minimum probability to filter weak detections")

args = vars(ap.parse_args())

ct = CentroidTracker()

(H, W) = (None, None)

print("[INFO] loading model...")

net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])

print("[INFO] starting video stream...")

vs = VideoStream(src=0).start()

time.sleep(2.0)

while True:

frame = vs.read()

frame = imutils.resize(frame, width=600)

if W is None or H is None:

(H, W) = frame.shape[:2]

blob = cv2.dnn.blobFromImage(frame, 1.0, (W, H),

(104.0, 177.0, 123.0))

net.setInput(blob)

detections = net.forward()

rects = []

for i in range(0, detections.shape[2]):

if detections[0, 0, i, 2] > args["confidence"]:

box = detections[0, 0, i, 3:7] * np.array([W, H, W, H])

rects.append(box.astype("int"))

(startX, startY, endX, endY) = box.astype("int")

cv2.rectangle(frame, (startX, startY), (endX, endY),

(0, 255, 0), 2)

objects = ct.update(rects)

for (objectID, centroid) in objects.items():

text = "ID {}".format(objectID)

cv2.putText(frame, text, (centroid[0] - 10, centroid[1] - 10),

cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)

cv2.circle(frame, (centroid[0], centroid[1]), 4, (0, 255, 0), -1)

cv2.imshow("Frame", frame)

key = cv2.waitKey(1) & 0xFF

if key == ord("q"):

break

cv2.destroyAllWindows()

vs.stop()

执行程序

实验环境:pyCharm中安装了opencv3.4,和一些基本库(NumPy,SciPy 和 imutils)

pip install numpy scipy imutils              #执行此命令进行安装

执行命令:python object_tracker.py   --prototxt deploy.prototxt    --model res10_300x300_ssd_iter_140000.caffemodel

注意:这里需要指定的两个参数文件 deploy.prototxt 为检测人脸时的配置(基于opencv深度学习)

res10_300x300_ssd_iter_140000.caffemodel 为检测人脸的模型,可以直接使用(在文章后面会给大家下载)

在pyCharm的命令窗口中执行:

实验效果:

文章中代码,放到网盘了,有需要可以去提取。

链接: https://pan.baidu.com/s/1h13-FPlnP2JyikHGesQRUA   提取码: erd4

备注:本程序只给大家学习研究,请不要作为商业用途,大家加油。

补充一下 欧氏距离(EUCLIDEAN DISTANCE)

欧氏距离定义: 欧氏距离( Euclidean distance)是一个通常采用的距离定义,它是在m维空间中两个点之间的真实距离。

在二维和三维空间中的欧式距离的就是两点之间的距离,二维的公式是
d = sqrt((x1-x2)^+(y1-y2)^)

三维的公式是
d=sqrt(x1-x2)^+(y1-y2)^+(z1-z2)^)

推广到n维空间,欧式距离的公式是
d=sqrt( ∑(xi1-xi2)^ ) 这里i=1,2..n    ( xi1表示第一个点的第i维坐标,xi2表示第二个点的第i维坐标 )
n维欧氏空间是一个点集,它的每个点可以表示为(x(1),x(2),...x(n)),其中x(i)(i=1,2...n)是实数,称为x的第i个坐标,两个点x和y=(y(1),y(2)...y(n))之间的距离d(x,y)定义为上面的公式.

欧氏距离看作信号的相似程度。 距离越近就越相似,就越容易相互干扰,误码率就越高。

看下图解释:求ab边两端点的距离

设a(x1,y1),b(x2,y2),c边两点距离其实就是:sqrt((x1-x2)^+(y1-y2)^)

希望对你有帮助。

网址:OpenCV 实时对象跟踪(质心跟踪) https://www.yuejiaxmz.com/news/view/434911

相关内容

任务跟踪系统 开源
高效工作:8款工作任务跟踪软件对比指南
15 年 2024 款最佳时间跟踪应用、工具和软件
2024年最佳工作任务跟踪软件:8款推荐
哪些免费助眠APP提供智能睡眠跟踪?
React任务跟踪器:优化日常生活管理
[百姓生活] “暖心社区”,一送一请一跟踪
科技赋能健康,一站式体检报告监测与跟踪系统
Windows 7: 跟踪用户登陆事件
探索 Nomie 6 OSS:智能生活数据跟踪与管理的新篇章

随便看看