如何 医疗图像 加 荧光效果 opencv 图像旋转

SilkTest面试标题_“网易云阅览”-移动架构_光流Optical Flow引见与OpenCV实现__脚本百事通
稍等,加载中……
^_^请注意,有可能下面的2篇文章才是您想要的内容:
SilkTest面试标题
“网易云阅览”-移动架构
光流Optical Flow引见与OpenCV实现
SilkTest面试标题
SilkTest面试题目
好些年前我自己出的SilkTest面试题目,看看你能答对多少。
1)函数中参数列表里面的in, out, optional关键字代表什么意思?
2)一个testcase可以有参数么? testcase文件也就是.t文件中的main函数有什么作用?
3)如何指定某个变量是不可改变的?如果在脚本中用户尝试改变被定义为const的变量,会在编译期报错,还是执行期报错?为什么会出现这种情况?
4)引用其他文件使用什么关键字?
5) 启动silktest时报“No license for silktest GUI_8.5”,有哪些可能的原因?
1)Verify()函数的作用是什么?
2)如果不相等会如何?
3)如果抛出的异常没有处理会如何?
4)silktest中用什么函数抛出自定义异常?
5)silktest用什么语句来处理异常?
6)如果在异常处理完毕后,还想再次抛出异常使用什么函数?
1)tag和multitag的作用?
2)tag和nultitag有什么区别?
3)有一个曾经运行正常的testcase,突然有一天运行时,报错说某个对象找不到,可能是什么原因导致的?如何解决该问题?
是否调用过DLL文件中函数?
1)DLL文件对silktest有什么作用?
2)使用什么关键字来引用dll文件?
3)DLL中什么样的函数可以被silktest调用?
4)在配置文件(.inc文件)中声明DLL中函数的原型,有什么需要注意的么?
“网易云阅览”-移动架构
“网易云阅读”-移动架构
过年回家,手机中有两个应用是爱不释手的,一个是微信,一个就是网易云阅读了。这里不谈论微信了,说说网易云阅读。刚刚接触网易云阅读,是偶然的,具体咋知道的已经忘了。这个APP且不谈交互体验好不好(在交互细节上面只能说还凑活,能够满足需求,但是没有超出期望),但确实解决了我的问题,零碎时间的阅读问题。之前网页端阅读36氪文档以及其他网站的文章,下了个虎嗅的客户端看文章,觉得有点分散,后来这个app有了之后,直接订阅了,减少了看文章来回切换的麻烦了,至此之后,爱不释手呵呵。
正好最近Infoq上面有篇关于移动架构的文章,大体看了一下PPT,觉得写得挺实在,例子就是网易云阅读,所以正好算是简介翻译一下这篇文章,结合我这个菜鸟的理解,也算是学习一下优秀的架构。
网易云阅读的下载地址:/
移动应用架构策略(infoq地址):q.com/cn/presentations/mobile-application-architecture-strategy (作者和我是一个工种呵呵,IT中的服务端开发)
1、平台类的应用
第一次使用这个app,就发现他是平台级的应用产品,自己不生产内容,聚合第三方的信息,为用户提供阅读服务,作为用户不需要到处查看文章内容,内容提供者不需要考虑推广等事情,可以专注于自己的内容。
2、移动产品存在的问题
A、目前的网络十分复杂,导致的就是网络速度不均匀,有地地方会出现网络死角、在移动过程中网速不稳定;(根据友盟的数据来看,目前2G和wifi的联网方式各占40%左右,3G的占20%左右)。
B、不同设备的屏幕尺寸不统一,导致需要根据尺寸来进行内容适配,要达到两盒的视觉呈现还是有点费劲的;(IOS系列的产品有十余种,其中iPhone和iPad占比比较大;android系列的产品更是很多,友盟的数据有四十余种
/#android_device
C、移动设备自身硬件能力具有局限性
移动设备运行着APP,此时就相当于一个独立的服务器啊。首先电池容量小,这要求编写的app要能够省电;内存小,经常会出现应为内存不足而造成app闪退的现象(话说我之前搞的那个玩具在测试的时候也经常闪退呢);CPU处理能力有限,要进行复杂的逻辑处理,做好在云端服务器中处理掉;存储空间有限,这个受限于内存卡,大家都懂的。
3、服务器端架构
这个的话没有啥特别之处,典型的web应用的架构形式(为app提供http请求的服务,如果是静态图片或者静态文件,会有相应的CDN服务器,来加速这类的请求)。最前端有负载均衡处理器(例如运行的LVS程序的机器);然后是webserver(例如apache或者nginx,目前淘宝系主推tengine,一个改善的nginx的版本,有一个团队在维护);之后是appServer(作为java开发,我就暂且理解为java的web程序,appServer是分布式的,可以动态水平扩展,就是加减机器对于前台请求以及后台数据没有影响);然后再后面是数据库、缓存处理器、分布式文件系统等持久化设施。
对于云阅读产品来说,貌似之前听说有几种获取信息的策略,虽然是坊间传闻,但是我觉得也差不多。
A、开放平台对接,内容提供者通过调用API接口,把最新的文章信息同步给appServer对应的持久化设施,这种最方便,但是需要监控接口的稳定程度;
B、内容提供者把内容维护在网易云阅读提供的后台,在后台直接录入文章等信息;
C、网易云阅读搞一个服务端程序,去抓取内容提供者发布的信息,然后过滤、清洗,存储起来对外提供服务;
下图是抓取服务的架构图:
Manager负责load第三方提供的URL信息,然后Crawler负责抓取信息,之后Analyzer负责分析页面的DOM结构,之后存储在DB中,对外提供服务。
4、客户端架构
从下面这张图来看,客户端设计是分层的,非常清晰。
A、客户端本地数据库,负责存储用户个人信息、系统配置信息,以及缓存数据,这里存储的数据,是需要在服务器端也存储起来的,就是数据要同步,负责我更换了一个手机,之前设置的信息没有同步过来,是一个比较痛苦的事情;
B、View层,总体负责View的展现、UI的优化。动画效果、以及页面回调等,类似web中的View层,就是负责展示的;
C、网络层,我个人理解,负责网络请求的封装(组装参数、发起请求、解析返回结果);
D、逻辑控制、服务组合和数据持久化我认为是一层,就是核心逻辑处理,运行在客户端,数据获取和存储依赖于网络层向服务器端发起请求;
这样,客户端的架构就比较清晰,维护起来也就没那么蛋疼了。
5、优化策略
A、图片服务器智能化,尽量返回客户端合适的图片,例如pad类的产品,就直接返回他尺寸大一点的图片,手机类的就返回尺寸小一点的图片,图片的剪裁和浓缩在服务器端完成,需要在客户端再来做这些事情;
B、确定是否进行预加载和加载的优先级,图片或者文章,都有“下一页”和“上一页”的翻页操作,可以根据用户的使用习惯,来进行预先加载,例如用户在看文章的时候,习惯进行“下一页”操作,那我们就在用户“阅读当前页面”的时候,把下一页的文章加载进行,这样用户在进行下一页阅读的时候,体验会很好(可以在客户端维持几个变量,把用户的行为转变为可衡量的数字,这样就可以依赖这些变量来判断是否需要预先加载);
C、缓存要进行管理,缓存是否需要失效,需要有判断的原则,一种是请求服务器端,如果数据过期,则直接进行失效即可,另外一种就是客户端根据容量情况来进行失效(这一点类似于服务器端缓存失效策略呵呵);
D、数据压缩,要省流量,需要压缩(使用UC浏览器能省流量,原因也是由于压缩),网易云阅读使用的是GZIP的压缩方式,服务器端在发送数据的时候,把数据通过Gzip来压缩,然后客户端接受之后,再按照协议来解压缩,这样流量就省下了;
E、使用http长连接(因为构建http链接是很耗时的操作,所以可以保值长连接,减少反复握手的网络和资源开销),断点续传(对于较大文件,能够减少网络流量),重连策略(如果网络异常,则可以根据适当的算法来进行重连,但是方法最好是幂等的);
F、消息推送,IOS有自带的通知机制(IOS Push),android的话google有产品,但是在国内不好用,你懂的,需要自己为移动终端自建Push服务。有一个原则是网易云阅读分享出来的,一个是移动终端登录后和Push服务器保持连接,Push服务器主动心跳来保持这个连接(移动终端可以动态调整Push服务器的心跳间隔);
6、系统复用
A、 尽量使用现有的解决方案,因为成本低、风险小;
B、UI组件复用、源代码复用、开源组件复用,框架设计巧妙,直接插件开发即可;
最理想的情况是,集成现用的系统来创建新的应用。
PPT中基本上介绍了“网易云阅读”这款产品的情况,十分详尽,后面作者有提到关于产品设计以及需求处理方面,这里就不多讲了。
光流Optical Flow引见与OpenCV实现
光流Optical Flow介绍与OpenCV实现光流Optical Flow介绍与OpenCV实现
http://blog.csdn.net/zouxy09
光流(optic flow)是什么呢?名字很专业,感觉很陌生,但本质上,我们是最熟悉不过的了。因为这种视觉现象我们每天都在经历。从本质上说,光流就是你在这个运动着的世界里感觉到的明显的视觉运动(呵呵,相对论,没有绝对的静止,也没有绝对的运动)。例如,当你坐在火车上,然后往窗外看。你可以看到树、地面、建筑等等,他们都在往后退。这个运动就是光流。而且,我们都会发现,他们的运动速度居然不一样?这就给我们提供了一个挺有意思的信息:通过不同目标的运动速度判断它们与我们的距离。一些比较远的目标,例如云、山,它们移动很慢,感觉就像静止一样。但一些离得比较近的物体,例如建筑和树,就比较快的往后退,然后离我们的距离越近,它们往后退的速度越快。一些非常近的物体,例如路面的标记啊,草地啊等等,快到好像在我们耳旁发出嗖嗖的声音。
光流除了提供远近外,还可以提供角度信息。与咱们的眼睛正对着的方向成90度方向运动的物体速度要比其他角度的快,当小到0度的时候,也就是物体朝着我们的方向直接撞过来,我们就是感受不到它的运动(光流)了,看起来好像是静止的。当它离我们越近,就越来越大(当然了,我们平时看到感觉还是有速度的,因为物体较大,它的边缘还是和我们人眼具有大于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新版本中有引入。
稠密光流需要使用某种插值方法在比较容易跟踪的像素之间进行插值以解决那些运动不明确的像素,所以它的计算开销是相当大的。而对于稀疏光流来说,在他计算时需要在被跟踪之前指定一组点(容易跟踪的点,例如角点),因此在使用LK方法之前我们需要配合使用cvGoodFeatureToTrack()来寻找角点,然后利用金字塔LK光流算法,对运动进行跟踪。但个人感觉,对于少纹理的目标,例如人手,LK稀疏光流就比较容易跟丢。
至于他们的API的使用说明,我们直接参考OpenCV的官方手册就行:
http://www./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颜色系统来显示。
关于孟塞尔颜色系统(MunsellColor System),可以看wikibaike。它是美国艺术家阿尔伯特孟塞尔(Albert H. Munsell,)在1898年创制的颜色描述系统。
孟塞尔颜色系统的空间大致成一个圆柱形:
南北轴=明度(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
// HomePage : http://blog.csdn.net/zouxy09
// 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"
#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;
for (i = 0; i & RY; i++) colorwheel.push_back(Scalar(255,
for (i = 0; i & YG; i++) colorwheel.push_back(Scalar(255-255*i/YG, 255,
for (i = 0; i & GC; i++) colorwheel.push_back(Scalar(0,
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,
for (i = 0; i & MR; i++) colorwheel.push_back(Scalar(255,
255-255*i/MR));
void motionToColor(Mat flow, Mat &color)
if (color.empty())
color.create(flow.rows, flow.cols, CV_8UC3);
static vector&Scalar& //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. ++i)
for (int j = 0; j & flow. ++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))
float rad = sqrt(fx * fx + fy * fy);
maxrad = maxrad & rad ? maxrad :
for (int i= 0; i & flow. ++i)
for (int j = 0; j & flow. ++j)
uchar *data = color.data + color.step[0] * i + color.step[1] *
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))
data[0] = data[1] = data[2] = 0;
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)
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
col *= .75; // out of range
data[2 - b] = (int)(255.0 * col);
int main(int, char**)
capture.open(0);
//cap.open("test_02.wmv");
if( !cap.isOpened() )
return -1;
Mat prevgray, gray, flow, cflow,
namedWindow("flow", 1);
Mat motion2
double t = (double)cvGetTickCount();
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)
std::swap(prevgray, gray);
t = (double)cvGetTickCount() -
cout && "cost time: " && t / ((double)cvGetTickFrequency()*1000.) &&
这个是效果:
一个挥动的手:
虽然也有背景在动,但是因为他们的运动方向不一样,所以还是可以辨认出来前面那个是手,在前景和背景运动不统一的时候,还是可以辨认出来的。
如果您想提高自己的技术水平,欢迎加入本站官方1号QQ群:&&,&&2号QQ群:,在群里结识技术精英和交流技术^_^
本站联系邮箱:只需一步,快速开始
扫一扫,访问微社区
后使用快捷导航没有帐号?
查看: 1036|回复: 2
光流Optical Flow介绍与OpenCV实现
加入社区,轻松玩转无人机!
才可以下载或查看,没有帐号?
本帖最后由 Bluesky 于
13:21 编辑
blog.csdn.net/zouxy09
& &光流(optic flow)是什么呢?名字很专业,感觉很陌生,但本质上,我们是最熟悉不过的了。因为这种视觉现象我们每天都在经历。从本质上说,光流就是你在这个运动着的世界里感觉到的明显的视觉运动(呵呵,相对论,没有绝对的静止,也没有绝对的运动)。例如,当你坐在火车上,然后往窗外看。你可以看到树、地面、建筑等等,他们都在往后退。这个运动就是光流。而且,我们都会发现,他们的运动速度居然不一样?这就给我们提供了一个挺有意思的信息:通过不同目标的运动速度判断它们与我们的距离。一些比较远的目标,例如云、山,它们移动很慢,感觉就像静止一样。但一些离得比较近的物体,例如建筑和树,就比较快的往后退,然后离我们的距离越近,它们往后退的速度越快。一些非常近的物体,例如路面的标记啊,草地啊等等,快到好像在我们耳旁发出嗖嗖的声音。
& && & 光流除了提供远近外,还可以提供角度信息。与咱们的眼睛正对着的方向成90度方向运动的物体速度要比其他角度的快,当小到0度的时候,也就是物体朝着我们的方向直接撞过来,我们就是感受不到它的运动(光流)了,看起来好像是静止的。当它离我们越近,就越来越大(当然了,我们平时看到感觉还是有速度的,因为物体较大,它的边缘还是和我们人眼具有大于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&,工程网站是:&&在OpenCV新版本中有引入。
& && & 稠密光流需要使用某种插值方法在比较容易跟踪的像素之间进行插值以解决那些运动不明确的像素,所以它的计算开销是相当大的。而对于稀疏光流来说,在他计算时需要在被跟踪之前指定一组点(容易跟踪的点,例如角点),因此在使用LK方法之前我们需要配合使用cvGoodFeatureToTrack()来寻找角点,然后利用金字塔LK光流算法,对运动进行跟踪。但个人感觉,对于少纹理的目标,例如人手,LK稀疏光流就比较容易跟丢。
& && & 至于他们的API的使用说明,我们直接参考OpenCV的官方手册就行:
& && & IJCV2011有一篇文章,《A Database and Evaluation Methodology for Optical Flow》里面对主流的光流算法做了简要的介绍和对不同算法进行了评估。网址是:
& && & 感觉这个文章在光流算法的解说上非常好,条例很清晰。想了解光流的,推荐看这篇文章。另外,需要提到的一个问题是,光流场是图片中每个像素都有一个x方向和y方向的位移,所以在上面那些光流计算结束后得到的光流flow是个和原来图像大小相等的双通道图像。那怎么可视化呢?这篇文章用的是Munsell颜色系统来显示。
& && & 关于孟塞尔颜色系统(MunsellColor System),可以看。它是美国艺术家阿尔伯特孟塞尔(Albert H. Munsell,)在1898年创制的颜色描述系统。
1.jpg (49.2 KB, 下载次数: 12)
13:16 上传
孟塞尔颜色系统的空间大致成一个圆柱形:
南北轴=明度(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)大部分参数在论文中都有一套比较好的值的,直接采用他们的就好了。[C++] 纯文本查看 复制代码// Farneback dense optical flow calculate and show in Munsell system of colors
// Author : Zouxy
// HomePage : [url]http://blog.csdn.net/zouxy09[/url]
: [email][/email]
// 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&
#define UNKNOWN_FLOW_THRESH 1e9
// Color encoding of flow vectors from:
// [url]http://members.shaw.ca/quadibloc/other/colint.htm[/url]
// This code is modified from:
// [url]http://vision.middlebury.edu/flow/data/[/url]
void makecolorwheel(vector&Scalar& &colorwheel)
int RY = 15;
int YG = 6;
int GC = 4;
int CB = 11;
int BM = 13;
int MR = 6;
for (i = 0; i & RY; i++) colorwheel.push_back(Scalar(255,
for (i = 0; i & YG; i++) colorwheel.push_back(Scalar(255-255*i/YG, 255,
for (i = 0; i & GC; i++) colorwheel.push_back(Scalar(0,
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,
for (i = 0; i & MR; i++) colorwheel.push_back(Scalar(255,
255-255*i/MR));
void motionToColor(Mat flow, Mat &color)
if (color.empty())
color.create(flow.rows, flow.cols, CV_8UC3);
static vector&Scalar& //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. ++i)
for (int j = 0; j & flow. ++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))
float rad = sqrt(fx * fx + fy * fy);
maxrad = maxrad & rad ? maxrad :
for (int i= 0; i & flow. ++i)
for (int j = 0; j & flow. ++j)
uchar *data = color.data + color.step[0] * i + color.step[1] *
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))
data[0] = data[1] = data[2] = 0;
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)
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
col *= .75; // out of range
data[2 - b] = (int)(255.0 * col);
int main(int, char**)
cap.open(0);
//cap.open(&test_02.wmv&);
if( !cap.isOpened() )
return -1;
Mat prevgray, gray, flow, cflow,
namedWindow(&flow&, 1);
Mat motion2
double t = (double)cvGetTickCount();
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)
std::swap(prevgray, gray);
t = (double)cvGetTickCount() -
cout && &cost time: & && t / ((double)cvGetTickFrequency()*1000.) &&
这个是效果:一个挥动的手:
2.jpg (13.5 KB, 下载次数: 8)
13:16 上传
& && &虽然也有背景在动,但是因为他们的运动方向不一样,所以还是可以辨认出来前面那个是手,在前景和背景运动不统一的时候,还是可以辨认出来的。
3.jpg (20.1 KB, 下载次数: 11)
13:16 上传
大赞,很好的开源图像处理
very good!&&初识“光流”
Powered by}

我要回帖

更多关于 opencv 图像分割 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信