簡體   English   中英

加速OpticalFlow算法-OpenCV

[英]Accelerating OpticalFlow Algorithm - OpenCV

我正在從事一個使用光流算法估算無人機位置的項目。 我目前正在為此使用cv::calcOpticalFlowFarneback
我的硬件是Odroid U3 ,它將最終連接到無人機飛行控制器。

問題是這種方法對於這種硬件來說確實很重,我正在尋找其他方法來優化/加速它。

我已經嘗試過的事情:

  • 將分辨率降低到320x240甚至160x120。
  • 使用OpenCV TBB(使用WITH_TBB=ON BUILD_TBB=ON編譯, WITH_TBB=ON BUILD_TBB=ON並添加-ltbb )。
  • 改變光流參數的建議這里

添加我的代碼的相關部分:

int opticalFlow(){

    // capture from camera
    VideoCapture cap(0);
    if( !cap.isOpened() )
        return -1;

    // Set Resolution - The Default Resolution Is 640 x 480
    cap.set(CV_CAP_PROP_FRAME_WIDTH,WIDTH_RES);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT,HEIGHT_RES);

    Mat flow, cflow, undistortFrame, processedFrame, origFrame, croppedFrame;
    UMat gray, prevgray, uflow;

    currLocation.x = 0;
    currLocation.y = 0;

    // for each frame calculate optical flow
    for(;;)
    {
        // take out frame- still distorted
        cap >> origFrame;

        // Convert to gray
        cvtColor(origFrame, processedFrame, COLOR_BGR2GRAY);

        // rotate image - perspective transformation
        rotateImage(processedFrame, gray, eulerFromSensors.roll, eulerFromSensors.pitch, 0, 0, 0, 1, cameraMatrix.at<double>(0,0),
        cameraMatrix.at<double>(0,2),cameraMatrix.at<double>(1,2));

        if( !prevgray.empty() )
        {
            // calculate flow
            calcOpticalFlowFarneback(prevgray, gray, uflow, 0.5, 3, 10, 3, 3, 1.2, 0);
            uflow.copyTo(flow);

            // get average
            calcAvgOpticalFlow(flow, 16, corners);

            /*
            Some other calculations
            .
            .
            .
            Updating currLocation struct
            */
        }
        //break conditions
        if(waitKey(1)>=0)
            break;
        if(end_run)
            break;
        std::swap(prevgray, gray);
    }
    return 0;
}

筆記:

  • 我已經運行了callgrind並且瓶頸如預期的那樣是calcOpticalFlowFarneback函數。
  • 我在運行程序時檢查了CPU內核的負載,並且沒有大量使用所有4個內核,在給定的時間中只有一個內核處於100%處於運行狀態(即使使用TBB):

在此處輸入圖片說明

通常,光流估計是一種安靜的耗時操作。 我建議改變光流法。

DualTVL1OpticalFlow是您可以使用的OpenCV中性能更高的方法。 如果此方法仍然很慢,則應使用calcOpticalFlowPyrLK 但是,該方法是稀疏運動估計方法,不會直接返回密集運動場。 為此,請執行以下操作:在框架的網格上初始化一組點(例如,網格步長= 10),使用這些點通過calcOpticalFlowPyrLK跟蹤它們。 跟蹤點和初始點之間的差異為您提供了每個柵格位置的光流。 最后,您必須在網格點之間進行插值。 例如,使用最近鄰或線性插值。

首先,我想對下面的這個答案表示感謝,我用它來構建最終的解決方案,我將盡可能詳細地解釋。

我的解決方案分為兩部分:

  1. 多線程 -將每幀分成4個矩陣,每個矩陣在不同的矩陣中。 創建4個線程,並在不同的線程中運行每個季度的處理。 我創建了四個四分之一矩陣,以便它們之間有一些(5%)重疊,這樣我就不會失去它們之間的連接(請參見下圖-黃色部分占寬度的55%,占高度的55%)。

    在此處輸入圖片說明

     Q1 = cv::UMat(gray, Range(0, HEIGHT_RES*0.55), Range(0, WIDTH_RES*0.55)); Q2 = cv::UMat(gray, Range(0, HEIGHT_RES*0.55), Range(WIDTH_RES*0.45, WIDTH_RES)); Q3 = cv::UMat(gray, Range(0.45*HEIGHT_RES, HEIGHT_RES), Range(0, WIDTH_RES*0.55)); Q4 = cv::UMat(gray, Range(0.45*HEIGHT_RES, HEIGHT_RES), Range(WIDTH_RES*0.45, WIDTH_RES)); 

    每個線程都進行四分之一的光流處理(下面的第2部分),主循環正在等待所有線程完成以收集結果並求平均值。

  2. 使用稀疏方法 -在選定的ROI網格內使用calcOpticalFlowPyrLK方法,而不是使用calcOpticalFlowFarneback 使用Lucas-Kanade稀疏方法代替Farneback密集方法消耗的CPU時間要少得多。 就我而言,我創建了一個帶有gridstep=10的網格。 這是創建網格的簡單功能:

     void createGrid(vector<cv::Point2f> &grid, int16_t wRes, int16_t hRes, int step){ for (int i= 0; i < wRes ; i+=step) for (int j= 0; j < hRes; j+=step) grid.push_back(cv::Point2f(i,j)); } 

    請注意,如果網格在整個運行過程中是恆定的,則最好在進入主循環之前只創建一次。

在實現了這兩個部分之后,在運行程序時,Odroid U3的所有4個核心始終在60%-80%上工作,並且性能得到了提高。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM