首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >加速OpticalFlow算法- OpenCV

加速OpticalFlow算法- OpenCV
EN

Stack Overflow用户
提问于 2016-05-29 08:12:00
回答 2查看 3.1K关注 0票数 2

我正在做一个用光流算法估计无人机位置的项目.我目前正为此目的使用cv::calcOpticalFlowFarneback

我的硬件是一个卵巢U3,将最终连接到无人机飞行控制器。

问题是这个方法对于这个硬件来说真的很重,我正在寻找一些其他的方法来优化/加速它。

我已经尝试过的事物:

  • 将分辨率降低到320x240甚至160x120。
  • 使用OpenCV TBB (使用WITH_TBB=ON BUILD_TBB=ON编译并添加-ltbb)。
  • 如建议的这里改变光流参数

添加代码的相关部分:

代码语言:javascript
复制
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):

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-06-06 19:44:14

首先,我想对下面的回答表示感谢,我用它来构建我的最终解决方案,我将尽可能多地详细解释这个解决方案。

我的解决方案分为两部分:

  1. Multithreading -将每一帧分割成4个矩阵,每个四分之一在一个不同的矩阵中。创建4个线程,并在不同的线程中运行每个季度的处理。我创建了4个季度矩阵,这样它们之间就会有一些(5%)的重叠,这样我就不会失去它们之间的连接(见下图-黄色部分从宽度到高度分别是55%和55% )。

Q1 =cv::UMat(灰度,范围(0,HEIGHT_RES*0.55),范围(0,WIDTH_RES*0.55)),Q2 =cv::UMat(灰度,范围(0,HEIGHT_RES*0.55),范围(WIDTH_RES*0.45,WIDTH_RES)),Q3 =cv:UMat(灰度,范围(0.45*HEIGHT_RES,HEIGHT_RES),范围(0,WIDTH_RES*0.55));Q4 =cv::UMat(灰度,范围(0.45*HEIGHT_RES,HEIGHT_RES),范围(WIDTH_RES*0.45,WIDTH_RES));

每个线程在四分之一上进行光流处理(下面第2部分),主循环等待所有线程完成,以便收集结果和平均。

  1. 使用稀疏方法-在选定的ROI网格中使用calcOpticalFlowPyrLK方法,而不是使用calcOpticalFlowFarneback。使用Lucas-Kanade稀疏方法代替Farneback稠密方法消耗的CPU时间要少得多。在我的例子中,我用gridstep=10创建了一个网格。这是创建网格的简单函数: void createGrid(vector &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%的范围内工作,并且性能得到了提高。

票数 3
EN

Stack Overflow用户

发布于 2016-06-01 21:34:15

光流估计一般是一种安静、耗时的操作。我建议改变光流法。

在您可以使用的DualTVL1OpticalFlow中,OpenCV是一种性能更好的方法。如果这个方法还是慢的话,应该使用calcOpticalFlowPyrLK。然而,该方法是一种稀疏运动估计方法,不直接返回密集的运动场。为此:初始化框架网格上的一组点(例如,网格步骤= 10),使用这些点来使用calcOpticalFlowPyrLK跟踪它们。跟踪点和输入点之间的差异给出了每个栅格位置的光流。最后,必须在网格点之间进行插值。例如,使用最近的邻域或线性插值。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37507645

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档