我正在做一个用光流算法估计无人机位置的项目.我目前正为此目的使用cv::calcOpticalFlowFarneback。
我的硬件是一个卵巢U3,将最终连接到无人机飞行控制器。
问题是这个方法对于这个硬件来说真的很重,我正在寻找一些其他的方法来优化/加速它。
我已经尝试过的事物:
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函数。

发布于 2016-06-06 19:44:14
首先,我想对下面的这回答表示感谢,我用它来构建我的最终解决方案,我将尽可能多地详细解释这个解决方案。
我的解决方案分为两部分:

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部分),主循环等待所有线程完成,以便收集结果和平均。
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%的范围内工作,并且性能得到了提高。
发布于 2016-06-01 21:34:15
光流估计一般是一种安静、耗时的操作。我建议改变光流法。
在您可以使用的DualTVL1OpticalFlow中,OpenCV是一种性能更好的方法。如果这个方法还是慢的话,应该使用calcOpticalFlowPyrLK。然而,该方法是一种稀疏运动估计方法,不直接返回密集的运动场。为此:初始化框架网格上的一组点(例如,网格步骤= 10),使用这些点来使用calcOpticalFlowPyrLK跟踪它们。跟踪点和输入点之间的差异给出了每个栅格位置的光流。最后,必须在网格点之间进行插值。例如,使用最近的邻域或线性插值。
https://stackoverflow.com/questions/37507645
复制相似问题