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

Posted

技术标签:

【中文标题】在光流路径场周围创建一个边界框【英文标题】:creating a bounding box around a field of optical flow paths 【发布时间】:2017-02-11 12:56:40 【问题描述】:

我已经使用cv::calcOpticalFlowFarneback 在 openFrameworks 中使用 ofxOpenCv 计算当前和前一帧视频中的光流。

然后我在顶部绘制带有光流场的视频,然后在高于特定阈值的区域绘制显示运动流的矢量。

我现在要做的是创建这些运动区域的边界框并获取质心并将 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 );
                
              
            
           

【问题讨论】:

【参考方案1】:

对于您的问题,没有简单的答案。这是一个建议的解决方案。它涉及多个步骤,但如果您的域足够简单,则可以简化。

对于每一帧,

    将流计算为两个图像flow_x,flow_y 使用 farneback 方法比较当前帧与前一帧。(您的代码中似乎正在这样做)

    将流图转换为hsv图,其中每个像素的hue分量表示流的角度atan2(flow_y/flow_x),每个像素的value分量表示流的大小sqrt(flow_x\*\*2 + flow_y\*\*2)

    在上述步骤中,使用您的阈值机制来抑制幅值低于某个阈值的流动像素(使其变黑)。

    根据颜色范围分割 HSV 图像。您可以使用有关您的域的先验信息,或者您可以获取色调分量的直方图并识别突出的色调范围以对像素进行分类。作为此步骤的结果,您可以为每个像素分配一个类。

    将属于每个类别的像素分成多个图像。属于分段类 1 的所有像素将转到图像 1,属于分段类 2 的所有像素将转到图像 2 等等。现在每个分段图像都包含 HSV 图像中特定颜色范围内的像素。

    将每个分割后的图像转换为黑白图像,并使用opencv的形态学操作使用连通性分割成多个区域。 (连接的组件)。

    找到每个连通分量的质心。

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

【讨论】:

这有助于更多地理解概念。我猜 cv::Mat 处理不同运动向量中的三角函数,因为我只需要在从两者中获取像素后对图像进行阈值处理。谢谢。【参考方案2】:

我通过从我的 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;

【讨论】:

以上是关于在光流路径场周围创建一个边界框的主要内容,如果未能解决你的问题,请参考以下文章

从周围的边界框中提取车牌平行四边形?

Python - opencv 在 Canny 边缘图像周围绘制边界框

光流法详解之二(HS光流)

Python:检测到运动周围的重叠框

如何在Word周围绘制边界框并将其保存在文件夹opencv python中

tesseract 4.0.0-beta.1 字符周围的边界框