文档章节

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

Pulsar-V
 Pulsar-V
发布于 2017/07/29 22:17
字数 1452
阅读 102
收藏 0
点赞 0
评论 0

光流简单的来说就是通过摄像头的移动,在移动过程中,每一帧的图像特征点会发生移动,这个移动的过程中(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后加到下一层。

© 著作权归作者所有

共有 人打赏支持
Pulsar-V
粉丝 43
博文 82
码字总数 67791
作品 1
成都
后端工程师
视频分析(二):光流(Optical Flow)

目标 在这一章当中, 我们将使用Lucas-Kanade方法理解光流的概念及其估计。 我们将使用像cv2.calcOpticalFlowPyrLK()这样的函数来跟踪视频中的特征点。 光学流程 光流是由物体或相机的运动...

漫步当下
05/19
0
0
基于OpenCV和Python的文件操作——捕获摄像头的帧,在窗口显示图像,在窗口显示摄像头帧和视频文件的读/写

0 写在前面 这篇博客主要参考资料为《OpenCV 3计算机视觉Python语言实现》(Learning OpenCV 3 Computer Vison with Python)。 因为之前用Faster R-CNN做过一个红绿灯检测的小实践,但是Git...

learning_tortosie
04/12
0
0
【联想】使用opencv接口进行人脸识别算法优化

一、【需求描述】 目的:使用opencv接口进行人脸识别算法优化 使用场景:通过网络摄像机使用rtsp流方式读取视频流并实时监控视频中出现的人物头像进行抓取保存 1. 要求:使用C++集成opencv进...

北京知识动力信息技术有限公司
06/04
0
0
基于OpenCV的iOS图像处理

关于图片处理 随着科技的发展,AI、机器学习、AR、VR等已经逐渐走进生活,模式识别、图像捕捉、图片拼接等已经成为其中的重要环节。因此,图像处理技术在未来会被移动端广泛使用。其中,有很...

无忌不悔
2017/09/06
0
0
人脸检测原理及示例(OpenCV+Python)

前言 关于opencv OpenCV 是 Intel 开源计算机视觉库 (Computer Version) 。它由一系列 C 函数和少量 C++类构成,实现了图像处理和计算机视觉方面的很多通用算法。 OpenCV 拥有包括 300 多个 ...

张卫泉
2012/09/12
0
2
图片人脸检测(OpenCV版)

图片人脸检测 人脸检测使用到的技术是OpenCV,上一节已经介绍了OpenCV的环境安装,点击查看. 功能展示 识别一种图上的所有人的脸,并且标出人脸的位置,画出人眼以及嘴的位置,展示效果图如下...

vipstone
05/21
0
0
玩转智能路由器-WRTnode添加OpenCV支持

opencv libs库文件ipk编译 opencv ipk源码 利用openwrt package的编译机制仅仅需要一个Makefile即可编译opencv。 为何会如此简单神奇,下面就对Makefile详解(个人看法,欢迎指正): $vim M...

openthings
2015/03/04
0
0
Android opencv 2.3.1 调试及应用(第一篇)

OpenCV 是开源的人像识别库,在Android上的应用我也刚刚开始摸索。 首先搞定开发环境,看能不能把测试程序给跑起来。 http://sourceforge.net/projects/opencvlibrary/files/opencv-android...

氪金
2013/06/27
0
5
OpenCV-Python(1)在Python中使用OpenCV进行人脸检测

OpenCV是如今最流行的计算机视觉库,而我们今天就是要学习如何安装使用OpenCV,以及如何去访问我们的摄像头。然后我们一起来看看写一个人脸检测程序是如何地简单,简单到只需要几行代码。 在...

煎鱼不可能有BUG
05/23
0
0
OpenCV 2.1 new features

OpenCV 2.1 is basically a stabilized OpenCV 2.0, yet there are a few new features. >>> General modifications - SVN repository has been migrated from SourceForge to https://code.......

heartfly
2010/05/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

大数据教程(2.13):keepalived+nginx(多主多活)高可用集群搭建教程【自动化脚本】

上一章节博主为大家介绍了目前大型互联网项目的keepalived+nginx(主备)高可用系统架构体系,相信大家应该看了博主的文章对keepalived/nginx技术已经有一定的了解,在本节博主将为大家分享k...

em_aaron
7分钟前
0
0
Git 2.18版本发布:支持Git协议v2,提升性能

在最新的官方 Git 客户端正式版2.18中添加了对 Git wire 协议 v2 的支持,并引入了一些性能与 UI 改进的新特性。在 Git 的核心团队成员 Brandon Williams 公开宣布这一消息前几周,Git 协议 ...

六库科技
11分钟前
0
0
Java8新特性之接口

在JDK8以前,我们定义接口类中,方法都是抽象的,并且不能存在静态方法。所有的方法命名规则基本上都是 public [返回类型] [方法名](参数params) throws [异常类型] {}。 JDK8为接口的定义带...

developlee的潇洒人生
49分钟前
0
0
aop + annotation 实现统一日志记录

aop + annotation 实现统一日志记录 在开发中,我们可能需要记录异常日志。由于异常比较分散,每个 service 方法都可能发生异常,如果我们都去做处理,会出现很多重复编码,也不好维护。这种...

长安一梦
今天
2
0
将博客搬至CSDN

AHUSKY
今天
1
0
Python web框架Django学习(1)

1.Django简介 (1)Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。Django是一个开放源代码的Web应用框架,由Python写成。 (2...

十年磨一剑3344
今天
0
0
Databook-数据之书

Databook-数据之书 用于数据分析的Jupyter Notebooks。 不需购买服务器,快速开始自己的数据分析过程。 源码:https://github.com/openthings/databook 作者:openthings,https://github.co...

openthings
今天
7
0
Python PIPEs

https://www.python-course.eu/pipes.php https://www.tutorialspoint.com/python/os_pipe.htm

zungyiu
今天
1
0
gRPC学习笔记

gRPC编程流程 1. proto文件定义 proto文件用于定义需要通过gRPC生成的接口,可以理解为接口定义文档 2. 通过构建工具生成服务基类代码-Maven或Gradle 3. 服务端开发 服务端实现类须实现通过构...

OSC_fly
今天
0
0
Docker Mac (三) Dockerfile 及命令

Dockerfile 最近学习docker的时候,遇到一件怪事,关于docker镜像可能会被破坏,还不知道它会有此措施 所以需要了解构建Dockerfile的正确方法 Dockerfile是由一系列命令和参数构成的脚本,这些命...

___大侠
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部