三种光流算法的实现源码及测试结果

合集下载

LK光流算法

LK光流算法
nad光流法)[27]。在这三种光流跟踪方法中,跟踪性能最优的是Lucas Kanade跟踪少量的特征点、迭代法收敛速度也很快而且算法的计算量不大,
已被广泛的应用于运动车辆跟踪和人脸特征点跟踪[47,48];下面介绍文献[27],并对其
进行相关实验。
§4.3.1问题提出
提下,推导出灰度图像光流场计算的基本等式,这是经典光流方法[18,24]。
光流的算法多种多样,其用于目标跟踪常用的算法有:检测和跟踪特征点[25]、跟
好的特征点[26]、金字塔图像的Lucas Kanade特征点跟踪算法(因为其跟踪过程是迭
的光流法计算过程,因此,为了更好的体现光流的作用,本文将其简称为:Lucas
(4-3-13)
B(x,y)~=JL(x+gL
x
,y+gL
y
)
?(x,y)∈[px?ωx,px+ωx]×[py?ωy,py+ωy]
(4-3-14)
注意到A(x,y)和B(x,y)的定义域稍微有些差异。实际上,A(x,y)是在窗口大小为
(2ωx+3)×(2ωy+3)的范围内定义,而不是(2ωx+1)×(2ωy+1)。在后面运用中心差分算子
px+ωx
x=px?ωx
py+ωy
y=py?ωy
(A(x,y)?B(x,y)?[?
B
?x
?B
?y
]υ)?[
?B
?x
?B
?y]
(4-3-18)
注意到A(x,y)?B(x,y)可以看作是在点[x,y]T的一个导数,所以:
δI(x,y)~=A(x,y)?B(x,y)
?(x,y)∈[px?ωx,px+ωx]×[py?ωy,py+ωy]

计算机视觉中的光流计算算法分析

计算机视觉中的光流计算算法分析

计算机视觉中的光流计算算法分析计算机视觉是一门涉及计算机处理和理解视觉数据的学科。

光流计算算法是其中一项重要的技术之一。

光流计算是指基于图像序列的时间相邻性,计算图像上每一个像素的运动速度和方向。

光流计算算法的应用非常广泛,可以被用于目标跟踪、图像稳定、自动驾驶等领域。

本文将从光流计算算法的原理、分类及其应用方面进行探讨。

一、光流计算算法的原理光流计算基于运动恒定假设,假设图像上同一物体在不同时间间隔内位置的变化量是连续的,图像的颜色值变化是由物体的运动引起的。

在计算光流时,需要利用相邻两帧图像之间的变化来计算每个像素在X和Y方向上的运动速度和方向。

设两幅灰度图像的亮度值分别为I(x, y, t)和I(x+u, y+v,t+1),其中(x, y)为图像中的像素坐标,t为时间,u和v是在像素上的位移,光流v=(u, v) 是取决于基于灰度不变假设的图像变量,因此可以用下式来计算:Ixu+Iyv+It=0;其中Ix表示灰度图像在x方向上的梯度,Iy表示灰度图像在y方向上的梯度,It表示两帧图像之间的灰度值变化。

二、光流计算算法的分类为了更好地研究和解决光流计算问题,光流计算算法可以分为密集算法、稠密算法和稀疏算法等几种不同的算法类别。

密集算法密集算法的优势在于可以对整个图像进行运动的跟踪,因此,可以检查相邻像素之间的连续性,并可以提高图像的精度。

但是,这种算法的缺点在于经常需要更强大的计算硬件来处理。

稠密算法稠密算法是基于密集的光流计算,它可以保证准确性和稳定性。

这种算法可以提高像素之间光流的连续性,并抑制误差的导致。

稠密算法有丰富的应用,例如可以用于图像稳定和视频抖动消除。

稀疏算法稀疏算法的优势在于计算量较小,这使得该算法非常适合于在计算能力低的计算机设备上实现。

然而,由于其只针对某些特定像素的元素计算光流,因此可能会导致图像间断。

三、光流计算算法的应用光流计算算法已经有广泛的应用领域,包括了目标跟踪、图像稳定、自动驾驶等等。

H-S光流算法及仿真总结

H-S光流算法及仿真总结

H-S光流算法及仿真总结一、光流的概念二维图像是三维实景在成像面的投影,反映了三维实景中物体的位置等信息。

假设Po是三维实景中的一点,Pi是Po在成像面上的投影,Po的运动反映在成像面中就是Pi的运动,假设Po在δt时间内运动了δs到Po’,Pi则运动了δs’到Pi,Pi运动的速度为'stδδ。

如下图所示:图1 Po的运动在成像面上反映为Pi的运动Pi的运动速度'stδδ就是Pi的光流。

由此得出,光流就是三维实景在成像面上的投影的运动速度。

三维实景中的某一点在成像面上的投影的运动速度形成点光流,所有点在成像面上的投影的运动速度则形成光流场。

光流场反映了三维实景中物体的位置、运动等信息。

光照的变化必然引起光流的变化,有些运动不产生光流,如光照不变时,均匀亮度的球体绕中心轴自转的运动。

因此我们在研究实际问题时常常假设光照亮度不变。

二、光流的H-S算法1、光流基本约束方程假定:1、图像的灰度始终不变,2、光流在整个图像中满足一定的约束条件,即全局性约束,3光流在整个图像中均匀变化, 无重叠,即平滑性约束。

设I (x ,y ,t )是图像上点(x ,y )某一时刻t 的亮度,u (x ,y )和v (x ,y )分别是点(x ,y )在x 方向和y 方向上的光流分量,点(x ,y )在t+δt 时间内运动到(x+δx ,y+δy ),其中,δx=u*δt ,δy=v*δt 。

由于亮度不变,所以有I (x+δx ,y+δy ,t+δt )=I (x ,y ,t ) 用泰勒级数展开得(,,)(,,)I I II x y t dx dy dt I x y t x y tε∂∂∂++++=∂∂∂ 其中ε是关于δx 、δy 、δt 的二阶以上的项,可以忽略不计 两边同除以δt 得0I dx I dy dI x dt y dt dt ∂∂++=∂∂ 设x I I x ∂=∂,y I I y ∂=∂,t I I t ∂=∂,dx u dt =,dy v dt =,则有光流基本约束方程x y t I u I v I ++=2、H-S 提出的光流算法迭代方程 迭代方程()()(1)()222k k x y tk k xx yI u I v I uuI I Iλ+++=-++,()()(1)()222k k x y tk k yx yI u I v I vvI I Iλ+++=-++其中,k 是迭代次数, u 和v 是光流局部平均值,λ为权重系数。

特征点 光流法 直接法-概念解析以及定义

特征点 光流法 直接法-概念解析以及定义

特征点光流法直接法-概述说明以及解释1.引言概述:特征点、光流法和直接法是计算机视觉中常用的技术手段,用于图像和视频处理、运动估计以及SLAM等领域。

特征点是图像中具有显著特征的点,可以通过特征点检测算法来提取。

光流法是一种通过计算图像序列中像素点的位移来描绘物体运动的方法。

直接法则是直接使用像素值和相机运动来进行匹配和估计,相较于特征点法,直接法减少了特征点提取和匹配的过程,从而提高了算法的速度和鲁棒性。

本文将分别介绍特征点的定义、光流法的原理和直接法在SLAM中的应用。

"5.3 展望": {} }}}请编写文章1.1 概述部分的内容1.2 文章结构文章结构章节为了更好地组织和呈现论文内容,通常包括以下几个部分:1. 引言:介绍研究背景、问题意义和研究现状,引出文章的主题和目的。

2. 文章结构:概述文中各个章节的内容和主题,提供读者整体了解文章结构的指引。

3. 主体部分:包括对特征点、光流法和直接法的详细介绍和讨论。

4. 结论:总结论文的主要发现和观点,强调研究的贡献和局限性,提出展望和未来研究方向。

5. 参考文献:列出引用过的文献和资料,为读者提供查证和深入研究的依据。

在文章结构部分中,我们将对以上内容进行详细展开,并说明各个章节的主要内容和关联性,使读者能够更好地理解整篇文章的脉络和逻辑思路。

1.3 目的本文的目的是探讨特征点、光流法和直接法在计算机视觉和SLAM (Simultaneous Localization and Mapping)领域的应用。

通过对特征点的定义、检测算法以及在计算机视觉中的应用进行介绍,读者可以更加深入地了解特征点在图像处理中的重要性和作用。

同时,对光流法和直接法的概念、原理和在运动估计以及SLAM中的具体应用进行详细讨论,旨在帮助读者了解这两种方法在实际场景中的工作原理和优缺点。

通过本文的阐述,读者可以更好地理解和应用特征点、光流法和直接法在计算机视觉和SLAM领域中的重要性,为相关研究和应用提供指导和参考。

光流法(OpticalFlowMethod)

光流法(OpticalFlowMethod)

光流法(OpticalFlowMethod)在计算机视觉中,光流法即可用于运动目标检测,也可以用于目标跟踪。

本文主要介绍光流法在运动目标检测和目标跟踪中的区别与联系。

1、光流与光流场光流的概念最初是由 Gibson 于 1950 年首先提出来的。

当人的眼睛观察运动物体时,物体的景象在人眼的视网膜上形成一系列连续变化的图像,这一系列连续变化的信息不断“流过”视网膜(即图像平面),好像是一种光的“流”,故称之为光流。

光流表达图像的变化,包含目标运动的信息,可用来确定目标的运动。

光流三个要素:一是运动速度场,这是形成光流的必要条件;二是带光学特征的部分例如有灰度的象素点,它可以携带运动信息;三是成像投影从场景到图像平面,因而能被观察到。

定义光流以点为基础,具体来说,设(u, v) 为图像点 (x, y) 的光流,则把 (x, y, u, v) 称为光流点。

所有光流点的集合称为光流场。

当带光学特性的物体在三维空间运动时,在图像平面上就形成了相应的图像运动场,或称为图像速度场。

在理想情况下,光流场对应于运动场。

总而言之,光流是由图像的亮度变化形成的,因此,光流场近似于运动场。

2、光流场的计算2.1、光流约束方程光流场的计算最初是由 Horn 和 Schunck[1]于 1981 年提出的,而后由 Lueas 和 Kanad[2]提出了改进光流算法。

光流法的核心就是求解出运动目标的光流,即速度。

根据视觉感知原理,客观物体在空间上一般是相对连续运动的,在运动过程中,投射到传感器平面上的图像实际上也是连续变化的。

为此可以假设瞬时灰度值不变,即灰度不变性原理。

由此可以得到光流基本方程,灰度对时间的变化率等于灰度的空间梯度与光流速度的点积。

如下:约束方程只有一个,而方程的变量有两个,在这种情况下无法求得 u 和 v 的确切值。

这种不确定性称为孔径问题(aperture problem)。

此时需要引入另外的约束条件,从不同的角度引入约束条件,导致了不同的光流场计算方法。

光流匹配算法 -回复

光流匹配算法 -回复

光流匹配算法-回复光流匹配算法:理论与应用引言:光流是计算机视觉领域中的一项重要研究内容,它可以用于目标跟踪、运动估计、深度计算等多个应用领域。

光流匹配算法是一种基于图像序列的方法,通过对图像的像素点进行跟踪和匹配,从而获取图像序列中物体的运动信息。

本文将以光流匹配算法为主题,详细介绍该算法的原理、实现步骤以及应用领域。

一、光流的定义与原理光流是指在连续时间的两幅图像之间,同一点的运动矢量。

它是由图像序列中不同帧的像素对应关系得到的。

光流的计算过程基于两个基本原理:一致性原理和亮度恒定性原理。

1. 一致性原理一致性原理假设在一个图像序列中,同一物体的不同帧图像中的像素点具有相同的运动矢量。

这是基于物体在连续的时间间隔内,其运动状态是相对连续稳定的。

2. 亮度恒定性原理亮度恒定性原理假设在图像序列中,一个像素点的灰度值在连续帧中保持不变。

这是因为在一个相对较小的时间间隔内,只要物体的运动速度不过大,像素的灰度值不会发生显著改变。

基于以上原理,光流匹配算法通过图像序列中的像素点间的灰度值变化,计算出像素点的运动矢量,从而实现物体运动信息的获取。

二、光流匹配算法的步骤光流匹配算法主要包括以下步骤:图像预处理、特征提取、匹配计算和结果优化。

1. 图像预处理图像预处理包括对原始图像进行去噪、灰度化、边缘检测等操作,以提高后续处理步骤的准确性和稳定性。

2. 特征提取特征提取是指从图像中提取出具有代表性的局部区域,用于计算光流。

常用的特征提取算法有Harris角点检测、SIFT、SURF等。

3. 匹配计算匹配计算是光流匹配算法的核心步骤,它通过计算相邻帧中提取到的特征点之间的灰度变化,得到光流场。

常用的光流计算算法有Lucas-Kanade 算法、Horn-Schunck算法等。

4. 结果优化结果优化是对得到的光流场进行滤波和平滑处理,以减少噪声和误差,提高光流计算的准确性和稳定性。

常用的结果优化算法有中值滤波、高斯滤波等。

【视觉SLAM十四讲】直接法视觉里程计

【视觉SLAM十四讲】直接法视觉里程计

2 LK 光流(5分,约3小时)2.1光流文献综述(1分)我们课上演示了Lucas-Kanade 稀疏光流,用OpenCV 函数实现了光流法追踪特征点。

实际上,光流法有很长时间的研究历史,直到现在人们还在尝试用Deeplearning 等方法对光流进行改进[1,2]。

本题将指导你完成基于Gauss-Newton 的金字塔光流法。

首先,请阅读文献[3](paper 目录下提供了pdf ),回答下列问题。

问题:1. 按此文的分类,光流法可分为哪几类?答:作者在文中对光流法按照两种不同的方法进行分类。

➢ 按照估计的是参数的叠加增量还是增量Warp 将光流法分为叠加(additional)和组合(compositional)算法➢ 按照Warp 更新规则可以将光流法分为前向(forward )和逆向/反向(inverse)两种算法综上:可以分4类,分别是 FA(Forward Additional), FC(Forward Composition), (Inverse Additional) 和 IC(Inverse Compositional)。

2. 在compositional 中,为什么有时候需要做原始图像的wrap ?该wrap 有何物理意义?答: 与Lucas-Kanade 算法中那样简单地将迭代的更新 p ∆添加到当前估计的参数p 不同,组合(compositional )算法中,对扭曲();W x p ∆的增量更新必须由Warp 的当前估计组成() ;Wx p 。

这两个 warp 的组合可能更复杂。

因此,我们对 warp 集合有两个要求: 1)warp 集合必须包含 identity warp 。

2)warp 集合必须在组合运算中闭合。

需要在当前位姿估计之前引入增量式 warp (incremental warp )以建立半群约束要求(the semi-group requirement )。

calcopticalflowpyrlk 用法

calcopticalflowpyrlk 用法

Calcopticalflowpyrlk是OpenCV中的一个函数,用于计算稀疏特征光流。

在计算机视觉中,光流是指图像中的像素随着时间的变化而产生的位移。

光流可以用来估计目标的运动轨迹,对于运动跟踪、目标检测等任务具有重要意义。

1. 算法原理calcopticalflowpyrlk算法是基于图像金字塔的Lucas-Kanade算法的改进版本。

它通过构建图像金字塔来实现多尺度处理,从而提高光流的稳定性和精度。

该算法首先对输入的两幅图像进行金字塔分解,然后从粗到细依次计算光流,最终得到目标的像素位移。

2. 输入参数calcopticalflowpyrlk函数的输入参数包括当前帧图像、前一帧图像、前一帧的特征点、输出的特征点位置、特征点的状态等。

其中,前一帧的特征点可以通过GoodFeaturesToTrack函数或其他方式获得。

3. 输出结果calcopticalflowpyrlk函数的输出结果包括当前帧的特征点位置、特征点的运动状态等。

这些结果可以用来进行目标跟踪、运动分析等应用。

4. 使用步骤使用calcopticalflowpyrlk函数进行光流计算的步骤如下:(1)导入OpenCV库import cv2(2)读取输入的两幅图像prev_img = cv2.imread('prev.jpg')curr_img = cv2.imread('curr.jpg')(3)获取前一帧的特征点prev_pts = cv2.goodFeaturesToTrack(prev_img, maxCorners=100, qualityLevel=0.01, minDistance=10)(4)调用calcopticalflowpyrlk函数计算光流curr_pts, status, err = cv2.calcOpticalFlowPyrLK(prev_img, curr_img, prev_pts, None)(5)根据光流结果进行目标跟踪等应用...5. 注意事项在使用calcopticalflowpyrlk函数时,需要注意以下几点:(1)输入的两幅图像应该是连续的帧,且图像尺寸应该相同。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

基于OpenCV的三种光流算法实现源码及测试结果本文包括三种基于OpenCV的光流算法实现源码及测试结果。

具体为HS算法,LK算法,和ctfLK算法,算法的原实现作者是Eric Yuan,这里是作者的博客主页:http://eric-yuan.me。

本文对这三种光流算法进行了相关调试及结果验证,供大家在自己的项目开发中参考。

1.第一种:HS光流法(作者HORN 和SCHUNCK)#include"opencv2/core/core.hpp"#include"opencv2/imgproc/imgproc.hpp"#include"opencv2/highgui/highgui.hpp"#include<math.h>#include<fstream>#include<iostream>using namespace cv;using namespace std;#define ATD at<double>#define elif else if#ifndef bool#define bool int#define false ((bool)0)#define true ((bool)1)#endifMat get_fx(Mat &src1, Mat &src2){Mat fx;Mat kernel = Mat::ones(2, 2, CV_64FC1);kernel.ATD(0, 0) = -1.0;kernel.ATD(1, 0) = -1.0;Mat dst1, dst2;filter2D(src1, dst1, -1, kernel);filter2D(src2, dst2, -1, kernel);fx = dst1 + dst2;return fx;}Mat get_fy(Mat &src1, Mat &src2){Mat fy;Mat kernel = Mat::ones(2, 2, CV_64FC1);kernel.ATD(0, 0) = -1.0;kernel.ATD(0, 1) = -1.0;Mat dst1, dst2;filter2D(src1, dst1, -1, kernel);filter2D(src2, dst2, -1, kernel);fy = dst1 + dst2;return fy;}Mat get_ft(Mat &src1, Mat &src2){Mat ft;Mat kernel = Mat::ones(2, 2, CV_64FC1);kernel = kernel.mul(-1);Mat dst1, dst2;filter2D(src1, dst1, -1, kernel);kernel = kernel.mul(-1);filter2D(src2, dst2, -1, kernel);ft = dst1 + dst2;return ft;}bool isInsideImage(int y, int x, Mat &m){int width = m.cols;int height = m.rows;if (x >= 0 && x < width && y >= 0 && y < height) return true;else return false;}double get_Average4(Mat &m, int y, int x){if (x < 0 || x >= m.cols) return 0;if (y < 0 || y >= m.rows) return 0;double val = 0.0;int tmp = 0;if (isInsideImage(y - 1, x, m)){++tmp;val += m.ATD(y - 1, x);}if (isInsideImage(y + 1, x, m)){++tmp;val += m.ATD(y + 1, x);}if (isInsideImage(y, x - 1, m)){++tmp;val += m.ATD(y, x - 1);}if (isInsideImage(y, x + 1, m)){++tmp;val += m.ATD(y, x + 1);}return val / tmp;}Mat get_Average4_Mat(Mat &m){Mat res = Mat::zeros(m.rows, m.cols, CV_64FC1);for (int i = 0; i < m.rows; i++){for (int j = 0; j < m.cols; j++){res.ATD(i, j) = get_Average4(m, i, j);}}return res;}void saveMat(Mat &M, string s){s += ".txt";FILE *pOut = fopen(s.c_str(), "w+");for (int i = 0; i<M.rows; i++){for (int j = 0; j<M.cols; j++){fprintf(pOut, "%lf", M.ATD(i, j));if (j == M.cols - 1) fprintf(pOut, "\n");else fprintf(pOut, " ");}}fclose(pOut);}void getHornSchunckOpticalFlow(Mat img1, Mat img2){double lambda = 0.05;Mat u = Mat::zeros(img1.rows, img1.cols, CV_64FC1);Mat v = Mat::zeros(img1.rows, img1.cols, CV_64FC1);Mat fx = get_fx(img1, img2);Mat fy = get_fy(img1, img2);Mat ft = get_ft(img1, img2);int i = 0;double last = 0.0;while (1){Mat Uav = get_Average4_Mat(u);Mat Vav = get_Average4_Mat(v);Mat P = fx.mul(Uav) + fy.mul(Vav) + ft;Mat D = fx.mul(fx) + fy.mul(fy) + lambda;Mat tmp;divide(P, D, tmp);Mat utmp, vtmp;utmp = Uav - fx.mul(tmp);vtmp = Vav - fy.mul(tmp);Mat eq = fx.mul(utmp) + fy.mul(vtmp) + ft;double thistime = mean(eq)[0];cout << "i = " << i << ", mean = " << thistime << endl;if (i != 0 && fabs(last) <= fabs(thistime)) break;i++;last = thistime;u = utmp;v = vtmp;}saveMat(u, "U");saveMat(v, "V");imshow("U", u);imshow("v", v);waitKey(20000);}int main(){Mat img1 = imread("table1.jpg", 0);Mat img2 = imread("table2.jpg", 0);img1.convertTo(img1, CV_64FC1, 1.0 / 255, 0);img2.convertTo(img2, CV_64FC1, 1.0 / 255, 0);getHornSchunckOpticalFlow(img1, img2);// waitKey(0);return 0;}图1 HS光流法原始图像(之一)图2:HS光流法计算结果:U图3 HS光流法计算结果:V2.第二种:LK光流法(作者LUCAS 和KANADE)#include"opencv2/core/core.hpp"#include"opencv2/imgproc/imgproc.hpp"#include"opencv2/highgui/highgui.hpp"#include<math.h>#include<fstream>#include<iostream>using namespace cv;using namespace std;#define ATD at<double>#define elif else if#ifndef bool#define bool int#define false ((bool)0)#define true ((bool)1)#endifMat get_fx(Mat &src1, Mat &src2){Mat fx;Mat kernel = Mat::ones(2, 2, CV_64FC1);kernel.ATD(0, 0) = -1.0;kernel.ATD(1, 0) = -1.0;Mat dst1, dst2;filter2D(src1, dst1, -1, kernel);filter2D(src2, dst2, -1, kernel);fx = dst1 + dst2;return fx;}Mat get_fy(Mat &src1, Mat &src2){Mat fy;Mat kernel = Mat::ones(2, 2, CV_64FC1);kernel.ATD(0, 0) = -1.0;kernel.ATD(0, 1) = -1.0;Mat dst1, dst2;filter2D(src1, dst1, -1, kernel);filter2D(src2, dst2, -1, kernel);fy = dst1 + dst2;return fy;}Mat get_ft(Mat &src1, Mat &src2){Mat ft;Mat kernel = Mat::ones(2, 2, CV_64FC1);kernel = kernel.mul(-1);Mat dst1, dst2;filter2D(src1, dst1, -1, kernel);kernel = kernel.mul(-1);filter2D(src2, dst2, -1, kernel);ft = dst1 + dst2;return ft;}bool isInsideImage(int y, int x, Mat &m){int width = m.cols;int height = m.rows;if (x >= 0 && x < width && y >= 0 && y < height) return true;else return false;}double get_Sum9(Mat &m, int y, int x){if (x < 0 || x >= m.cols) return 0;if (y < 0 || y >= m.rows) return 0;double val = 0.0;int tmp = 0;if (isInsideImage(y - 1, x - 1, m)){++tmp;val += m.ATD(y - 1, x - 1);}if (isInsideImage(y - 1, x, m)){++tmp;val += m.ATD(y - 1, x);}if (isInsideImage(y - 1, x + 1, m)){++tmp;val += m.ATD(y - 1, x + 1);}if (isInsideImage(y, x - 1, m)){++tmp;val += m.ATD(y, x - 1);}if (isInsideImage(y, x, m)){++tmp;val += m.ATD(y, x);}if (isInsideImage(y, x + 1, m)){++tmp;val += m.ATD(y, x + 1);}if (isInsideImage(y + 1, x - 1, m)){++tmp;val += m.ATD(y + 1, x - 1);}if (isInsideImage(y + 1, x, m)){++tmp;val += m.ATD(y + 1, x);}if (isInsideImage(y + 1, x + 1, m)){++tmp;val += m.ATD(y + 1, x + 1);}if (tmp == 9) return val;else return m.ATD(y, x) * 9;}Mat get_Sum9_Mat(Mat &m){Mat res = Mat::zeros(m.rows, m.cols, CV_64FC1);for (int i = 1; i < m.rows - 1; i++){for (int j = 1; j < m.cols - 1; j++){res.ATD(i, j) = get_Sum9(m, i, j);}}return res;}void saveMat(Mat &M, string s){s += ".txt";FILE *pOut = fopen(s.c_str(), "w+");for (int i = 0; i<M.rows; i++){for (int j = 0; j<M.cols; j++){fprintf(pOut, "%lf", M.ATD(i, j));if (j == M.cols - 1) fprintf(pOut, "\n");else fprintf(pOut, " ");}}fclose(pOut);}void getLucasKanadeOpticalFlow(Mat &img1, Mat &img2, Mat &u, Mat &v){Mat fx = get_fx(img1, img2);Mat fy = get_fy(img1, img2);Mat ft = get_ft(img1, img2);Mat fx2 = fx.mul(fx);Mat fy2 = fy.mul(fy);Mat fxfy = fx.mul(fy);Mat fxft = fx.mul(ft);Mat fyft = fy.mul(ft);Mat sumfx2 = get_Sum9_Mat(fx2);Mat sumfy2 = get_Sum9_Mat(fy2);Mat sumfxft = get_Sum9_Mat(fxft);Mat sumfxfy = get_Sum9_Mat(fxfy);Mat sumfyft = get_Sum9_Mat(fyft);Mat tmp = sumfx2.mul(sumfy2) - sumfxfy.mul(sumfxfy);u = sumfxfy.mul(sumfyft) - sumfy2.mul(sumfxft);v = sumfxft.mul(sumfxfy) - sumfx2.mul(sumfyft);divide(u, tmp, u);divide(v, tmp, v);saveMat(u, "U");saveMat(v, "V");imshow("U", u);imshow("V", v);waitKey(2000);}int main(){Mat img1 = imread("car1.jpg", 0);Mat img2 = imread("car2.jpg", 0);img1.convertTo(img1, CV_64FC1, 1.0 / 255, 0);img2.convertTo(img2, CV_64FC1, 1.0 / 255, 0);Mat u = Mat::zeros(img1.rows, img1.cols, CV_64FC1);Mat v = Mat::zeros(img1.rows, img1.cols, CV_64FC1);getLucasKanadeOpticalFlow(img1, img2, u, v);cout << "done" << endl;return 0;}图4 LK光流法原始图像(之一)图5 LK光流法计算结果:U图6 LK光流法计算结果:V3.第三种:ctfLK光流法(LK光流法的Coarse to fine版本)#include"opencv2/core/core.hpp"#include"opencv2/imgproc/imgproc.hpp"#include"opencv2/highgui/highgui.hpp"#include<math.h>#include<fstream>#include<iostream>using namespace cv;using namespace std;#define ATD at<double>#define ATF at<float>#define elif else if#ifndef bool#define bool int#define false ((bool)0)#define true ((bool)1)#endifMat get_fx(Mat &src1, Mat &src2){Mat fx;Mat kernel = Mat::ones(2, 2, CV_64FC1);kernel.ATD(0, 0) = -1.0;kernel.ATD(1, 0) = -1.0;Mat dst1, dst2;filter2D(src1, dst1, -1, kernel);filter2D(src2, dst2, -1, kernel);fx = dst1 + dst2;return fx;}Mat get_fy(Mat &src1, Mat &src2){Mat fy;Mat kernel = Mat::ones(2, 2, CV_64FC1);kernel.ATD(0, 0) = -1.0;kernel.ATD(0, 1) = -1.0;Mat dst1, dst2;filter2D(src1, dst1, -1, kernel);filter2D(src2, dst2, -1, kernel);fy = dst1 + dst2;return fy;}Mat get_ft(Mat &src1, Mat &src2){Mat ft;Mat kernel = Mat::ones(2, 2, CV_64FC1);kernel = kernel.mul(-1);Mat dst1, dst2;filter2D(src1, dst1, -1, kernel);kernel = kernel.mul(-1);filter2D(src2, dst2, -1, kernel);ft = dst1 + dst2;return ft;}bool isInsideImage(int y, int x, Mat &m){int width = m.cols;int height = m.rows;if (x >= 0 && x < width && y >= 0 && y < height) return true;else return false;}double get_Sum9(Mat &m, int y, int x){if (x < 0 || x >= m.cols) return 0;if (y < 0 || y >= m.rows) return 0;double val = 0.0;int tmp = 0;for (int i = -1; i <= 1; i++){for (int j = -1; j <= 1; j++){if (isInsideImage(y + i, x + j, m)){++tmp;val += m.ATD(y + i, x + j);}}}if (tmp == 9) return val;else return m.ATD(y, x) * 9;}Mat get_Sum9_Mat(Mat &m){Mat res = Mat::zeros(m.rows, m.cols, CV_64FC1);for (int i = 1; i < m.rows - 1; i++){for (int j = 1; j < m.cols - 1; j++){res.ATD(i, j) = get_Sum9(m, i, j);}}return res;}void saveMat(Mat &M, string s){s += ".txt";FILE *pOut = fopen(s.c_str(), "w+");for (int i = 0; i<M.rows; i++){for (int j = 0; j<M.cols; j++){fprintf(pOut, "%lf", M.ATD(i, j));if (j == M.cols - 1) fprintf(pOut, "\n");else fprintf(pOut, " ");}}fclose(pOut);}void getLucasKanadeOpticalFlow(Mat &img1, Mat &img2, Mat &u, Mat &v){Mat fx = get_fx(img1, img2);Mat fy = get_fy(img1, img2);Mat ft = get_ft(img1, img2);Mat fx2 = fx.mul(fx);Mat fy2 = fy.mul(fy);Mat fxfy = fx.mul(fy);Mat fxft = fx.mul(ft);Mat fyft = fy.mul(ft);Mat sumfx2 = get_Sum9_Mat(fx2);Mat sumfy2 = get_Sum9_Mat(fy2);Mat sumfxft = get_Sum9_Mat(fxft);Mat sumfxfy = get_Sum9_Mat(fxfy);Mat sumfyft = get_Sum9_Mat(fyft);Mat tmp = sumfx2.mul(sumfy2) - sumfxfy.mul(sumfxfy);u = sumfxfy.mul(sumfyft) - sumfy2.mul(sumfxft);v = sumfxft.mul(sumfxfy) - sumfx2.mul(sumfyft);divide(u, tmp, u);divide(v, tmp, v);}vector<Mat> getGaussianPyramid(Mat &img, int nLevels){vector<Mat> pyr;pyr.push_back(img);for (int i = 0; i < nLevels - 1; i++){Mat tmp;pyrDown(pyr[pyr.size() - 1], tmp);pyr.push_back(tmp);}return pyr;}void coarseToFineEstimation(Mat &img1, Mat &img2, Mat &u, Mat &v, int nLevels){vector<Mat> pyr1 = getGaussianPyramid(img1, nLevels);vector<Mat> pyr2 = getGaussianPyramid(img2, nLevels);Mat upu, upv;for (int i = nLevels - 1; i >= 0; i--){Mat tmpu = Mat::zeros(pyr1[i].rows, pyr1[i].cols, CV_64FC1);Mat tmpv = Mat::zeros(pyr2[i].rows, pyr2[i].cols, CV_64FC1);getLucasKanadeOpticalFlow(pyr1[i], pyr2[i], tmpu, tmpv);if (i != nLevels - 1){tmpu += upu;tmpv += upv;}if (i == 0){u = tmpu;v = tmpv;return;}pyrUp(tmpu, upu);pyrUp(tmpv, upv);Mat map1(upu.size(), CV_32FC2);Mat map2(upu.size(), CV_32FC2);for (int y = 0; y < map1.rows; ++y){for (int x = 0; x < map1.cols; ++x){Point2f f = Point2f((float)(upu.ATD(y, x)),(float)(upv.ATD(y, x)));map1.at<Point2f>(y, x) = Point2f(x + f.x / 2, y + f.y / 2);map2.at<Point2f>(y, x) = Point2f(x - f.x / 2, y - f.y / 2);}}Mat warped1, warped2;remap(pyr1[i - 1], warped1, map1, cv::Mat(), INTER_LINEAR);remap(pyr2[i - 1], warped2, map2, cv::Mat(), INTER_LINEAR);warped1.copyTo(pyr1[i - 1]);warped2.copyTo(pyr2[i - 1]);}}int getMaxLayer(Mat &img){int width = img.cols;int height = img.rows;int res = 1;int p = 1;while (1){int tmp = pow(2, p);if (width % tmp == 0) ++p;else break;}res = p;p = 1;while (1){int tmp = pow(2, p);if (height % tmp == 0) ++p;else break;}res = res < p ? res : p;return res;}int main(){Mat ori1 = imread("table1.jpg", 0);Mat ori2 = imread("table2.jpg", 0);Mat img1 = ori1(Rect(0, 0, 640, 448));Mat img2 = ori2(Rect(0, 0, 640, 448));int maxLayer = getMaxLayer(img1);cout << img1.rows << ", " << img1.cols << ", Max layer = " << maxLayer << endl;img1.convertTo(img1, CV_64FC1, 1.0 / 255, 0);img2.convertTo(img2, CV_64FC1, 1.0 / 255, 0);Mat u = Mat::zeros(img1.rows, img1.cols, CV_64FC1);Mat v = Mat::zeros(img1.rows, img1.cols, CV_64FC1);Mat u2 = Mat::zeros(img1.rows, img1.cols, CV_64FC1);Mat v2 = Mat::zeros(img1.rows, img1.cols, CV_64FC1);if (maxLayer >= 1){coarseToFineEstimation(img1, img2, u, v, maxLayer);saveMat(u, "U");saveMat(v, "V");}getLucasKanadeOpticalFlow(img1, img2, u2, v2);saveMat(u2, "U2");saveMat(v2, "V2");imshow("U2", u2);imshow("v2", v2);waitKey(20000);return 0;}图7 ctfLK光流法测试原始图像(之一)图8 ctfLK光流法计算结果:U2图9 ctfLK光流法计算结果:v2。

相关文档
最新文档