2017-02-11 40 views
1

我已經使用cv::calcOpticalFlowFarneback在openFrameworks中使用ofOOpenCv來計算當前和前一幀視頻中的光流。在光流路徑周圍創建邊界框

然後,我用光流場在上面繪製視頻,然後繪製矢量,顯示超過某個閾值的區域中的運動流。

我現在想要做的是創建一個運動區域的邊界框,並獲取質心,並將x,y位置存儲在用於跟蹤的變量中。

這是我如何繪製我的流場,如果有幫助。

if (calculatedFlow){ 
    ofSetColor(255, 255, 255); 
    video.draw(0, 0); 
    int w = gray1.width; 
    int h = gray1.height; 
    //1. Input images + optical flow 
    ofPushMatrix(); 
    ofScale(4, 4); 
    //Optical flow 
    float *flowXPixels = flowX.getPixelsAsFloats(); 
    float *flowYPixels = flowY.getPixelsAsFloats(); 
    ofSetColor(0, 0, 255); 
    for (int y=0; y<h; y+=5) { 
     for (int x=0; x<w; x+=5) { 
      float fx = flowXPixels[ x + w * y ]; 
      float fy = flowYPixels[ x + w * y ]; 
      //Draw only long vectors 
      if (fabs(fx) + fabs(fy) > .5) { 
       ofDrawRectangle(x-0.5, y-0.5, 1, 1); 
       ofDrawLine(x, y, x + fx, y + fy); 
       } 
       } 
      } 
      } 

回答

0

我解決了我的問題,從我的flowX和flowY創建新圖像。這是通過將flowX和flowY添加到新的CV FloatImage中完成的。

flowX +=flowY; 
flowXY = flowX; 

然後,我能夠做的輪廓從新創建的圖像的像素髮現,然後我可以存儲移動的所有斑點的全部重心。

像這樣:

contourFinder.findContours(mask, 10, 10000, 20, false); 
//Storing the objects centers with contour finder. 
vector<ofxCvBlob> &blobs = contourFinder.blobs; 
int n = blobs.size();  //Get number of blobs 
obj.resize(n);   //Resize obj array 
for (int i=0; i<n; i++) { 
    obj[i] = blobs[i].centroid; //Fill obj array 
} 

我最初注意到,運動只被跟蹤在一個方向上的x軸和y軸,因爲負值。我通過調用cv :: Mat中的abs()函數來改變光流的計算來解決這個問題。

Mat img1(gray1.getCvImage()); //Create OpenCV images 
Mat img2(gray2.getCvImage()); 
Mat flow; 
calcOpticalFlowFarneback(img1, img2, flow, 0.7, 3, 11, 5, 5, 1.1, 0); 
//Split flow into separate images 
vector<Mat> flowPlanes; 
Mat newFlow; 
newFlow = abs(flow); //abs flow so values are absolute. Allows tracking in both directions. 
split(newFlow, flowPlanes); 
//Copy float planes to ofxCv images flowX and flowY 
IplImage iplX(flowPlanes[0]); 
flowX = &iplX; 
IplImage iplY(flowPlanes[1]); 
flowY = &iplY; 
0

對於你所問的問題,沒有簡單的答案。這是一個建議的解決方案。它涉及多個步驟,但如果您的域名足夠簡單,則可以簡化此操作。

對於每一幀,

  1. 計算流量爲兩個圖像flow_xflow_y使用farneback方法與前一幀比較當前幀。(你似乎是這樣,在你的代碼)

  2. 將流圖像轉換爲hsv圖像,其中每個像素的色調分量表示流的角度atan2(flow_y/flow_x)並且每個像素的值分量表示流量的大小sqrt(flow_x\*\*2 + flow_y\*\*2)

  3. 在上面的步驟中,使用閾值機制來抑制流量像素(使它們變黑),其大小低於某個閾值。
  4. 根據顏色範圍對HSV圖像進行分段。您可以使用有關您的域的先驗信息,也可以採用色調分量的直方圖並確定突出的色調範圍以對像素進行分類。作爲此步驟的結果,您可以爲每個像素分配一個類。

  5. 將屬於每個類的像素分爲多個圖像。屬於分段類別1的所有像素將轉到圖像-1,屬於分段類別2的所有像素將轉到圖像-2等。現在,每個分段圖像包含HSV圖像中的特定顏色範圍中的像素。

  6. 將每個分割的圖像轉換爲黑白圖像,並使用opencv的形態學操作使用連接將其分割爲多個區域。 (連接組件)。

  7. 查找每個連接組件的質心。

我發現this reference在這方面很有幫助。

+0

這有助於理解更多的概念。我猜cv :: Mat處理不同運動矢量中的三角函數,因爲我只是需要在從兩個像素中獲取像素之後對圖像進行閾值處理。謝謝。 – Elliot