目录

前言

一、实验需求

二、原理与代码分步讲解

2.1 库导入、视频读取与初始化

2.2 Shi‑Tomasi 角点检测参数配置,提取初始跟踪点

2.3 LK 金字塔光流配置参数

2.4 逐帧循环,执行光流计算

2.5 筛选有效点,绘制运动轨迹

2.6 更新迭代与退出逻辑

三、完整可运行代码

四、核心 API 说明

五、实验现象与问题分析

六、本章小结


前言

在视频序列中,目标跟踪的核心任务是捕捉特征点在连续帧之间的运动轨迹。光流表征图像中像素随时间变化的运动矢量,能够描述物体的移动方向与位移距离。本章采用金字塔 Lucas‑Kanade 光流算法,先通过 Shi‑Tomasi 算子提取图像角点作为跟踪特征,再利用calcOpticalFlowPyrLK完成前后帧特征点匹配,绘制运动轨迹,实现视频特征点的持续跟踪。

一、实验需求

读取视频文件,在视频首帧检测高质量角点作为待跟踪特征;在后续每一帧使用金字塔 LK 光流计算特征点新位置;筛选有效跟踪点,在画布上绘制特征点的运动轨迹;将轨迹图与原始视频叠加可视化,完成长序列特征跟踪。

二、原理与代码分步讲解

2.1 库导入、视频读取与初始化

  1. 导入 OpenCV 与数值计算库 numpy。
  2. 创建视频读取对象,加载测试视频。
  3. 预定义随机颜色数组,保证每个特征点的轨迹拥有独立配色,可视化效果更清晰。
  4. 提取视频首帧并转换为灰度图像,角点检测与光流运算均基于灰度图完成,降低计算量。

2.2 Shi‑Tomasi 角点检测参数配置,提取初始跟踪点

feature_params = dict(maxCorners = 100,
                      qualityLevel = 0.3,
                      minDistance = 7)

p0 = cv2.goodFeaturesToTrack(old_gray,mask = None,**feature_params)
# 创建和原图尺寸一致的黑色画布,用来绘制轨迹
mask = np.zeros_like(old_frame)

  • maxCorners=100:最多提取 100 个优质角点;

  • qualityLevel=0.3:角点可接受的最低质量阈值;
  • minDistance=7:两个角点之间最小间隔像素,避免特征点扎堆;
  • cv2.goodFeaturesToTrack即 Shi‑Tomasi 角点检测算法,返回初始待跟踪特征点坐标p0
  • mask为全黑空白图像,专门用来绘制光流运动轨迹,不污染原始画面。

2.3 LK 金字塔光流配置参数

lk_params = dict(
    winSize = (15,15),
    maxLevel = 2
)
  • winSize=(15,15):计算光流时每个特征点对应的局部搜索窗口大小;
  • maxLevel=2:金字塔层数,多层金字塔可以处理更大幅度的目标运动,解决大位移下光流跟踪失败的问题。

2.4 逐帧循环,执行光流计算

while True:
    ret,frame = cap.read()
    if not ret:
        break
    frame_gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)

    # LK金字塔光流计算
    p1,st,err = cv2.calcOpticalFlowPyrLK(old_gray,frame_gray,p0,None,**lk_params)

API功能详解:cv2.calcOpticalFlowPyrLK()

该函数是金字塔Lucas-Kanade稀疏光流算法的核心接口,专门用于实现连续视频帧间的特征点跟踪。基于灰度不变假设与局部窗口纹理匹配原理,依托图像金字塔分层迭代机制,精准计算指定特征点在相邻帧中的位移位置,适配小幅度、大幅度的目标运动场景,是稀疏特征跟踪的核心函数。

函数输入:依次传入前一帧灰度图像、当前帧灰度图像、上一帧有效特征点坐标,结合预设的光流窗口尺寸、金字塔层数等参数,为特征点匹配运算提供数据与规则支撑。

函数返回值解析

  1. p1(更新后特征点坐标):输出当前帧中所有特征点迭代匹配后的最新坐标,是目标位置实时更新的核心依据。算法通过比对特征点邻域窗口的灰度纹理相似度,求解最优位移矢量,从而更新特征点位置。
  2. st(跟踪状态标记数组):全局二值判定标识,用于区分特征点跟踪状态。数值为1表示该特征点邻域纹理匹配成功、跟踪有效;数值为0表示纹理匹配失效,因遮挡、形变、光照突变、超量程位移等问题导致特征点跟踪丢失,后续不再参与迭代跟踪。
  3. err(匹配误差数组):对应每个特征点的灰度匹配误差,量化表征前后帧特征窗口的纹理差异程度。误差数值越小,代表窗口纹理相似度越高,匹配结果越精准;误差过大则判定为匹配无效,辅助筛选有效跟踪点。

2.5 筛选有效点,绘制运动轨迹

good_new = p1[st==1]
    good_old = p0[st==1]
    for i ,(new,old) in enumerate(zip(good_new,good_old)):
        a,b = new
        c,d = old
        a,b,c,d = int(a),int(b),int(c),int(d)
        mask = cv2.line(mask,(a,b),(c,d),color[i].tolist(),2)
        cv2.imshow("mask",mask)
    img = cv2.add(frame,mask)
    cv2.imshow("frame",img)
  1. 通过st==1过滤,只保留跟踪成功的特征点;
  2. 遍历成功匹配的新旧坐标,在 mask 画布上绘制线段,连接同一特征点在上一帧与当前帧的位置;
  3. cv2.add(frame,mask)把原始视频画面和轨迹画布叠加显示,直观看到物体运动路径。

2.6 更新迭代与退出逻辑

k = cv2.waitKey(60)
    if k == 27:
        break
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1,1,2)
cap.release()
cv2.destroyAllWindows()
  1. 将当前帧灰度图作为下一轮运算的旧帧;
  2. 将本轮成功跟踪的新坐标赋值给p0,作为下一帧的跟踪起点,实现持续追踪;
  3. 按下 ESC 键结束程序,释放资源关闭窗口。

三、完整可运行代码

import numpy as np
import cv2

cap = cv2.VideoCapture(r"D:\pythoncode2\bigdata_ai40\data\test.avi")
color = np.random.randint(0,255,(100,3))

ret,old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame,cv2.COLOR_BGR2GRAY)

# Shi‑Tomasi角点检测参数
feature_params = dict(maxCorners = 100,
                      qualityLevel = 0.3,
                      minDistance = 7)

p0 = cv2.goodFeaturesToTrack(old_gray,mask = None,**feature_params)
mask = np.zeros_like(old_frame)

# LK金字塔光流参数
lk_params = dict(
    winSize = (15,15),
    maxLevel = 2
)

while True:
    ret,frame = cap.read()
    if not ret:
        break
    frame_gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)

    p1,st,err = cv2.calcOpticalFlowPyrLK(old_gray,frame_gray,p0,None,**lk_params)
    good_new = p1[st==1]
    good_old = p0[st==1]

    for i ,(new,old) in enumerate(zip(good_new,good_old)):
        a,b = new
        c,d = old
        a,b,c,d = int(a),int(b),int(c),int(d)
        mask = cv2.line(mask,(a,b),(c,d),color[i].tolist(),2)
    img = cv2.add(frame,mask)
    cv2.imshow("frame",img)

    k = cv2.waitKey(60)
    if k == 27:
        break
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1,1,2)

cap.release()
cv2.destroyAllWindows()

四、核心 API 说明

  1. cv2.goodFeaturesToTrack():Shi‑Tomasi 角点检测,提取适合跟踪的稳定特征点。
  2. cv2.calcOpticalFlowPyrLK():金字塔 Lucas‑Kanade 稀疏光流,计算特征点在下一帧的位置。
  3. np.random.randint():随机生成 RGB 颜色值,用于区分不同特征轨迹。
  4. cv2.line():在空白 mask 画布上绘制特征点运动轨迹。
  1. cv2.add():将原图与轨迹图层叠加融合显示。

五、实验现象与问题分析

  1. 跟踪效果:物体移动时画面上会留下彩色轨迹线条,直观展示角点的运动路径;
  2. 跟踪丢失:当目标快速移动、被遮挡或者旋转过大时,部分特征点状态st=0,该点停止跟踪;
  3. 稀疏光流特点:只跟踪少量角点,计算速度快;对比稠密光流,不会计算整张图像每个像素的运动;
  4. 金字塔作用:多层图像缩放,可以处理更大幅度的位移,提升大运动场景下的跟踪鲁棒性。

六、本章小结

稀疏金字塔 LK 光流跟踪完整流程:
读取首帧 → Shi‑Tomasi 提取初始角点 → 设置光流窗口与金字塔层数 → 逐帧迭代计算光流 → 筛选跟踪有效的特征点 → 在画布绘制运动轨迹 → 更新特征点实现持续跟踪。

Lucas‑Kanade 属于稀疏光流,仅跟踪少量高稳定性角点,实时性较好;缺点是目标遮挡、剧烈形变时容易丢失跟踪。后续可以对比稠密光流 Farneback 算法,观察全像素运动矢量的可视化效果。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐