1. 程式人生 > >Opencv學習筆記(九)光流法

Opencv學習筆記(九)光流法

    原創文章,轉貼請註明:http://blog.csdn.net/crzy_sparrow/article/details/7407604

本文目錄:

      一.基於特徵點的目標跟蹤的一般方法

      二.光流法

      三.opencv中的光流法函式

      四.用類封裝基於光流法的目標跟蹤方法

      五.完整程式碼

      六.參考文獻

一.基於特徵點的目標跟蹤的一般方法

      基於特徵點的跟蹤演算法大致可以分為兩個步驟:

      1)探測當前幀的特徵點;

      2)通過當前幀和下一幀灰度比較,估計當前幀特徵點在下一幀的位置;

      3)過濾位置不變的特徵點,餘下的點就是目標了。

      很顯然,基於特徵點的目標跟蹤演算法和1),2)兩個步驟有關。特徵點可以是Harris角點(見我的另外一篇博文),也可以是邊緣點等等,而估計下一幀位置的方法也有不少,比如這裡要講的光流法,也可以是卡爾曼濾波法(咱是控制系的,上課經常遇到這個,所以看光流法看著看著就想到這個了)。

      本文中,用改進的Harris角點提取特徵點(見我另一篇博文:http://blog.csdn.net/crzy_sparrow/article/details/7391511),用Lucas-Kanade光流法實現目標跟蹤。

二.光流法

      這一部分《learing opencv》一書的第10章Lucas-Kanade

光流部分寫得非常詳細,推薦大家看書。我這裡也粘帖一些選自書中的內容。

      另外我對這一部分附上一些個人的看法(謬誤之處還望不吝指正):

      1.首先是假設條件:

       (1)亮度恆定,就是同一點隨著時間的變化,其亮度不會發生改變。這是基本光流法的假定(所有光流法變種都必須滿足),用於得到光流法基本方程;

       (2)小運動,這個也必須滿足,就是時間的變化不會引起位置的劇烈變化,這樣灰度才能對位置求偏導(換句話說,小運動情況下我們才能用前後幀之間單位位置變化引起的灰度變化去近似灰度對位置的偏導數),這也是光流法不可或缺的假定;

       (3)空間一致,一個場景上鄰近的點投影到影象上也是鄰近點,且鄰近點速度一致。這是Lucas-Kanade

光流法特有的假定,因為光流法基本方程約束只有一個,而要求x,y方向的速度,有兩個未知變數。我們假定特徵點鄰域內做相似運動,就可以連立n多個方程求取x,y方向的速度(n為特徵點鄰域總點數,包括該特徵點)。

      2.方程求解

      多個方程求兩個未知變數,又是線性方程,很容易就想到用最小二乘法,事實上opencv也是這麼做的。其中,最小誤差平方和為最優化指標。

      3.好吧,前面說到了小運動這個假定,聰明的你肯定很不爽了,目標速度很快那這貨不是二掉了。幸運的是多尺度能解決這個問題。首先,對每一幀建立一個高斯金字塔,最大尺度圖片在最頂層,原始圖片在底層。然後,從頂層開始估計下一幀所在位置,作為下一層的初始位置,沿著金字塔向下搜尋,重複估計動作,直到到達金字塔的底層。聰明的你肯定發現了:這樣搜尋不僅可以解決大運動目標跟蹤,也可以一定程度上解決孔徑問題(相同大小的視窗能覆蓋大尺度圖片上儘量多的角點,而這些角點無法在原始圖片上被覆蓋)。


三.opencv中的光流法函式

      opencv2.3.1中已經實現了基於光流法的特徵點位置估計函式(當前幀位置已知,前後幀灰度已知),介紹如下(摘自opencv2.3.1參考手冊):

calcOpticalFlowPyrLK
Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade method with pyramids.

void calcOpticalFlowPyrLK(InputArray prevImg, InputArray nextImg, InputArray prevPts,
InputOutputArray nextPts, OutputArray status, OutputArray err,
Size winSize=Size(15,15), int maxLevel=3, TermCriteria crite-
ria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),
double derivLambda=0.5, int flags=0 )

Parameters
prevImg – First 8-bit single-channel or 3-channel input image.
nextImg – Second input image of the same size and the same type as prevImg .
prevPts – Vector of 2D points for which the flow needs to be found. The point coordinates
must be single-precision floating-point numbers.
nextPts – Output vector of 2D points (with single-precision floating-point coordinates)
containing the calculated new positions of input features in the second image. When
OPTFLOW_USE_INITIAL_FLOW flag is passed, the vector must have the same size as in the
input.
status – Output status vector. Each element of the vector is set to 1 if the flow for the
corresponding features has been found. Otherwise, it is set to 0.
err – Output vector that contains the difference between patches around the original and
moved points.
winSize – Size of the search window at each pyramid level.

maxLevel – 0-based maximal pyramid level number. If set to 0, pyramids are not used
(single level). If set to 1, two levels are used, and so on.
criteria – Parameter specifying the termination criteria of the iterative search algorithm
(after the specified maximum number of iterations criteria.maxCount or when the search
window moves by less than criteria.epsilon .
derivLambda – Not used.

flags – Operation flags:
– OPTFLOW_USE_INITIAL_FLOW Use initial estimations stored in nextPts . If the
flag is not set, then prevPts is copied to nextPts and is considered as the initial estimate.

四.用類封裝基於光流法的目標跟蹤方法

      廢話少說,附上程式碼,包括特徵點提取,跟蹤特徵點,標記特徵點等。

//幀處理基類
class FrameProcessor{
    public:
        virtual void process(Mat &input,Mat &ouput)=0;
};

//特徵跟蹤類,繼承自幀處理基類
class FeatureTracker :  public FrameProcessor{
    Mat gray;  //當前灰度圖
    Mat gray_prev;  //之前的灰度圖
    vector<Point2f> points[2];//前後兩幀的特徵點
    vector<Point2f> initial;//初始特徵點
    vector<Point2f> features;//檢測到的特徵
    int max_count; //要跟蹤特徵的最大數目
    double qlevel; //特徵檢測的指標
    double minDist;//特徵點之間最小容忍距離
    vector<uchar> status; //特徵點被成功跟蹤的標誌
    vector<float> err; //跟蹤時的特徵點小區域誤差和
public:
    FeatureTracker():max_count(500),qlevel(0.01),minDist(10.){}
    void process(Mat &frame,Mat &output){
        //得到灰度圖
        cvtColor (frame,gray,CV_BGR2GRAY);
        frame.copyTo (output);
        //特徵點太少了,重新檢測特徵點
        if(addNewPoint()){
            detectFeaturePoint ();
            //插入檢測到的特徵點
            points[0].insert (points[0].end (),features.begin (),features.end ());
            initial.insert (initial.end (),features.begin (),features.end ());
        }
        //第一幀
        if(gray_prev.empty ()){
                gray.copyTo (gray_prev);
        }
        //根據前後兩幀灰度圖估計前一幀特徵點在當前幀的位置
        //預設視窗是15*15
        calcOpticalFlowPyrLK (
                gray_prev,//前一幀灰度圖
                gray,//當前幀灰度圖
                points[0],//前一幀特徵點位置
                points[1],//當前幀特徵點位置
                status,//特徵點被成功跟蹤的標誌
                err);//前一幀特徵點點小區域和當前特徵點小區域間的差,根據差的大小可刪除那些運動變化劇烈的點
        int k = 0;
        //去除那些未移動的特徵點
        for(int i=0;i<points[1].size ();i++){
            if(acceptTrackedPoint (i)){
                initial[k]=initial[i];
                points[1][k++] = points[1][i];
            }
        }
        points[1].resize (k);
        initial.resize (k);
        //標記被跟蹤的特徵點
        handleTrackedPoint (frame,output);
        //為下一幀跟蹤初始化特徵點集和灰度影象
        std::swap(points[1],points[0]);
        cv::swap(gray_prev,gray);
    }

    void detectFeaturePoint(){
        goodFeaturesToTrack (gray,//輸入圖片
                                 features,//輸出特徵點
                                 max_count,//特徵點最大數目
                                 qlevel,//質量指標
                                 minDist);//最小容忍距離
    }
    bool addNewPoint(){
        //若特徵點數目少於10,則決定新增特徵點
        return points[0].size ()<=10;
    }

    //若特徵點在前後兩幀移動了,則認為該點是目標點,且可被跟蹤
    bool acceptTrackedPoint(int i){
        return status[i]&&
                (abs(points[0][i].x-points[1][i].x)+
                  abs(points[0][i].y-points[1][i].y) >2);
    }

    //畫特徵點
    void  handleTrackedPoint(Mat &frame,Mat &output){
            for(int i=0;i<points[i].size ();i++){
                //當前特徵點到初始位置用直線表示
                line(output,initial[i],points[1][i],Scalar::all (0));
                //當前位置用圈標出
                circle(output,points[1][i],3,Scalar::all(0),(-1));
            }
        }
};

五.完整程式碼
  完整的執行程式碼有300+行,粘上來太多了,大家去我傳的資源裡下載吧。

  下載地址:http://download.csdn.net/detail/crzy_sparrow/4183674

  執行結果:


六.參考文獻

【1】The classic article by B. Lucas and T. Kanade, An iterative image registration technique with an application to stereo vision in Int. Joint Conference in Artificial Intelligence, pp. 674-679,1981, that describes the original feature point tracking algorithm.
【2】The article by J. Shi and C. Tomasi, Good Features to Track in IEEE Conference on Computer Vision and Pattern Recognition, pp. 593-600, 1994, that describes an improved version of the original feature point tracking algorithm.



相關推薦

Opencv學習筆記

    原創文章,轉貼請註明:http://blog.csdn.net/crzy_sparrow/article/details/7407604 本文目錄:       一.基於特徵點的目標跟蹤的一般方法       二.光流法       三.opencv中的光流法函式

opencv學習筆記捕獲攝像頭的視訊並儲存成avi格式

        這個程式引用自下面的部落格,但是執行之後我發現視訊儲存之後,要利用前面提到的opencv播放視訊程式播放,不能用普通播放器播放——而且用前面的opencv程式播放時,影象是倒置的,需要我們在程式裡面改一下。在while(1)裡面加上一句     cvFlip

python OpenCV學習筆記:圖片的幾何變形

縮放 import numpy as np import cv2 as cv img = cv.imread('test.jpg') res = cv.resize(img, None, fx=2, fy=2, interpolation=

Ceres Solver 官方教程學習筆記——自動微分Automatic Derivatives

現在我們將討論自動微分演算法。它是一種可以快速計算精確導數的演算法,同時使用者只要做與數值微分法類似的工作。下面的程式碼片段實現了對Rat43(見前兩節)的CostFunction。 struct Rat43CostFunctor { Rat43C

java學習筆記:Java (Stream)、文件(File)和IO

用戶輸入 public 文件內容 輸出流 out 單個 java 我們 ready Java 的控制臺輸入由 System.in 完成。 為了獲得一個綁定到控制臺的字符流,你可以把 System.in 包裝在一個 BufferedReader 對象中來創建一個字符流。需要i

TypeScript學習筆記:裝飾器Decorators

標註 時裝 als cal () 操作 enume 筆記 文檔 裝飾器簡介 裝飾器(Decorators)為我們在類的聲明及成員上通過元編程語法添加標註提供了一種方式。 需要註意的是:裝飾器是一項實驗性特性,在未來的版本中可能會發生改變。 若要啟用實驗性的裝飾器特性

如鵬網學習筆記JavaScript

計算機編程 lean 有效 拼接字符串 {} efault 含義 函數重載 cas JavaScript筆記 一、JavaScript簡介   1,JavaScript是一種計算機編程語言,可以像等其他編程語言那樣定義變量,執行循環等。   2,JavaScript代碼主

Python學習筆記

port 驗證方式 模塊 install name 第三方模塊 rom pip private 一、Python模塊的引入   import sys #可以通過模塊名以及import關鍵字導入模塊 二、if __name__ == "__main__"   當Python在

深度學習筆記感受野計算

lds 時有 輸入 計算 ret name %d have imsi 1 感受野的概念   在卷積神經網絡中,感受野的定義是 卷積神經網絡每一層輸出的特征圖(feature map)上的像素點在原始圖像上映射的區域大小。一般感受野大小是目標大小的兩倍左右最合適!      

學習筆記——數據庫存儲結構:頁、聚集索引、非聚集索引

分享 style end 宋體 blog lec storage rop cas 1、頁 SQL Server用8KB 的頁來存儲數據,並且在SQL Server裏磁盤 I/O 操作在頁級執行。也就是說,SQL Server 讀取或寫入所有數據頁。頁有不同的類型,像

Elasticsearch學習筆記partial update

cse adding 操作 nbsp 進行 樂觀 gin clas 比較 一、什麽是partial update? PUT /index/type/id,創建文檔&替換文檔,就是一樣的語法 一般對應到應用程序中,每次的執行流程基本是這樣的: (1)應

python學習筆記之語句1

如果 red 開始 就是 整除 for 循環 個數 hello 基本 python學習筆記(九)之語句1printpython2中,print是一個語句,python3中它是一個函數。實例1: >> print "hello,world!"

day5-Python學習筆記json數據類型

class json mps pen log imp color python 文件 import json#json串就是字符串。d = { ‘car‘:{‘color‘:‘red‘,‘price‘:100,‘count‘:50}, ‘挨糞叉‘:{‘color‘:

《Qt5 開發與實例第三版學習筆記

nal inf lin exc ken right item vbo ott 1 // 3.4 基本布局(QLayout) 2 //dialog.h 3 #ifndef DIALOG_H 4 #define DIALOG_H 5 6 #incl

Linux學習筆記find、文件名後綴

行為 指定文件類型 type install 需要 所有 如果 查找文件 size 一、linux中查找文件有很多種法,例如之前用過的which、whereis,此外還有locate 如果沒有安裝locate ,則需要運行 yum install -y mlocate

kettle學習筆記——子轉換、集群與變量

bec param TP 一個 字段 暴露 空格 參數用法 用法 一、概述   kettle中3個重要的步驟:     子轉換/映射       在轉換裏調用一個子轉換,便於封裝和重用。     集群       集群模式     變量和參數       變量和參數的用法

WPF 學習筆記

toolbar 添加 mas eight click top dock horizon ima 一、菜單的創建 <Window x:Class="WpfApplication6.MainWindow" xmlns="http://schemas

OpenCV學習筆記31KAZE 演算法原理與原始碼分析KAZE的原始碼優化及與SIFT的比較

  KAZE系列筆記: 1.  OpenCV學習筆記(27)KAZE 演算法原理與原始碼分析(一)非線性擴散濾波 2.  OpenCV學習筆記(28)KAZE 演算法原理與原始碼分析(二)非線性尺度空間構建 3.  Op

OpenCV學習筆記30KAZE 演算法原理與原始碼分析KAZE特徵的效能分析與比較

      KAZE系列筆記: 1.  OpenCV學習筆記(27)KAZE 演算法原理與原始碼分析(一)非線性擴散濾波 2.  OpenCV學習筆記(28)KAZE 演算法原理與原始碼分析(二)非線性尺度空間構

OpenCv學習筆記—cv::Mat學習

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!