光流估计
要是觉得内容枯燥,您可以点击左下角的播放按钮,让您在音乐的熏陶下愉快的阅读
本文总字数:2385
光流估计
光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。
三个前提条件:
- 亮度恒定:同一点随着时间的变化,其亮度不会发生改变。
- 小运动:随着时间的变化不会引起位置的剧烈变化,只有小运动情况下才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数。
- 空间一致:一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。所以需要连立n多个方程求解。
Lucas—Kanade算法
如何求解方程组呢?看起来一个像素点根本不够,在物体移动过程中还有哪些特性呢?
注意前提条件里的第三个空间一致还没有使用
例如对于一个n*n的像素范围点1和点2邻近和点3邻近...由空间一致得
最终可以表示为
但ATA 不一定可逆。由于可逆矩阵的特征值非0。
若ATA可逆,则λ1,λ2非0,联想到角点检测λ1,λ2都不靠近0时,即λ1,λ2都很大时,为角点
所以,可以利用判断是否是角点来判断是否可逆
当是角点是,成立。
步骤:
- 1.读入视频
- 2. 对视频的每一帧操作,转换为灰度图
- 3.检测角点
- 4 .创建掩膜
- 5.利用cv2.calcOpticalFlowPyrLK跟踪特征向量
参数:
- prevImage 前一帧图像- nextImage 当前帧图像
- prevPts 待跟踪的特征点向量
- winSize 搜索窗口的大小
- maxLevel 最大的金字塔层数
返回:
- nextPts 输出跟踪特征点向量
- status 特征点是否找到,找到的状态为1,未找到的状态为0
- 6.对于找到的特征点绘制轨迹
- 7.展示
- 8.更新旧特征点
cap = cv2.VideoCapture('test.avi') #角点检测所需参数 feature_params = dict(maxCorners=100, qualityLevel=0.3, minDistance=7) #lucas kanade参数 lk_params = dict(winSize=(15, 15), maxLevel=2) #随机颜色条 color = np.random.randint(0, 255, (100, 3)) #拿到第一帧图像 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() frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) #需要传入前一帧和当前图像以及前一帧检测到的角点 p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params) #st=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() # mask = cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2) # frame = cv2.circle(frame, (a, b), 5, color[i].tolist(), -1) #绘制轨迹 for i, (new, old) in enumerate(zip(good_new, good_old)): a = new.ravel() b = old.ravel() mask = cv2.line(mask, tuple(a), tuple(b), color[i].tolist(), 2) frame = cv2.circle(frame, tuple(a), 5, color[i].tolist(), -1) img = cv2.add(frame, mask) cv2.imshow('frame', img) k = cv2.waitKey(150) & 0xff if k == 27: break #更新 old_gray = frame_gray.copy() p0 = good_new.reshape(-1, 1,2) cap.release() cv2.destroyAllWindows()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现