目录
1.简介
基于单目的光流法是一种常见的计算机视觉技术,用于估计图像序列中物体的运动速度。它通过分析连续帧之间的像素变化来推断物体在图像中的移动情况。
背景: 光流法是计算机视觉领域中最早的运动估计方法之一,最早由Horn和Schunck在1981年提出。它基于光流假设,即相邻帧上的像素具有相似的灰度值,且相似的像素在移动过程中会产生相同的位移。光流法不仅可以用于物体的运动跟踪和姿态估计,还可以应用于目标检测、行为分析、视频压缩等领域。
意义: 基于单目的光流法进行速度测量在实际应用中具有广泛的意义,以下是其中一些重要的方面:
-
交通监控和智能交通:通过分析交通摄像头拍摄的连续图像序列,可以估计车辆、行人或其他交通参与者的速度。这对于交通管理、拥堵监测、事故预警等都非常重要。
-
运动分析和姿态估计:光流法可以帮助理解物体的运动行为,如运动目标的速度、加速度以及物体的姿态变化。这对于运动分析、动作捕捉和姿态估计等应用非常有价值,比如在体育训练、动画制作和人机交互中广泛应用。
-
视频增强和稳定:利用光流法可以对图像序列进行运动补偿和稳定,减少图像中的抖动或运动模糊。这对于视频增强、图像合成和虚拟现实等应用非常重要。
-
无人驾驶和机器人导航:光流法可以帮助无人驾驶车辆和机器人估计周围环境中物体的运动状态和速度信息,从而更好地规划路径、避障和控制运动。
总之,基于单目的光流法测速在多个领域具有广泛的应用前景,能够提供有关物体运动速度和行为的关键信息,从而为实时控制、决策和分析提供支持。
2.代码实现
光流法是一种基于图像序列的运动估计方法,其中涉及到的主要函数包括:
-
cv2.calcOpticalFlowPyrLK()
:该函数用于计算稀疏光流。它接受前一帧图像和当前帧图像作为输入,并根据给定的特征点或兴趣区域跟踪这些特征点在两个图像之间的位置变化。函数返回被成功追踪的特征点的新位置以及一个状态值。 -
cv2.calcOpticalFlowFarneback()
:该函数用于计算稠密光流。它接受前一帧图像和当前帧图像作为输入,并估计整个图像中每个像素点的运动向量。函数返回每个像素点的光流向量值。 -
cv2.goodFeaturesToTrack()
:该函数用于在图像中检测良好的特征点。它接受输入图像和一些参数,如角点检测方法、特征点数量等,并返回检测到的良好特征点的坐标。 -
cv2.drawOpticalFlow()
:该函数用于可视化光流结果。它接受一张彩色图像和光流向量作为输入,并在图像上绘制箭头表示运动方向和强度。
这些函数是常见的在OpenCV库中使用的光流算法相关函数,可以帮助实现光流法的运动估计和分析。根据具体的应用场景和需求,您可以选择合适的函数进行使用和调整参数。
像素级测速,真实世界测速需要拿到相机内参
import cv2
import time
import numpy as np
from ours import *
# 打开摄像头(也可打开视频文件)
cap = cv2.VideoCapture('./10.mp4')
# onnx_path = 'yolov5s.onnx'
# model = Yolov5ONNX(onnx_path)
# 创建随机颜色向量,用于绘制光流向量
color = np.random.randint(0, 255, (100, 3))
# 获取第一帧图像
ret, frame_pre = cap.read()
frame_preGray = cv2.cvtColor(frame_pre, cv2.COLOR_BGR2GRAY)
# 设置角点检测参数
feature_params = dict(maxCorners=50, 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))
# 获取第一帧角点
p0 = cv2.goodFeaturesToTrack(frame_preGray, mask=None, **feature_params)
# 创建蒙版
mask = np.zeros_like(frame_pre)
while True:
# 获取当前帧图像
ret, frame = cap.read()
img = frame.copy()
# or_img, box_coords = model.detect(img)
frameGray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 使用光流法计算运动向量
p1, st, err = cv2.calcOpticalFlowPyrLK(
frame_preGray, frameGray, 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, (int(a), int(b)), (int(c), int(d)), color[i].tolist(), 2)
frame = cv2.circle(frame, (int(a), int(b)), 5, color[i].tolist(), -1)
# 绘制运动速度直方图
magnitude, angle = cv2.cartToPolar(
good_new[..., 0] - good_old[..., 0], good_new[..., 1] - good_old[..., 1])
hist, bins = np.histogram(magnitude, bins=50)
bin_mids = (bins[:-1] + bins[1:]) / 2.
speed = bin_mids[np.where(hist == np.max(hist))[0][0]]
# 将光流运动轨迹叠加到原始图像上
img = cv2.add(frame, mask)
# 显示结果图像
cv2.imshow('frame', img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 更新下一帧的角点
frame_preGray = frameGray.copy()
p0 = good_new.reshape(-1, 1, 2)
# 输出速度信息
print("当前速度为: {:.2f} 像素/帧".format(speed))
# 释放摄像头并关闭窗口
cap.release()
cv2.destroyAllWindows()
当前速度为: 0.55 像素/帧
当前速度为: 0.82 像素/帧
当前速度为: 0.34 像素/帧
当前速度为: 0.56 像素/帧
当前速度为: 0.22 像素/帧
当前速度为: 1.03 像素/帧
当前速度为: 1.33 像素/帧