下面是对于“OpenCV 光流Optical Flow示例”的完整攻略以及两个示例说明。
简介
Optical Flow是指在视频中的相邻两帧之间,在像素级别上计算出像素点在两帧之间的位移的技术。OpenCV是一个广泛使用的计算机视觉库,也支持光流技术。本攻略将介绍如何使用OpenCV进行光流分析。
步骤
- 安装OpenCV。
如果你还没有安装OpenCV,请先前往官方网站下载安装。
- 加载视频。
将视频加载到OpenCV中。
import cv2
cap = cv2.VideoCapture('path/to/video')
- 设置参数。
设置角点检测器的最大角点数,角点检测器的质量水平等等。
feature_params = dict(maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)
lk_params = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
color = (0, 255, 0)
- 计算光流。
计算相邻两帧之间的光流,并将其绘制到新图像中。
# 读取一帧
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
# 寻找角点
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
# 创建一个mask用来绘制轨迹
mask = np.zeros_like(old_frame)
# 循环读取视频并计算光流
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.ravel()
c, d = old.ravel()
mask = cv2.line(mask, (a, b), (c, d), color, 2)
frame = cv2.circle(frame, (a, b), 5, color, -1)
img = cv2.add(frame, mask)
cv2.imshow('frame', img)
# 更新帧和角点点
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1, 1, 2)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cv2.destroyAllWindows()
cap.release()
示例1
在这个示例中,我们模拟一个二维的均匀平移,它会随着时间的推移而减小。
import cv2
import numpy as np
# 创建画布
canvas = np.zeros((400, 400), dtype="uint8")
# 初始化变量
shift = 0
delta = 4
# 绘制旋转方格
for x in range(10, 390, 25):
shift += delta
pts = np.array([[10 + shift, x], [390, x], [390 - shift, x + 25], [10, x + 25]], dtype=np.int32)
cv2.fillConvexPoly(canvas, pts, (255))
# 循环将画布变换
for i in range(120):
M = np.float32([[1, 0, i * 3], [0, 1, 0]])
rotated = cv2.warpAffine(canvas, M, (400, 400))
# 计算光流
flow = cv2.calcOpticalFlowFarneback(canvas, rotated, None, 0.5, 3, 25, 3, 5, 1.2, 0)
magnitude, angle = cv2.cartToPolar(flow[..., 0], flow[..., 1])
# 构造HSV图像
hsv = np.zeros((400, 400, 3), dtype="uint8")
hsv[..., 0] = angle * (180 / np.pi / 2)
hsv[..., 1] = 255
hsv[..., 2] = cv2.normalize(magnitude, None, 0, 255, cv2.NORM_MINMAX)
# 转换为BGR图像并输出
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
cv2.imshow("Optical Flow", bgr)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cv2.destroyAllWindows()
该示例演示了如何在画布上进行均匀平移,然后使用OpenCV的calcOpticalFlowFarneback
函数计算出运动的光流。最终使用cvtColor
函数将光流图像转换为BGR空间,以便将其显示出来。
示例2
在这个示例中,我们将通过直接对NGC 2237进行光流处理来演示OpenCV的光流功能。NGC 2237是Rosette星云中的一个部分,是一个美丽的星云。
import cv2
import numpy as np
from urllib import request
# 加载图像
url = "https://www.winhelponline.com/blog/wp-content/uploads/2017/12/Windows-10-default-background-3.jpg"
resp = request.urlopen(url)
image = np.asarray(bytearray(resp.read()), dtype="uint8")
image = cv2.imdecode(image, cv2.IMREAD_GRAYSCALE)
# 初始化前一帧和光流
previous_frame = None
optical_flow = None
# 不断循环,直到用户终止程序
while True:
# 如果前一帧为空,则将当前帧设置为前一帧
if previous_frame is None:
previous_frame = image.copy()
else:
previous_frame = current_frame.copy()
# 如果当前帧为空,则退出循环
current_frame = image.copy()
if current_frame is None:
break
# 如果光流为空,则使用Farneback计算光流
if optical_flow is None:
optical_flow = cv2.calcOpticalFlowFarneback(previous_frame, current_frame, None, 0.5, 3, 15, 3, 5, 1.2, 0)
# 在当前帧上绘制运动向量
for y in range(0, current_frame.shape[0], 5):
for x in range(0, current_frame.shape[1], 5):
dx, dy = optical_flow[y, x].astype(np.int0)
cv2.arrowedLine(current_frame, (x, y), (x + dx, y + dy), (255, 255, 255))
# 显示帧
cv2.imshow("Rosette Nebula (NGC 2237)", current_frame)
# 侦听键盘事件,确定是否退出
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
该示例加载一个图像,然后使用calcOpticalFlowFarneback
函数计算出前一帧和当前帧之间的运动光流。最终,使用光流图像在当前帧上绘制运动向量,并显示结果。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:OpenCV 光流Optical Flow示例 - Python技术站