L-K光流推导及OpenCV代码实现

光流简单的来说就是通过摄像头的移动,在移动过程中,每一帧的图像特征点会发生移动,这个移动的过程中(x1,y1,z1)在我们下一帧的动作中,去找到原来的所有特征点的新坐标,而这个移动路径,就是所谓的,光流。

推导式

在移动的过程中,图像的像素坐标系的局部矢量局部图像流(速度)矢量

必须满足满足下面的条件 第一帧

其中q1,q2,q3,q4是窗口内的像素

是图像在当前时间位置相对于评估点的 x,y,z和时间t的偏导数

以此类推到达第n帧的时候

现在就不妨可以构造一个矩阵进行计算

系统中的数据未知量过大,因此呢,需要一种方法去解决这样的未知数数据。 L-K(Lucas-Kanade)方法通过最小二乘法得到期望的解值 方法如下

求解表达式

将矩阵代入这个式子中得出求解的表达式如下

其中矩阵

通常称为点p处图像的结构张量 这个矩阵表达式很长,下面附上Latex的代码

\begin{bmatrix}
V_x\\ 
V_y \\
V_z
\end{bmatrix}=\begin{bmatrix}
\sum _i I_x(q_i)^{2} &\sum _i I_x(q_i) I_y(q_i) &\sum _i I_x(q_i) I_z(q_i) \\ 
\sum _i I_x(q_i) I_y(q_i) &\sum _i I_y(q_i)^{2} &\sum _i I_y(q_i) I_z(q_i) \\
\sum _i I_x(q_i) I_z(q_i)& \sum _i I_y(q_i) I_z(q_i) &\sum _i I_z(q_i)^{2}
\end{bmatrix}\begin{bmatrix}
-\sum_i I_xI_t(q_i)\\ 
-\sum_i I_yI_t(q_i)\\ 
-\sum_i I_zI_t(q_i)
\end{bmatrix}

但是上面的算法中,会出现一个问题,就是图像中的所有数据都具有相同的权重,这样的话就会去计算图像边界上的东西,在实际的运行过程当中,要考虑的问题,是图像中间位置的像素点。

加权改进

下面用加权窗口方法对图像中央的一些点进行加权计算(最小二乘法的加权版本)

其中W是包含权重的n × n 对角矩阵 Wii=wi 被分配给像素方程qi 也就是说,它计算 代入矩阵得

权重wi 通常为qi和p的高斯分布的距离

高斯分布公式

f(x|\mu ,\sigma^{2} )=\frac{1}{\sqrt{2\pi \sigma^{2}}}e^{-\frac{(x-\mu^{2} )}{2\sigma^{2}}}

μ 是分布的平均值或期望值 (以及其中位数和模式 )。

是标准偏差

是方差

正态分布的最简单的情况称为标准正态分布 。 这是特殊情况 μ = 0

= 1 其余正太分布方法我会在后面的博客当中给出,暂时按照标准正态分布进行加权

最小二乘法隐式假定图像数据中的误差具有零均值的高斯分布。 如果有人希望窗口包含一定百分比的“ 异常值 ”(严重错误的数据值,不遵循“普通”高斯误差分布),可以使用统计分析来检测它们,并相应地减小它们的权重。 Lucas-Kanade方法本身只能用于图像流向量 V X , V ÿ 两个帧之间的距离足够小以保持光流的微分方程,通常小于像素间隔。 当流向量可能超过该限制时,例如在立体匹配或扭曲图像中,L-K方法仍然可以通过其他方式细化获得的粗略估计; 例如,通过推算为先前帧计算的流向量,或者通过在图像的缩小版本上运行Lucas-Kanade算法。其中最为常用的是特征匹配算法。

下面给出OpenCV的L-K光流计算法: LK.h

void cvCalcOpticalFlowPyrLK(
    const CvArr* imgA,//初始图像
    const CvArr* imgB,//最终图像
    CvArr* pyrA,
    CvArr* pyrB,//pyrA,B申请存放两幅图像金字塔的缓存
    CvPoint2D32f* featuresA,//存放的是用于寻找运动的点
    CvPoint2D32f* featuresB,//存放featuresA中点的新位置
    int count,//featuresA中点的数目
    CvSize winsize,//定义了计算局部连续运动的窗口尺寸
    int level,//用于设置构建的图像金字塔的栈的层数,若设置为0,则不使用金字塔
    char* status,//函数调用结束时,status中的每个元素被置1(对应点在第二幅图中发现)或者0(未发现)
    float* track_error,//为可选参数,表示被跟踪点的原始图像小区域与此点在第二幅图像的小区域间的差的数组
    CvTermCriteria criteria,//迭代终止条件
    int flags//标志位
);

LK.cpp

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
const int MAX_CORNERS = 500;

int main()
{
    IplImage *imgA = cvLoadImage("0.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    IplImage *imgB = cvLoadImage("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);

    CvSize img_sz = cvGetSize(imgA);
    int win_size = 10;
    IplImage *imgC = cvLoadImage("1.jpg", CV_LOAD_IMAGE_UNCHANGED);

    IplImage *eig_image = cvCreateImage(img_sz, IPL_DEPTH_32F,1);
    IplImage *tmp_image = cvCreateImage(img_sz, IPL_DEPTH_32F, 1);

    int corner_count = MAX_CORNERS;
    CvPoint2D32f *cornersA = new CvPoint2D32f[MAX_CORNERS];

    cvGoodFeaturesToTrack(
        imgA,
        eig_image,
        tmp_image,
        cornersA,
        &corner_count,
        0.01,
        5.0,
        0,
        3,
        0,
        0.04
        );

    cvFindCornerSubPix(
        imgA,
        cornersA,
        corner_count,
        cvSize(win_size, win_size),
        cvSize(-1, -1),
        cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03)
    );

    char features_found[MAX_CORNERS];
    float features_errors[MAX_CORNERS];
    CvSize pyr_sz = cvSize(imgA->width + 8, imgB->height / 3);
    IplImage *pyrA = cvCreateImage(pyr_sz, IPL_DEPTH_32F, 1);
    IplImage *pyrB = cvCreateImage(pyr_sz, IPL_DEPTH_32F, 1);
    CvPoint2D32f *cornersB = new CvPoint2D32f[MAX_CORNERS];

    cvCalcOpticalFlowPyrLK(
        imgA,
        imgB,
        pyrA,
        pyrB,
        cornersA,
        cornersB,
        corner_count,
        cvSize(win_size, win_size),
        5,
        features_found,
        features_errors,
        cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.3),
        0
        );

    for (int i = 0; i < corner_count; ++i)
    {
        if (features_found[i] == 0 || features_errors[i] > 550)
        {
            cout << "Error is " << features_errors[i];
            continue;
        }

        CvPoint p0 = cvPoint(cvRound(cornersA[i].x), cvRound(cornersA[i].y));
        CvPoint p1 = cvPoint(cvRound(cornersB[i].x), cvRound(cornersB[i].y));
        cvLine(imgC, p0, p1, CV_RGB(255, 0, 0),2);
    }

    cvNamedWindow("ImageA", 0);
    cvNamedWindow("ImageB", 0);
    cvNamedWindow("LKpyr_OpticalFlow", 0);
    cvShowImage("ImageA", imgA);
    cvShowImage("ImageB", imgB);
    cvShowImage("LKpyr_OpticalFlow", imgC);
    cvWaitKey(0);
    return 0;
}

文尾

在大距离移动的时候需要采用图像金字塔的方法,对图像进行计算需要在多层图像缩放金字塔上求解,每一层的求解结果乘以2后加到下一层。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏专知

【论文推荐】最新6篇目标检测相关论文—场景文本检测 、显著对象、语义知识转移、混合监督目标检测、域自适应、车牌识别

【导读】专知内容组整理了最近六篇目标检测(Object Detection)相关文章,为大家进行介绍,欢迎查看! 1. Rotation-Sensitive R...

6776
来自专栏专知

【论文推荐】最新5篇目标检测相关论文——显著目标检测、弱监督One-Shot检测、多框检测器、携带物体检测、假彩色图像检测

【导读】专知内容组整理了最近目标检测相关文章,为大家进行介绍,欢迎查看! 1. MSDNN: Multi-Scale Deep Neural Network f...

4827
来自专栏Deep learning进阶路

深度学习论文(八)---DeepLabV1-SEMANTIC IMAGE SEGMENTATION WITH DEEP CONVOLUTIONAL NETS AND FULLY CONNECTED C

注:本篇算是半讲解半翻译吧,我真的觉得这篇论文写的很难理解.......可能是我水平不够,也可能作者省略了一些具体信息,主要是提供了他的idea吧。 但是De...

9941
来自专栏专知

【论文推荐】最新九篇目标检测相关论文—常识性知识转移、尺度不敏感、多尺度位置感知、渐进式域适应、时间感知特征图、人机合作

【导读】专知内容组整理了最近七篇目标检测(Object Detection)相关文章,为大家进行介绍,欢迎查看! 1.Single-Shot Object De...

8287
来自专栏专知

【专知荟萃25】文字识别OCR知识资料全集(入门/进阶/论文/综述/代码/专家,附查看)

OCR文字,车牌,验证码识别 专知荟萃 入门学习 论文及代码 文字识别 文字检测 验证码破解 手写体识别 车牌识别 实战项目 视频 入门学习 端到端的OCR...

2K8
来自专栏Ldpe2G的个人博客

图像素描风格生成

2402
来自专栏小小挖掘机

推荐系统遇上深度学习(二)--FFM模型理论和实践

推荐系统遇上深度学习系列: 推荐系统遇上深度学习(一)--FM模型理论和实践 1、FFM理论 在CTR预估中,经常会遇到one-hot类型的变量,one-ho...

9904
来自专栏ATYUN订阅号

使用生成式对抗网络进行图像去模糊

AiTechYun 编辑:yuxiangyu 本文主要讨论使用生成式对抗网络实现图像去模糊。 代码:https://github.com/RaphaelMeu...

3.1K9
来自专栏ATYUN订阅号

使用Python实现无监督学习

人工智能研究的负责人Yan Lecun说,非监督式的学习——教机器自己学习,而不用被明确告知他们做的每一件事是对还是错——是实现“真”AI的关键。

2525
来自专栏机器学习和数学

[机智的机器在学习] TensorFlow实现Kmeans聚类

对于机器学习算法来说,主要分为有监督学习和无监督学习,前面有篇文章介绍过机器学习算法的分类,不知道的童鞋可以去看看。然后今天要讲的Kmeans算法属于无监督算法...

1.2K13

扫码关注云+社区

领取腾讯云代金券