视频连续目标跟踪实现的两种方法和示例
偶尔看到了一个利用卡尔曼滤波器进行目标跟踪的标题视频,但是没有代码,干脆,就目标跟踪来一段吧。可能做不到一举两得,不过卡尔曼滤波器本身的原理小编也会另外再写一篇,以便可以让读者进一步了解目标跟踪中的如何使用。
我们之前通过YOLOv8已经检测到了目标,跟踪不就排个序吗?非也。其实这个检测好比检测到了一群人,甚至人数都提供给你了,但就是每次只告诉你一堆随机编号和各自的参数。随机编号是指望不上了,现在请你利用这些参数来帮忙指出连续的每帧中的某个或者多个人在下一个帧里的位置在哪里。
这就是我们这次要做的事情。
在本文中,直接介绍两种在视频中跟踪目标的方法。
·一种是使用OpenCV中自带的功能包CSRT(Channel & Spatial Reliability Tracker)跟踪器实现的视频中被选目标的稳定跟踪;
·另一种是组合了YOLOv8目标识别,卡尔曼滤波器和匈牙利算法(Hungarian Algorithm)进行的多目标稳定跟踪。
1.OpenCV CSRT目标跟踪
OpenCV的TrackerCSRT有单目标和多目标跟踪两种可调用函数。
cv2.TrackerCSRT_create() #单目标跟踪
cv2.legacy.MultiTracker() #多目标跟踪
OpenCV库中创建的这个CSRT(Channel and Spatial Reliability Tracker)跟踪器,是一种基于相关滤波器(Correlation Filter)的方法,适用于视觉目标跟踪。CSRT在跟踪的过程中利用了更复杂的特征和更细致的背景抑制机制,从而提高轨迹的精度和可靠性。
CSRT的实现包含以下几个关键特性:
·特征的多样性:CSRT使用多通道特征,包括颜色、梯度等信息,从而能够更全面地描述目标。
·空间可靠性:通过估计不同特征通道的空间可靠性,CSRT能动态调整特征的权重,以增强稳定性。
·优化的滤波过程:采用更复杂的背景滤波策略,更好地抑制非目标区域的干扰。
这里我们需要一个背景相对稳定,前景有多个移动目标的视频来进行测试。感谢来自“秋风细雨8911”视频号提供的一份授权使用的视频。
在测试中,我们分布使用了单目标和多目标跟踪这两种函数。提供的演示代码中,大致分为两步:
·手动框选目标区域
·开始运行并持续跟踪
框选目标(选定后回车)
运行并跟踪(未保留伴乐)
示例代码(1)-OpenCV-单目标跟踪(可以保留音频):
import cv2
from moviepy.editor import VideoFileClip
import os
tracker = cv2.TrackerCSRT_create()
input_video_path = 'Your_Video_Source_Path/Dancers.mp4'
video = cv2.VideoCapture(input_video_path)
ret, frame = video.read()
bbox = cv2.selectROI('Frame', frame, fromCenter=False, showCrosshair=True)
tracker.init(frame, bbox)
# 获取视频属性
fps = int(video.get(cv2.CAP_PROP_FPS))
width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 定义输出视频编码和创建 VideoWriter 对象
output_video_path = 'Your_Video_Output_Save_Path/Dancers_track1.mp4'
# 获取视频的音频
temp_video_path = 'Your_Video_TempOutput_Save_Path/temp_video.avi'
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(temp_video_path, fourcc, fps, (width, height))
while True:
ret, frame = video.read()
if not ret:
break
success, bbox = tracker.update(frame)
if success:
# 处理添加框边
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame, p1, p2, (255,0,0), 1)
else:
cv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0,0,255),1)
cv2.imshow('Tracking', frame)
out.write(frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video.release()
out.release()
cv2.destroyAllWindows()
# 使用 moviepy 来合成音频和视频
video_clip = VideoFileClip(temp_video_path)
audio_clip = VideoFileClip(input_video_path).audio
final_clip = video_clip.set_audio(audio_clip)
final_clip.write_videofile(output_video_path, codec='libx264')
# 删除临时视频文件
os.remove(temp_video_path)
一般单独的视频处理后,音频部分就没有了。在这段代码中,特别地提取了音频,然后在最后加入处理后的视频,保持了原来的音频。
示例代码(2)-OpenCV-多目标跟踪(不保存处理后的视频):
import cv2
# 读取视频
video = cv2.VideoCapture('Your_Video_Source_Path/Dancers.mp4')
# 初始化多个追踪器:可以在程序开始时定义一个接口来选择多个对象。
# 读取第一帧
ret, frame = video.read()
# 创建多目标追踪器容器
multi_tracker = cv2.legacy.MultiTracker()
# 手动选择多个目标并添加到追踪器中
while True:
# 选择ROI
bbox = cv2.selectROI('Frame', frame, fromCenter=False, showCrosshair=True)
print(frame.dtype) # 应该是 uint8
print(frame.shape) # 应该是 (height, width, 3)
# 为每个ROI创建一个特定类型的追踪器实例(例如CSRT)
tracker = cv2.legacy.TrackerCSRT_create()
multi_tracker.add(tracker, frame, bbox)
print("Press 'q' to stop selecting objects and start tracking.")
if cv2.waitKey(0) & 0xFF == ord('q'):
break
# 开始跟踪
while video.isOpened():
ret, frame = video.read()
if not ret:
break
# 更新多目标追踪器
success, boxes = multi_tracker.update(frame)
# 绘制标记
for i, newbox in enumerate(boxes):
p1 = (int(newbox[0]), int(newbox[1]))
p2 = (int(newbox[0] + newbox[2]), int(newbox[1] + newbox[3]))
cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)
cv2.putText(frame, f"D{i+1}", (int(newbox[0]), int(newbox[1]-10)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,0,0), 2)
# 显示追踪结果
cv2.imshow('Multi-Object Tracking', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video.release()
cv2.destroyAllWindows()
上面这段多目标跟踪代码中,每次选定之后回车两次,待前一个选框消失后再选第二个再回车两次...这样重复——目标选好结束时,点击‘q’退出框选目标,开始运行跟踪。当然,目标越多,每帧处理的耗时越长,对没有GPU加持的电脑此时播放的跟踪视频看起来也会越慢。
2. YOLOv8+卡尔曼滤波器多目标跟踪
这里我们利用了YOLOv8的目标探测功能,再通过卡尔曼滤波器对检测到的每个目标的路径进行预测校正判断,然后使用匈牙利算法对YOLO检测到的目标框体的中心位置坐标和长宽4个参数(x,y,w,h)组成的向量和卡尔曼滤波器预测校正后的相同类型目标参数构成的矩阵之间的距离进行匹配,就可以获取多目标的稳定跟踪。其中关于匈牙利算法的特点,示例中在对应函数(linear_sum_assignment)处有一点注释说明。
虽然YOLOv8的目标探测功能很强,但是检测到的目标在不同帧之间的顺序却是有点随机,否则哪里需要这么费劲后面加上的处理?另外,为了获取更好的性能,这里YOLOv8处理视频时,先把前面的视频转换为640x640尺寸的了。示例中也没有特别设定目标类型,其实应该需要设定,也需要设置目标数目的上限。
关于卡尔曼滤波器,我们会另外介绍。这里示例中使用的扩展卡尔曼滤波器(EKF)还是一个打包后现成的函数。我们直接上代码,以及代码后面的跟踪演示视频。
示例代码(3)-YOLOv8+EKF-多目标跟踪:
import cv2
import numpy as np
from scipy.optimize import linear_sum_assignment
from filterpy.kalman import KalmanFilter
from ultralytics import YOLO
# Load a pre-trained YOLOv8 model from PyTorch Hub
model = YOLO("Your_YOLO_Models_Path/models/yolov8n.pt")
# YOLOv8 的导入和初始化(假设 YOLOv8 的检测模型已加载)
def detect_with_yolov8(frame):
# 使用 YOLOv8 模型对帧进行检测,并返回结果
# 假设detect返回 [(x, y, w, h), ...] 格式
results = model.predict(frame, save=False, conf=0.3) # 设置conf,任何小于该阈值的都不标识
detection_arrays = [
[det.boxes.xywh[0].tolist(), det.boxes.xywh[1].tolist(), det.boxes.xywh[2].tolist(), det.boxes.xywh[3].tolist()]
for det in results
]
return detection_arrays[0]
# 卡尔曼滤波器初始化
def create_kalman_filter():
kf = KalmanFilter(dim_x=7, dim_z=4) # 状态由7个变量组成[x, y, vx, vy, w, h, s],测量返回值由4个变量组成[x, y, w, h]
dt = 1.0 # time interval
#(x, y, vx, vy, w, h, s)
kf.F = np.array([[1, 0, dt, 0, 0, 0, 0],
[0, 1, 0, dt, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1]])
# 测量返回:[x, y, w, h]
kf.H = np.array([[1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0]])
kf.P *= 100.0 # Initial uncertainty
kf.R = np.eye(4) * 2 # Measurement noise
kf.Q = np.eye(7) * 0.5 # Process noise
return kf
class MultiObjectTracker:
def __init__(self):
self.filters = []
self.object_ids = [] # 用于分配独立的ID
def add_object(self, detection):
kf = create_kalman_filter()
x, y, w, h = detection
kf.x = np.array([x, y, 0, 0, w, h, 0]).reshape((7, 1))
self.filters.append(kf)
self.object_ids.append(len(self.object_ids)) # 以索引生成唯一ID
def update(self, detections): # YOLOv8 返回的detections只有4个参数:[x, y, w, h]
if len(self.filters)==0:
for det in detections:
self.add_object(det) # 初始位置输入
for kf in self.filters:
kf.predict()
return
predictions = [kf.x[[0, 1, 4, 5]].flatten() for kf in self.filters] # 取预测位置的prediction = [x,y, w, h]
detected_positions = [sublist[:4] for sublist in detections] # YOLOv8中得到的detection = [x,y, w, h]
if len(self.filters) > 0 and len(detections) > 0:
cost_matrix = np.zeros((len(self.filters), len(detections)))
for i, prediction in enumerate(predictions): # x, y,of each object center, and w, h
for j, detection in enumerate(detected_positions):
cost_matrix[i, j] = np.linalg.norm(prediction - detection)
"""
线性和分配函数(linear_sum_assignment)是一种用于解决分配问题的工具,广泛应用于组合优化中。
它被称为“匈牙利算法”或“库恩-蒙克雷斯算法”。
该函数的主要功能是找到一个最优的任务分配方案,使得总的分配成本最小化。
"""
row_ind, col_ind = linear_sum_assignment(cost_matrix)
assigned_detections = set()
for i, j in zip(row_ind, col_ind):
if cost_matrix[i, j] < 50: # 调整矢量距离阈值
# 把YOLOv8检测到的参数来更新EKF中的状态变量
self.filters[i].update(detections[j][:4])
assigned_detections.add(j)
# 没有标注的
unassigned_detections = set(range(len(detections))) - assigned_detections
for j in unassigned_detections:
self.add_object(detections[j])
# 对所有Kalman滤波器进行预测处理
for kf in self.filters:
kf.predict()
def get_states_and_ids(self):
states = [kf.x[:6].flatten().tolist() for kf in self.filters]
return list(zip(states, self.object_ids))
# 视频示例使用
video = cv2.VideoCapture('Your_Video_Output_Save_Path/Dancers_640x640.mp4')
tracker = MultiObjectTracker()
while video.isOpened():
ret, frame = video.read()
if not ret:
break
# 检测人体
detections = detect_with_yolov8(frame)
# 更新跟踪器
tracker.update(detections)
# 获取当前预测状态和对应ID
predictions_and_ids = tracker.get_states_and_ids()
# 在帧中展示跟踪结果(如ID与框)
for (state, obj_id) in predictions_and_ids:
x, y, vx, vy, w, h = map(int, state)
cv2.rectangle(frame, (x - w // 2, y - h // 2), (x + w // 2, y + h // 2), (255, 0, 0), 2)
cv2.putText(frame, f'{obj_id}', (x - w // 2, y - h // 2 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.imshow("Frame", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video.release()
cv2.destroyAllWindows()
示例代码中考虑了没有被检测到的目标的添加,以及目标的漏检。卡尔曼滤波器中的参数是需要调整的,异常的情况下,你可能会看到一个在镜头中飘过的被忘记的框图。
YOLOv8+EKF多目标跟踪
如果有感兴趣的测试了OpenCV的多目标跟踪,可以比较一下两者的差异。YOLOv8的检测看起来会更加紧凑。
文章结尾处,我们再提供一个OpenCV通过摄像头在跟踪过程中动态更换框选目标然后跟踪的python示例。
示例代码(4)-OpenCV-单目标动态框选目标跟踪:
import cv2
# 初始化变量
sel_drawing = False # 鼠标是否正在画矩形框
ix, iy = -1, -1 # 初始化起点坐标
bbox = None # 目标边界框
tracker = None # CSRT 追踪器
gx, gy = -1, -1
# 鼠标回调函数
def draw_rectangle(event, x, y, flags, param):
global ix, iy, sel_drawing, bbox, tracker, gx, gy
if event == cv2.EVENT_LBUTTONDOWN:
sel_drawing = True
ix, iy = x, y
bbox = None # 重置 bbox
tracker = None # 重置追踪器
elif event == cv2.EVENT_MOUSEMOVE:
if sel_drawing:
img_copy = frame.copy()
cv2.rectangle(img_copy, (ix, iy), (x, y), (255, 0, 0), 2)
cv2.imshow('Frame', img_copy)
gx = x
gy = y
elif event == cv2.EVENT_LBUTTONUP:
sel_drawing = False
bbox = (ix, iy, x - ix, y - iy) # 计算矩形
gx = x
gy = y
if bbox[2] > 0 and bbox[3] > 0: # 确保有效的选择区域
tracker = cv2.legacy.TrackerCSRT_create() # 创建新追踪器
tracker.init(frame, bbox)
# 初始化摄像头
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("无法打开摄像头")
exit()
cv2.namedWindow('Frame')
cv2.setMouseCallback('Frame', draw_rectangle)
while True:
ret, frame = cap.read()
if not ret:
break
if sel_drawing:
cv2.rectangle(frame, (ix, iy), (gx, gy), (255, 0, 0), 2)
cv2.imshow('Frame', frame)
if tracker:
success, bbox = tracker.update(frame)
if success:
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame, p1, p2, (255, 0, 0), 2, 1)
else:
cv2.putText(frame, "Tracking failure", (100, 80),
cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
cv2.imshow('Frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
这里再提一下卡尔曼滤波器,这个声称传感器的融合器的工具,确实还是很有意思的。
- |
- +1 赞 0
- 收藏
- 评论 0
本文由samsara转载自AMPHENOL SENSORS(安费诺传感器学堂公众号),原文标题为:视频连续目标跟踪实现的两种方法和示例(更新),本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。
相关研发服务和供应服务
相关推荐
CHANKO长江传感CPA圆柱形光电式传感器系列的安装介绍 ∣视频
视频主要介绍品牌CHANKO(长江传感)CPA圆柱形光电式传感器系列产品是如何安装的?
【应用】迈来芯应用于机器人领域的传感器芯片解决方案介绍 ∣ 视频
迈来芯传感器芯片在机器人上的应用视频介绍。
米博IPE超小型接近传感器,响应频率2000Hz,不受安装空间限制,可适用于狭小空间安装 ∣视频
IPE Series超小型方形接近传感器响应频率:2000Hz,浪涌吸收,工作温度:-25~+70℃,保护结构IP67。
【应用】基于Newsight传感器NSI1000的eTOF激光雷达,体积小功耗低,支持室内/外3D测量 |视频
视频展现了基于NSI1000传感器芯片的eTOF激光雷达效果呈现,内容还包括NSI1000的基本参数介绍,以及eTOF激光演示模组使用简介。
【IC】豪威集团推出1/2.88英寸5000万像素图像传感器,适用于多种智能手机摄像头并具备视频HDR功能
豪威集团推出1/2.88英寸5000万像素图像传感器,适用于多种智能手机摄像头并具备视频HDR功能,OV50M40图像传感器可用于多种智能手机摄像头,实现优异的低光性能、高品质长焦变焦性能、常开模式超低功耗应用等功能。
米博PBN红外传感器,IP65防护等级,可选NPN/PNP输出模式,可精准调节检测距离 ∣视频
PBN Series红外圆柱传感器:简单连接,便于安装及应用;检测稳定、可靠,工作指示;多重保护:过载保护、短路保护;电缆导线柔韧、耐曲折;保护结构IP65;工作温度:0~+55℃。
水位传感器——检测液体位置常见的传感器,支持光电、电容、超声波等多种检测原理 ∣ 视频
液位传感器是一种常见的检测液体位置的传感器,有光电、电容、超声波等多种检测原理。光电液位传感器是利用光在两种不同的介质界面发生反射折射原理而开发的接触点式液位测控装置。
【视频】迈来芯针对消费市场与工业市场的高性价比磁位置传感器
型号- MLX90370,MLX90392,MLX90360,MLX90371,MLX90393,MLX90372,MLX90373,MLX90316,MLX90317,MLX90363,MLX90374,MLX90364,MLX90397,MLX90365,MLX90333,MLX90367,MLX90324
久昌科技产品及应用培训(霍尔传感器、风扇马达) ∣ 视频
久昌科技成立于2011年8月,为一专业的类比IC设计公司,经营团队拥有电源管理领域及霍尔元件丰富的经历,由完整产品线、高品质、及良好客户服务获得市场肯定。同时,久昌随时掌握电子产业发展趋势,与客户紧密合作开发,不断推出符合市场需求的产品。
【产品】宜科高精度测距传感器,分辨率高达0.01mm,检测距离覆盖35mm~4000mm | 视频
宜科高精度测距传感器,实现多领域精确检测。
【IC】芯感智MEMS压力传感器GZP6818A和GZP6878A在-40℃极限温度下性能符合要求 ∣ 视频
较多客户咨询无锡芯感智多款MEMS压力传感器产品在极限温度-40℃下,性能是否符合要求?那么本次试验挑选两款明星产品GZP6818A和GZP6878A绝压压力传感器。跟随本视频和无锡芯感智研发主管魏巍一探究竟吧。
长江传感CPK光电式传感器模拟实测演示:户外阴雨天,在灰尘较多或木工机械机械场景可准确稳定检测输出 ∣视频
长江传感CPK光电式传感器系列产品不仅通过了欧盟认证,还具备了各种权威报告。该视频使用模拟实测方式介绍长江传感的CPK系列光电式传感器产品在不同的环境下,比如户外阴雨天,在灰尘较多或木工机械机械场景仍可准确稳定检测输出,同时在不同的检测距离下,比如靠近发射端,距离发射端4米等依旧保持稳定检测。
【视频】2023年8月31日传感器新技术研讨会
TE、Crocus、TDK InvenSense、EPSON等全球顶级原厂分享MEMS、车规传感、激光雷达、生物识别等传感器领域最新产品,展示高精度、更强感知、集成化方案的新技术成果。
奥松电子新推低功耗高稳定的一氧化碳传感器ACM2000,快速响应,抗干扰性强 |视频
本视频介绍奥松电子的一氧化碳传感器ACM2000的产品性能特点及应用市场。
电子商城
品牌:AMPHENOL SENSORS
品类:Assembly NTC temperature sensor
价格:¥5.0624
现货: 2,000
品牌:AMPHENOL SENSORS
品类:Surface Mount Pressure Sensors
价格:¥97.5000
现货: 51
品牌:AMPHENOL SENSORS
品类:Air Quality Sensors IR LED Dust Sensor
价格:¥40.5000
现货: 35
品牌:AMPHENOL SENSORS
品类:Board Mount Pressure Sensors
价格:¥253.8839
现货: 30
品牌:AMPHENOL SENSORS
品类:Low Pressure Compact Sensors
价格:¥125.9778
现货: 25
品牌:AMPHENOL SENSORS
品类:Board Mount Pressure Sensors
价格:¥253.8839
现货: 25
品牌:AMPHENOL SENSORS
品类:Board Mount Pressure Sensors
价格:¥227.5314
现货: 25
品牌:AMPHENOL SENSORS
品类:Board Mount Pressure Sensors
价格:¥227.5314
现货: 25
现货市场
品牌:SILICON LABS
品类:Switch Hall Effect Magnetic Position Sensor
价格:¥2.2924
现货:126,000
服务
可自由定制铜排形状尺寸;检测精度:0.5%~1.0;电流测量范围 ±300-500A。低噪音 (0.27mVpp);低磁力残余误差:2mV;响应性能<4μSec;支持RoHS指令 、AEC-Q200。
最小起订量: 100个 提交需求>
支持定制透气膜的宽度,ePTFE材质,耐温范围-40℃-260℃,防水等级IP67/IP68,具有疏水性(拒水性)和不粘性。
最小起订量: 1 提交需求>
登录 | 立即注册
提交评论