在光流路径的场周围创建一个边界框

时间:2017-02-11 12:56:41

标签: c++ opencv openframeworks opticalflow

我使用cv::calcOpticalFlowFarneback来计算openFrameworks中使用xOpenCv的当前和之前视频帧中的光流。

然后我用顶部的光流场绘制视频,然后绘制向量,显示高于某个阈值的区域内的运动流。

我现在要做的是创建这些运动区域的边界框并获取质心,并将xy位置存储在变量中以进行跟踪。

如果有帮助,这就是我绘制流场的方法。

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 );
                }
              }
            }
          } 

2 个答案:

答案 0 :(得分: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. 找到每个连接组件的质心。

  8. 我发现this reference在这种情况下很有帮助。

答案 1 :(得分: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;