当前位置: 首页 > news >正文

Lucas-Kanade光流法详解

简介:个人学习分享,如有错误,欢迎批评指正。

光流(Optical Flow)描述的是图像序列中各像素点随时间的运动情况,是计算机视觉中的基本问题之一。光流问题涉及尝试找出一幅图像中的许多点在第二幅图像中移动的位置–通常是以视频序列完成的,因此可以假定第一幅图像中的大部分点框架都可以在第二幅图像中找到。光流可以用于场景中物体的运动估计,设置用于相机相对于整个场景的自运动估计。光流算法的理想输出是两帧图像中每个像素的速度的估计关联,或者等效的,一幅图像中每个像素的位移矢量,指示该像素在另一幅图像中的相对位置,如果图像中的每个像素都采用这种方法通常称为“稠密光流”。还有一种算法称为“稀疏光流”,仅仅只跟踪图像中某些点的子集,该算法通常是快速且可靠的,因为其将注意力只放在容易跟踪的特定点上,稀疏跟踪的计算成本远远低于稠密跟踪,这也导致了后者的研究基本被限制在了学术圈。

在这里插入图片描述

一、基本假设

Lucas-Kanade方法基于以下三个主要假设,这些假设简化了光流估计问题,使其在实际应用中可行:

  • 亮度恒定假设(Brightness Constancy Assumption):

    • 定义:同一物体点在连续两帧图像中的亮度值保持不变。

    • 数学表达:对于任意时间 t t t,点 ( x , y ) (x, y) (x,y) t t t t + Δ t t + \Delta t t+Δt时刻的亮度满足
      I ( x , y , t ) = I ( x + Δ x , y + Δ y , t + Δ t ) I(x, y, t) = I(x + \Delta x, y + \Delta y, t + \Delta t) I(x,y,t)=I(x+Δx,y+Δy,t+Δt)

    • 意义:将物体的运动与亮度变化联系起来,为光流估计提供约束条件。

  • 小位移假设(Small Motion Assumption):

    • 定义:物体的运动在时间间隔 Δ t \Delta t Δt内是微小的,位移 ( Δ x , Δ y ) (\Delta x, \Delta y) (Δx,Δy)较小。

    • 数学表达 Δ x \Delta x Δx Δ y \Delta y Δy相对于图像尺度而言足够小。

    • 意义:允许对图像亮度进行泰勒展开,并忽略高阶项,简化光流方程的线性化过程。

  • 局部光流一致性假设(Local Flow Constancy Assumption):

    • 定义:在一个小的邻域窗口内,所有像素点的光流向量相同。
    • 数学表达:对于窗口内的所有点 ( x i , y i ) (x_i, y_i) (xi,yi),光流向量 ( u , v ) (u, v) (u,v)相同。
    • 意义:将每个像素的光流问题转化为局部一致的运动估计,简化求解过程。

这些假设为光流估计提供了必要的约束,使得原本不可解的方程组变为可解的形式。然而,这些假设在实际应用中可能不完全成立,导致算法在某些场景下性能下降。

二、数学原理

1.亮度恒定方程的推导

基于亮度恒定假设,Lucas-Kanade方法首先建立亮度恒定方程,连接图像的空间变化与时间变化。

1.1 亮度恒定假设

I ( x , y , t ) I(x, y, t) I(x,y,t)表示在时间 t t t的图像,其中 ( x , y ) (x, y) (x,y)是像素坐标。对于一个物体点 ( x , y ) (x, y) (x,y),其在时间 t t t t + Δ t t + \Delta t t+Δt的亮度满足:
I ( x , y , t ) = I ( x + Δ x , y + Δ y , t + Δ t ) I(x, y, t) = I(x + \Delta x, y + \Delta y, t + \Delta t) I(x,y,t)=I(x+Δx,y+Δy,t+Δt)

其中, Δ x \Delta x Δx Δ y \Delta y Δy分别是物体点在 x x x y y y方向上的位移。

1.2 泰勒展开

由于假设 Δ t \Delta t Δt较小,位移 Δ x \Delta x Δx Δ y \Delta y Δy也较小,可以对 I ( x + Δ x , y + Δ y , t + Δ t ) I(x + \Delta x, y + \Delta y, t + \Delta t) I(x+Δx,y+Δy,t+Δt) ( x , y , t ) (x, y, t) (x,y,t)处进行泰勒展开,并忽略高阶项(即 O ( Δ x 2 , Δ y 2 , Δ t 2 ) O(\Delta x^2, \Delta y^2, \Delta t^2) O(Δx2,Δy2,Δt2)):
I ( x + Δ x , y + Δ y , t + Δ t ) ≈ I ( x , y , t ) + I x Δ x + I y Δ y + I t Δ t I(x + \Delta x, y + \Delta y, t + \Delta t) \approx I(x, y, t) + I_x \Delta x + I_y \Delta y + I_t \Delta t I(x+Δx,y+Δy,t+Δt)I(x,y,t)+IxΔx+IyΔy+ItΔt

其中, I x = ∂ I ∂ x I_x = \frac{\partial I}{\partial x} Ix=xI I y = ∂ I ∂ y I_y = \frac{\partial I}{\partial y} Iy=yI I t = ∂ I ∂ t I_t = \frac{\partial I}{\partial t} It=tI分别表示图像在 x x x y y y方向的空间梯度和时间梯度。

1.3 代入亮度恒定方程

根据亮度恒定假设,将泰勒展开式代入,得到:

I ( x , y , t ) + I x Δ x + I y Δ y + I t Δ t = I ( x , y , t ) I(x, y, t) + I_x \Delta x + I_y \Delta y + I_t \Delta t = I(x, y, t) I(x,y,t)+IxΔx+IyΔy+ItΔt=I(x,y,t)

两边减去 I ( x , y , t ) I(x, y, t) I(x,y,t),得到:
I x Δ x + I y Δ y + I t Δ t = 0 I_x \Delta x + I_y \Delta y + I_t \Delta t = 0 IxΔx+IyΔy+ItΔt=0

1.4 引入光流向量

定义光流向量 ( u , v ) (u, v) (u,v)为位移 ( Δ x , Δ y ) (\Delta x, \Delta y) (Δx,Δy)与时间间隔 Δ t \Delta t Δt的比值:

u = Δ x Δ t , v = Δ y Δ t u = \frac{\Delta x}{\Delta t}, \quad v = \frac{\Delta y}{\Delta t} u=ΔtΔx,v=ΔtΔy

将其代入上式,得到:
I x u + I y v + I t = 0 I_x u + I_y v + I_t = 0 Ixu+Iyv+It=0

这就是光流约束方程,它将图像的空间梯度、时间梯度与光流向量联系起来。其中 ( u , v ) (u, v) (u,v)代表两个方向(x方向和y方向)的移动速度,把 ( u , v ) (u, v) (u,v)计算出来,咱们的光流也就算出来了。

拿到当前帧,假设我们要计算点p的光流。其中 I x I_x Ix, I y I_y Iy都可以通过当前帧计算出来,而 I t I_t It 可以通过两帧的差分计算出来。所以,对于公式 I x u + I y v + I t = 0 I_x u + I_y v + I_t = 0 Ixu+Iyv+It=0 而言,未知数只有 u u u v v v

LK算法就是用来求解公式 I x u + I y v + I t = 0 I_x u + I_y v + I_t = 0 Ixu+Iyv+It=0 的。LK有一个window的概念,即我先划定一块区域比如(5x5)的像素区域,我们可以认为这块区域每个点的移动速度 u u u v v v是一致的。
首先, I x I_x Ix, I y I_y Iy是怎么得到的呢?对于光流法,咱们有个理想的假定就是:运动物体只会做平移。所以,亮度梯度咱们只需考虑当前帧的梯度即可。对于 I t I_t It 我们在两帧做一个差分就可以得到。

在这里插入图片描述

咱们看当前帧,也就是右边那个。 I x ( 3 , 3 ) = 0 I_x(3,3)=0 Ix(3,3)=0 是因为在x轴的数值左右都是3,没有梯度变化。 I y ( 3 , 3 ) = 1 I_y(3,3)=1 Iy(3,3)=1 是因为在y轴数值变化幅度为1。上图显示的情况,咱们只能算出y轴速度v,没有办法算出水平(x轴)速度u。这是因为该移动目标本身在x轴方向上就没有亮度变化。这也是一种典型的问题,叫孔径问题(Aperture Problem)。
孔径问题是讲,如果我们通过一个小孔来看全局,很多情况下的移动信息我们是看不出来的,这个用一张图就可以很好理解:
在这里插入图片描述
假设墙上破了一个洞,咱们通过这个洞来看一个图形的移动情况。假设,我们看到的是上图这种情况,绿色部分就是我们的视野,我们无法判断这个图形是否是沿着切线方向移动或者是静止。
那么基于小区域的LK光流法也可能遇到Aperture Problem,所以我们在追光流的时候,选点通常会选目标的角点(corner)。角点的情况如下图:
在这里插入图片描述
如果角点在视野内的话,咱们就可以判断这个图形的运动方向。
接着公式 I x u + I y v + I t = 0 I_x u + I_y v + I_t = 0 Ixu+Iyv+It=0 ,咱们如果通过window方式求解u、v,那还是很好办的。假设咱们取的是5x5的window,那么window内的每个点,我们都认为有一样的移动方向,咱们可以构建出25个等式。求解二元一次方程,通常两个等式就可以求解。但那是理想情况,实际情况是没有一组( u , v ) 能同时满足这25个等式,咱们要做的是最小化这个差异。

在这里插入图片描述
写成矩阵形式:
在这里插入图片描述

只需找到一组( u , v ),即上图中的x,满足

在这里插入图片描述
公式(5)
这里就可以用最小二乘法来进行优化了,分别求偏导得出导数为0的点的值就是最优值。可推导出,
在这里插入图片描述

这便是Lucas-Kanade光流算法的公式了。

2.光流约束方程的建立

对于上述问题进行重新表述:在单个像素点,光流约束方程 I x u + I y v + I t = 0 I_x u + I_y v + I_t = 0 Ixu+Iyv+It=0 包含两个未知数 u u u v v v,无法直接求解。Lucas-Kanade方法通过在一个小窗口内(如 3 × 3 3 \times 3 3×3像素)对多个像素点的光流约束方程进行组合,形成一个过定的线性方程组,从而估计出统一的 u u u v v v

2.1 局部窗口内的光流方程

假设在一个 N × N N \times N N×N的窗口内(共 n = N 2 n = N^2 n=N2个像素点),每个像素点 ( x i , y i ) (x_i, y_i) (xi,yi)都有一个光流约束方程:

I x i u + I y i v + I t i = 0 , i = 1 , 2 , … , n I_{x_i} u + I_{y_i} v + I_{t_i} = 0, \quad i = 1, 2, \dots, n Ixiu+Iyiv+Iti=0,i=1,2,,n

将这些方程表示为矩阵形式:

[ I x 1 I y 1 I x 2 I y 2 ⋮ ⋮ I x n I y n ] [ u v ] = [ − I t 1 − I t 2 ⋮ − I t n ] \begin{bmatrix} I_{x_1} & I_{y_1} \\ I_{x_2} & I_{y_2} \\ \vdots & \vdots \\ I_{x_n} & I_{y_n} \end{bmatrix} \begin{bmatrix} u \\ v \end{bmatrix} =\begin{bmatrix} -I_{t_1} \\ -I_{t_2} \\ \vdots \\ -I_{t_n} \end{bmatrix} Ix1Ix2IxnIy1Iy2Iyn [uv]= It1It2Itn

记作:
A ⋅ d = b A \cdot \mathbf{d} = \mathbf{b} Ad=b

其中:
A = [ I x 1 I y 1 I x 2 I y 2 ⋮ ⋮ I x n I y n ] , d = [ u v ] , b = [ − I t 1 − I t 2 ⋮ − I t n ] A = \begin{bmatrix} I_{x_1} & I_{y_1} \\ I_{x_2} & I_{y_2} \\ \vdots & \vdots \\ I_{x_n} & I_{y_n} \end{bmatrix}, \quad \mathbf{d} = \begin{bmatrix} u \\ v \end{bmatrix}, \quad \mathbf{b} = \begin{bmatrix} -I_{t_1} \\ -I_{t_2} \\ \vdots \\ -I_{t_n} \end{bmatrix} A= Ix1Ix2IxnIy1Iy2Iyn ,d=[uv],b= It1It2Itn

2.2 方程组的特性

  • 过定性:由于 n > 2 n > 2 n>2,方程组为过定的,存在多个方程与两个未知数。
  • 最小二乘解:通过最小化误差平方和,求解最优的 u u u v v v

3.最小二乘法求解

为了求解光流向量 ( u , v ) (u, v) (u,v),Lucas-Kanade方法采用最小二乘法,具体步骤如下:

3.1 最小二乘法基本原理

目标是找到 d = [ u v ] \mathbf{d} = \begin{bmatrix} u \ v \end{bmatrix} d=[u v],使得误差平方和最小:

E ( d ) = ∑ i = 1 n ( I x i u + I y i v + I t i ) 2 = ∥ A d − b ∥ 2 E(\mathbf{d}) = \sum_{i=1}^{n} (I_{x_i} u + I_{y_i} v + I_{t_i})^2 = \|A\mathbf{d} - \mathbf{b}\|^2 E(d)=i=1n(Ixiu+Iyiv+Iti)2=Adb2

3.2 正规方程(Normal Equations)

通过对 E ( d ) E(\mathbf{d}) E(d)关于 d \mathbf{d} d求导并设为零,可以得到正规方程:

A T A d = A T b A^T A \mathbf{d} = A^T \mathbf{b} ATAd=ATb

3.3 解的存在性与唯一性

  • 解存在的条件:矩阵 A T A A^T A ATA是对称且半正定的。
  • 解唯一性的条件 A T A A^T A ATA是正定的,即窗口内的梯度信息足够丰富(线性无关),矩阵 A A A的秩为2。

如果 A T A A^T A ATA是非奇异的(可逆),则正规方程有唯一解:

d = ( A T A ) − 1 A T b \mathbf{d} = (A^T A)^{-1} A^T \mathbf{b} d=(ATA)1ATb

3.4 解析解与数值求解方法

3.4.1 直接求逆

对于小窗口(如 3 × 3 3 \times 3 3×3),可以直接计算 ( A T A ) − 1 A T b (A^T A)^{-1} A^T \mathbf{b} (ATA)1ATb,得到光流向量。

3.4.2 矩阵分解方法
  • QR分解

    • 分解 A A A Q R Q R QR,其中 Q Q Q是正交矩阵, R R R是上三角矩阵。
    • 解方程 R d = Q T b R \mathbf{d} = Q^T \mathbf{b} Rd=QTb
  • 奇异值分解(SVD):

    • A A A分解为 U Σ V T U \Sigma V^T UΣVT,其中 U U U V V V是正交矩阵, Σ \Sigma Σ是对角矩阵。

    • 最小二乘解为 d = V Σ − 1 U T b \mathbf{d} = V \Sigma^{-1} U^T \mathbf{b} d=VΣ1UTb

    • 优点:提高数值稳定性,尤其在 A T A A^T A ATA接近奇异时。

  • Cholesky分解

    • 适用于正定矩阵 A T A A^T A ATA,通过分解为下三角矩阵和其转置的乘积,快速求解。
3.4.3 数值稳定性

在实际计算中, A T A A^T A ATA可能接近奇异,导致数值不稳定。为提高稳定性,可以采取以下措施:

  • 增加窗口内像素点数量:扩大窗口尺寸,提供更多约束条件。
  • 正则化:引入Tikhonov正则化(岭回归),在正规方程中加入正则项:
    d = ( A T A + λ I ) − 1 A T b \mathbf{d} = (A^T A + \lambda I)^{-1} A^T \mathbf{b} d=(ATA+λI)1ATb

其中, λ \lambda λ是正则化参数, I I I是单位矩阵。正则化可以改善矩阵 A T A A^T A ATA的条件数,增强解的稳定性。

鲁棒估计方法:如RANSAC,通过迭代剔除异常值,提高求解的鲁棒性。

3.5 最终光流向量

通过最小二乘法求解,得到光流向量:

d = [ u v ] = ( A T A ) − 1 A T b \mathbf{d} = \begin{bmatrix} u \\ v \end{bmatrix} = (A^T A)^{-1} A^T \mathbf{b} d=[uv]=(ATA)1ATb

其中, u u u v v v分别表示光流在 x x x y y y方向上的分量。

4.矩阵性质与数值稳定性

为了确保最小二乘解的有效性和稳定性,需要深入理解矩阵 A A A及其转置乘积 A T A A^T A ATA的性质。

4.1 矩阵 A A A的结构

矩阵 A A A的每一行对应窗口内一个像素点的空间梯度:

A = [ I x 1 I y 1 I x 2 I y 2 ⋮ ⋮ I x n I y n ] A = \begin{bmatrix} I_{x_1} & I_{y_1} \\ I_{x_2} & I_{y_2} \\ \vdots & \vdots \\ I_{x_n} & I_{y_n} \end{bmatrix} A= Ix1Ix2IxnIy1Iy2Iyn

4.2 矩阵 A T A A^T A ATA的性质

  • 对称性: A T A A^T A ATA是对称矩阵。
  • 正定性:
    • 如果窗口内的梯度向量 [ I x i I y i ] \begin{bmatrix} I_{xi} \ I_{yi} \end{bmatrix} [Ixi Iyi]线性无关,则 A T A A^TA ATA是正定的。
    • 否则, A T A A^T A ATA是半正定的。

4.3 条件数与数值稳定性

  • 条件数:矩阵 A T A A^T A ATA的条件数衡量了其数值稳定性。条件数越大,矩阵越接近奇异,数值求解越不稳定。
  • 梯度分布:窗口内梯度向量的分布影响 A T A A^T A ATA的条件数。例如:
    • 高纹理区域:梯度分布丰富, A T A A^T A ATA的条件数较小,数值稳定。
    • 低纹理区域:梯度分布稀疏或线性相关, A T A A^T A ATA的条件数较大,可能导致数值不稳定。

4.4 解决数值不稳定的方法

  • 窗口大小调整:在低纹理区域使用更大的窗口,增加方程组的约束。
  • 正则化:如前述,加入正则项改善条件数。
  • 奇异值分解:使用SVD求解最小二乘问题,避免直接求逆带来的数值不稳定。
  • 多尺度方法:通过构建图像金字塔,从粗到细估计光流,缓解局部条件数较差的问题。

三、算法步骤

Lucas-Kanade方法的具体实现包括以下主要步骤,每个步骤都包含若干子步骤和技术细节:

1. 图像预处理

图像预处理是Lucas-Kanade方法中的首要步骤,其主要目的是提高光流估计的准确性和鲁棒性。预处理通常包括图像平滑和梯度计算。

1.1. 图像平滑

目的:减小图像噪声对光流估计的影响,提升梯度计算的稳定性。

方法

  • 高斯滤波:最常用的平滑方法,通过卷积一个高斯核来平滑图像,减少高频噪声。
    G ( x , y ) = 1 2 π σ 2 e − x 2 + y 2 2 σ 2 G(x, y) = \frac{1}{2\pi\sigma^2} e^{-\frac{x^2 + y^2}{2\sigma^2}} G(x,y)=2πσ21e2σ2x2+y2

其中, σ \sigma σ是高斯核的标准差,控制平滑的程度。

  • 其他平滑方法:如中值滤波、双边滤波等,根据具体应用需求选择。

实现细节:

  • 核大小选择:核大小通常选择为奇数(如3×3、5×5、7×7),较大的核提供更强的平滑效果,但可能模糊细节。
  • 边缘处理:常用的方法包括镜像扩展、零填充等,以处理图像边缘的卷积操作。

1.2. 梯度计算

目的:计算图像在 x x x y y y方向的空间梯度 I x I_x Ix I y I_y Iy,以及时间梯度 I t I_t It,为光流约束方程提供必要的信息。

方法:

  • 空间梯度
    • Sobel算子:
      I x = [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] ∗ I I y = [ − 1 − 2 − 1 0 0 0 + 1 + 2 + 1 ] ∗ I I_x =\begin{bmatrix} -1 & 0 & +1 \\ -2 & 0 & +2 \\ -1 & 0 & +1 \end{bmatrix}* I \quad I_y = \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ +1 & +2 & +1 \end{bmatrix}* I Ix= 121000+1+2+1 IIy= 10+120+210+1 I

    • Scharr算子:类似于Sobel算子,但具有更好的旋转对称性和梯度响应。

    • Prewitt算子:另一种常见的梯度算子,与Sobel类似。

  • 时间梯度
    • 计算连续两帧图像 I t ( x , y ) = I ( x , y , t + Δ t ) − I ( x , y , t ) I_t(x, y) = I(x, y, t+\Delta t) - I(x, y, t) It(x,y)=I(x,y,t+Δt)I(x,y,t)
    • 可以使用更精确的方法,如中心差分法,计算时间梯度。

实现细节:

  • 边缘处理:与平滑步骤类似,需要处理图像边缘的梯度计算。

  • 梯度精度:选择合适的梯度算子和参数,以平衡梯度的精度和计算复杂度。

2. 窗口选择

窗口选择是Lucas-Kanade方法中的关键步骤,决定了局部光流估计的区域范围和光流一致性的假设。

2.1. 窗口类型

  • 固定窗口:常用的固定大小窗口(如3×3、5×5、7×7),适用于光流估计假设有效的区域。
  • 自适应窗口:根据图像内容动态调整窗口大小,如在纹理丰富区域使用较小窗口,在纹理稀疏区域使用较大窗口。

2.2. 窗口形状

  • 矩形窗口:最常用的窗口形状,覆盖一个矩形区域。
  • 其他形状:如圆形窗口,可以更好地适应某些应用需求。

2.3. 窗口中心的选择

  • 稠密光流:为图像中的每个像素点选择窗口,生成稠密的光流场。
  • 稀疏光流:仅为图像中的特征点(如角点、边缘点)选择窗口,减少计算量。

2.4. 窗口大小的选择

影响因素:

  • 运动范围:较大的窗口能够捕捉更大范围的运动,但可能降低局部精度。
  • 纹理信息:较大的窗口在纹理稀疏区域更有效,较小窗口在纹理丰富区域更精准。

选择策略:

  • 经验法则:根据应用场景和图像特性选择合适的窗口大小。
  • 多尺度方法:结合金字塔Lucas-Kanade方法,通过多尺度处理适应不同窗口大小。

3. 构建局部方程组

在选定的窗口内,构建光流约束方程组,以求解统一的光流向量。

3.1. 收集窗口内的梯度和时间梯度

对于窗口内的每个像素点 ( x i , y i ) (x_i, y_i) (xi,yi),收集其空间梯度 I x i I_{xi} Ixi I y i I_{yi} Iyi和时间梯度 I t i I_{ti} Iti

3.2. 构建矩阵$ A 和向量 和向量 和向量 b $

根据光流约束方程 I x u + I y v = − I t I_x u + I_y v = -I_t Ixu+Iyv=It,为窗口内的每个像素点构建一个方程,形成过定的线性方程组:

A = [ I x 1 I y 1 I x 2 I y 2 ⋮ ⋮ I x n I y n ] , b = [ − I t 1 − I t 2 ⋮ − I t n ] A = \begin{bmatrix} I_{x1} & I_{y1} \\ I_{x2} & I_{y2} \\ \vdots & \vdots \\ I_{xn} & I_{yn} \end{bmatrix}, \quad b = \begin{bmatrix} -I_{t1} \\ -I_{t2} \\ \vdots \\ -I_{tn} \end{bmatrix} A= Ix1Ix2IxnIy1Iy2Iyn ,b= It1It2Itn

其中,$ n $是窗口内像素点的数量。

3.3. 数据质量检查

在构建方程组之前,需检查数据质量:

  • 梯度的非零性:确保窗口内存在足够的梯度信息,避免平坦区域导致矩阵 A A A退化。
  • 异常值检测:剔除异常的梯度值或时间梯度,提升方程组的稳定性。

4. 最小二乘解法

通过最小二乘法求解过定的线性方程组,获得光流向量 ( u , v ) (u, v) (u,v)

4.1. 最小二乘法基本原理

目标是找到 ( u , v ) (u, v) (u,v),使得 ∣ A ⋅ [ u v ] − b ∣ 2 | A \cdot \begin{bmatrix} u \ v \end{bmatrix} - b |^2 A[u v]b2最小,即最小化误差平方和。

4.2. 解析解

当矩阵 A T A A^T A ATA可逆时,解析解为:

4.3 数值求解方法

直接求逆:在小窗口情况下(如3×3),可以直接计算 ( A T A ) − 1 A T b (A^T A)^{-1} A^T b (ATA)1ATb

矩阵分解

  • QR分解:分解 A A A Q R Q R QR,然后解 R [ u v ] = Q T b R \begin{bmatrix} u \ v \end{bmatrix} = Q^T b R[u v]=QTb
  • 奇异值分解(SVD):将 A A A分解为 U Σ V T U \Sigma V^T UΣVT,避免直接求逆,提高数值稳定性。
  • Cholesky分解:用于正定矩阵 A T A A^T A ATA的高效分解。

梯度下降法:在大规模问题或需要迭代优化时使用,但在小窗口情况下通常不必要。

4.4 正则化(可选)

为处理矩阵 A T A A^T A ATA接近奇异的情况,可以引入正则化项,如Tikhonov正则化:

[ u v ] = ( A T A + λ I ) − 1 A T b \begin{bmatrix} u \\ v \end{bmatrix} = (A^T A + \lambda I)^{-1} A^T b [uv]=(ATA+λI)1ATb

其中, λ \lambda λ是正则化参数, I I I是单位矩阵。

4.5. 解的有效性检查

  • 可逆性检查:确保 A T A A^T A ATA的条件数合理,避免数值不稳定。
  • 异常值检测:在解出 ( u , v ) (u, v) (u,v)后,检查是否存在异常值,如过大的光流向量,可能需要进一步处理。

5. 光流向量估计

将求解得到的光流向量 ( u , v ) (u, v) (u,v)赋值给窗口中心的像素点,完成局部光流估计。

5.1 光流场的构建

通过遍历整个图像,对每个需要计算光流的像素点执行上述步骤,构建整个图像的光流场。

5.2 数据结构选择

  • 稀疏光流:存储为特征点及其光流向量的列表,适用于稀疏光流估计。
  • 稠密光流:存储为与图像同尺寸的二维向量场,适用于稠密光流估计。

5.3 插值与填充(可选)

在某些应用中,可能需要对光流场进行插值或填充,以处理缺失的光流向量或增强光流场的连续性。

5.4 后处理(可选)

  • 光流平滑:对光流场进行平滑处理,减少噪声影响。
  • 边缘保留:在光流估计中保留运动边界,避免模糊运动区域。
  • 一致性检查:通过前向和后向光流的一致性,检测和剔除错误的光流向量。

6. 整体流程概述

以下是Lucas-Kanade方法的整体算法流程:

1.输入:连续两帧图像 I ( t ) I(t) I(t) I ( t + Δ t ) I(t+\Delta t) I(t+Δt)

2.预处理

  • I ( t ) I(t) I(t) I ( t + Δ t ) I(t+\Delta t) I(t+Δt)进行高斯平滑。
  • 计算 I x I_x Ix I y I_y Iy I t I_t It

3.光流估计:

对每个需要计算光流的像素点:

  • 选择包含该点的窗口。
  • 构建局部光流约束方程组。
  • 通过最小二乘法求解 ( u , v ) (u, v) (u,v)
  • 赋值给窗口中心点。

4.输出:光流场,包含每个像素点的光流向量 ( u , v ) (u, v) (u,v)

7.实例分析

1. 示例场景
假设在一个 3 × 3 3 \times 3 3×3的窗口内,有以下梯度信息:

Pixel I x I_x Ix I y I_y Iy I t I_t It
110-1
220-2
310-1
4010
5010
6010
710-1
820-2
910-1

2. 构建矩阵 A A A和向量 b b b
根据上表,矩阵 A A A和向量 b b b如下:

A = [ 1 0 2 0 1 0 0 1 0 1 0 1 1 0 2 0 1 0 ] , b = [ − ( − 1 ) − ( − 2 ) − ( − 1 ) − 0 − 0 − 0 − ( − 1 ) − ( − 2 ) − ( − 1 ) ] = [ 1 2 1 0 0 0 1 2 1 ] A = \begin{bmatrix} 1 & 0 \\ 2 & 0 \\ 1 & 0 \\ 0 & 1 \\ 0 & 1 \\ 0 & 1 \\ 1 & 0 \\ 2 & 0 \\ 1 & 0 \end{bmatrix}, \quad b = \begin{bmatrix} -(-1) \\ -(-2) \\ -(-1) \\ -0 \\ -0 \\ -0 \\ -(-1) \\ -(-2) \\-(-1)\end{bmatrix} =\begin{bmatrix} 1 \\ 2 \\ 1 \\ 0 \\ 0 \\ 0 \\ 1 \\ 2 \\ 1 \end{bmatrix} A= 121000121000111000 ,b= (1)(2)(1)000(1)(2)(1) = 121000121

3. 计算 A T A A^T A ATA A T b A^T b ATb

A T A = [ 1 2 1 0 0 0 1 2 1 0 0 0 1 1 1 0 0 0 ] [ 1 0 2 0 1 0 0 1 0 1 0 1 1 0 2 0 1 0 ] = [ 1 2 + 2 2 + 1 2 + 0 2 + 0 2 + 0 2 + 1 2 + 2 2 + 1 2 1 ⋅ 0 + 2 ⋅ 0 + 1 ⋅ 0 + 0 ⋅ 1 + 0 ⋅ 1 + 0 ⋅ 1 + 1 ⋅ 0 + 2 ⋅ 0 + 1 ⋅ 0 0 ⋅ 1 + 0 ⋅ 2 + 0 ⋅ 1 + 1 ⋅ 0 + 1 ⋅ 0 + 1 ⋅ 0 + 0 ⋅ 1 + 0 ⋅ 2 + 0 ⋅ 1 0 2 + 0 2 + 0 2 + 1 2 + 1 2 + 1 2 + 0 2 + 0 2 + 0 2 ] = [ 12 0 0 3 ] A^T A = \begin{bmatrix} 1 & 2 & 1 & 0 & 0 & 0 & 1 & 2 & 1 \\ 0 & 0 & 0 & 1 & 1 & 1 & 0 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 & 0 \\ 2 & 0 \\ 1 & 0 \\ 0 & 1 \\ 0 & 1 \\ 0 & 1 \\ 1 & 0 \\ 2 & 0 \\ 1 & 0 \end{bmatrix} =\begin{bmatrix} 1^2 + 2^2 + 1^2 + 0^2 + 0^2 + 0^2 + 1^2 + 2^2 + 1^2 & 1 \cdot 0 + 2 \cdot 0 + 1 \cdot 0 + 0 \cdot 1 + 0 \cdot 1 + 0 \cdot 1 + 1 \cdot 0 + 2 \cdot 0 + 1 \cdot 0 \\ 0 \cdot 1 + 0 \cdot 2 + 0 \cdot 1 + 1 \cdot 0 + 1 \cdot 0 + 1 \cdot 0 + 0 \cdot 1 + 0 \cdot 2 + 0 \cdot 1 & 0^2 + 0^2 + 0^2 + 1^2 + 1^2 + 1^2 + 0^2 + 0^2 + 0^2 \end{bmatrix} =\begin{bmatrix} 12 & 0 \\ 0 & 3 \end{bmatrix} ATA=[102010010101102010] 121000121000111000 =[12+22+12+02+02+02+12+22+1201+02+01+10+10+10+01+02+0110+20+10+01+01+01+10+20+1002+02+02+12+12+12+02+02+02]=[12003]

A T b = [ 1 2 1 0 0 0 1 2 1 0 0 0 1 1 1 0 0 0 ] [ 1 2 1 0 0 0 1 2 1 ] = [ 1 ⋅ 1 + 2 ⋅ 2 + 1 ⋅ 1 + 0 ⋅ 0 + 0 ⋅ 0 + 0 ⋅ 0 + 1 ⋅ 1 + 2 ⋅ 2 + 1 ⋅ 1 0 ⋅ 1 + 0 ⋅ 2 + 0 ⋅ 1 + 1 ⋅ 0 + 1 ⋅ 0 + 1 ⋅ 0 + 0 ⋅ 1 + 0 ⋅ 2 + 0 ⋅ 1 ] = [ 1 + 4 + 1 + 0 + 0 + 0 + 1 + 4 + 1 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 ] = [ 12 0 ] A^T b = \begin{bmatrix} 1 & 2 & 1 & 0 & 0 & 0 & 1 & 2 & 1 \\ 0 & 0 & 0 & 1 & 1 & 1 & 0 & 0 & 0 \end{bmatrix} \begin{bmatrix} 1 \\ 2 \\ 1 \\ 0 \\ 0 \\ 0 \\ 1 \\ 2 \\ 1 \end{bmatrix} =\begin{bmatrix} 1 \cdot 1 + 2 \cdot 2 + 1 \cdot 1 + 0 \cdot 0 + 0 \cdot 0 + 0 \cdot 0 + 1 \cdot 1 + 2 \cdot 2 + 1 \cdot 1 \\ 0 \cdot 1 + 0 \cdot 2 + 0 \cdot 1 + 1 \cdot 0 + 1 \cdot 0 + 1 \cdot 0 + 0 \cdot 1 + 0 \cdot 2 + 0 \cdot 1 \end{bmatrix} =\begin{bmatrix} 1 + 4 + 1 + 0 + 0 + 0 + 1 + 4 + 1 \\ 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 \end{bmatrix} =\begin{bmatrix} 12 \\ 0 \end{bmatrix} ATb=[102010010101102010] 121000121 =[11+22+11+00+00+00+11+22+1101+02+01+10+10+10+01+02+01]=[1+4+1+0+0+0+1+4+10+0+0+0+0+0+0+0+0]=[120]

4. 求解正规方程
正规方程为:
A T A d = A T b ⟹ [ 12 0 0 3 ] [ u v ] = [ 12 0 ] A^T A d = A^T b \implies \begin{bmatrix} 12 & 0 \\ 0 & 3 \end{bmatrix} \begin{bmatrix} u \\ v \end{bmatrix} =\begin{bmatrix} 12 \\ 0 \end{bmatrix} ATAd=ATb[12003][uv]=[120]

解得:

12 u = 12 ⟹ u = 1 3 v = 0 ⟹ v = 0 12u = 12 \implies u = 1 \\ 3v = 0 \implies v = 0 12u=12u=13v=0v=0

因此,光流向量为 ( u , v ) = ( 1 , 0 ) (u, v) = (1, 0) (u,v)=(1,0),表示图像在 x x x方向上以单位速度移动,而在 y y y方向上无运动。

5. 分析

  • 矩阵 A T A A^T A ATA的可逆性:在本例中, A T A A^T A ATA是对角矩阵,且对角元素均大于零,故可逆。
  • 条件数 A T A A^T A ATA的条件数为 λ max λ min = 12 3 = 4 \frac{\lambda_{\text{max}}}{\lambda_{\text{min}}} = \frac{12}{3} = 4 λminλmax=312=4,较小,数值稳定。
  • 光流方向:光流仅在 x x x方向上有运动,符合光流向量的计算结果。

四、代码实例

简单版

import cv2
import numpy as npdef lucas_kanade_optical_flow(I1, I2, window_size=5, max_iterations=10):# 1. Preprocessing: Convert to grayscale if necessaryif len(I1.shape) == 3:I1 = cv2.cvtColor(I1, cv2.COLOR_BGR2GRAY)if len(I2.shape) == 3:I2 = cv2.cvtColor(I2, cv2.COLOR_BGR2GRAY)# 2. Smooth imagesI1_blur = cv2.GaussianBlur(I1, (5, 5), sigmaX=1.5)I2_blur = cv2.GaussianBlur(I2, (5, 5), sigmaX=1.5)# 3. Compute gradientsIx = cv2.Sobel(I1_blur, cv2.CV_64F, 1, 0, ksize=3)Iy = cv2.Sobel(I1_blur, cv2.CV_64F, 0, 1, ksize=3)It = I2_blur - I1_blur# 4. Initialize flow fieldflow_u = np.zeros(I1.shape)flow_v = np.zeros(I1.shape)# 5. Iterate over each pixelhalf_w = window_size // 2for y in range(half_w, I1.shape[0] - half_w):for x in range(half_w, I1.shape[1] - half_w):# Define windowIx_window = Ix[y - half_w : y + half_w + 1, x - half_w : x + half_w + 1].flatten()Iy_window = Iy[y - half_w : y + half_w + 1, x - half_w : x + half_w + 1].flatten()It_window = It[y - half_w : y + half_w + 1, x - half_w : x + half_w + 1].flatten()# Construct A and bA = np.vstack((Ix_window, Iy_window)).T  # Shape: (window_size^2, 2)b = -It_window  # Shape: (window_size^2,)# Check if A^T A is invertibleATA = A.T @ Aif np.linalg.cond(ATA) < 1 / np.finfo(float).eps:# Solve for (u, v) using least squaresnu, nv = np.linalg.lstsq(A, b, rcond=None)[0]flow_u[y, x] = nuflow_v[y, x] = nvelse:flow_u[y, x] = 0flow_v[y, x] = 0# Combine flow fieldsflow = np.stack((flow_u, flow_v), axis=2)return flow# 示例使用
if __name__ == "__main__":# 读取连续两帧图像I1 = cv2.imread('frame1.png')I2 = cv2.imread('frame2.png')# 计算光流flow = lucas_kanade_optical_flow(I1, I2, window_size=5)# 可视化光流hsv = np.zeros_like(I1)hsv = cv2.cvtColor(hsv, cv2.COLOR_BGR2HSV)mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])hsv[...,0] = ang * 180 / np.pi / 2hsv[...,1] = 255hsv[...,2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)rgb_flow = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)cv2.imshow('Optical Flow', rgb_flow)cv2.waitKey(0)cv2.destroyAllWindows()

复杂版:图像对齐融合中的光流法

import rawpy
import cv2
import numpy as np
import matplotlib.pyplot as plt
import imutilsdef read_dng(file_path, scale=1.0):"""读取DNG图像并转换为RGB和灰度图像。Args:file_path (str): DNG图像文件路径。scale (float): 图像缩放比例,默认为1.0(不缩放)。Returns:tuple: (RGB图像, 灰度图像)"""with rawpy.imread(file_path) as raw:# 使用raw.postprocess将RAW数据转换为RGB图像,设置输出位深为16位rgb = raw.postprocess(use_camera_wb=True, no_auto_bright=True, output_bps=16)if scale != 1.0:rgb = cv2.resize(rgb, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR)# 将RGB图像转换为灰度图gray = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)# 检查灰度图像的类型if gray.dtype == np.uint16:# 16-bit到8-bit的转换,归一化gray = cv2.convertScaleAbs(gray, alpha=(255.0 / 65535.0))elif gray.dtype != np.uint8:# 如果不是8位,进行归一化并转换为8位gray = cv2.normalize(gray, None, 0, 255, cv2.NORM_MINMAX)gray = gray.astype(np.uint8)# 高斯平滑,减少噪声gray = cv2.GaussianBlur(gray, (5, 5), 0)return rgb, graydef detect_features(gray, maxCorners=500, qualityLevel=0.3, minDistance=7, blockSize=7):"""使用Shi-Tomasi方法检测特征点。Args:gray (ndarray): 灰度图像。maxCorners (int): 最大特征点数。qualityLevel (float): 质量水平阈值。minDistance (float): 特征点之间的最小距离。blockSize (int): 阻塞大小。Returns:ndarray: 检测到的特征点坐标。"""feature_params = dict(maxCorners=maxCorners,qualityLevel=qualityLevel,minDistance=minDistance,blockSize=blockSize)p = cv2.goodFeaturesToTrack(gray, mask=None, **feature_params)return pdef track_features(old_gray, new_gray, p0, lk_params):"""使用Lucas-Kanade方法跟踪特征点。Args:old_gray (ndarray): 上一帧的灰度图像。new_gray (ndarray): 当前帧的灰度图像。p0 (ndarray): 上一帧的特征点坐标。lk_params (dict): Lucas-Kanade方法参数。Returns:tuple: (新特征点, 上一帧的特征点, 状态)"""p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, new_gray, p0, None, **lk_params)if p1 is None:return None, None, Nonegood_new = p1[st == 1]good_old = p0[st == 1]return good_new, good_old, stdef estimate_global_transform(good_new, good_old):"""使用RANSAC方法估计全局仿射变换矩阵。Args:good_new (ndarray): 当前帧的特征点。good_old (ndarray): 参考帧的特征点。Returns:tuple: (变换矩阵, inliers mask)"""if len(good_new) < 3:return None, NoneM, mask = cv2.estimateAffinePartial2D(good_old, good_new, method=cv2.RANSAC, ransacReprojThreshold=5.0)return M, maskdef estimate_local_transforms(good_new, good_old, grid_size=(8, 8), block_size=50):"""分块估计局部仿射变换矩阵。Args:good_new (ndarray): 当前帧的特征点。good_old (ndarray): 参考帧的特征点。grid_size (tuple): 网格大小(x, y)。block_size (int): 每个块的大小。Returns:dict: 每个块的变换矩阵。"""transforms = {}for x in range(grid_size[0]):for y in range(grid_size[1]):# 定义块的区域mask = (good_new[:, 0] > x * block_size) & (good_new[:, 0] < (x + 1) * block_size) & \(good_new[:, 1] > y * block_size) & (good_new[:, 1] < (y + 1) * block_size)block_new = good_new[mask]block_old = good_old[mask]if len(block_new) >= 3:M, _ = cv2.estimateAffinePartial2D(block_old, block_new, method=cv2.RANSAC, ransacReprojThreshold=5.0)if M is not None:transforms[(x, y)] = Mreturn transformsdef apply_global_transform(img, M):"""应用全局仿射变换矩阵到图像。Args:img (ndarray): 目标图像。M (ndarray): 仿射变换矩阵。Returns:ndarray: 变换后的图像。"""if M is None:return imgrows, cols, _ = img.shapewarped = cv2.warpAffine(img, M, (cols, rows), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT)return warpeddef apply_local_transforms(img, transforms, grid_size=(8, 8), block_size=50):"""应用分块的局部仿射变换矩阵到图像。Args:img (ndarray): 目标图像。transforms (dict): 每个块的变换矩阵。grid_size (tuple): 网格大小(x, y)。block_size (int): 每个块的大小。Returns:ndarray: 变换后的图像。"""warped = np.zeros_like(img)for x in range(grid_size[0]):for y in range(grid_size[1]):M = transforms.get((x, y))if M is not None:# 定义块的区域start_x = x * block_sizestart_y = y * block_sizeend_x = (x + 1) * block_sizeend_y = (y + 1) * block_size# 提取块block = img[start_y:end_y, start_x:end_x]if block.shape[0] == 0 or block.shape[1] == 0:continue# 应用变换warped_block = cv2.warpAffine(block, M, (block.shape[1], block.shape[0]), flags=cv2.INTER_LINEAR,borderMode=cv2.BORDER_REFLECT)warped[start_y:end_y, start_x:end_x] = warped_blockreturn warpeddef laplacian_pyramid_fusion(img1, img2, levels=5):"""使用拉普拉斯金字塔方法融合两张图像。Args:img1 (ndarray): 参考图像。img2 (ndarray): 对齐后的图像。levels (int): 金字塔层数。Returns:ndarray: 融合后的图像。"""# 构建高斯金字塔G1 = img1.copy()G2 = img2.copy()gp1 = [G1]gp2 = [G2]for i in range(levels):G1 = cv2.pyrDown(G1)G2 = cv2.pyrDown(G2)gp1.append(G1)gp2.append(G2)# 构建拉普拉斯金字塔lp1 = [gp1[levels - 1]]lp2 = [gp2[levels - 1]]for i in range(levels - 1, 0, -1):GE1 = cv2.pyrUp(gp1[i])GE2 = cv2.pyrUp(gp2[i])L1 = cv2.subtract(gp1[i - 1], GE1)L2 = cv2.subtract(gp2[i - 1], GE2)lp1.append(L1)lp2.append(L2)# 融合拉普拉斯金字塔LS = []for l1, l2 in zip(lp1, lp2):rows, cols, dpt = l1.shapels = np.hstack((l1, l2))LS.append(ls)# 重建图像fused_image = LS[0]for i in range(1, levels):fused_image = cv2.pyrUp(fused_image)fused_image = cv2.add(fused_image, LS[i])return fused_imagedef main():# 多帧DNG图像路径列表(请替换为实际的DNG文件路径)dng_files = ['./input_file/payload_N000.dng', './input_file/payload_N001.dng', './input_file/payload_N002.dng', './input_file/payload_N003.dng']# 读取所有DNG图像images_rgb = []images_gray = []for file in dng_files:rgb, gray = read_dng(file, scale=1.0)  # 根据需要调整scaleimages_rgb.append(rgb)images_gray.append(gray)# 设定参考帧为第一帧ref_rgb = images_rgb[0]ref_gray = images_gray[0]# 特征点检测参数feature_params = dict(maxCorners=500,qualityLevel=0.3,minDistance=7,blockSize=7)# Lucas-Kanade光流参数lk_params = dict(winSize=(15, 15),maxLevel=4,  # 使用更高的金字塔层数处理更大位移criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))# 检测参考帧的特征点p0 = detect_features(ref_gray, **feature_params)if p0 is None:print("参考帧未检测到任何特征点。")return# 初始化融合图像列表fused_images = [ref_rgb.copy()]# 依次处理后续帧for i in range(1, len(images_rgb)):print(f"Processing frame {i + 1}/{len(images_rgb)}...")current_rgb = images_rgb[i]current_gray = images_gray[i]# 跟踪特征点good_new, good_old, st = track_features(ref_gray, current_gray, p0, lk_params)if good_new is None or good_old is None:print(f"No features tracked in frame {i + 1}. Skipping...")continue# 全局变换矩阵估计M_global, mask_global = estimate_global_transform(good_new, good_old)if M_global is None:print(f"Global transform estimation failed for frame {i + 1}. Skipping...")continue# 应用全局变换对齐图像aligned_img = apply_global_transform(current_rgb, M_global)# 局部变换矩阵估计(分块)transforms_local = estimate_local_transforms(good_new, good_old, grid_size=(8, 8), block_size=50)# 应用局部变换对齐图像aligned_img_local = apply_local_transforms(aligned_img, transforms_local, grid_size=(8, 8), block_size=50)# 图像融合(拉普拉斯金字塔融合)fused_img = laplacian_pyramid_fusion(ref_rgb, aligned_img, levels=5)# 更新参考帧为当前融合结果ref_rgb = fused_img.copy()ref_gray = cv2.cvtColor(ref_rgb, cv2.COLOR_RGB2GRAY)ref_gray = cv2.GaussianBlur(ref_gray, (5, 5), 0)# 重新检测特征点# p0 = detect_features(ref_gray, **feature_params)if p0 is None:print(f"No features detected in fused frame {i + 1}.")# 添加到融合图像列表fused_images.append(fused_img)# 显示最终融合结果plt.figure(figsize=(10, 10))plt.imshow(cv2.cvtColor(fused_images[-1], cv2.COLOR_RGB2BGR))plt.title('Fused Image')plt.axis('off')plt.show()# 保存最终融合结果cv2.imwrite('fused_image.png', cv2.cvtColor(fused_images[-1], cv2.COLOR_RGB2BGR))print("Fused image saved as 'fused_image.png'.")if __name__ == "__main__":main()

五、优缺点分析

1. 优点

  • 计算效率高:Lucas-Kanade方法基于局部线性假设,计算简单,适合实时应用。
  • 实现简单:算法流程明确,易于实现,适合嵌入式系统和实时视频处理。
  • 鲁棒性强:通过窗口内多个像素点的约束,提高了对噪声和误差的鲁棒性。
  • 适用性广:在小位移和亮度变化较小的情况下,具有较高的准确性。

2. 缺点

  • 小位移限制:对于大位移或快速运动的场景,单次估计可能不准确,需多次迭代或金字塔方法。

  • 纹理依赖性:依赖于图像的梯度信息,对于纹理稀疏或均匀区域,光流估计不准确。

  • 遮挡处理困难:难以处理复杂的遮挡情况,可能导致错误的运动估计。

  • 假设限制:局部恒定光流和亮度恒定假设在实际场景中可能不完全成立,影响估计精度。

Lucas-Kanade方法作为光流估计的经典算法,凭借其简洁高效的特点在计算机视觉领域占据重要地位。尽管存在一些局限性,但通过各种改进和结合现代技术,Lucas-Kanade方法及其衍生算法在实际应用中依然表现出色。随着深度学习和计算能力的提升,未来光流估计将朝着更加精确、高效和智能化的方向发展,Lucas-Kanade方法仍将在其中发挥基础性作用。

参考文献:
经典光流算法Lucas-Kanade(有图助理解)

结~~~

相关文章:

Lucas-Kanade光流法详解

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正。 光流&#xff08;Optical Flow&#xff09;描述的是图像序列中各像素点随时间的运动情况&#xff0c;是计算机视觉中的基本问题之一。光流问题涉及尝试找出一幅图像中的许多点在第二幅图像中移动的…...

基于YOLO5的机械臂视觉抓取实现

前言&#xff1a; 机器人视觉系统标定是保证机器人精确运动和控制的关键环节之一。通过对机器人的运动学进行分析&#xff0c;可以精确计算出机器人末端执行器的位姿信息&#xff0c;从而实现对目标的精准定位和控制。相机标定是计算机视觉和图像处理中的重要步骤&#xff0c;标…...

Git 仓库与文件管理笔记

Git 的三种仓库概念 本地仓库 (Local Repository) 位于本地 .git 文件夹中通过 git init 或 git clone 创建存储完整的项目历史和分支信息 远程仓库 (Remote Repository) 位于 GitHub、GitLab 等平台服务器使用 git remote -v 查看所有远程仓库默认远程仓库名通常为 origin 工…...

Qt 5.14.2 学习记录 —— 오 信号与槽机制(2)

文章目录 1、信号与槽的参数2、为什么要有信号槽机制&#xff1f;3、断开并重新连接4、槽函数lambda写法 1、信号与槽的参数 信号和槽可以带参数&#xff0c;当信号带有参数时&#xff0c;槽的参数必须和信号的一致&#xff0c;此时发送信号就可以给信号函数传递实参&#xff…...

043_小驰私房菜_MTK Camera,Hal层将camera型号写到property属性中

【问题背景】 app层需要知道当前设备的摄像头型号,然后做一些差异化处理。底下如何上报这个摄像头型号? 【分析】 在kernel和hal层,都是有地方能获取到当前摄像头的型号,就看在哪里添加方便。获取到摄像头硬件型号后,将其写入到property属性, 然后app就可以通过读取该…...

Java线程

目录 一、线程入门 二、线程同步 三、死锁 四、线程的方法 五、线程的流程图 六、线程池 一、线程入门 1.进程&#xff1a;每一个软件都是一个进程。 2.线程&#xff1a;进程是由多个线程组成的。 3.进程和线程的关系&#xff1a;一个进程是对应一个或者是多个线程的。…...

JMeter 的 If Controller:开启性能测试的智能大门

嘿&#xff0c;宝子们&#xff01;今天咱们就来聊聊 JMeter 里超级厉害的 If Controller&#xff0c;它就像是一把神奇的钥匙&#xff0c;能帮我们打开灵活测试的大门&#xff0c;让你的测试计划变得更加智能和高效。 一、If Controller 初印象 想象一下&#xff0c;你正在指…...

node内置模块之---os 模块

os 模块的作用 os 模块是 Node.js 的一个核心模块&#xff0c;提供了与操作系统交互的一些功能。它使得 Node.js 应用可以访问操作系统的底层信息&#xff0c;并执行一些系统级的操作&#xff0c;比如文件系统操作、环境变量、进程管理等。 os 模块的相关api 文件系统路径操…...

PgSQL如何用cmd命令行备份和还原数据库

一、备份 备份为压缩的二进制格式&#xff08;通常更快且占用空间更少&#xff09; pg_dump -U username -Fc -h hostname -p port -d dbname -F p -f backup.sql-U username&#xff1a;指定连接数据库的用户名&#xff08;默认是 postgres&#xff09;。-Fc&#xff1a;备…...

neo4j学习笔记

图数据库 图数据库是基于图论实现的一种NoSQL数据库&#xff0c;其数据存储结构和数据查询方式都是图论为基础的&#xff0c;图数据库主要用于存储更多的连接数据。 图论&#xff08;GraphTheory&#xff09;是数学的一个分支。图论以图为研究对象&#xff0c;图论的图是由若干…...

Halcon 显示异常

//For Halcon System HOperatorSet.SetSystem("clip_region", "false"); set_system( clip_region, false) *旋转 hom_mat2d_identity (HomMat2DIdentity1) hom_mat2d_rotate (HomMat2DIdentity1, rad( 90), 0, 0, HomMat2DRotate) affine_trans_region …...

2021年3月多省联考《申论》B卷真题解析

2021年福建公务员考试申论试题&#xff08;乡镇卷&#xff09; 材料一 在传统乡镇布局中&#xff0c;部分乡镇面积小、人口少&#xff0c;但管理机构、干部职数、机构编制、财政投入均不少&#xff0c;行政运行成本较高。合理调整乡镇行政区划&#xff0c;有助于统筹设置乡镇服…...

Mac iTerm2集成DeepSeek AI

1. 去deepseek官网申请api key&#xff0c;DeepSeek 2. 安装iTerm2 AI Plugin插件&#xff0c;https://iterm2.com/ai-plugin.html&#xff0c;插件解压后直接放到和iTerms相同的位置&#xff0c;默认就在/Applications 下 3. 配置iTerm2 4. 重启iTerm2,使用快捷键呼出AI对话…...

主机A与主机B建立TCP连接的三次握手过程

&#xff08; 1 &#xff09;主机 A 的 TCP 向主机 B 发出连接请求 SYN 报文段&#xff08;第一次握手&#xff09;。&#xff08; 1 分&#xff09; &#xff08; 2 &#xff09;一旦包含 SYN 报文段的 IP 数据报到达主机 B &#xff0c; SYN 报文段被从数据报…...

vue3 vite 动态加载路由遇到的问题

记录一下动态加载路由遇到的问题 正常使用import引入静态路由是没问题的 component: () > import(/components/ExampleComponent.vue)动态引入的时候写成import就不行了 由于后端给的路由格式比较反人类…我这边先递归把获取到的数据格式做了一个整合. const processedDa…...

仿生的群体智能算法总结之一(十种)

群体智能算法是一类通过模拟自然界中的群体行为来解决复杂优化问题的方法。以下是10种常见的群体智能算法: 编号 算法名称(英文) 算法名称(中文) 年份 作者 1 Ant Colony Optimization (ACO) 蚁群优化算法 1991 Marco Dorigo 2 Particle Swarm Optimization (PSO) 粒子群优…...

02pandas读取和保存数据的方法

pandas读取和保存数据的方法 一、pandas支持的数据格式二、pandas常用数据读取方法1. 准备工作2. 代码示例1.pandas数据读取常用的方法2. read_excel 方法&#xff08;1&#xff09;read_excel()方法&#xff1a;读取excel文件&#xff08;2&#xff09;head()方法&#xff1a;…...

【STM32项目】智能物联网驱动的生物样本培育与管理辅助系统(完整工程资料源码)

视频功能演示: 智能物联网驱动的生物样本培育与管理辅助系统 目录: 目录 视频功能演示: 目录:...

家教老师预约平台小程序系统开发方案

家教老师预约平台小程序系统将连接学生/家长与家教老师&#xff0c;提供一站式的家教服务预约体验。 一、用户需求分析1、家教老师&#xff1a;希望获得更多的学生资源&#xff0c;通过平台展示自己的教学特长和经验&#xff0c;管理个人日程&#xff0c;接收并确认预约请求&a…...

uniapp 自定义类微信支付键盘 (微信小程序)

效果图 代码: <view class"popups popupsB"><view class"appreciatePrice"><view class"appreciatePriceTitle">赞赏金额</view><view class"appreciatePriceInput flex ac">&#xffe5;<input typ…...

推荐5款局域网IP扫描工具,支持电脑+Android!

在日常网络管理中&#xff0c;快速扫描局域网中的设备和IP地址是一项基本但非常重要的任务。无论是排查网络问题还是进行设备管理&#xff0c;一款好用的 IP 扫描工具都能让你事半功倍。 如何选择适合自己需求的局域网 IP 扫描工具&#xff1f;有哪些功能强大又易于上手的工具…...

第十一章 图论

/* * 题目名称&#xff1a;连通图 * 题目来源&#xff1a;吉林大学复试上机题 * 题目链接&#xff1a;http://t.cn/AiO77VoA * 代码作者&#xff1a;杨泽邦(炉灰) */#include <iostream> #include <cstdio>using namespace std;const int MAXN 1000 10;int fathe…...

算法学习(21)—— BFS解决FloodFill问题

关于FloodFill 关于FloodFill算法&#xff0c;我们之前在dfs章节已经介绍过了&#xff1a;算法学习&#xff08;17&#xff09;—— FloodFill算法-CSDN博客 下面是用bfs宽搜来解决的实例 部分OJ题详解 733. 图像渲染 733. 图像渲染 - 力扣&#xff08;LeetCode&#xf…...

计算机网络基础(7)中科大郑铨老师笔记

应用层 目标&#xff1a;  网络应用的 原理&#xff1a;网络应用协议的概念和实现方面 传输层的服务模型 客户-服务器模式 对等模式(peerto-peer) 内容分发网络  网络应用的 实例&#xff1a;互联网流行的应用层协 议  HTTP  FTP  SMTP / POP3 / IMAP  DNS…...

CSS 之 响应式设计 前世今生

CSS系列文章目录 CSS 之 display 布局属性详解 CSS 之 position 定位属性详解一文搞懂flex布局 【弹性盒布局】 文章目录 CSS系列文章目录一、前言二、历史上的网站布局三、响应式设计之前的灵活布局四、响应式设计五、媒介查询六、灵活网格七、现代布局技术7.1 多栏布局7.2 伸…...

前端,npm install安装依赖卡在sill idealTree buildDeps(设置淘宝依赖)

输入npm i后&#xff0c;一直卡在sill idealTree buildDeps&#xff0c;一动不动 cnpm可以安装成功&#xff0c;但使用cnpm不会生成package-lock.json文件 设置淘宝依赖&#xff0c;依然卡住&#xff0c;挂梯子也不行 解决方法&#xff1a; // 取消ssl验证 set strict-ssl …...

【Rust自学】9.2. Result枚举与可恢复的错误 Pt.1:match、expect和unwrap处理错误

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 9.2.1. Result枚举 通常情况下&#xff0c;错误都没有严重到需要停止整个程序的地步。某个函数之所以运行失败或者是遇到错误通常是由一些…...

[241231] CachyOS 2024 年终总结:性能飞跃与社区繁荣 | ScyllaDB 宣布转向开源可用许可证

目录 CachyOS 2024 年终总结&#xff1a;性能飞跃与社区繁荣ScyllaDB 宣布转向开源可用许可证 CachyOS 2024 年终总结&#xff1a;性能飞跃与社区繁荣 CachyOS 2024 年的最后一个版本 (也是第 13 个版本) 已经发布&#xff0c;同时也迎来了辞旧迎新之际。让我们一起回顾 Cachy…...

9.系统学习-卷积神经网络

9.系统学习-卷积神经网络 简介输入层卷积层感受野池化层全连接层代码实现 简介 卷积神经网络是一种用来处理局部和整体相关性的计算网络结构&#xff0c;被应用在图像识别、自然语言处理甚至是语音识别领域&#xff0c;因为图像数据具有显著的局部与整体关系&#xff0c;其在图…...

java并发之AQS

一、简介 AQS&#xff0c;全称&#xff1a;AbstractQueuedSynchronizer&#xff0c;是一个JDK提供的用于构建锁、同步器等线程协作工具类的框架&#xff0c;内部维护FIFO双向队列&#xff08;双向链表实现&#xff09;。 AQS重要属性&#xff1a; // 表示同步状态。它既可以表…...

Synthesia技术浅析(一)

Synthesia 是一款利用人工智能技术生成视频内容的产品&#xff0c;其中变分自编码器&#xff08;Variational Autoencoder, VAE&#xff09;技术在视频生成过程中起到了关键作用。 1. 变分自编码器&#xff08;VAE&#xff09;概述 变分自编码器&#xff08;VAE&#xff09;是…...

SQL偏移类窗口函数—— LAG()、LEAD()用法详解

SQL偏移类窗口函数&#xff1a;LAG() 和 LEAD() 用法详解 在 SQL 中&#xff0c;偏移类窗口函数 LAG() 和 LEAD() 用于访问当前行的前几行或后几行的值。 1. LAG() 函数 LAG() 函数返回当前行的前几行的数据。 LAG(Expression, OffSetValue, DefaultVar) OVER (PARTITION BY …...

PHP语言的计算机基础

计算机基础与PHP语言入门 在当今信息技术高速发展的时代&#xff0c;计算机已经成为我们日常生活中不可或缺的重要工具。学习计算机基础知识&#xff0c;不仅能增强我们对信息技术的理解&#xff0c;还会为我们后续学习编程语言打下良好的基础。本文将以PHP语言为切入点&#…...

39. 解压报文

题目描述 为了提升数据传输的效率&#xff0c;会对传输的报文进行压缩处理输入一个压缩后的报文&#xff0c;请返回它解压后的原始报文.压缩规则:n[str]&#xff0c;表示方括号内部的str正好重复n次。注意n为正整数(0<n<100)&#xff0c;str只包含小写英文字母&#xff0…...

SpringBoot日志快速集成详解-生产实战

SpringBoot日志快速集成详解 1. 添加依赖2. 创建 logback-spring.xml 配置文件示例 logback-spring.xml 配置&#xff1a; 3. 启用 Spring Boot 自动配置4. 配置 Spring Boot 启动日志级别5. 运行与验证 博文专注于最快速的实战&#xff0c;没有那么多逼逼叨叨的理论&#xff0…...

基于 Node.js 的 ORM(对象关系映射)工具——Sequelize介绍与使用,并举案例分析

便捷性介绍 支持多种数据库&#xff0c;包括 PostgreSQL、MySQL、MariaDB、SQLite 和 Microsoft SQL Server。Sequelize 提供了丰富的功能&#xff0c;帮助开发者用 JavaScript&#xff08;或 TypeScript&#xff09;代码操作数据库&#xff0c;而无需直接书写 SQL 语句。 Se…...

电子应用设计方案85:智能 AI门前柜系统设计

智能 AI 门前柜系统设计 一、引言 智能 AI 门前柜系统旨在提供便捷、安全和智能的物品存储与管理解决方案&#xff0c;适用于家庭、公寓或办公场所的入口区域。 二、系统概述 1. 系统目标 - 实现无接触式物品存取&#xff0c;减少交叉感染风险。 - 具备智能识别和分类功能&am…...

ts是什么、tsc是什么、tsx是什么、jsx是什么、scss是什么

一、TS (TypeScript): TypeScript 是一种由微软开发的开源编程语言&#xff0c;它是 JavaScript 的一个超集&#xff0c;增加了类型系统和对ES6及以后版本新特性的支持。TypeScript 旨在解决 JavaScript 开发中的可维护性、可扩展性和大型项目中的复杂性问题。它允许开发者在编…...

【虚拟机】VMware 16图文安装和配置 AlmaLinux OS 9.5 教程

准备工作 下载AlmaLinux ISO文件&#xff1a;从AlmaLinux官方网站&#xff08;https://almalinux.org/&#xff09;下载最新版本的ISO文件。 安装VMware Workstation&#xff1a;确保您的计算机上已安装VMware Workstation。&#xff08;注&#xff1a;我这边使用的是VMware16…...

使用MySQL SLES存储库安装MYSQL

MySQL SLES存储库提供RPM包&#xff0c;用于在SUSE EnterpriseLinuxServer上安装和管理MySQL服务器、客户端和其他组件。 添加MySQLSLES存储库 为系统的存储库列表添加或更新官方MySQLSLES存储库&#xff1a; 配置文件名的开头部分&#xff0c;如mysql84&#xff0c;描述了为…...

30分钟学会HTML

HTML 基本语法 HTML&#xff08;HyperText Markup Language&#xff09;是构成网页内容的基础。它使用一系列的标签来描述网页的结构&#xff0c;包括文本、图片、链接等元素。浏览器会解析这些标签并渲染成我们看到的网页。 在线体验一下 CodePen (在线 HTML 编辑器)。 千万不…...

vue——滑块验证

1. 介绍 1.1 简介 基于滑动式的验证码&#xff0c;免于字母验证码的繁琐输入 用于网页注册或者登录 1.2 来源说明 vue使用滑块验证功能&#xff0c;是基于vue-monoplasty-slide-verify这样的一个开源项目&#xff0c;进行实现的&#xff0c;这是这个开源项目的网址传送阵&#…...

编程入门(2)-2024年 RAD Studio version 12发布综述

随着2024年即将画上句号&#xff0c;我想借此机会回顾一下我们在这一年中发布的一些Embarcadero产品、行业趋势&#xff0c;并感谢我们尊贵的客户们对我们的产品一如既往的支持。这一年对我们来说充满了激动人心的变化和发展&#xff0c;我们非常高兴能与您一起踏上这段旅程。 …...

2025年1月4日蜻蜓q旗舰版st完整开源·包含前后端所有源文件·开源可商用可二开·优雅草科技·优雅草kir|优雅草星星|优雅草银满|优雅草undefined

2025年1月4日蜻蜓q旗舰版st完整开源包含前后端所有源文件开源可商用可二开优雅草科技优雅草kir|优雅草星星|优雅草银满|优雅草undefined 产品介绍&#xff1a; 本产品主要贡献者优雅草科技优雅草kir|优雅草星星|优雅草银满|优雅草undefined-青史留名&#xff0c;时光如川浪淘…...

米哈游可切换角色背景动态壁纸

米哈游可切换角色背景动态壁纸 0. 视频 B站演示: 米哈游可切换角色背景动态壁纸-wallpaper 1. 基本信息 作者: 啊是特嗷桃系列: 复刻系列 (衍生 wallpaper壁纸引擎 用)网站: 网页版在线预览 (没有搞大小适配, 建议横屏看; 这个不能切角色, 只能在wallpaper中切)仓库: GitHub…...

框架Tensorflow2

深度学习框架之Tensorflow2 Tensorflow2版本的介绍 Tensorflow(简称tf)是深度学习框架&#xff0c;大大简化了建模的方法和步骤&#xff0c;把Keras Api当作核心&#xff0c;使用非常简单&#xff0c;跨平台&#xff0c;集成各种现成模型&#xff0c;eager mode使得调试起来不…...

急需升级,D-Link 路由器漏洞被僵尸网络广泛用于 DDoS 攻击

僵尸网络活动增加 &#xff1a;新的“FICORA”和“CAPSAICIN”僵尸网络&#xff08;Mirai 和 Kaiten 的变体&#xff09;的活动激增。 被利用的漏洞 &#xff1a;攻击者利用已知的 D-Link 路由器漏洞&#xff08;例如 CVE-2015-2051、CVE-2024-33112&#xff09;来执行恶意命…...

银行大数据平台管理系统的设计与实现

标题:银行大数据平台管理系统的设计与实现 内容:1.摘要 摘要&#xff1a;本文介绍了银行大数据平台管理系统的设计与实现。该系统旨在解决银行数据管理中的数据量大、数据类型多、数据处理复杂等问题。通过采用大数据技术&#xff0c;如 Hadoop、Spark 等&#xff0c;实现了数…...

leetcode 732. 我的日程安排表 III

题目&#xff1a;732. 我的日程安排表 III - 力扣&#xff08;LeetCode&#xff09; 这个数据规模&#xff0c;暴力就够了 struct Book {int begin;int end;Book(int b, int e) {begin b;end e;} }; class MyCalendarThree { public:MyCalendarThree() {}int book(int star…...

公共数据授权运营系统建设手册(附下载)

在全球范围内&#xff0c;许多国家和地区已经开始探索公共数据授权运营的路径和模式。通过建立公共数据平台&#xff0c;推动数据的开放共享&#xff0c;促进数据的创新应用&#xff0c;不仅能够提高政府决策的科学性和公共服务的效率&#xff0c;还能够激发市场活力&#xff0…...