目标追踪
1 目标追踪概述
- 目前追踪算法
- **BOOSTING:**算法原理类似于Haar cascades (AdaBoost),是一种很老的算法。这个算法速度慢并且不是很准。
- MIL:比BOOSTING准一点。
- KCF:速度比BOOSTING和MIL更快,与BOOSTING和MIL一样不能很好地处理遮挡问题。
- CSRT:比KCF更准一些,但是速度比KCF稍慢。
- **MedianFlow:**对于快速移动的目标和外形变化迅速的目标效果不好。
- **TLD:**会产生较多的false-positives。
- MOSSE:算法速度非常快,但是准确率比不上KCF和**CSRT。**在一些追求算法速度的场合很适用。
- **GOTURN:**OpenCV中自带的唯一一个基于深度学习的算法。运行算法需要提前下载好模型文件。
综合算法速度和准确率考虑,个人觉得CSRT、KCF、MOSSE这三个目标跟踪算法较好。
-
CF
正负样本选择,变换矩阵,得到更多样本训练分类器
-
KCF算法原理
KCF将待跟踪的目标表示为一个矩形框,然后在每一帧图像中通过计算目标区域与全局图像中所有可能的位置之间的相似度,找到最接近目标的位置。该相似度值通过傅里叶变换和核函数计算得出,然后通过最大化相似度值来更新目标区域的位置和大小
KCF算法的关键在于采用了核技巧,这意味着可以使用非线性函数对输入数据进行映射,从而使得滤波器更加灵活。因此,KCF算法比其他相关滤波器算法更加适合处理复杂场景下的目标追踪任务,例如光照变化和旋转等。
较于CF提速
2 多目标追踪
追踪算法涉及到一些遮蔽现象之后效果会变差
一些深度学习算法或许可以解决
3 深度学习检测框架加载
-
看2015年论文Faster-RCNN比较有价值的论文,这是后面的很多框架的基础
-
简介
Faster-RCNN是一个目标检测算法,它采用了两阶段的检测框架。首先,将输入图像通过卷积神经网络提取特征,然后在这些特征上使用区域建议网络(RPN)生成一些候选框。接下来,对这些候选框进行进一步的分类和回归,得到最终的目标检测结果。相比于其他单阶段的目标检测算法,如YOLO和SSD,Faster-RCNN有着更高的准确率和更低的误检率。但是,由于需要两个网络模型,因此其速度较慢。
-
-
SSD
-
简介
Opencv SSD是一种目标检测算法,它基于深度神经网络,可以在图像或视频中检测出特定物体的位置和类别。SSD代表“Single Shot MultiBox Detector”,它可以快速地检测出多个不同大小和形状的物体。在使用Opencv SSD时,需要首先训练一个模型来识别所需的物体类别,然后将该模型应用于输入的图像或视频中。当检测到物体时,SSD会返回一个包含物体位置和类别的边界框,这些信息可以用于进一步处理和分析图像或视频数据
-
-
YOLO
-
简介
YOLO是一种单阶段的目标检测算法,它可以实现实时目标检测。它将输入图像分成网格,并在每个网格中预测目标的位置和类别。与Faster-RCNN等两阶段方法不同,YOLO直接从原始图像中回归目标框,因此速度更快。但是由于网络结构相对简单,所以其检测精度可能会受到一些限制,而且对于小物体的检测效果可能不如其他算法。同时,YOLO也有不同版本,如YOLOv3、YOLOv4等,它们在网络结构和训练策略上都有所改进,提高了检测性能。
-
-
MASK-RCNN
-
简介
MASK-RCNN是一个多任务学习算法,它在Faster-RCNN的基础上增加了一个分割头来实现物体实例分割。与单纯的目标检测不同,物体实例分割需要同时得到每个目标的位置和像素级的语义分割结果。MASK-RCNN通过在ROI池化操作后增加一个子网络,来预测每个RoI中物体的掩模信息,从而实现物体实例分割。MASK-RCNN可以同时进行目标检测和物体实例分割,在一些应用场景下具有很高的实用价值。但是由于增加了掩模预测子网络,所以其计算复杂度相较于Faster-RCNN也会有所提升。
-
4 基于dlib与ssd的追踪
-
dlib库
dlib是一个用于机器学习和图像处理的C++库,它提供了一系列计算机视觉和机器学习算法的实现,并且能够在Python中进行使用。其主要功能包括:
-
人脸检测:使用HOG特征和级联分类器(cascade classifier)对图像中的人脸进行检测。
-
关键点检测:对人脸图像进行关键点检测,例如眼睛、鼻子、嘴巴等部位。
-
人脸识别:使用深度学习技术实现人脸识别,可以用于验证身份或者对人脸进行分类。
-
姿态估计:对人脸图像进行姿态估计,可以判断人脸的朝向和角度。
-
目标跟踪:对视频中的目标进行跟踪,可以用于自动驾驶、人员监控等领域。
-
图像变形:对图像进行变形,例如拉伸、扭曲等操作。
-
其他机器学习算法:dlib还包含了一些其他的机器学习算法,例如支持向量机(SVM)、线性回归等。
-
总步骤
-
检测阶段:使用SSD网络对图像中的物体进行检测,得到其位置和类别信息。
-
特征提取阶段:利用dlib库中的人脸检测器或者目标检测器来获取检测到的物体的特征向量,并将其保存。
-
匹配阶段:通过比较当前帧和上一帧中物体的特征向量,来匹配相同物体。可以使用各种方法如卡尔曼滤波、最近邻搜索等来实现匹配。
-
更新阶段:根据匹配结果,更新每个物体的位置和其他状态信息,例如速度、加速度等。
-
输出阶段:输出更新后的物体位置以及其它状态信息。
import cv2 as cv
import numpy as np
import dlib
print(dlib.DLIB_USE_CUDA)
video_file = 'videos/v2.mp4'
output = "output2.mp4"
CONFIDENCE_LIMIT = 0.4
# SSD标签
CLASSES = ["backgroud","aeroplane","bicycle","bird","boat",
"bottle","bus","car","cat","chair","cow","diningtalble",
"dog","horse","motorbike","person","pottedplant","sheep",
"sofa","train","tvmoitor"]
# 读取网络模型
print('loading model...')
net = cv.dnn.readNetFromCaffe('dnn/MobileNetSSD_deploy.prototxt', 'dnn/MobileNetSSD_deploy.caffemodel')
# 初始化
print("[INFO] starting video stream...")
vs = cv.VideoCapture(video_file)
writer = None
trackers = []
labels = []
while True:
ret, frame = vs.read()
if not ret:
break
h, w = frame.shape[:2]
width = 600
r = width / float(w)
dim = (width,int(h*r))
frame = cv.resize(frame, dim, interpolation=cv.INTER_AREA)
rgb = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
if output is not None and writer is None:
fourcc = cv.VideoWriter_fourcc(*"MP4V")
writer = cv.VideoWriter(output, fourcc,25,(frame.shape[1],frame.shape[0]),True)
# 先检测,在追踪
if len(trackers) == 0:
(h, w) = frame.shape[:2]
# 归一化,输出 = (原始-127.5) * factor
blob = cv.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 > CONFIDENCE_LIMIT:
# 提取
idx = int(detections[0, 0, i, 1])
label = CLASSES[idx]
# 只保留人的
if CLASSES[idx] != "person":
continue
# 得到BBOX
print(detections[0, 0, i, 3:7])
# 检测出来的是一个相对的值,比如0.2w,0.2h这样
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype(int)
# 用dlib进行目标追踪
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)
# 绘测
cv.rectangle(frame, (startX, startY), (endX, endY), (0,0,255), 2)
cv.putText(frame, label, (startX, startY-15), cv.FONT_HERSHEY_SIMPLEX, 0.45,
(255, 0, 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())
cv.rectangle(frame, (startX, startY), (endX, endY), (0, 0, 255), 2)
cv.putText(frame, l, (startX, startY - 15), cv.FONT_HERSHEY_SIMPLEX, 0.45,
(255, 0, 0), 2)
# 可以保存下结果
# if writer is not None:
# writer.write(frame)
# 显示
cv.imshow("frame", frame)
key = cv.waitKey(10) & 0xff
if key == 27:
break
# 就是说第一帧先检测出哪些是人,然后后面那些帧直接用dlb追踪的框架来去追踪
cv.destroyAllWindows()
vs.release()
5 多进程目标追踪
处理函数,输入输出队列
import cv2 as cv
import numpy as np
import dlib
import multiprocessing
def start_tracker(box, label, rgb, inputQueue, outputQueue):
t = dlib.correlation_tracker()
rect = dlib.rectangle(int(box[0]), int(box[1]), int(box[2]), int(box[3]))
t.start_track(rgb, rect)
while True:
# 获取下一帧
rgb = inputQueue.get()
if rgb is not None:
t.update(rgb)
pos = t.get_position() # 得到新的追踪的位置
# 得到位置
startX = int(pos.left())
startY = int(pos.top())
endX = int(pos.right())
endY = int(pos.bottom())
# 把结果放到输出Q,因为多进程没办法返回
outputQueue.put((label, (startX, startY, endX, endY)))
inputQueues = []
outputQueues = []
video_file = 'videos/v2.mp4'
output = r"C:\Users\86189\Desktop\opencv\output2.avi"
CONFIDENCE_LIMIT = 0.4
# SSD标签
CLASSES = ["backgroud", "aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair", "cow", "diningtalble",
"dog", "horse", "motorbike", "person", "pottedplant", "sheep",
"sofa", "train", "tvmoitor"]
# 读取网络模型
print('[INFO] loading model...')
net = cv.dnn.readNetFromCaffe('dnn/MobileNetSSD_deploy.prototxt', 'dnn/MobileNetSSD_deploy.caffemodel')
# 初始化
print("[INFO] starting video stream...")
vs = cv.VideoCapture(video_file)
writer = None
trackers = []
labels = []
if __name__ == '__main__':
while True:
ret, frame = vs.read()
if not ret:
break
h, w = frame.shape[:2]
width = 600
r = width / float(w)
dim = (width, int(h * r))
frame = cv.resize(frame, dim, interpolation=cv.INTER_AREA)
rgb = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
if output is not None and writer is None:
fourcc = cv.VideoWriter_fourcc(*"MJPG")
writer = cv.VideoWriter(output, fourcc, 25, (frame.shape[1], frame.shape[0]), True)
# 先检测,在追踪
if len(inputQueues) == 0:
(h, w) = frame.shape[:2]
# 归一化,输出 = (原始-127.5) * factor
blob = cv.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 > CONFIDENCE_LIMIT:
# 提取
idx = int(detections[0, 0, i, 1])
label = CLASSES[idx]
# 只保留人的
if CLASSES[idx] != "person":
continue
# 得到BBOX
# print(detections[0, 0, i, 3:7])
# 检测出来的是一个相对的值,比如0.2w,0.2h这样
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
# 每个进程都有inputQ跟outputQ
iq = multiprocessing.Queue()
oq = multiprocessing.Queue()
inputQueues.append(iq)
outputQueues.append(oq)
# 每个进程都传入对应的队列
p = multiprocessing.Process(
target=start_tracker,
args=(bb, label, rgb, iq, oq)
)
p.daemon = True
p.start()
# 绘测
cv.rectangle(frame, (startX, startY), (endX, endY), (0, 0, 255), 2)
cv.putText(frame, label, (startX, startY - 15), cv.FONT_HERSHEY_SIMPLEX, 0.45,
(255, 0, 0), 2)
else:
# 多个追踪器处理的都是相同输入
for iq in inputQueues:
iq.put(rgb)
for oq in outputQueues:
# 得到更新结果
label, (startX, startY, endX, endY) = oq.get()
cv.rectangle(frame, (startX, startY), (endX, endY), (0, 0, 255), 2)
cv.putText(frame, label, (startX, startY - 15), cv.FONT_HERSHEY_SIMPLEX, 0.45,
(255, 0, 0), 2)
if writer is not None:
writer.write(frame)
# 显示
cv.imshow("frame", frame)
key = cv.waitKey(1) & 0xff
if key == 27:
break
# 就是说第一帧先检测出哪些是人,然后后面那些帧直接用dlb追踪的框架来去追踪
if writer is not None:
writer.release()
cv.destroyAllWindows()
vs.release()
速度巨快