天天看點

《OpenCV2 計算機視覺程式設計手冊》視訊處理二

本文結合上文《OpenCV2 計算機視覺編碼手冊》視訊處理一的基礎上,添加視訊跟蹤類,來對視訊中運動對象進行跟蹤。

1. 添加特征跟蹤類

#ifndef FTRACKER
#define FTRACKER

#include "head.h"
#include "videoprocessor.h"
#include <opencv2/video/tracking.hpp>
#include <opencv2/features2d/features2d.hpp>

class FeatureTracker : public FrameProcessor 
{    
private:
    cv::Mat gray;                        // 目前灰階圖像
    cv::Mat gray_prev;                    // 前一個灰階圖像
    std::vector<cv::Point2f> points[2]; // 兩幅圖像跟蹤特征 0->1
    std::vector<cv::Point2f> initial;   // 跟蹤點的初始化
    std::vector<cv::Point2f> features;  // 檢測到的特征
    int max_count;                        // 需要跟蹤的最大特征數目
    double qlevel;                      // 特征檢測中的品質等級
    double minDist;                     // 兩特征點之間的最小距離
    std::vector<uchar> status;          // 跟蹤的特征狀态
    std::vector<float> err;             // 跟蹤錯誤

public:
    // 構造函數
    FeatureTracker() : max_count(500), qlevel(0.01), minDist(10.) {}
    
    // 處理方法
    void process(cv:: Mat &frame, cv:: Mat &output) 
    {
        cv::cvtColor(frame, gray, CV_BGR2GRAY);  // 轉換為灰階圖像
        frame.copyTo(output);

        // 1. 如果需要添加新的特征點
        if(addNewPoints())
        {
            detectFeaturePoints();                                            // 檢測特征點
            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);
            
        // 2.跟蹤特征
        cv::calcOpticalFlowPyrLK(gray_prev, gray, // 兩幅連續圖像
            points[0],                            // 圖1中的輸入點坐标
            points[1],                            // 圖2中的輸出點坐标
            status,                               // 跟蹤成功
            err);                                 // 跟蹤失敗
           
        // 2. 周遊所有跟蹤點進行篩選
        int k=0;
        for( int i= 0; i < points[1].size(); i++ ) 
        {
            // 是否需要保留該跟蹤點?
            if (acceptTrackedPoint(i)) 
            {
                // 保留該跟蹤點到vector
                initial[k]= initial[i];
                points[1][k++] = points[1][i];
            }
        }

        // 去除不成功點
        points[1].resize(k);
        initial.resize(k);

        // 3. 處理接受的跟蹤點
        handleTrackedPoints(frame, output);

        // 4. 目前的點和圖像變為它之前的點和圖像
        std::swap(points[1], points[0]);
        cv::swap(gray_prev, gray);
    }

    // 特征點檢測
    void detectFeaturePoints() 
    {    // 檢測特征
        cv::goodFeaturesToTrack(gray, // 圖像
            features,   // 檢測到的特征
            max_count,  // 特征的最大數目
            qlevel,     // 品質等級
            minDist);   // 兩個特征之間的最小距離
    }

    // 決定是否添加新點
    bool addNewPoints()
    {
        // 如果點的數量太少
        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 handleTrackedPoints(cv:: Mat &frame, cv:: Mat &output) 
    {
        // 周遊所有跟蹤點
        for(int i= 0; i < points[1].size(); i++ ) 
        {
            // 繪制直線和圓
            cv::line(output, 
                initial[i],            // 初始位置
                points[1][i],          // 新位置
                cv::Scalar(255,255,255)// 白色
                );

            cv::circle(output,          // 輸出圖像
                points[1][i],           // 圓心
                3,                      // 半徑
                cv::Scalar(255,255,255),// 白色
                -1                      // 負數表示填充圓圈, 整數表示線條厚度
                );
        }
    }
};

#endif      

2. main函數

#include "featuretracker.h"

int main()
{
  VideoProcessor processor;                           // 建立一個視訊處理執行個體
  FeatureTracker tracker;                             // 建立一個特征跟蹤執行個體
  processor.setInput("../bike.avi");                  // 打開視訊檔案
  processor.setFrameProcessor(&tracker);              // 設定幀處理器為一個特征跟蹤執行個體tracker
  processor.displayOutput("Tracked Features");        // 聲明跟蹤特征顯示視窗
  processor.setDelay(1000./processor.getFrameRate()); // 設定視訊播放幀率為原始幀率
  processor.run();                                    // 開始處理
  cv::waitKey();                                      // 等待按鍵響應

  return 0;
}      
《OpenCV2 計算機視覺程式設計手冊》視訊處理二