光流optical flow的理解和求法

1.什么是光流

        通俗的讲就是通过一个图片序列,把每张图像中每个像素的运动速度和运动方向找出来就是光流场。那怎么找呢?咱们直观理解肯定是:第t帧的时候A点的位置是(x1, y1),那么我们在第t+1帧的时候再找到A点,假如它的位置是(x2,y2),那么我们就可以确定A点的运动了:(ux, vy) = (x2, y2) - (x1,y1)。那怎么知道第t+1帧的时候A点的位置呢? 这就存在很多的光流计算方法了。


       1981年,Horn和Schunck创造性地将二维速度场与灰度相联系,引入光流约束方程,得到光流计算的基本算法。人们基于不同的理论基础提出各种光流计算方法,算法性能各有不同。Barron等人对多种光流计算技术进行了总结,按照理论基础与数学方法的区别把它们分成四种:基于梯度的方法、基于匹配的方法、基于能量的方法、基于相位的方法。近年来神经动力学方法也颇受学者重视。      

        稀疏光流:只计算某些点集的光流。稠密光流:图像上所有像素点的光流都计算出来。光流场是图片中每个像素都有一个x方向和y方向的位移,所以在上面那些光流计算结束后得到的光流flow是个和原来图像大小相等的双通道图像

2.计算代码示例

    #include <iostream>  
    #include "opencv2/opencv.hpp"  
    using namespace cv;  
    using namespace std;  
    #define UNKNOWN_FLOW_THRESH 1e9  
      
    // Color encoding of flow vectors from:  
    // http://members.shaw.ca/quadibloc/other/colint.htm  
    // This code is modified from:  
    // http://vision.middlebury.edu/flow/data/  
    void makecolorwheel(vector<Scalar> &colorwheel)  
    {  
        int RY = 15;  
        int YG = 6;  
        int GC = 4;  
        int CB = 11;  
        int BM = 13;  
        int MR = 6;  
      
        int i;  
      
        for (i = 0; i < RY; i++) colorwheel.push_back(Scalar(255,       255*i/RY,     0));  
        for (i = 0; i < YG; i++) colorwheel.push_back(Scalar(255-255*i/YG, 255,       0));  
        for (i = 0; i < GC; i++) colorwheel.push_back(Scalar(0,         255,      255*i/GC));  
        for (i = 0; i < CB; i++) colorwheel.push_back(Scalar(0,         255-255*i/CB, 255));  
        for (i = 0; i < BM; i++) colorwheel.push_back(Scalar(255*i/BM,      0,        255));  
        for (i = 0; i < MR; i++) colorwheel.push_back(Scalar(255,       0,        255-255*i/MR));  
    }  
      
    void motionToColor(Mat flow, Mat &color)  
    {  
        if (color.empty())  
            color.create(flow.rows, flow.cols, CV_8UC3);  
      
        static vector<Scalar> colorwheel; //Scalar r,g,b  
        if (colorwheel.empty())  
            makecolorwheel(colorwheel);  
      
        // determine motion range:  
        float maxrad = -1;  
      
        // Find max flow to normalize fx and fy  
        for (int i= 0; i < flow.rows; ++i)   
        {  
            for (int j = 0; j < flow.cols; ++j)   
            {  
                Vec2f flow_at_point = flow.at<Vec2f>(i, j);  
                float fx = flow_at_point[0];  
                float fy = flow_at_point[1];  
                if ((fabs(fx) >  UNKNOWN_FLOW_THRESH) || (fabs(fy) >  UNKNOWN_FLOW_THRESH))  
                    continue;  
                float rad = sqrt(fx * fx + fy * fy);  
                maxrad = maxrad > rad ? maxrad : rad;  
            }  
        }  
      
        for (int i= 0; i < flow.rows; ++i)   
        {  
            for (int j = 0; j < flow.cols; ++j)   
            {  
                uchar *data = color.data + color.step[0] * i + color.step[1] * j;  
                Vec2f flow_at_point = flow.at<Vec2f>(i, j);  
      
                float fx = flow_at_point[0] / maxrad;  
                float fy = flow_at_point[1] / maxrad;  
                if ((fabs(fx) >  UNKNOWN_FLOW_THRESH) || (fabs(fy) >  UNKNOWN_FLOW_THRESH))  
                {  
                    data[0] = data[1] = data[2] = 0;  
                    continue;  
                }  
                float rad = sqrt(fx * fx + fy * fy);  
      
                float angle = atan2(-fy, -fx) / CV_PI;  
                float fk = (angle + 1.0) / 2.0 * (colorwheel.size()-1);  
                int k0 = (int)fk;  
                int k1 = (k0 + 1) % colorwheel.size();  
                float f = fk - k0;  
                //f = 0; // uncomment to see original color wheel  
      
                for (int b = 0; b < 3; b++)   
                {  
                    float col0 = colorwheel[k0][b] / 255.0;  
                    float col1 = colorwheel[k1][b] / 255.0;  
                    float col = (1 - f) * col0 + f * col1;  
                    if (rad <= 1)  
                        col = 1 - rad * (1 - col); // increase saturation with radius  
                    else  
                        col *= .75; // out of range  
                    data[2 - b] = (int)(255.0 * col);  
                }  
            }  
        }  
    }  
      
    int main(int, char**)  
    {  
        VideoCapture cap;  
        cap.open(0);  
        //cap.open("test_02.wmv");  
      
        if( !cap.isOpened() )  
            return -1;  
      
        Mat prevgray, gray, flow, cflow, frame;  
        namedWindow("flow", 1);  
      
        Mat motion2color;  
      
        for(;;)  
        {  
            double t = (double)cvGetTickCount();  
      
            cap >> frame;  
            cvtColor(frame, gray, CV_BGR2GRAY);  
            imshow("original", frame);  
      
            if( prevgray.data )  
            {  
                calcOpticalFlowFarneback(prevgray, gray, flow, 0.5, 3, 15, 3, 5, 1.2, 0);  
                motionToColor(flow, motion2color);  
                imshow("flow", motion2color);  
            }  
            if(waitKey(10)>=0)  
                break;  
            std::swap(prevgray, gray);  
      
            t = (double)cvGetTickCount() - t;  
            cout << "cost time: " << t / ((double)cvGetTickFrequency()*1000.) << endl;  
        }  
        return 0;  
    }

 

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: bounding box是指在图像中定位物体或区域的矩形框。而光流是指描述图像中像素在不同时间或帧之间的运动向量。 将bounding box作为optical flow输入可以通过以下步骤实现: 首先,根据任务的需求,在图像中选择目标物体或区域,并用bounding box进行标注。 然后,利用计算机视觉算法,例如基于深度学习的目标检测算法,对图像中的目标进行检测和定位。该算法将输入图像和bounding box作为输入,并输出目标检测结果。 接下来,对于每一帧图像中的bounding box,利用光流算法计算目标区域的运动向量。光流算法能够分析相邻帧之间的像素变化,并计算出物体在图像中的运动情况。 最后,根据光流算法计算出的运动向量,可以进一步分析目标物体的运动轨迹、速度和加速度等运动信息。这些信息可以应用于许多计算机视觉任务,例如运动跟踪、行为分析和视频压缩等。 通过将bounding box作为optical flow光流输入,可以更加准确地分析目标物体的运动情况,并为后续的任务提供更丰富的信息。这种方法在许多视觉任务中具有广泛的应用,例如视频监控、自动驾驶和虚拟现实等领域。 ### 回答2: bounding box(边界框)在计算机视觉领域中常用于表示物体在图像中的位置和范围。而optical flow光流)是一种用于估计图像中像素运动的技术。 将bounding box作为optical flow的输入意味着我们希望通过光流来估计给定物体在图像中的运动。通过监测bounding box的运动,我们可以了解物体的位移、速度和方向等运动信息。 在这种方法中,首先需要使用目标检测算法或手工标注的方式得到bounding box的位置。然后,我们可以使用光流算法对bounding box中的像素进行跟踪和分析,以获取物体的运动信息。 使用bounding box作为optical flow输入的好处是,只需对感兴趣的区域进行光流计算,减少了计算量,提高了计算效率。而且,通过对物体运动的分析,我们可以获得更精确的物体运动信息,有助于在视觉跟踪和行为分析等领域中的应用。 然而,bounding box作为optical flow输入也存在一些挑战和限制。首先,bounding box的准确性对光流计算结果有很大的影响,如果bounding box的位置不准确,可能会导致光流计算出的运动结果不准确。此外,如果物体发生较大的旋转、遮挡或形变等情况,bounding box的边界可能无法完整地包围物体,从而影响光流计算和分析结果。 综上所述,bounding box作为optical flow光流的输入可以用来估计给定物体在图像中的运动。但在使用时需要注意bounding box的准确性和在特定情况下的局限性。 ### 回答3: bounding box作为optical flow光流的输入,是指在目标跟踪或目标检测任务中,使用bounding box来框定目标区域,并将该区域作为输入,进行光流计算光流是一种用于分析图像中像素运动的技术。它能够通过比较相邻帧中的像素位置变化,推测像素的运动方向和速度。为了准确地计算光流,需要选择合适的输入区域。而bounding box提供了一个有效的方式来定义并限制光流计算的区域,以便准确地追踪目标的运动。 具体而言,使用bounding box作为光流的输入可以带来以下优势: 1. 限定区域:bounding box可以将光流计算限定在目标区域内,从而排除其他背景区域的干扰。这样可以提高光流计算精度和效率。 2. 快速目标跟踪:光流可以用于目标跟踪任务,而bounding box提供了目标的初始位置信息。通过光流计算,可以根据目标的运动轨迹对目标进行跟踪,并及时更新bounding box的位置。 3. 目标检测准确性:光流可以用于目标检测任务,通过计算不同帧之间的光流变化,可以检测出目标的运动。而bounding box则可以用来获取目标在当前帧中的位置,从而进一步提高目标检测的准确性。 总之,使用bounding box作为optical flow光流的输入,可以更好地限定光流计算的区域,提高光流计算精度和效率,同时也可以用于目标跟踪和目标检测任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值