opencv中calcOpticalFlowPyrLK实现的光流法(Lucas-Kanade Method for Sparse Optical Flow)原理解析 (摘要翻译)

本文截图及内容均来自learning opencv 第三版第16章 Keypoints and Descriptors

1.光流法介绍

光流法主要用于寻找不同图片间的特征点对应关系。特别是应用在视频中,因为对于视频,可以合理地认为当前帧中的许多点能够在下一帧中找到。

一个理想的光流算法输出应该是图中每个像素的速度预测集合,或是表示每个像素在相邻帧间相对位置的位移向量。当对图中每个像素求解时,就是密集光流法(dense optical flow)。相对的,也存在稀疏光流法(sparse optical flow)。稀疏光流法通过只追踪图中的特征点,同时达到快速和准确的目的。

2.Lucas-Kanade 稀疏光流法(Lucas-Kanade Method for Sparse Optical Flow )

Lucas-Kanade算法最早在1981年提出,最初为密集光流法。因为本方法很容易应用在图片像素子集中,所以变成了一种重要的稀疏光流法。Lucas-Kanade算法只依赖于围绕关键点的小窗口推断出的局部信息。这导致了Lucas-Kanade算法不能检测到物体的快速运动到窗口外部的点。这个缺点可以通过改进的金字塔LK光流法解决。

Lucas-Kanade原理

基本假设:

亮度恒定假设:目标物体像素的强度值在帧间亮度不变。对于灰度图,即对于追踪的像素点,帧间亮度不变。

时间连续:相邻帧间运动微小

空间一致性:图中临近的点属于相同的表面,具有相似的移动。


1.亮度恒定假设要求跟踪部分亮度不随时间变化:



2.时间连续假定,对上式中的 I(x(t), t) 求导得:


Ix是图像的偏导数,It是图像随时间的偏导数,v是观察到的速度。对于一维空间中的光流速度等式为:


3.空间一致性:

若一个局部区域的像素运动是一致的,就可以建立邻域像素的系统方程求解中心像素的运动。如使用5x5(窗口大小)的邻域像素亮度值,计算此像素的运动,就可建立25个方程:


注意窗口的大小选择,窗口太大会违背空间一致性假设,太小又会追踪不到窗口外的点。

以上方法是基于小而连贯运动的假设,但是对于大多数30Hz的摄像机,大而不连贯的运动是普遍存在的。所以需要更大的窗口来追踪运动,但这又会违背空间一致性假设。因此引入图像金字塔解决。最初在较大的空间尺度追踪,再在小的空间尺度上修正。


追踪方法:在图像金字塔最高层计算光流,得到的运动结果作为下层金字塔的起始点,重复这个过程直至最底层。这样就將不满足运动假定的可能性降到最低并实现更快更长的运动追踪。这个方法就叫金字塔Lucas-Kanade光流法。

在OpenCv中的实现函数为calcOpticalFlowPyrLK。



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); 步骤三:计算光流 现在我们已经提取了关键点,接下来我们需要计算这些关键点的光流向量。我们可以使用OpenCVcalcOpticalFlowPyrLK函数来计算光流向量。该函数使用金字塔表示法和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); 完整代码:
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值