opencv光流Optical Flow

2023-11-16

光流Optical Flow


现在四轴飞行器越来越火,如何在室内进行定位呢?不同于传统四轴的姿态控制,电机驱动,室外定位,都有了一套完整的方案,室内定位还是没有完全成熟。,目前大四轴可以利用的GPS定高,小四轴比较成熟的也就是光流方案了。
先看一下光流的效果

这是一个挥动的手


虽然也有背景在动,但是因为他们的运动方向不一样,所以还是可以辨认出来前面那个是手,在前景和背景运动不统一的时候,还是可以辨认出来的。



那么光流(optic flow)是什么呢?


名字很专业,感觉很陌生从本质上说,光流就是你在这个运动着的世界里感觉到的明显的视觉运动。例如,当你坐在火车上,然后往窗外看。你可以看到树、地面、建筑等等,他们都在往后退。这个运动就是光流。而且,我们都会发现,他们的运动速度居然不一样?这就给我们提供了一个挺有意思的信息:通过不同目标的运动速度判断它们与我们的距离。一些比较远的目标,例如云、山,它们移动很慢,感觉就像静止一样。但一些离得比较近的物体,例如建筑和树,就比较快的往后退,然后离我们的距离越近,它们往后退的速度越快。一些非常近的物体,例如路面的标记啊,草地啊等等,快到好像在我们耳旁发出嗖嗖的声音。
      

        光流除了提供远近外,还可以提供角度信息。与咱们的眼睛正对着的方向成90度方向运动的物体速度要比其他角度的快,当小到0度的时候,也就是物体朝着我们的方向直接撞过来,我们就是感受不到它的运动(光流)了,看起来好像是静止的。当它离我们越近,就越来越大。


比较官方的光流定义

光流的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。

       当人的眼睛观察运动物体时,物体的景象在人眼的视网膜上形成一系列连续变化的图像,这一系列连续变化的信息不断“流过”视网膜(即图像平面),好像一种光的“流”,故称之为光流(optical flow)。光流表达了图像的变化,由于它包含了目标运动的信息,因此可被观察者用来确定目标的运动情况。

       研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。运动场,其实就是物体在三维真实世界中的运动;光流场,是运动场在二维图像平面上(人的眼睛或者摄像头)的投影。

       那通俗的讲就是通过一个图片序列,把每张图像中每个像素的运动速度和运动方向找出来就是光流场。那怎么找呢?咱们直观理解肯定是:第t帧的时候A点的位置是(x1, y1),那么我们在第t+1帧的时候再找到A点,假如它的位置是(x2,y2),那么我们就可以确定A点的运动了:(ux, vy) = (x2, y2) - (x1,y1)。
那怎么知道第t+1帧的时候A点的位置呢? 这就存在很多的光流计算方法了。

       1981年,Horn和Schunck创造性地将二维速度场与灰度相联系,引入光流约束方程,得到光流计算的基本算法。人们基于不同的理论基础提出各种光流计算方法,算法性能各有不同。Barron等人对多种光流计算技术进行了总结,按照理论基础与数学方法的区别把它们分成四种:基于梯度的方法、基于匹配的方法、基于能量的方法、基于相位的方法。近年来神经动力学方法也颇受学者重视。

还是回归应用吧,目前OpenCV中实现了不少的光流算法。

1. calcOpticalFlowPyrLK

通过金字塔Lucas-Kanade 光流方法计算某些点集的光流(稀疏光流)。理解的话,可以参考这篇论文:”Pyramidal Implementation of the Lucas Kanade Feature TrackerDescription of the algorithm”
2. calcOpticalFlowFarneback
用Gunnar Farneback 的算法计算稠密光流(即图像上所有像素点的光流都计算出来)。它的相关论文是:"Two-Frame Motion Estimation Based on PolynomialExpansion"
3. CalcOpticalFlowBM
通过块匹配的方法来计算光流。
4. CalcOpticalFlowHS
用Horn-Schunck 的算法计算稠密光流。相关论文好像是这篇:”Determining Optical Flow”
5. calcOpticalFlowSF
这一个是2012年欧洲视觉会议的一篇文章的实现:"SimpleFlow: A Non-iterative, Sublinear Optical FlowAlgorithm",工程网站是:http://graphics.berkeley.edu/papers/Tao-SAN-2012-05/  在OpenCV新版本中有引入。
还有他们的API的使用说明,我们直接参考OpenCV的官方手册就行:
http://www.opencv.org.cn/opencvdoc/2.3.2/html/modules/video/doc/motion_analysis_and_object_tracking.html#calcopticalflowfarneback

IJCV2011有一篇文章,《A Database and Evaluation Methodology for Optical Flow》里面对主流的光流算法做了简要的介绍和对不同算法进行了评估。网址是:http://vision.middlebury.edu/flow/

       感觉这个文章在光流算法的解说上非常好,条例很清晰。想了解光流的,推荐看这篇文章。另外,需要提到的一个问题是,光流场是图片中每个像素都有一个x方向和y方向的位移,所以在上面那些光流计算结束后得到的光流flow是个和原来图像大小相等的双通道图像。那怎么可视化呢?这篇文章用的是Munsell颜色系统来显示。



孟塞尔颜色系统的空间大致成一个圆柱形:
南北轴=明度(value),从全黑(1)到全白(10)。
经度=色相(hue)。把一周均分成五种主色调和五种中间色:红(R)、红黄(YR)、黄(Y)、黄绿(GY)、绿(G)、绿蓝(BG)、蓝(B)、蓝紫(PB)、紫(P)、紫红(RP)。相邻的两个位置之间再均分10份,共100份。
距轴的距离=色度(chroma),表示色调的纯度。其数值从中间(0)向外随着色调的纯度增加,没有理论上的上限(普通的颜色实际上限为10左右,反光、荧光等材料可高达30)。由于人眼对各种颜色的的敏感度不同,色度不一定与每个色调和明度组合相匹配。
具体颜色的标识形式为:色相+明度+色度。
       在上面的那个评估的网站有这个从flow到color显示的Matlab和C++代码。但是感觉C++代码分几个文件,有点乱,然后我自己整理成两个函数了,并配合OpenCV的Mat格式。
       下面的代码是用calcOpticalFlowFarneback来计算稠密光流并且用这个颜色系统来显示的。这个计算稠密光流的方法与其他几个相比还是比较快的,640x480的视频我的是200ms左右一帧,但其他的一般都需要一两秒以上。结果图中,不同颜色表示不同的运动方向,深浅就表示运动的快慢了。
void calcOpticalFlowFarneback(InputArray prevImg, InputArray nextImg,InputOutputArray flow, double pyrScale, int levels, int winsize, intiterations, int polyN, double polySigma, int flags)
大部分参数在论文中都有一套比较好的值的,直接采用他们的就好了。



// Farneback dense optical flow calculate and show in Munsell system of colors
   // Author : Zouxy
   // Date   : 2013-3-15
   // HomePage : http://blog.csdn.net/zouxy09
   // Email  : zouxy09@qq.com
   // API calcOpticalFlowFarneback() comes from OpenCV, and this
   // 2D dense optical flow algorithm from the following paper:
   // Gunnar Farneback. "Two-Frame Motion Estimation Based on Polynomial Expansion".
   // And the OpenCV source code locate in ..\opencv2.4.3\modules\video\src\optflowgf.cpp
   #include <iostream>
   #include "opencv2/opencv.hpp"
   using namespace cv;
   using namespace std;
   #define UNKNOWN_FLOW_THRESH 1e9
   // Color encoding of flow vectors from:
   // http://members.shaw.ca/quadibloc/other/colint.htm
   // This code is modified from:
   // http://vision.middlebury.edu/flow/data/
   void makecolorwheel(vector<Scalar> &colorwheel)
   {
       int RY = 15;
       int YG = 6;
       int GC = 4;
       int CB = 11;
       int BM = 13;
       int MR = 6;
       int i;
       for (i = 0; i < RY; i++) colorwheel.push_back(Scalar(255,       255*i/RY,     0));
       for (i = 0; i < YG; i++) colorwheel.push_back(Scalar(255-255*i/YG, 255,       0));
       for (i = 0; i < GC; i++) colorwheel.push_back(Scalar(0,         255,      255*i/GC));
       for (i = 0; i < CB; i++) colorwheel.push_back(Scalar(0,         255-255*i/CB, 255));
       for (i = 0; i < BM; i++) colorwheel.push_back(Scalar(255*i/BM,      0,        255));
       for (i = 0; i < MR; i++) colorwheel.push_back(Scalar(255,       0,        255-255*i/MR));
   }
   void motionToColor(Mat flow, Mat &color)
   {
       if (color.empty())
           color.create(flow.rows, flow.cols, CV_8UC3);
       static vector<Scalar> colorwheel; //Scalar r,g,b
       if (colorwheel.empty())
           makecolorwheel(colorwheel);
       // determine motion range:
       float maxrad = -1;
       // Find max flow to normalize fx and fy
       for (int i= 0; i < flow.rows; ++i)
       {
           for (int j = 0; j < flow.cols; ++j)
           {
               Vec2f flow_at_point = flow.at<Vec2f>(i, j);
               float fx = flow_at_point[0];
               float fy = flow_at_point[1];
               if ((fabs(fx) >  UNKNOWN_FLOW_THRESH) || (fabs(fy) >  UNKNOWN_FLOW_THRESH))
                   continue;
               float rad = sqrt(fx * fx + fy * fy);
               maxrad = maxrad > rad ? maxrad : rad;
           }
       }
       for (int i= 0; i < flow.rows; ++i)
       {
           for (int j = 0; j < flow.cols; ++j)
           {
               uchar *data = color.data + color.step[0] * i + color.step[1] * j;
               Vec2f flow_at_point = flow.at<Vec2f>(i, j);
               float fx = flow_at_point[0] / maxrad;
               float fy = flow_at_point[1] / maxrad;
               if ((fabs(fx) >  UNKNOWN_FLOW_THRESH) || (fabs(fy) >  UNKNOWN_FLOW_THRESH))
               {
                   data[0] = data[1] = data[2] = 0;
                   continue;
               }
               float rad = sqrt(fx * fx + fy * fy);
               float angle = atan2(-fy, -fx) / CV_PI;
               float fk = (angle + 1.0) / 2.0 * (colorwheel.size()-1);
               int k0 = (int)fk;
               int k1 = (k0 + 1) % colorwheel.size();
               float f = fk - k0;
               //f = 0; // uncomment to see original color wheel
               for (int b = 0; b < 3; b++)
               {
                   float col0 = colorwheel[k0][b] / 255.0;
                   float col1 = colorwheel[k1][b] / 255.0;
                   float col = (1 - f) * col0 + f * col1;
                   if (rad <= 1)
                       col = 1 - rad * (1 - col); // increase saturation with radius
                   else
                       col *= .75; // out of range
                   data[2 - b] = (int)(255.0 * col);
               }
           }
       }
   }
   int main(int, char**)
   {
       VideoCapture cap;
       cap.open(0);
       //cap.open("test_02.wmv");
       if( !cap.isOpened() )
           return -1;
       Mat prevgray, gray, flow, cflow, frame;
       namedWindow("flow", 1);
       Mat motion2color;
       for(;;)
       {
           double t = (double)cvGetTickCount();
           cap >> frame;
           cvtColor(frame, gray, CV_BGR2GRAY);
           imshow("original", frame);
           if( prevgray.data )
           {
               calcOpticalFlowFarneback(prevgray, gray, flow, 0.5, 3, 15, 3, 5, 1.2, 0);
               motionToColor(flow, motion2color);
               imshow("flow", motion2color);
           }
           if(waitKey(10)>=0)
               break;
           std::swap(prevgray, gray);
           t = (double)cvGetTickCount() - t;
           cout << "cost time: " << t / ((double)cvGetTickFrequency()*1000.) << endl;
       }
       return 0;
   }


效果:在pc机上,计算160ms左右,也就是6帧,达不到实时的效果。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

opencv光流Optical Flow 的相关文章

  • 使用 OpenCV 绘制固定的网格线集

    是否可以根据 OpenCV 示例文件中颜色检测示例的输出 在所有交叉点处绘制具有定义点的用户定义网格线 基本上 网络摄像头需要从您上方检测人的头部和肩膀 然后 当检测到一个人时 我需要网格线在那里 以便我能够知道在 x 轴和 y 轴 前额和
  • 如何在 OpenCV 中删除 mouseCallback

    在使用 C 的 OpenCV 中 有没有办法删除 mouseHandler int event int x int y int flags void param 通过函数添加到窗口 image window cv setMouseCallb
  • 如何使用 Python 3 在 OpenCV 3 上正确加载 cv2.KeyPoint 和描述符?

    有一天 我不得不恢复一个使用 OpenCV 3 和 Python 2 7 的旧项目 在此代码中 要加载 cv2 KeyPoint 我执行以下操作 import numpy as np import cPickle import cv2 ke
  • 将 RGB 转换为黑色或白色

    我如何在Python中获取RGB图像并将其转换为黑白图像 不是灰度 我希望每个像素要么是全黑 0 0 0 要么是全白 255 255 255 流行的 Python 图像处理库中是否有任何内置功能可以完成此任务 如果不是 最好的方法是循环遍历
  • caffe安装:opencv libpng16.so.16链接问题

    我正在尝试在 Ubuntu 14 04 机器上使用 python 接口编译 caffe 我已经安装了 Anaconda 和 opencvconda install opencv 我还安装了咖啡中规定的所有要求 并更改了注释块makefile
  • 如何在没有 OpenCv Manager 的情况下运行 OpenCV 代码

    我正在使用 OpenCV4Android 版本 2 4 10 并在 Samsung Galayx GT I9300 上测试我的代码 我遇到的问题是 我必须从 Play 商店下载 Opencv Manager 以便我的 opencv 代码运行
  • 如何在 CMake Makefile 中包含 OpenCV 库

    我希望你可以帮助我 我有一个简单的 CMakeLists txt 以便在 Leopard 10 5 8 上构建我的项目 我正在使用 CMake 2 8 1 目前这是代码 cmake minimum required VERSION 2 8
  • OpenCV Python 删除图像中的某些对象

    我正在使用带有 opencv 和 numpy 的 python 来检测天文中的星星 例如这个1 https i stack imgur com AKwEJ jpg图片 使用模板匹配 我可以用阈值检测星星 单击 2 2 https i sta
  • OpenCV 中“IplImage”和“CvMat”的全称是什么?

    有一个IplImage and CvMat在 OpenCV 中 他们的全名是什么 IPL in IplImage代表英特尔处理库 这是Intel维护OpenCV时的残余 CV in cvMat代表计算机视觉矩阵 这是图形中常用的数据结构 I
  • 如何获得垂直线穿过的完整内轴线?

    我有一个图像 我想获取穿过其中轴的像素 我尝试使用骨架化 and 中轴方法来获取它们 但这两种方法都返回比相应对象短的一维线 这是带有示例图像的代码 gt gt gt import skimage filter gt gt gt impor
  • OpenCV 完美识别物体

    我有一个应用程序 我想一次跟踪 2 个在图片中相当小的对象 该应用程序应该在 Android 和 iPhone 上运行 因此算法应该是高效的 对于我的客户来说 如果我们提供一些模式以及附加到要跟踪的对象的软件 以获得易于识别的目标 那就完全
  • 在 Android 中使用 OpenCV 查找图像匹配

    我正在尝试构建一个 Android 应用程序 该应用程序可以比较设备相机拍摄的照片 以在一组图像中找到匹配项 我已经在 Android Studio 上配置了 OpenCV 但仅此而已 有人可以通过链接到资源或建议教程来提供帮助吗 Open
  • ValueError:当数组不是序列时设置带有序列的数组元素

    您好 此代码旨在存储使用 open cv 绘制的矩形的坐标 并将结果编译为单个图像 import numpy as np import cv2 im cv2 imread 1 jpg im3 im copy gray cv2 cvtColo
  • 使用 cv2 在 python 中创建多通道零垫

    我想用 cv2 opencv 包装器在 python 中创建一个多通道 mat 对象 我在网上找到了一些例子 其中 c Mat zeros 被 numpy zeros 替换 这看起来不错 但似乎没有多通道类型适合 看代码 import cv
  • 基本的 Python OpenCV 裁剪和调整大小

    有人可以帮我一些裁剪算法吗 它的 openCV 我想弄清楚这一点 我知道方法是crop image y y1 x x1 如果我有一个带有 new dimensionXxnew dimensionY 像素的图像 并且我想将其裁剪为相同的宽度
  • OpenCV 读取视频文件时内存不足

    此示例从文件中读取视频cv2 VideoCapture在 python OpenCV 中内存不足 import cv2 cap cv2 VideoCapture file mp4 while True ret frame cap read
  • 使用opencv+picamera流IO用树莓派捕获视频

    我使用 Raspberry 来简单地显示一个视频 目前仅此 为此 我必须使用 opencv cv2 我尝试了很多解决方案 但现在我想使用 Picamera 库捕获视频 我将向您展示我的代码 import io import time imp
  • 类型错误:只有长度为 1 的数组可以转换为 Python 标量

    我是 openCV 的初学者 正在尝试分析数独求解器的现有代码 有这一段代码会引发错误 samples np float32 np loadtxt feature vector pixels data responses np float3
  • 使用 openCV 对图像中的子图像进行通用检测

    免责声明 我是计算机视觉菜鸟 我看过很多关于如何在较大图像中查找特定子图像的堆栈溢出帖子 我的用例有点不同 因为我不希望它是具体的 而且我不确定如何做到这一点 如果可能的话 但我感觉应该如此 我有大量图像数据集 有时 其中一些图像是数据集的
  • OpenCV 中的 Gabor 内核参数

    我必须在我的应用程序中使用 Gabor 过滤器 但我不知道这个 OpenCV 方法参数值 我想对虹膜进行编码 启动 Gabor 过滤器并获取特征 我想对 12 组 Gabor 参数值执行此操作 然后我想计算 Hamming Dystans

随机推荐

  • [C++]使用关键字new创建对象

    1 首先解释new关键字的作用 在堆中开辟指定数据类型的空间 调用指定数据类型的构造函数 创建对象 返回创建的对象 int pn new int new与delete搭配使用 这种写法 pn为栈上的一个指针 指向堆上所对应的内存块 int
  • 逻辑地址、物理地址和线性地址

    逻辑地址 logical address 包含在机器语言指令中用来指定一个操作数或一条指令的地址 这种寻址方式在80X86著名的分段结构中表现的尤为具体 它促使MS DOS或Windows程序员把程序分成若干段 每一个逻辑地址都由一个段 s
  • 【pyspark】DataFrame基础操作(二)

    介绍一下 pyspark 的 DataFrame 基础操作 一 选择和访问数据 PySpark DataFrame 是惰性计算的 简单地选择一列不会触发计算 但它会返回一个 Column 实例 并且 大多数按列操作都返回 Column 实例
  • 代码审计工具学习之Seay(安装以及初步认识)

    目录 1 1名词解释 1 2代码审计的重要性 1 3代码审计的步骤 1 4代码审计的内容 1 5常见的代码审计工具 2 Seay 2 1什么是Seay 2 2 Seay的安装过程 3典型漏洞分析 3 1什么是命令注入漏洞 3 2 如何理解命
  • Windows下运用Tensorflow object detection API训练出现的问题--爬坑

    刚开始学习Tensorflow object detection API遇到了不少问题 下面就遇到的问题做下记录 我是在CPU下训练的模型 然后遇到训练到一百多步的时候会报这个错误 如图 用的训练模型为ssd mobilenet v1 co
  • VS2010中dumpbin工具的使用

    用VS2010生成的 obj文件 lib库 dll库 exe执行文件 如果想查看其中这些文件或库包含了哪些函数以及相关的信息 符号清单 可以通过VS2010自带的dumpbin工具来完成 dumpbin exe为Microsoft COFF
  • C++入门篇--函数

    C 的函数和C语言的函数是差不多的 都是把要重复使用的代码封装起来 以便我们后续使用 而C 的函数在c语言上右增加了几个特性 那就是缺省参数和函数重载 这一篇就分享一下C 函数的这些特性 开篇 说到函数 自然得提一下C 的输入函数和输出函数
  • ArcGIS应用基础知识

    ArcGIS应用基础 一 地理信息系统概念介绍 二 地图基本知识 三 ArcGIS体系介绍 四 ArcGIS数据格式介绍 五 基本工具介绍 一 地理信息系统概念介绍 地理信息系统 简称GIS Geographic Information S
  • Reflect中MethodInfo使用方法

    using System using System Collections Generic using System Linq using System Text using System Reflection namespace Meth
  • Spring——spring集成mybatis

    目录 1 spring集成mybatis相关说明 2 实现步骤 2 1实现步骤说明 2 2准备数据库 MySQL 创建新建表 Student 2 3 maven 依赖 pom xml 2 4 实体类 Student 2 5定义 Studen
  • pcl画圆球_点云视窗类CloudViewer的介绍以及PCL程序:圆球几何体代码解析

    点云视窗类CloudViewer是简单显示点云的可视化工具类 可以让用户用尽可能少的代码查看点云 注意 点云视窗类不能应用于多线程应用程序中 有关CloudViewer类的成员变量和函数等等 可以C Program Files PCL 1
  • 图片压缩插件image-compressor.js的使用和解决图片旋转问题(vue)

    1 安装 yarn add image compressor js npm i image compressor js 2 引入 import ImageCompressor from image compressor js 3 使用 语法
  • unity 加载场景时加载失败的问题

    需要实现场景跳转的功能 而且需要实现跳转的场景不是一个 其中一个可以很好的跳转 但是另一个新建的场景在跳转时却报错 Scene BatteryMaintenance couldn t be loaded because it has not
  • Apache PLC4X 副总裁宣布个人停止对项目提供免费支持;Linux 5.17 增加对中国 Soc 的支持;IPython 8.0 发布

    整理 宋彤彤 责编 屠敏 开源吞噬世界的趋势下 借助开源软件 基于开源协议 任何人都可以得到项目的源代码 加以学习 修改 甚至是重新分发 关注 开源日报 一文速览国内外今日的开源大事件吧 一分钟速览新闻点 开源大新闻 因缺少资金 Apach
  • 网络工程毕业设计选题大全 毕设题目推荐

    文章目录 0 简介 1 如何选题 2 最新网络工程选题 2 1 Java web SSM 系统 2 2 大数据方向 2 3 人工智能方向 2 4 其他方向 4 最后 0 简介 学长搜集分享最新的网络工程专业毕设毕设选题 难度适中 适合作为毕
  • Aspose.Diagram for Java V22.5

    Aspose Diagram for Java V22 5 Aspose Diagram for Java 是一个强大的 Microsoft Visio 文件处理 API 它提供了通用功能 例如创建 操作和转换本机 Visio 格式以及一些
  • 大数据学习脑图以及容易消化的入门教程

    近些年 大数据的火热可谓是技术人都知道啊 很多人呢 也想学习大数据相关 所以 这里分享几个大数据脑图 希望可以让你清楚明白从哪里入门大数据 知道该学习以及掌握哪些知识点 大数据相关脑图 想要在大数据这个领域汲取养分 让自己壮大成长 分享方向
  • sklearn中cross_val_score、cross_val_predict的用法比较

    交叉验证的概念 直接粘贴scikit learn官网的定义 scikit learn中计算交叉验证的函数 cross val score 得到K折验证中每一折的得分 K个得分取平均值就是模型的平均性能 cross val predict 得
  • 排列组合理解SQL JOINS的几种情况

    一 JOIN的三种方式 1 left join 2 right join 3 full join 二 Join的结果 两个集合的join可能出现多少中结果呢 利用数学里的排列组合知识很容易算出来 如上图 join相当于把两个集合分为三个部分
  • opencv光流Optical Flow

    光流Optical Flow 现在四轴飞行器越来越火 如何在室内进行定位呢 不同于传统四轴的姿态控制 电机驱动 室外定位 都有了一套完整的方案 室内定位还是没有完全成熟 目前大四轴可以利用的GPS定高 小四轴比较成熟的也就是光流方案了 先看