[英]Accelerating OpticalFlow Algorithm - OpenCV
我正在從事一個使用光流算法估算無人機位置的項目。 我目前正在為此使用cv::calcOpticalFlowFarneback
。
我的硬件是Odroid U3 ,它將最終連接到無人機飛行控制器。
問題是這種方法對於這種硬件來說確實很重,我正在尋找其他方法來優化/加速它。
我已經嘗試過的事情:
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
函數。 通常,光流估計是一種安靜的耗時操作。 我建議改變光流法。
DualTVL1OpticalFlow
是您可以使用的OpenCV中性能更高的方法。 如果此方法仍然很慢,則應使用calcOpticalFlowPyrLK
。 但是,該方法是稀疏運動估計方法,不會直接返回密集運動場。 為此,請執行以下操作:在框架的網格上初始化一組點(例如,網格步長= 10),使用這些點通過calcOpticalFlowPyrLK
跟蹤它們。 跟蹤點和初始點之間的差異為您提供了每個柵格位置的光流。 最后,您必須在網格點之間進行插值。 例如,使用最近鄰或線性插值。
首先,我想對下面的這個答案表示感謝,我用它來構建最終的解決方案,我將盡可能詳細地解釋。
我的解決方案分為兩部分:
多線程 -將每幀分成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部分),主循環正在等待所有線程完成以收集結果並求平均值。
使用稀疏方法 -在選定的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.