日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Optical_Flow(3)

發布時間:2023/12/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Optical_Flow(3) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文轉自:http://blog.csdn.net/zouxy09/article/details/8683859


光流Optical Flow介紹與OpenCV實現

?

? ? ? ?光流(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.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顏色系統來顯示。

? ? ? ?關于孟塞爾顏色系統(MunsellColor System),可以看wikibaike。它是美國藝術家阿爾伯特孟塞爾(Albert H. Munsell,1858-1918)在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)

大部分參數在論文中都有一套比較好的值的,直接采用他們的就好了。

[cpp]?view plaincopy
  • //?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;??
  • }??

  • 這個是效果:

    一個揮動的手:

    ? ? ? 雖然也有背景在動,但是因為他們的運動方向不一樣,所以還是可以辨認出來前面那個是手,在前景和背景運動不統一的時候,還是可以辨認出來的。




    總結

    以上是生活随笔為你收集整理的Optical_Flow(3)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。