1. 程式人生 > >opencv光流Optical Flow

opencv光流Optical Flow

光流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)
大部分引數在論文中都有一套比較好的值的,直接採用他們的就好了。

//FarnebackdenseopticalflowcalculateandshowinMunsellsystemofcolors
//Author:Zouxy
//Date:2013-3-15
//HomePage:http://blog.csdn.net/zouxy09
//Email:[email protected]
//APIcalcOpticalFlowFarneback()comesfromOpenCV,andthis
//2Ddenseopticalflowalgorithmfromthefollowingpaper:
//GunnarFarneback."Two-FrameMotionEstimationBasedonPolynomialExpansion".
//AndtheOpenCVsourcecodelocatein..\opencv2.4.3\modules\video\src\optflowgf.cpp
#include<iostream>
#include"opencv2/opencv.hpp"
usingnamespacecv;
usingnamespacestd;
#defineUNKNOWN_FLOW_THRESH1e9
//Colorencodingofflowvectorsfrom:
//http://members.shaw.ca/quadibloc/other/colint.htm
//Thiscodeismodifiedfrom:
//http://vision.middlebury.edu/flow/data/
voidmakecolorwheel(vector<Scalar>&colorwheel)
{
intRY=15;
intYG=6;
intGC=4;
intCB=11;
intBM=13;
intMR=6;
inti;
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));
}
voidmotionToColor(Matflow,Mat&color)
{
if(color.empty())
color.create(flow.rows,flow.cols,CV_8UC3);
staticvector<Scalar>colorwheel;//Scalarr,g,b
if(colorwheel.empty())
makecolorwheel(colorwheel);
//determinemotionrange:
floatmaxrad=-1;
//Findmaxflowtonormalizefxandfy
for(inti=0;i<flow.rows;++i)
{
for(intj=0;j<flow.cols;++j)
{
Vec2fflow_at_point=flow.at<Vec2f>(i,j);
floatfx=flow_at_point[0];
floatfy=flow_at_point[1];
if((fabs(fx)>UNKNOWN_FLOW_THRESH)||(fabs(fy)>UNKNOWN_FLOW_THRESH))
continue;
floatrad=sqrt(fx*fx+fy*fy);
maxrad=maxrad>rad?maxrad:rad;
}
}
for(inti=0;i<flow.rows;++i)
{
for(intj=0;j<flow.cols;++j)
{
uchar*data=color.data+color.step[0]*i+color.step[1]*j;
Vec2fflow_at_point=flow.at<Vec2f>(i,j);
floatfx=flow_at_point[0]/maxrad;
floatfy=flow_at_point[1]/maxrad;
if((fabs(fx)>UNKNOWN_FLOW_THRESH)||(fabs(fy)>UNKNOWN_FLOW_THRESH))
{
data[0]=data[1]=data[2]=0;
continue;
}
floatrad=sqrt(fx*fx+fy*fy);
floatangle=atan2(-fy,-fx)/CV_PI;
floatfk=(angle+1.0)/2.0*(colorwheel.size()-1);
intk0=(int)fk;
intk1=(k0+1)%colorwheel.size();
floatf=fk-k0;
//f=0;//uncommenttoseeoriginalcolorwheel
for(intb=0;b<3;b++)
{
floatcol0=colorwheel[k0][b]/255.0;
floatcol1=colorwheel[k1][b]/255.0;
floatcol=(1-f)*col0+f*col1;
if(rad<=1)
col=1-rad*(1-col);//increasesaturationwithradius
else
col*=.75;//outofrange
data[2-b]=(int)(255.0*col);
}
}
}
}
intmain(int,char**)
{
VideoCapturecap;
cap.open(0);
//cap.open("test_02.wmv");
if(!cap.isOpened())
return-1;
Matprevgray,gray,flow,cflow,frame;
namedWindow("flow",1);
Matmotion2color;
for(;;)
{
doublet=(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<<"costtime:"<<t/((double)cvGetTickFrequency()*1000.)<<endl;
}
return0;
}

效果:在pc機上,計算160ms左右,也就是6幀,達不到實時的效果。


相關推薦

OpenCV (Optical Flow)

// Farneback dense optical flow calculate and show in Munsell system of colors // Author : Zouxy // Date : 2013-3-15 // HomePage : htt

opencvOptical Flow

光流Optical Flow 現在四軸飛行器越來越火,如何在室內進行定位呢?不同於傳統四軸的姿態控制,電機驅動,室外定位,都有了一套完整的方案,室內定位還是沒有完全成熟。,目前大四軸可以利用的GPS定高,小四軸比較成熟的也就是光流方案了。先看一下光流的效果這是一個揮動的手

什麼是Optical Flow

無人機上經常提到的光流法定位是什麼? 作為無人機愛好者一枚,經常關注比如大疆(DJI)、零度智控、PARRET的人都會看到他們提及的光流定位、室內懸停等的宣傳標語,那麼今天我們就來一起探討下它。 光流定義 光流通俗理解 光流法分析 參見

optical flow介紹

            光流是空間運動物體在觀測成像面上的畫素運動的瞬時速度。光流的研究是利用影象序列中的畫素強度資料的時域變化和相關性來確定各自畫素位置的“運動”,即研究影象灰度在時間上的變化與景象中物體結構及其運動的關係。將二維影象平面特定座標點上的灰度瞬時變化率定

(Optical Flow)--未完待續

光流 (Optical Flow) 物體在運動的時候,它在影象上對應畫素點也在做相應的運動,這種影象畫素的表觀運動就是光流,即空間運動物體在觀察成像平面上的畫素運動的瞬時速度。 當人的眼睛觀察運動物體時,物體的景象在人眼的視網膜上形成一系列連續變化的影象,

圖示識別Optical Flow

對於光流法的介紹,如下部落格先看如下部落格,瞭解概念 Lucas–Kanade光流演算法介紹:http://www.cnblogs.com/gnuhpc/archive/2012/12/04/2802124.html 將連結2中的例項和連線點選開啟連結結合,改寫成視訊跟

【圖像處理】openCV法追蹤運動物體

num blank ndis water 不同 h+ width 相關性 ida openCV光流法追蹤運動物體 email:[email protected]/* */ 一、光流簡單介紹 摘自:zouxy09 光流的概念是G

opencv法對特定區域進行跟蹤

本例子使用了opencv3.0,利用滑鼠選擇矩形框,然後對選擇的區域進行跟蹤 //---------------------------------光流法對特定區域進行跟蹤----------------- #include <iostream> #include <o

【影象處理】openCV法追蹤運動物體

openCV光流法追蹤運動物體 email:[email protected] 一、光流簡介         光流的概念是Gibson在1950年首先提出來的。它是空間運動物體在觀察成像平面上的畫素運動的瞬時速度,是利用影象序列中畫素在時間域上的變化以及相鄰幀之

OpenCV 演算法加速---使用GPU來計算

一、依賴項 OpenCV 2.4.13.x + CUDA 8.0 OpenCV 3.2.0及以上 + CUDA 8.0 OpenCV 3.4.x + CUDA 9.1 OpenCV編譯時,需要新增CUDA 支援。安裝CUDA 以及OpenCV,可參考我的另外兩篇部落格

有關opencv法的解釋

1981年,Horn和Schunck創造性地將二維速度場與灰度相聯絡,引入光流約束方程,得到光流計算的基本演算法。人們基於不同的理論基礎提出各種光流計算方法,演算法效能各有不同。Barron等人對多種光流計算技術進行了總結,按照理論基礎與數學方法的區別把它們分成四種:基於

法(Optical Flow)及OpenCV實現

Optical Flow Optical flow 有兩個假設: 亮度恆定:在相鄰連續兩幀中一個目標的畫素強度不會變化。 空間一致性:周圍畫素有類似執行。 時間規律:相鄰幀時間足夠短,以至於在考慮執行變化時可以忽略它們之間的差異。 假設在第一幀中畫素

法 學習--optical flow

學習背景: 為了更好地去理解Sift_flow的提出背景,廢話不多說,步入正題。 《學習openCV》一書,把它放在第10章跟蹤與運動,想必定和跟蹤問題有關了,腦子裡可以大概過一下跟蹤方面的問題,,自己過吧,略。 http://blog.csdn.net/carson200

CNN計算--FlowNet: Learning Optical Flow with Convolutional Networks

本文使用CNN網路來計算光流,實現端對端訓練,自己製作了個訓練資料庫 Flying Chairs Network Architectures 因為最後的結果需要得到畫素級別的,所以需要對CNN網路得到卷積特徵圖進行方法 光流計算的輸入是一個影象

極簡optical flow

實在時間緊,還是僅上英文版的,諸位見諒。原文在我的個人主頁上。 Simple optical flow based on depth and pose information Recently, I was helping to implement a simpl

optical flow

概念 光流是Gibson在1950年首先提出的,它是指空間運動物體在觀察成像平面上的畫素運動瞬時速度。是利用影象序列中畫素在時間域上的變化以及相鄰幀之間的相關性來找到上一幀跟當前幀之間存在的相應關係。一般而言,光流是因為場景中前景目標本身的移動、相機的運動

幾分鐘走進神奇的|FlowNet 2.0: Evolution of Optical Flow Estimation with Deep Networks

故事背景 那是15年的春天,本文的作者和其他幾個人,使用CNN做光流估計,於是FlowNet成了第一個用CNN做光流的模型,當時的結果還不足以和傳統結果相匹配。2016年冬天,作者和一群小夥伴又基於Flow Net的工作進行了改進,效果得到了提升

OpenCV法跟蹤器的使用方法學習

一、基於特徵點的目標跟蹤的一般步驟 (1)探測當前幀的特徵點 (2)通過當前幀和下一幀的灰度比較,估計當前幀特徵點在下一幀的位置 (3)過濾位置不變的特徵點,餘下的點就是目標了 基於特徵點的目標跟蹤演算法和1,2兩個步驟有關,特徵點可以是Harris角點,也可以是邊緣點等等,第二步估

opencv學習筆記四十二:稠密跟蹤

利用Gunnar Farneback演算法計算全域性性的稠密光流演算法(即影象上所有畫素點的光流都計算出來),由於要計算影象上所有點的光流,故計算耗時,速度慢  稠密光流需要使用某種插值方法在比較容易跟蹤的畫素之間進行插值以解決那些運動不明確的畫素 calcOpticalF

OpenCV筆記】法之金字塔Lucas-Kanade

本文參考連結:https://blog.csdn.net/zy122121cs/article/details/44955353 參考論文:”Pyramidal Implementation of the Lucas Kanade Feature TrackerDescrip