
现在,四旋翼飞机越来越受欢迎,如何将它们定位在室内?与传统的四轴姿态控制,电机驱动和室外定位不同,它提供了一整套解决方案,而室内定位仍未完全成熟. 目前,可用于大四轴的GPS高度是光流解决方案,对于小四轴已经更加成熟.
先看光流的影响
这是一只挥手的手
尽管背景在移动,但由于它们朝不同的方向移动光流 计算,他们仍然可以识别出正面的手. 当前景和背景运动不一致时,仍然可以识别它们.
那么光流是什么?
这个名字很,我觉得很奇怪. 本质上,光流是您在这个动感世界中感受到的明显视觉运动. 例如,当您坐在火车上,看着窗外. 您可以看到树木,地面,建筑物等,它们都向后移动. 该运动是光流. 而且,我们都会发现他们的运动速度实际上是不同的吗?这为我们提供了非常有趣的信息: 通过不同目标的移动速度来判断它们之间的距离. 一些遥远的物体,例如云层和山脉,移动得非常缓慢,感觉好像静止不动. 但是,一些较近的物体(例如建筑物和树木)会向后移动得更快,然后它们离我们越近,它们就移动得越快. 一些非常接近的物体,例如道路标记,草等,几乎被我们的耳朵打颤.
除了提供距离之外,光流还可以提供角度信息. 一个物体向我们的眼睛所面对的方向移动90度的速度比其他角度更快. 当它小到0度时,也就是说,物体直接撞击我们的方向,我们只是感觉不到它的运动(光流),它似乎是静止的. 随着距离越来越近,它变得越来越大.
比较官方的光流定义
光流的概念最早是由吉布森(Gibson)于1950年提出的. 它是空间物体在像素观察平面中移动的瞬时速度. 它使用图像序列中像素的时域变化以及相邻帧之间的相关性来查找前一帧和当前帧之间的存在. 对应,一种计算相邻帧之间对象运动信息的方法. 一般来说,光流是由场景中前景物体的移动,相机的移动或两者的联合移动引起的.
当人眼观察运动物体时,物体的场景在人眼视网膜上形成一系列连续变化的图像. 这一系列不断变化的信息像“光束”一样连续“流”过视网膜(即像平面). “光”流称为光流. 光流表示图像的变化. 因为它包含有关目标运动的信息,所以观察者可以使用它来确定目标的运动.
研究光流场的目的是近似无法直接从图像序列获得的运动场. 运动场实际上是三维现实世界中物体的运动. 光流场是运动场在二维图像平面(人眼或相机)上的投影.
一种流行的方法是通过一系列图片(即光流场)找出每个图像中每个像素的运动速度和方向. 如何找到它?我们的直观理解必须是: 点A在帧t处的位置为(x1,y1),然后我们在帧t + 1处找到点A,如果其位置为(x2,y2),则我们可以确定点A: (ux,vy)=(x2,y2)-(x1,y1).
那么您怎么知道点A在帧t + 1的位置?光流计算方法很多.
1981年,Horn和Schunck创造性地将二维速度场连接到灰度,引入了光流约束方程,并获得了光流计算的基本算法. 根据不同的理论基础,提出了各种光流计算方法,并且算法的性能也有所不同. Barron等. 总结了各种光流计算技术,根据理论和数学方法之间的差异将其分为四种类型: 基于梯度的方法,基于匹配的方法,基于能量的方法和基于相位的方法. 近年来,神经动力学方法也引起了学者的广泛关注.
让我们回到该应用程序. 目前,OpenCV中实现了许多光流算法.
1. calcOpticalFlowPyrLK
通过金字塔Lucas-Kanade光流方法计算某些点集的光流(稀疏光流). 如果您了解,则可以参考本文: “ Lucas Kanade Feature Tracker的金字塔式实现算法说明”
2. calcOpticalFlowFarneback
使用Gunnar Farneback的算法来计算密集的光流(即,计算图像上所有像素的光流). 相关论文有: “基于多项式展开的两帧运动估计”
3. CalcOpticalFlowBM
通过块匹配计算光通量.
4. CalcOpticalFlowHS
使用Horn-Schunck算法计算密集的光流. 相关文章似乎是: “确定光流”
5. calcOpticalFlowSF
这是2012年欧洲视觉会议的一篇文章的实现: “ SimpleFlow: 一种非迭代的亚线性光流算法”,该工程网站是: 在新版本的OpenCV中引入的.
还有使用其API的说明,我们可以直接参考OpenCV的官方手册:
#calcopticalflowfarneback
IJCv2011有一篇文章“光流的和评估方法”,简要介绍了主流的光流算法并评估了不同的算法. 网址是:
我觉得本文非常善于解释光流算法,并且规定也很明确. 如果您想了解光流,建议阅读这篇文章. 另外,需要提及的问题是光流场是图片中的每个像素在x方向和y方向上都有位移,因此上述光流计算后得到的光流是相同的. 作为原始图像尺寸双通道图像. 如何形象化?本文使用Munsell颜色系统进行显示.
孟塞尔色彩系统的空间大致为圆柱形:
南北轴=亮度(值),从全黑(1)到全白(10).
经度=色相. 将周分为五种主要颜色和五种中间颜色: 红色(R),红色(YR),(Y),黄绿色(GY),绿色(G),绿蓝色(BG),蓝色(B ),蓝紫色(PB),紫色(P),紫色红色(RP). 在两个相邻位置之间,等分10个部分,总共100个部分.

与轴的距离=色度(色度),表示色相的纯度. 随着色纯度的增加,其值从中间(0)到外部逐渐增加,并且没有理论上限(常规颜色实际上限制在10种左右,反射,荧光和其他材料可以高达30种). 由于人眼对各种颜色的敏感性不同,因此色度不一定与每种色调和亮度组合都匹配.
具体的颜色标识形式是: 色相+亮度+色度.
上面的评估网站上显示了从流程到颜色的matlab和C ++代码. 但是我觉得C ++代码被分成几个文件,这有点混乱,然后我将自己组织成两个函数并与OpenCV的Mat格式配合使用.
以下代码使用calcOpticalFlowFarneback计算密集的光流,并使用此颜色系统显示它. 与其他几种方法相比,这种计算密集光流的方法相对较快. 640x480视频地雷每帧约为200ms,但另一个通常要花费一秒或两秒以上的时间. 在结果图中,不同的颜色表示不同的移动方向,深度表示移动的速度.
void calcOpticalFlowFarneback(InputArray prevImg,InputArray nextImg,InputOutputArray流,double pyrScale,int级别,int winsize,整数,int polyN光流 计算,double polySigma,int标志)
本文中大多数参数都有一组很好的值,只需直接使用它们即可.
// Farneback密集光流在Munsell彩色系统中计算并显示
//作者: Zouxy
//日期: 2013-3-15
//主页:
//电子邮件: zouxy09@qq.com
// API calcOpticalFlowFarneback()来自OpenCV,而此
//来自以下论文的2D密集光流算法:
// Gunnar Farneback. “基于多项式展开的两帧运动估计”.
//和OpenCV源代码位于.. \ opencv2.4.3 \ modules \ video \ src \ optflowgf.cpp
#include
#include“ opencv2 / opencv.hpp”
使用命名空间cv;
使用命名空间标准;
#define UNKNOWN_FLOW_THRESH 1e9
//来自以下内容的流向量的颜色编码:
//
//此代码是从以下位置修改的:
//
void makecolorwheel(vector
{
int RY = 15;
int YG = 6;
int GC = 4;
int CB = 11;
int BM = 13;
int MR = 6;

int i;
for(i = 0; i for(i = 0; i 对于(i = 0; i for(i = 0; i 对于(i = 0; i 对于(i = 0; i } void motionToColor(垫子流,垫子和颜色) { 如果(color.empty()) color.create(flow.rows,flow.cols,CV_8UC3); 静态矢量 如果(colorwheel.empty()) makecolorwheel(colorwheel); //确定运动范围: float maxrad = -1; //找到最大流量以标准化fx和fy for(int i = 0; i { for(int j = 0; j { Vec2f flow_at_point = flow.at float fx = flow_at_point [0]; float fy = flow_at_point [1]; 如果((fabs(fx)> UNKNOWN_FLOW_THRESH)||(fabs(fy)> UNKNOWN_FLOW_THRESH)) 继续; float rad = sqrt(fx * fx + fy * fy); maxrad = maxrad>拉德? maxrad: rad; } } for(int i = 0; i { for(int j = 0; j { uchar * data = color.data + color.step [0] * i + color.step [1] * j; Vec2f flow_at_point = flow.at float fx = flow_at_point [0] / maxrad; float fy = flow_at_point [1] / maxrad; 如果((fabs(fx)> UNKNOWN_FLOW_THRESH)||(fabs(fy)> UNKNOWN_FLOW_THRESH)) { 数据[0] =数据[1] =数据[2] = 0; 继续; } float rad = sqrt(fx * fx + fy * fy); 浮角= atan2(-fy,-fx)/ CV_PI; float fk =(角度+ 1.0)/ 2.0 *(colorwheel.size()-1); int k0 =(int)fk; int k1 =(k0 + 1)%colorwheel.size(); float f = fk-k0; // f = 0; //取消注释以查看原始色轮 for(int b = 0; b <3; b ++) { float col0 =色轮[k0] [b] / 255.0; float col1 =色轮[k1] [b] / 255.0; float col =(1-f)* col0 + f * col1; 如果(rad <= 1) col = 1-rad *(1-col); //使用半径增加饱和度 其他 col * = .75; //超出范围 data [2-b] =(int)(255.0 * col); } } } } int main(int,char **) { VideoCapture上限; cap.open(0); // cap.open(“ test_02.wmv”); if(!cap.isOpened()) 返回-1; 棕垫,灰色,流,cflow,框架; namedWindow(“ flow”,1); 垫子Motion2color; for(;;) { double t =(double)cvGetTickCount(); 盖帽>>框架; cvtColor(frame,grey,CV_BGR2GRAY); imshow(“原始”,框架); 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) 休息; std :: swap(prevgray,grey); t =(double)cvGetTickCount()-t; cout <<“花费时间: ” << t /(((double)cvGetTickFrequency()* 1000. )<< endl; } 返回0; } 复制代码

本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/tongxinshuyu/article-237737-1.html
太完美了
因为现代战争将没有胜利者
我是导弹手