📜  Python OpenCV:使用 Lucas-Kanade 方法的光流(1)

📅  最后修改于: 2023-12-03 14:46:01.619000             🧑  作者: Mango

Python OpenCV:使用 Lucas-Kanade 方法的光流

光流是计算图像序列中像素运动的技术。Lucas-Kanade 方法是一种计算密集的光流技术,用于估计两个图像之间像素的运动。在本文中,我们将使用 Python 和 OpenCV 库实现 Lucas-Kanade 光流算法。

安装 OpenCV

在开始编写代码之前,我们需要安装 OpenCV 库。可以使用以下命令在 Python 中安装此库:

pip install opencv-python

在安装 OpenCV 之后,我们可以运行以下代码来检查安装是否成功:

import cv2

print(cv2.__version__)

如果输出 cv2 库的版本号,则说明安装成功。

加载图像和设置 ROI

在使用 Lucas-Kanade 算法之前,我们需要加载两个图像并选择感兴趣区域(ROI)。感兴趣区域是算法的输入。我们将使用前两帧视频作为我们的输入图像。

import cv2

cap = cv2.VideoCapture("video.mp4")

# 加载第一帧图像
ret, frame1 = cap.read()

# 选择感兴趣区域(ROI)
x, y, w, h = cv2.selectROI(frame1, False)

# 将感兴趣区域添加到第一帧图像中
roi1 = frame1[y:y+h, x:x+w]

# 将感兴趣区域转化为灰度图像
gray_roi1 = cv2.cvtColor(roi1, cv2.COLOR_BGR2GRAY)

在上述代码中,我们首先加载视频并读取第一帧。我们使用 cv2.selectROI 函数选择感兴趣区域。x,y,w 和 h 分别是感兴趣区域的左上角坐标和宽度和高度。我们然后提取感兴趣区域并将其转换为灰度图像。

计算光流

在具有第一帧和第二帧的感兴趣区域的情况下,我们可以计算两帧之间的光流。使用 cv2.calcOpticalFlowPyrLK 函数来计算光流。

# 进入循环, 不断读取每一帧图像进行处理
while True:
    # 读取下一帧视频
    ret, frame2 = cap.read()

    # 如果没有帧,则跳出循环
    if not ret:
        break

    # 获取感兴趣区域
    roi2 = frame2[y:y+h, x:x+w]

    # 将感兴趣区域转化为灰度图像
    gray_roi2 = cv2.cvtColor(roi2, cv2.COLOR_BGR2GRAY)

    # 计算光流
    p1, _, _ = cv2.calcOpticalFlowPyrLK(gray_roi1, gray_roi2, None, None, maxLevel=1, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 15, 0.08))

    # 选择跟踪点
    good_new = p1
    good_old = p0

    # 绘制跟踪线
    for i, (new, old) in enumerate(zip(good_new, good_old)):
        a, b = new.ravel()
        c, d = old.ravel()
        mask = cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2)
        frame2 = cv2.circle(frame2, (a, b), 5, color[i].tolist(), -1)

    # 显示图像
    img = cv2.add(frame2, mask)
    cv2.imshow('frame', img)

    # 更新老的点
    p0 = good_new.reshape(-1, 1, 2)

    # 按下 ESC 键退出
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break

# 清理
cap.release()
cv2.destroyAllWindows()

在计算光流之后,我们可以选择光流跟踪点并绘制跟踪线。使用 cv2.line 函数绘制跟踪线,并使用 cv2.circle 函数将跟踪点绘制在当前帧上。最后,我们将带有跟踪线和跟踪点的帧显示为视频。

完整代码
import cv2
import numpy as np

# 定义光流跟踪点的颜色
color = np.random.randint(0, 255, (100, 3))

# 加载视频
cap = cv2.VideoCapture("video.mp4")

# 加载第一帧图像
ret, frame1 = cap.read()

# 选择感兴趣区域(ROI)
x, y, w, h = cv2.selectROI(frame1, False)

# 将感兴趣区域添加到第一帧图像中
roi1 = frame1[y:y+h, x:x+w]

# 将感兴趣区域转化为灰度图像
gray_roi1 = cv2.cvtColor(roi1, cv2.COLOR_BGR2GRAY)

# 获取感兴趣区域的兴趣点
p0 = cv2.goodFeaturesToTrack(gray_roi1, maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)

# 创建掩膜图像用于绘制跟踪线和跟踪点
mask = np.zeros_like(roi1)

# 进入循环, 不断读取每一帧图像进行处理
while True:
    # 读取下一帧视频
    ret, frame2 = cap.read()

    # 如果没有帧,则跳出循环
    if not ret:
        break

    # 获取感兴趣区域
    roi2 = frame2[y:y+h, x:x+w]

    # 将感兴趣区域转化为灰度图像
    gray_roi2 = cv2.cvtColor(roi2, cv2.COLOR_BGR2GRAY)

    # 计算光流
    p1, _, _ = cv2.calcOpticalFlowPyrLK(gray_roi1, gray_roi2, None, None, maxLevel=1, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 15, 0.08))

    # 选择跟踪点
    good_new = p1
    good_old = p0

    # 绘制跟踪线
    for i, (new, old) in enumerate(zip(good_new, good_old)):
        a, b = new.ravel()
        c, d = old.ravel()
        mask = cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2)
        frame2 = cv2.circle(frame2, (a, b), 5, color[i].tolist(), -1)

    # 显示图像
    img = cv2.add(frame2, mask)
    cv2.imshow('frame', img)

    # 更新老的点
    p0 = good_new.reshape(-1, 1, 2)

    # 按下 ESC 键退出
    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break

# 清理
cap.release()
cv2.destroyAllWindows()
结论

Lucas-Kanade 方法是一种广泛使用的光流技术,用于计算运动像素。在本文中,我们使用 Python 和 OpenCV 库实现了 Lucas-Kanade 方法,熟悉了如何加载视频、选择感兴趣区域、计算光流并绘制跟踪线。 利用此技术,我们可以跟踪运动物体,并用于许多计算机视觉应用程序。