首先

  首先我想先介绍一下,什么是对象跟踪和GOTURN。
  GOTURN(Generic Object Tracking Using Regression Networks)本身是一种基于深度学习的目标跟踪算法,在Caffe中搭建。
  GOTURN通过以离线方式学习对象的运动,改变了之前部分深度学习进行跟踪问题训练的方式。其模型在许多视频上已经得到了训练,为此在我们运行时不再需要进行任何学习。

技术要点

  其论文可以点击下载。接下来我想对该论文中的部分内容进行一些解读。
  其在论文中提到的主要结构如下所示。

  其使用带有边界框标签(但没有类别信息)的视频和图像集合,他们训练一个神经网络来跟踪一般对象。在测试时,网络能够跟踪新对象,而无需任何微调。通过避免微调,我们的网络能够以100 fps进行跟踪。
  给定在视频的一帧中标记的一些感兴趣的对象,“单目标跟踪”的目标是在随后的视频帧中定位该对象,而不管对象运动、视点变化、照明变化或其他变化。
  如上方右侧图片所示,其会使用两帧的数据,一个是基准帧,另一个是当前帧。第一帧(也称为前一帧)中对象的位置是已知的且对象位置始终在框中处于居中位置。由于对象可能已移动,因此对象不在第二帧中居中。训练卷积神经网络(CNN)以预测第二帧中边界框的位置。
  而其整个的架构如下所示。

  跟踪网络架构中,其将当前帧中的搜索区域和前一帧中的目标输入网络。网络学习比较这些作物以在当前图像中找到目标对象。
  在论文的最后,其阐释了该模型的结果,用蓝色圆圈表示GOTURN模型,沿黑线显示的点表示来自14、37、157和307个视频的训练,在每种情况下使用相同数量的训练图像,结果如下图所示。

  这说明该跟踪器具有良好的鲁棒性,精度接近最高。此外,其总体排名(计算为准确度和鲁棒性的平均值)在该基准上优于之前的所有跟踪器。因此,该模型的作者认为其证明了离线培训对于提高跟踪性能的价值。此外,在论文中也提到:这些结果是在仅对307个短片进行培训后获得的。该图以及补充资料中的分析表明,如果通过标记更多视频来增加培训集的大小,则可以实现进一步的收益。

代码实现

  接下来的一部分主要想介绍的是代码实现的内容,其中需要使用到GOTURN的caffe模型,此处可以使用OpenCV提供的跟踪API来进行实现。首先需要进行相关文件的下载,主要包含GOTURN的caffemodel and prototxt文件,以及后续演示中使用到的演示视频,点击此处进行下载,提取码为:1234。下载完成后,放到与py文件同一目录下即可。
  接下来需要使用到OpenCV中的Tracker,OpenCV的版本不宜过低。整体代码如下所示。

import cv2
import sys
import os

# 如果没有找到相关模型文件
if not (os.path.isfile('goturn.caffemodel') and os.path.isfile('goturn.prototxt')):
    print("Could Not Find The Model In The Current Folder")
    sys.exit()

# 创建跟踪器
tracker = cv2.TrackerGOTURN_create()

# 读取视频信息
cap = cv2.VideoCapture("2.mp4")

# 判断视频是否已经成功打开,如果没有打开,需要进行报错
if not cap.isOpened():
    print("Could not open video")
    sys.exit()

# 读取第一帧数据
ret, frame = cap.read()
# 若读取失败
if not ret:
    print("Cannot read video file")
    sys.exit()

# 此处因为我的视频文件画面过大,所以使用了缩放变换进行缩小
frame = cv2.resize(frame, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)

# 定义一个框定框
bbox = (276, 23, 86, 320)

# 框定框由用户自行框取,进行ROI
bbox = cv2.selectROI(frame, False)

# 通过第一帧以及框定框的位置来初始化跟踪器
ok = tracker.init(frame, bbox)

while True:
    # 读取新的一帧
    ret, frame = cap.read()
    if not ret:
        break
    frame = cv2.resize(frame, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)
    # 开启计时器
    timer = cv2.getTickCount()
    # 更新跟踪器
    ret, bbox = tracker.update(frame)
    # 计算FPS
    fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);
    # 画出框定框
    if ret:
        # 如果跟踪成功
        # 因为cv2.rectangle函数中的坐标需要是整数,所以需要进行一次强制类型转换
        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 detected", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
    # 将跟踪器的类型打在屏幕上,此处为GOTURN Tracker
    cv2.putText(frame, "GOTURN Tracker", (100, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50, 170, 50), 2);
    # 将当前的FPS数据打出在屏幕上
    cv2.putText(frame, "FPS : " + str(int(fps)), (100, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50, 170, 50), 2);
    # 展示我们的跟踪结果
    cv2.imshow("Tracking", frame)
    # 如果用户按下ESC键,则停止跟踪
    k = cv2.waitKey(1) & 0xff
    if k == 27:
        break

  使用cv2.selectROI函数,我们在框定好所需要跟踪的目标后,可以通过按下Space键、Enter键、ESC键来结束选定的过程,如果需要取消之前已经选定好的选定框的话,可以通过直接选定真正需要的框。
  最后我们的运行结果如下所示。

总结

  相比较于其他的深度学习跟踪器而言,其速度更快,但如果不是在特定物体上进行目标跟踪,其精度会变得很低,为此读者可以根据自身需要进行相应的选择。
  本文到此结束,谢谢大家。