OpenCV 之 实现基于Lucas-Kanade算法的光流追踪

引言

在计算机视觉中,光流是指物体、场景或摄像机之间的相对运动造成的像素变化。光流估计是计算机视觉中的一个基础课题,广泛应用于许多领域,比如自动驾驶汽车、机器人导航、手势识别等。OpenCV是一个开源的计算机视觉库,提供了许多功能强大的算法,其中包括光流算法。本文将介绍如何使用Python结合OpenCV来实现基于Lucas-Kanade算法的光流追踪,并展示如何在视频中追踪特征点的运动轨迹。

实现步骤

准备工作

首先,确保已经安装了numpyopencv-python库。如果尚未安装,可以使用pip命令进行安装:

pip install numpy opencv-python

代码解析

下面是一个使用Lucas-Kanade算法追踪视频中特征点并绘制轨迹的例子。我们将逐步解释代码的每一部分。

import numpy as np
import cv2

# 打开视频文件
cap = cv2.VideoCapture(r'picture_video\test.avi')

# 随机生成颜色,用于绘制轨迹
color = np.random.randint(0, 255, (100, 3))

# 读取视频的第一帧
ret, old_frame = cap.read()

# 将第一帧转换为灰度图像
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

# 定义特征点检测参数
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)

# 定义Lucas-Kanade光流参数
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)
    
    # 选择好的点(状态为1的点)
    good_new = p1[st == 1]
    good_old = p0[st == 1]
    
    # 绘制轨迹
    for i, (new, old) in enumerate(zip(good_new, good_old)):
        a, b = new.ravel()  # 获得新点的坐标
        c, d = old.ravel()  # 获得旧点的坐标
        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)
    
    # 等待150ms,检测是否按下了Esc键(键码为27)
    k = cv2.waitKey(150) & 0xff
    if k == 27:  # 按下Esc键,退出循环
        break
    
    # 更新旧灰度图和旧特征点
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1, 1, 2)  # 重新整理特征点为适合下次计算的形状

# 释放资源
cv2.destroyAllWindows()
cap.release()

代码解释

  1. 导入必要的库:导入numpy用于数值运算,导入cv2模块用于图像处理。
  2. 打开视频文件:使用cv2.VideoCapture来打开指定路径下的视频文件。
  3. 初始化颜色:随机生成一系列颜色,以便后续绘制轨迹。
  4. 读取第一帧并转换为灰度图:读取视频的第一帧,并将其转换成灰度图,因为光流算法通常在灰度图上进行。
  5. 特征点检测:使用cv2.goodFeaturesToTrack来检测特征点。
  6. 初始化掩模:创建一个与原图像同样大小的全零矩阵,作为绘制轨迹的画布。
  7. 定义光流参数:设置Lucas-Kanade算法所需的参数。
  8. 主循环:读取每一帧视频,计算光流向量,并绘制轨迹。
  9. 显示结果:在每一帧上叠加轨迹后显示图像。
  10. 更新状态:在每次循环结束时更新旧的灰度图像和特征点位置。
  11. 清理资源:最后,释放视频文件和关闭所有OpenCV窗口。

结论

通过以上代码,我们可以实现基于Lucas-Kanade算法的光流追踪,并在视频中可视化特征点的移动轨迹。这种方法不仅可以帮助我们理解视频中物体的运动情况,而且对于开发需要感知环境动态变化的应用来说也是非常有用的。希望这篇博客能对你有所帮助!

Lucas-Kanade光流算法是一种基于局部区域的光流算法,它假设图像中任意两帧之间的像素值变化是平滑的,然后使用局部区域内的像素值变化来估计每个像素的运动向量。在本文中,我们将介绍如何在OpenCV中自实现Lucas-Kanade光流算法。 步骤一:读取图像 首先,我们需要读取两张待计算光流的图像。在本例中,我们将使用名为“frame1”和“frame2”的两张图像。 Mat frame1 = imread("frame1.jpg"); Mat frame2 = imread("frame2.jpg"); 步骤二:提取关键点 接下来,我们需要从两个图像中提取关键点。我们可以使用OpenCV中的FAST或SIFT等算法来提取关键点。在本例中,我们将使用FAST算法。 vector<KeyPoint> keypoints1, keypoints2; int threshold = 20; // 设置FAST算法的阈值 bool nonmaxSuppression = true; // 设置是否进行非极大值抑制 FAST(frame1, keypoints1, threshold, nonmaxSuppression); FAST(frame2, keypoints2, threshold, nonmaxSuppression); 步骤三:计算光流 现在我们已经提取了关键点,接下来我们需要计算这些关键点的光流向量。我们可以使用OpenCV中的calcOpticalFlowPyrLK函数来计算光流向量。该函数使用金字塔表示法和Lucas-Kanade算法来计算光流向量。 vector<uchar> status; vector<float> err; Size winSize = Size(21, 21); // 设置光流计算窗口的大小 int maxLevel = 3; // 设置金字塔的最大层数 TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01); // 设置终止条件 calcOpticalFlowPyrLK(frame1, frame2, keypoints1, keypoints2, status, err, winSize, maxLevel, criteria); 步骤四:绘制光流 最后,我们可以将光流向量绘制在第一张图像上,以便我们可以观察到光流的效果。 for (int i = 0; i < keypoints1.size(); i++) { if (status[i]) { Point2f p1 = keypoints1[i].pt; Point2f p2 = keypoints2[i].pt; line(frame1, p1, p2, Scalar(0, 0, 255), 2); } } imshow("Optical Flow", frame1); 完整代码:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值