精华内容
下载资源
问答
  • opencv 光流法详解

    千次阅读 2014-07-25 22:02:43
    一.基本概念 光流的概念是Gibson于1950年提出的。所谓光流是指图像中模式运动的速度,...因此,光流场携带了有关物体运动和景物三维结构的丰富信息,通过对速度场(光流场)的分析可以判断在检测区域内车辆的有无。

    一.基本概念

    光流的概念是Gibson于1950年提出的。所谓光流是指图像中模式运动的速度,光流场是一种二维(2D)瞬时速度场,其中二维速度向量是可见的三维速度向量在成像平面上的投影。光流法是把检测区域的图像变为速度的矢量场,每一个向量表示了景物中一个点在图像中位置的瞬时变化。因此,光流场携带了有关物体运动和景物三维结构的丰富信息,通过对速度场(光流场)的分析可以判断在检测区域内车辆的有无。

    思路:求得整个图像检测区域的速度场,根据每个像素点的速度向量特征,可以对图像进行分析。如果是静止背景即无车通过时,则光流向量在整个检测区域是连续变化的;当有车通过时,光流向量必然和其邻域背景的光流向量不同,从而检测出车辆及其出现的位置。

    光流法的前提假设:
    (1)相邻帧之间的亮度恒定值,
    (2)相邻视频帧的取帧的时间连续,或者相邻帧之间物体的运动比较“微小”;
    (3)保持空间一致性,即,同一子图像的像素点具有相同的运动。

    原理:
    (1)对一个连续的视频帧序列进行处理;
    (2)针对每一个视频序列,利用一定的目标检测方法,检测可能出现的前景目标;
    (3)如果某一帧出现了前景目标,找到其具有代表性的关键特征点(如shi-Tomasi算法);
    (4)对之后的任意两个相邻视频帧而言,寻找上一帧中出现的关键特征点在当前帧中的最佳位置,从而得到前景目标在当前帧中的位置坐标;
    (5)如此迭代进行,便可实现目标的跟踪;

    二.程序中重要函数解释

          (1)void cvGoodFeaturesToTrack( const CvArr* image, CvArr* eig_image, CvArr* temp_image,CvPoint2D32f* corners, int* corner_count,double quality_level, double                   min_distance,const CvArr* mask=NULL );

                    程序中此函数代码:cvGoodFeaturesToTrack(frame1_1C, eig_image, temp_image, frame1_features, &number_of_features, .01, .01, NULL);
                    这是shi-Tomasi算法,该算法主要用于feature selection,即一张图中哪些是我 们感兴趣需要跟踪的点(interest point) 
                    input:                     
                         * "frame1_1C" 输入图像. 
                         * "eig_image" and "temp_image" 只是给该算法提供可操作的内存区域
                         * 第一个".01" 规定了特征值的最小质量,因为该算法要得到好的特征点,哪就需要一个选择的阈值
                         * 第二个".01" 规定了像素之间最小的距离,用于减少运算复杂度,当然也一定程度降低了跟踪精度
                         * "NULL" 意味着处理整张图片,当然你也可以指定一块区域
                    output: 
                         * "frame1_features" 将会包含fram1的特征值 
                         * "number_of_features" 将在该函数中自动填充上所找到特征值的真实数目

           (2)迭代算法的终止准则 

                     typedef struct CvTermCriteria  
                    {  
       int    type;  /* CV_TERMCRIT_ITER 和CV_TERMCRIT_EPS二值之一,或者二者的组合 */  
      int    max_iter; /* 最大迭代次数 */  
               double epsilon; /* 结果的精确性 */  
                     } 

           (3) void cvCalcOpticalFlowPyrLK( const CvArr* prev, const CvArr* curr, CvArr* prev_pyr,CvArr* curr_pyr, const CvPoint2D32f* prev_features, CvPoint2D32f*curr_features, int count, CvSize win_size, int level, char* status,  float*track_error, CvTermCriteria criteria, int flags );

       计算一个稀疏特征集的光流,使用金字塔中的迭代 Lucas-Kanade 方法。参数:*prev在时间 t 的第一帧;*curr在时间 t + dt 的第二帧;*prev_pyr第一帧的金字塔缓存. 如果指针非 NULL , 则缓存必须有足够的空间来存储金字塔从层 1 到层 #level 的内容。尺寸 (image_width+8)*image_height/3 比特足够了;*curr_pyr与 prev_pyr 类似, 用于第二帧;*prev_features需要发现光流的点集;*curr_features包含新计算出来的位置的 点集;*count特征点的数目;*win_size每个金字塔层的搜索窗口尺寸;*level最大的金字塔层数。如果为 0 , 不使用金字塔 (即金字塔为单层), 如果为 1 , 使用两层,下面依次类推;*status数组。如果对应特征的光流被发现,数组中的每一个元素都被设置为 1,否则设置为 0;*error双精度数组,包含原始图像碎片与移动点之间的差。为可选参数,可以是 NULL ;*criteria准则,指定在每个金字塔层,为某点寻找光流的迭代过程的终止条件;*flags其它选项:(1)CV_LKFLOW_PYR_A_READY , 在调用之前,第一帧的金字塔已经准备好(2)CV_LKFLOW_PYR_B_READY , 在调用之前,第二帧的金字塔已经准备好(3)CV_LKFLOW_INITIAL_GUESSES , 在调用之前,数组 B 包含特征的初始坐标 (Hunnish: 在本节中没有出现数组 B,不知是指的哪一个)

    函数 cvCalcOpticalFlowPyrLK 实现了金字塔中 Lucas-Kanade 光流计算的稀疏迭代版本([Bouguet00])。它根据给出的前一帧特征点坐标计算当前视频帧上的特征点坐标。函数寻找具有子象素精度的坐标值。

    两个参数 prev_pyr 和 curr_pyr 都遵循下列规则:如果图像指针为 0, 函数在内部为其分配缓存空间,计算金字塔,然后再处理过后释放缓存。否则,函数计算金字塔且存储它到缓存中,除非设置标识 CV_LKFLOW_PYR_A[B]_READY 。 图像应该足够大以便能够容纳Gaussian 金字塔数据。调用函数以后,金字塔被计算而且相应图像的标识可以被设置,为下一次调用准备就绪 (比如:对除了第一个图像的所有图像序列,标识 CV_LKFLOW_PYR_A_READY 被设置).

    三.程序源代码

    [cpp]  view plain copy
    1. #include <stdio.h>  
    2. #include <cv.h>  
    3. #include <highgui.h>  
    4. #include <math.h>  
    5. static const double pi = 3.14159265358979323846;  
    6.   
    7.   
    8. inline static double square(int a)  
    9. {  
    10.     return a * a;  
    11. }  
    12.   
    13.   
    14. /*此函数主要目的:给img分配内存空间(除非此图像已经非NULL),并设定图像大小、位深以及通道数。 
    15.   即使该图像的大小、深度或信道数与要求的不同,也会创建一个非NULL图像。*/  
    16. inline static void allocateOnDemand( IplImage **img, CvSize size, int depth, int channels)  
    17. {  
    18.     if ( *img != NULL ) return;  
    19.         *img = cvCreateImage( size, depth, channels );  
    20.     if ( *img == NULL )  
    21.     {  
    22.         fprintf(stderr, "Error: Couldn't allocate image. Out of memory?\n");  
    23.         exit(-1);  
    24.     }  
    25. }  
    26.   
    27.   
    28. int main(void)  
    29. {  
    30.     CvCapture *input_video = cvCaptureFromFile("video1.avi");  //创建一个对象,读取avi视频。  
    31.     if (input_video == NULL)  
    32.     {  
    33.         fprintf(stderr, "Error: Can't open video.\n");  //视频不存在或格式不支持时显示  
    34.         return -1;  
    35.     }  
    36.   
    37.     cvQueryFrame( input_video );  // 读取一帧是为了获得帧的长宽。  
    38.                                       
    39.     CvSize frame_size;  
    40.     frame_size.height = (int) cvGetCaptureProperty( input_video, CV_CAP_PROP_FRAME_HEIGHT );  
    41.     frame_size.width =  (int) cvGetCaptureProperty( input_video, CV_CAP_PROP_FRAME_WIDTH );  
    42.   
    43.     long number_of_frames;  //视频帧的长度  
    44.   
    45.     cvSetCaptureProperty( input_video, CV_CAP_PROP_POS_AVI_RATIO, 1. );  //跳到视频结束,以便获取视频长度(帧数)  
    46.     number_of_frames = (int) cvGetCaptureProperty( input_video, CV_CAP_PROP_POS_FRAMES );  //得到帧数  
    47.   
    48.     cvSetCaptureProperty( input_video, CV_CAP_PROP_POS_FRAMES, 0. );  //重新回到视频开始,以便下续步骤进行  
    49.   
    50.       
    51. /*开始进行光流法*/  
    52.     cvNamedWindow("Optical Flow", CV_WINDOW_AUTOSIZE);  //创建窗口,显示输出,大小自动调节  
    53.     long current_frame = 0;  
    54.     while(true)  
    55.     {  
    56.         static IplImage *frame = NULL, *frame1 = NULL, *frame1_1C = NULL, *frame2_1C =  
    57.         NULL, *eig_image = NULL, *temp_image = NULL, *pyramid1 = NULL, *pyramid2 = NULL;  
    58.   
    59.           
    60.         cvSetCaptureProperty( input_video, CV_CAP_PROP_POS_FRAMES, current_frame );  
    61.       
    62.         frame = cvQueryFrame( input_video );  //读取第一帧  
    63.         if (frame == NULL)  
    64.         {  
    65.             fprintf(stderr, "Error: Hmm. The end came sooner than we thought.\n");   
    66.             return -1;  
    67.         }  
    68.   
    69.         allocateOnDemand( &frame1_1C, frame_size, IPL_DEPTH_8U, 1 );  //分配给frame1_1C内存空间  
    70.         cvConvertImage(frame, frame1_1C, CV_CVTIMG_FLIP);  //将帧数据赋给frame1_1C  
    71.   
    72.         allocateOnDemand( &frame1, frame_size, IPL_DEPTH_8U, 3 );  //把具有全部颜色信息的原帧保存,以备最后在屏幕上显示用  
    73.         cvConvertImage(frame, frame1, CV_CVTIMG_FLIP);  
    74.   
    75.         frame = cvQueryFrame( input_video );  //读取第二帧  
    76.         if (frame == NULL)  
    77.         {  
    78.             fprintf(stderr, "Error: Hmm. The end came sooner than we thought.\n");  
    79.             return -1;  
    80.         }  
    81.         allocateOnDemand( &frame2_1C, frame_size, IPL_DEPTH_8U, 1 );  
    82.         cvConvertImage(frame, frame2_1C, CV_CVTIMG_FLIP);  
    83.   
    84.     /* 施和托马斯特征跟踪! */  
    85.   
    86.         allocateOnDemand( &eig_image, frame_size, IPL_DEPTH_32F, 1 );  //分配需要的内存  
    87.         allocateOnDemand( &temp_image, frame_size, IPL_DEPTH_32F, 1 );  //分配需要的内存  
    88.   
    89.         CvPoint2D32f frame1_features[400];  //创建数组,存放一帧的特征  
    90.   
    91.         int number_of_features;  //函数运行前先设定特征数的最大值,运行后将是找到的特征数真正数量  
    92.         number_of_features = 400;  //可以改变此值,折中精确性  
    93.   
    94.         cvGoodFeaturesToTrack(frame1_1C, eig_image, temp_image, frame1_features, &number_of_features, .01, .01, NULL);  //施和托马斯算法  
    95.   
    96.     /* 金字塔的 Lucas Kanade 光流法! */  
    97.       
    98.         CvPoint2D32f frame2_features[400];  //数组用于存放帧二中来自帧一的特征。  
    99.         char optical_flow_found_feature[400];  //当且仅当frame1中的特征值在frame2中找到时,对应值为非零。  
    100.         float optical_flow_feature_error[400];  //数组第i个元素表对应点光流误差  
    101.           
    102.         CvSize optical_flow_window = cvSize(3,3);  //lucas-kanade光流法运算窗口,可以去其他大小,不过运算量加大  
    103.   
    104.         CvTermCriteria optical_flow_termination_criteria = cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .3 ); //终止条件  
    105.   
    106.         allocateOnDemand( &pyramid1, frame_size, IPL_DEPTH_8U, 1 );  
    107.         allocateOnDemand( &pyramid2, frame_size, IPL_DEPTH_8U, 1 );  
    108.   
    109.         //跑Lucas Kanade算法  
    110.         cvCalcOpticalFlowPyrLK(frame1_1C, frame2_1C, pyramid1, pyramid2, frame1_features,  
    111.                                frame2_features, number_of_features, optical_flow_window, 5,  
    112.                                optical_flow_found_feature, optical_flow_feature_error,  
    113.                                optical_flow_termination_criteria, 0 );    
    114.   
    115.     /* 画光流场,画图是依据两帧对应的特征值,这个特征值就是图像上我们感兴趣的点,如边缘上的点P(x,y)*/  
    116.         for(int i = 0; i < number_of_features; i++)  
    117.         {  
    118.             if ( optical_flow_found_feature[i] == 0 ) continue;  //如果Lucas Kanade算法没找到特征点,跳过  
    119.               
    120.             int line_thickness;   
    121.             line_thickness = 1;  
    122.               
    123.             CvScalar line_color;   
    124.             line_color = CV_RGB(255,0,0);  
    125.   
    126.             /* 画箭头,因为帧间的运动很小,所以需要缩放,不然看不见箭头,缩放因子为3 */  
    127.             CvPoint p,q;  
    128.             p.x = (int) frame1_features[i].x;  
    129.             p.y = (int) frame1_features[i].y;  
    130.             q.x = (int) frame2_features[i].x;  
    131.             q.y = (int) frame2_features[i].y;  
    132.   
    133.             double angle;  
    134.             angle = atan2( (double) p.y - q.y, (double) p.x - q.x ); //方向  
    135.             double hypotenuse;   
    136.             hypotenuse = sqrt( square(p.y - q.y) + square(p.x - q.x) );  //长度  
    137.   
    138.             q.x = (int) (p.x - 3 * hypotenuse * cos(angle)); //放大三倍  
    139.             q.y = (int) (p.y - 3 * hypotenuse * sin(angle));  
    140.   
    141.             cvLine( frame1, p, q, line_color, line_thickness, CV_AA, 0 );  //画箭头主体  
    142.             //画箭的头部  
    143.             p.x = (int) (q.x + 9 * cos(angle + pi / 4));  
    144.             p.y = (int) (q.y + 9 * sin(angle + pi / 4));  
    145.             cvLine( frame1, p, q, line_color, line_thickness, CV_AA, 0 );  
    146.             p.x = (int) (q.x + 9 * cos(angle - pi / 4));  
    147.             p.y = (int) (q.y + 9 * sin(angle - pi / 4));  
    148.             cvLine( frame1, p, q, line_color, line_thickness, CV_AA, 0 );  
    149.         }  
    150.   
    151.         cvShowImage("Optical Flow", frame1);  
    152.   
    153.         int key_pressed;  
    154.         key_pressed = cvWaitKey(33);  //隔33ms显示一帧  
    155.   
    156.         /* 触发B键,视频回一帧 */  
    157.         if (key_pressed == 'b' || key_pressed == 'B') current_frame--;  
    158.         else current_frame++;  
    159.   
    160.         /* 不要超出视频的头和尾 */  
    161.         if (current_frame < 0) current_frame = 0;  
    162.         if (current_frame >= number_of_frames - 1) current_frame = number_of_frames - 2;  
    163.     }  
    164. }  
    【整合】
    【链接】 http://download.csdn.net/detail/u012756029/6518397 (《Optical Flow》 Written by David Stavens有ppt和注释,详细的英文解释)
    展开全文
  • opencv光流估计

    2021-07-06 21:08:04
    光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。 亮度恒定:同一点随着时间的变化,其亮度不会发生改变。 小运动:随着时间...

    光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。

    • 亮度恒定:同一点随着时间的变化,其亮度不会发生改变。
    • 小运动:随着时间的变化不会引起位置的剧烈变化,只有小运动情况下才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数。
    • 空间一致:一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。所以需要连立n多个方程求解。

    Lucas-Kanade 算法


    如何求解方程组呢?看起来一个像素点根本不够,在物体移动过程中还有哪些特性呢?

    cv2.calcOpticalFlowPyrLK():

    参数:

    • prevImage 前一帧图像
    • nextImage 当前帧图像
    • prevPts 待跟踪的特征点向量
    • winSize 搜索窗口的大小
    • maxLevel 最大的金字塔层数

    返回:

    • nextPts 输出跟踪特征点向量
    • status 特征点是否找到,找到的状态为1,未找到的状态为0
    import numpy as np
    import cv2
    
    cap = cv2.VideoCapture('test.avi')
    
    # 角点检测所需参数
    feature_params = dict( maxCorners = 100,
                           qualityLevel = 0.3,
                           minDistance = 7)
    
    # lucas kanade参数
    lk_params = dict( winSize  = (15,15),
                      maxLevel = 2)
    
    # 随机颜色条
    color = np.random.randint(0,255,(100,3))
    
    # 拿到第一帧图像
    ret, old_frame = cap.read()
    old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
    # 返回所有检测特征点,需要输入图像,角点最大数量(效率),品质因子(特征值越大的越好,来筛选)
    # 距离相当于这区间有比这个角点强的,就不要这个弱的了
    p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
    
    # 创建一个mask
    mask = np.zeros_like(old_frame)
    
    while(True):
        ret,frame = cap.read()
        frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
        # 需要传入前一帧和当前图像以及前一帧检测到的角点
        p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
    
        # st=1表示
        good_new = p1[st==1]
        good_old = p0[st==1]
    
        # 绘制轨迹
        for i,(new,old) in enumerate(zip(good_new,good_old)):
            a,b = new.ravel()
            c,d = old.ravel()
            mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2)
            frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)
        img = cv2.add(frame,mask)
    
        cv2.imshow('frame',img)
        k = cv2.waitKey(150) & 0xff
        if k == 27:
            break
    
        # 更新
        old_gray = frame_gray.copy()
        p0 = good_new.reshape(-1,1,2)
    
    cv2.destroyAllWindows()
    cap.release()
    

    参考:https://www.bilibili.com/video/BV1oJ411D71z?p=17仅作个人学习用,如需删除请联系本人

    展开全文
  • OpenCv_光流法运动目标检测

    万次阅读 2015-03-06 14:43:06
    以下内容摘自一篇硕士论文《视频序列中运动目标检测与跟踪算法的研究》:1950年Gibson首先提出了光流的概念,光流(optical flow)是空间运动物体在观测成像面上的像素运动的瞬时速度。物体在运动的时候,它在图像上...

    以下内容摘自一篇硕士论文《视频序列中运动目标检测与跟踪算法的研究》:

    1950年Gibson首先提出了光流的概念,光流(optical flow)法是空间运动物体在观测成像面上的像素运动的瞬时速度。物体在运动的时候,它在图像上对应点的亮度模式也在做相应的运动,这种图像亮度模式的表观运动就是光流。光流的研究就是利用图像序列中像素的强度数据的时域变化和相关性来确定各自像素位置的“运动”。光流表达了图像的变化,因此可被观察者用来确定目标的运动情况。一般情况下,光流由相机运动、场景中目标运动或两者的共同运动产生。

    光流场是由光流引申出来的,它指的是景物中可见像素点的三维速度矢量在成像表面投影形成的二维瞬时速度场。空间中的运动场转移到图像上就表示为光流场,光流场反映了图像上每一点的灰度变化趋势。光流场包含了被观察物体的运动信息以及有关景物丰富的三维结构的信息,它是如今计算机视觉及有关研究领域中的一个重要组成部分。

    光流法检测运动目标,其基本思想是赋予图像中的每一个像素点一个速度矢量,从而形成了该图像的运动场。图像上的点和三维物体上的点在某一特定的运动时刻是一一对应的,根据各像素点的速度矢量特征对图像进行动态的分析。若图像中不存在运动目标,那么光流矢量在整个图像区域则是连续变化的,而当物体和图像背景中存在相对运动时,运动物体所形成的速度矢量则必然不同于邻域背景的速度矢量,从而将运动物体的位置检测出来。

    光流不能由运动图像的局部信息来唯一的确定,例如,亮度等值线上的点或者亮度比较均匀的区域都无法唯一的确定其点的运动对应性,但是运动是可以进行观察得到。由此说明运动场和光流不一定是唯一对应的,即光流不一定是由物体运动产生的,反之如果物体发生了运动也不一定就能产生光流。但是一般情况下,表观运动和物体真实运动之间的差异是可以忽略的,可以用光流场代替运动场来分析图像中的运动目标及其相关的运动参数。

    可以证明动能场不仅仅是分块连续的,并且其间断点恰好为物体的边缘。如此,我们便可以利用图像每一帧的运动场,在动能变化矩阵中提取极值点,便可以得到运动物体的边缘。可将动能大致相同的点归于同一物体,进而对图像序列进行分割,从而检测出多个运动目标。这样,我们就将运动目标检测问题,借助光流场转换为静态图像的区域分割问题。

    算法步骤如下:

    (1)令i=1,获得第i帧图像I(x,i);

    (2)获得第i+1帧图像I(x,i+1);

    (3)对图像去噪,得到去燥后图像I ‘(x, i)和I ‘(x, i+1);

    (4)利用I ‘(x, i)和I ‘(x, i+1)计算得到光流场;

    (5)计算得到局部动能场K(i);

    (6)利用边缘检测算法(如基于小波的方法)局部动能场并分割图像得到不同的运动单元也理解为一个运动单元);

    (7)由于目标一般较背景小,故提取出体积较运动单元作为检测目标;

    (8)计算其质心作为目标位置;

    (9)置i=i+1,重复(2)~(8),直至检测结束。

    基于光流场分析的运动目标检测方法,不仅包含了被观察物体的运动信息,而且携带了三维结构的丰富信息,因此它不仅可以用于运动目标检测,还可以直接应用于运动目标跟踪,能够很精确的计算出运动目标的速度,同时在摄像机存在运动的情况下也能够检测出运动目标。而在实际的应用中,由于存在多光源、遮挡性、噪声和透明性等多方面的原因,光流场基本方程中的灰度守恒这个假设条件是得不到满足的,因此不能求解出正确的光流场,同时由于其采用的是迭代的求解计算方法,故需要的计算时间比较长,从而无法满足实时的要求,并且该方法受噪声的影响较大,因而该方法多适用于目标运动速度不大,图像噪声比较小的情况。

    转自:http://blog.csdn.net/zht9961020/article/details/7032059

    cvCalcOpticalFlowPyrLK 函数在使用时,首先要确定特征点,也就是目标旧的位置。

    本程序通过使用cvGoodFeaturesToTrack 函数选择角点作为特征点。

    本程序只是一个简单的运动检测,在具体应用过程中,可以根据自己的需要修正

    
    #include <cv.h>
    
    #include <highgui.h>
    
    
    
    int main (int argc, char **argv)
    
    { 
    
        CvCapture* capture = 0;
    
        capture = cvCaptureFromCAM(  CV_CAP_ANY ); 
    
    
    
        int i;
    
    
    
        int corner_count = 1000; 
    
    
    
        CvTermCriteria criteria; 
    
        criteria = cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 64, 0.01);
    
    
    
        IplImage *src_img1;
    
        IplImage *src_img2;
    
        IplImage *dst_img;
    
        IplImage *pre_img;
    
    
    
        IplImage *eig_img;
    
        IplImage *temp_img;
    
        IplImage *prev_pyramid;
    
        IplImage *curr_pyramid;
    
    
    
        CvPoint2D32f *corners1;
    
        CvPoint2D32f *corners2; 
    
        corners1 = (CvPoint2D32f *) cvAlloc (corner_count * sizeof (CvPoint2D32f)); 
    
        corners2 = (CvPoint2D32f *) cvAlloc (corner_count * sizeof (CvPoint2D32f));
    
        cvNamedWindow ("Image", 1);
    
        char *status;
    
        status = (char *) cvAlloc (corner_count); 
    
        while (1)
    
        {
    
            pre_img = cvQueryFrame(capture);
    
    
    
            CvSize img_sz = cvGetSize(pre_img);
    
            src_img1 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
    
            cvCvtColor(pre_img, src_img1, CV_RGB2GRAY);
    
    
    
            dst_img = cvQueryFrame(capture);
    
            src_img2 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
    
            cvCvtColor(dst_img, src_img2, CV_RGB2GRAY);
    
    
    
            eig_img = cvCreateImage (img_sz, IPL_DEPTH_32F, 1);
    
            temp_img = cvCreateImage (img_sz, IPL_DEPTH_32F, 1);
    
    
    
            prev_pyramid = cvCreateImage (cvSize (src_img1->width + 8, src_img1->height / 3), IPL_DEPTH_8U, 1); 
    
            curr_pyramid = cvCreateImage (cvSize (src_img1->width + 8, src_img1->height / 3), IPL_DEPTH_8U, 1);
    
    
    
            cvGoodFeaturesToTrack (src_img1, eig_img, temp_img, corners1, &corner_count, 0.001, 5, NULL);
    
    
    
            cvCalcOpticalFlowPyrLK (src_img1, src_img2, prev_pyramid, curr_pyramid,                      
    
                corners1, corners2, corner_count, cvSize (10, 10), 4, status, NULL, criteria, 0); 
    
    
    
            for (i = 0; i < corner_count; i++)
    
            {   
    
                if (status[i])     
    
                    cvLine (dst_img, cvPointFrom32f (corners1[i]), cvPointFrom32f (corners2[i]), CV_RGB (255, 0, 0), 1, CV_AA, 0); 
    
            } 
    
    
    
            cvShowImage ("Image", dst_img); 
    
            cvWaitKey (1);
    
            cvReleaseImage (&src_img1); 
    
            cvReleaseImage (&src_img2);
    
            cvReleaseImage (&eig_img);
    
            cvReleaseImage (&temp_img); 
    
            cvReleaseImage (&prev_pyramid); 
    
            cvReleaseImage (&curr_pyramid);
    
        }
    
    
    
        cvDestroyWindow ("Image");
    
        cvReleaseImage (&dst_img);
    
        cvReleaseImage(&pre_img);
    
        return 0;
    
    }
    
    转自:http://blog.csdn.net/zht9961020/article/details/7032061
    
    cvCalcOpticalFlowPyrLK 需要确定特征点。
    
    本程序,通过帧差获得运动的点作为特征点。
    
    本程序原本的目的是计算运动点的速度,通过修正可以进行运动跟踪。
    
    ``` c++
    
    
    
    
    
    <div class="se-preview-section-delimiter"></div>
    
    #include <cv.h>
    
    
    
    
    
    <div class="se-preview-section-delimiter"></div>
    
    #include <highgui.h>
    
    
    
    
    
    <div class="se-preview-section-delimiter"></div>
    
    #include <iostream>
    
    using namespace std;
    
    int const MAX_CORNERS = 1000;
    
    int main (int argc, char **argv)
    
    { 
    
        CvCapture* capture = 0;
    
        capture = cvCaptureFromCAM(  CV_CAP_ANY );  //get frame
    
    
    
        IplImage *src_img1;  //the previous frame (gray)
    
        IplImage *src_img2;  //the current frame(gray)
    
    
    
        IplImge *dst_img;   //the result
    
        IplImage *cur_img;   
    
        IplImage *pre_img;
    
    
    
        CvPoint2D32f * move_old_point = new CvPoint2D32f[ MAX_CORNERS];
    
        CvPoint2D32f * move_new_point = new CvPoint2D32f[ MAX_CORNERS];
    
        char *features_found = new char[MAX_CORNERS];
    
        float *features_error = new float[MAX_CORNERS];
    
        CvTermCriteria criteria;
    
        criteria = cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 64, 0.01);
    
        while(1)
    
        {
    
            int i,j;
    
            int dx, dy;
    
            int p = 0;
    
            int rows, cols;
    
            int countn = MAX_CORNERS;
    
            pre_img = cvQueryFrame(capture);
    
    
    
            CvSize img_sz = cvGetSize(pre_img);
    
            src_img1 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
    
            cvCvtColor(pre_img, src_img1, CV_RGB2GRAY);
    
    
    
            cur_img = cvQueryFrame(capture);
    
            src_img2 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
    
            cvCvtColor(cur_img, src_img2, CV_RGB2GRAY);
    
            dst_img = (IplImage *)cvClone(cur_img);
    
    
    
            IplImage *move_img = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
    
            cvZero(move_img);
    
            //cvAbsDiff(src_img1, src_img2,move_img);
    
            cols = src_img1->width; 
    
            rows = src_img1->height;
    
            for (i = 0; i <cols; i++)
    
            {
    
                for (j = 0; j<rows; j++)
    
                {
    
                    double a = abs(cvGet2D(src_img1, j, i).val[0]-cvGet2D(src_img2, j, i).val[0]);
    
                    CvScalar b = cvScalar(a, 0, 0,0);
    
                    cvSet2D(move_img, j, i,b);
    
                    if (a>40)
    
                    {
    
                        if (p<MAX_CORNERS-1)
    
                        {
    
                            int d = ++p;
    
                            move_old_point[d].x = i;
    
                            move_old_point[d].y = j;
    
                        }
    
                    }
    
                }
    
            }
    
            cvNamedWindow("moving object", 1);
    
            cvShowImage("moving object", move_img);
    
    
    
            CvSize Pyrsize = cvSize(src_img1->width +8, src_img1->height/3);
    
            IplImage * pyrA = cvCreateImage(Pyrsize, IPL_DEPTH_32F, 1); //pyrA是需要寻找的点,不是没有初始化的
    
            IplImage * pyrB = cvCreateImage(Pyrsize, IPL_DEPTH_32F, 1);
    
    
    
            cvCalcOpticalFlowPyrLK(src_img1,
    
                src_img2,
    
                pyrA,
    
                pyrB,
    
                move_old_point,
    
                move_new_point,
    
                countn,
    
                cvSize(10, 10),
    
                3,
    
                features_found,
    
                features_error,
    
                criteria,
    
                0
    
                );
    
            for (i = 0; i < countn; i++)
    
            {  
    
                int x1 = (int)move_new_point[i].x;
    
                int x2 = (int)move_old_point[i].x;
    
                int y1 = (int)move_new_point[i].y;
    
                int y2 = (int)move_old_point[i].y;
    
    
    
                dx =(int) abs(x1 - x2) ;
    
                dy = (int)abs(y1 - y2);
    
                if (dx >= 5&& dy >= 5)
    
                {
    
                    cvLine (dst_img, cvPoint(x2, y2),cvPoint(x2+5, y2+5) , CV_RGB (255, 0, 0), 1, CV_AA, 0);
    
                }
    
            }
    
    
    
            cvNamedWindow ("ImagePyrLK", 1); 
    
            cvShowImage ("ImagePyrLK", dst_img);
    
            cvWaitKey (1);
    
            cvReleaseImage (&dst_img);
    
            cvReleaseImage(&pyrA);
    
            cvReleaseImage(&pyrB);
    
            cvReleaseImage(&move_img);
    
        }
    
    
    
        cvDestroyWindow("moving object");
    
        cvDestroyWindow ("ImagePyrLK"); 
    
        cvReleaseImage (&src_img1);
    
        cvReleaseImage (&src_img2);
    
    
    
        cvReleaseImage (&pre_img);
    
        cvReleaseImage (&cur_img);
    
    
    
        return 0;
    
    }
    

    其它参考文献:

    1、 http://blog.csdn.net/gnuhpc/article/details/4355137

    2、 http://blog.csdn.net/yang_xian521/article/details/6987447

    3、 http://blog.csdn.net/gnuhpc/article/details/4355137

    4、 http://blog.csdn.net/gnuhpc/article/details/4329857

    5、 http://blog.csdn.net/gnuhpc/article/details/4291460

    include

    using namespace std;

    int const MAX_CORNERS = 1000;

    int main (int argc, char **argv)

    {

    CvCapture* capture = 0;
    
    capture = cvCaptureFromCAM(  CV_CAP_ANY );  //get frame
    
    
    
    IplImage *src_img1;  //the previous frame (gray)
    
    IplImage *src_img2;  //the current frame(gray)
    
    
    
    IplImge *dst_img;   //the result
    
    IplImage *cur_img;   
    
    IplImage *pre_img;
    
    
    
    CvPoint2D32f * move_old_point = new CvPoint2D32f[ MAX_CORNERS];
    
    CvPoint2D32f * move_new_point = new CvPoint2D32f[ MAX_CORNERS];
    
    char *features_found = new char[MAX_CORNERS];
    
    float *features_error = new float[MAX_CORNERS];
    
    CvTermCriteria criteria;
    
    criteria = cvTermCriteria (CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 64, 0.01);
    
    while(1)
    
    {
    
        int i,j;
    
        int dx, dy;
    
        int p = 0;
    
        int rows, cols;
    
        int countn = MAX_CORNERS;
    
        pre_img = cvQueryFrame(capture);
    
    
    
        CvSize img_sz = cvGetSize(pre_img);
    
        src_img1 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
    
        cvCvtColor(pre_img, src_img1, CV_RGB2GRAY);
    
    
    
        cur_img = cvQueryFrame(capture);
    
        src_img2 = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
    
        cvCvtColor(cur_img, src_img2, CV_RGB2GRAY);
    
        dst_img = (IplImage *)cvClone(cur_img);
    
    
    
        IplImage *move_img = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
    
        cvZero(move_img);
    
        //cvAbsDiff(src_img1, src_img2,move_img);
    
        cols = src_img1->width; 
    
        rows = src_img1->height;
    
        for (i = 0; i <cols; i++)
    
        {
    
            for (j = 0; j<rows; j++)
    
            {
    
                double a = abs(cvGet2D(src_img1, j, i).val[0]-cvGet2D(src_img2, j, i).val[0]);
    
                CvScalar b = cvScalar(a, 0, 0,0);
    
                cvSet2D(move_img, j, i,b);
    
                if (a>40)
    
                {
    
                    if (p<MAX_CORNERS-1)
    
                    {
    
                        int d = ++p;
    
                        move_old_point[d].x = i;
    
                        move_old_point[d].y = j;
    
                    }
    
                }
    
            }
    
        }
    
        cvNamedWindow("moving object", 1);
    
        cvShowImage("moving object", move_img);
    
    
    
        CvSize Pyrsize = cvSize(src_img1->width +8, src_img1->height/3);
    
        IplImage * pyrA = cvCreateImage(Pyrsize, IPL_DEPTH_32F, 1); //pyrA是需要寻找的点,不是没有初始化的
    
        IplImage * pyrB = cvCreateImage(Pyrsize, IPL_DEPTH_32F, 1);
    
    
    
        cvCalcOpticalFlowPyrLK(src_img1,
    
            src_img2,
    
            pyrA,
    
            pyrB,
    
            move_old_point,
    
            move_new_point,
    
            countn,
    
            cvSize(10, 10),
    
            3,
    
            features_found,
    
            features_error,
    
            criteria,
    
            0
    
            );
    
        for (i = 0; i < countn; i++)
    
        {  
    
            int x1 = (int)move_new_point[i].x;
    
            int x2 = (int)move_old_point[i].x;
    
            int y1 = (int)move_new_point[i].y;
    
            int y2 = (int)move_old_point[i].y;
    
    
    
            dx =(int) abs(x1 - x2) ;
    
            dy = (int)abs(y1 - y2);
    
            if (dx >= 5&& dy >= 5)
    
            {
    
                cvLine (dst_img, cvPoint(x2, y2),cvPoint(x2+5, y2+5) , CV_RGB (255, 0, 0), 1, CV_AA, 0);
    
            }
    
        }
    
    
    
        cvNamedWindow ("ImagePyrLK", 1); 
    
        cvShowImage ("ImagePyrLK", dst_img);
    
        cvWaitKey (1);
    
        cvReleaseImage (&dst_img);
    
        cvReleaseImage(&pyrA);
    
        cvReleaseImage(&pyrB);
    
        cvReleaseImage(&move_img);
    
    }
    
    
    
    cvDestroyWindow("moving object");
    
    cvDestroyWindow ("ImagePyrLK"); 
    
    cvReleaseImage (&src_img1);
    
    cvReleaseImage (&src_img2);
    
    
    
    cvReleaseImage (&pre_img);
    
    cvReleaseImage (&cur_img);
    
    
    
    return 0;
    

    }

    “`

    其它参考文献:

    1、 http://blog.csdn.net/gnuhpc/article/details/4355137

    2、 http://blog.csdn.net/yang_xian521/article/details/6987447

    3、 http://blog.csdn.net/gnuhpc/article/details/4355137

    4、 http://blog.csdn.net/gnuhpc/article/details/4329857

    5、 http://blog.csdn.net/gnuhpc/article/details/4291460

    展开全文
  • OpenCV光流法运动目标跟踪

    千次阅读 2018-04-08 10:45:25
    [光流Optical Flow]的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应...

    [光流Optical Flow]的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。
    一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。当人的眼睛观察运动物体时,物体的景象在人眼的视网膜上形成一系列连续变化的图像,这一系列连续变化的信息不断流过视网膜(即图像平面),好像一种光的流;,故称之为光流(optical flow)。
    光流表达了图像的变化,由于它包含了目标运动的信息,因此可被观察者用来确定目标的运动情况。从图片序列中近似得到不能直接得到的运动场<运动场,其实就是物体在三维真实世界中的运动;光流场,是运动场在二维图像平面上(人的眼睛或者摄像头)的投影。
    那通俗的讲就是通过一个图片序列,把每张图像中每个像素的运动速度和运动方向找出来就是光流场。那怎么找呢?咱们直观理解肯定是:第t帧的时候A点的位置是(x1, y1),那么我们在第t+1帧的时候再找到A点,假如它的位置是(x2,y2),那么我们就可以确定A点的运动了:(ux, vy) = (x2, y2) - (x1,y1)。 
    那怎么知道第t+1帧的时候A点的位置呢? 这就存在很多的光流计算方法了。


    光流计算方法

    大致可分为三类:基于匹配的方法、频域的方法和梯度的方法。
    1. 基于匹配的光流计算方法包括基于特征和基于区域两种
    2. 基于频域的方法,也称为基于能量的方法,利用速度可调的滤波组输出频率或相位信息。
    3. 基于梯度的方法利用图像序列亮度的时空微分计算2D速度场(光流)。

    当前对于光流法的研究主要有两个方向

    一是研究在固有硬件平台基础上实现现有算法 
    二是研究新的算法。

    光流算法的主要目的就是基于序列图像实现对光流场的可靠、快速、精确以及鲁棒性的估计。然而,由于图像序列目标的特性、场景中照明,光源的变化、运动的速度以及噪声的影响等多种因素影响着光流算法的有效性。

    函数详解

    1.CalcOpticalFlowPyrLK

    计算一个稀疏特征集的光流,使用金字塔中的迭代 Lucas-Kanade 方法 
    C++函数代码

       void calcOpticallFlowPyrLK (
             InuputArray prevImg, 
             InputArray prevPts, 
             InputOutputArraynextPts,
             OutputArray err, 
             Size winSize = Size(21,21), 
             int maxLevel = 3, 
             TermCriteriacriteria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), 
             int flags = 0,
             double minEigThreshold = 1e-4
     ); 

    函数参数详解

    参数解释
    prevImg深度为8位的前一帧图像或金字塔图像。
    nextImg和prevImg有相同的大小和类型,后一帧图像或金字塔。
    prevPts计算光流所需要的输入2D点矢量,点坐标必须是单精度浮点数。
    nextPts输出2D点矢量(也是单精度浮点数坐标),点矢量中包含的是在后一帧图像上计算得到的输入特征新位置。
    status输出状态矢量(元素是无符号char类型,uchar),如果相应特征的流发现则矢量元素置为1,否则,为0。
    err输出误差矢量。
    winSize每个金字塔层搜索窗大小。
    maxLevel金字塔层的最大数目;如果置0,金字塔不使用(单层);如果置1,金字塔2层,等等以此类推。
    criteria指定搜索算法收敛迭代的类型
    minEigTheshold算法计算的光流等式的2x2常规矩阵的最小特征值。

    金字塔Lucas-Kannade算法:

    LK算法有三个假设:亮度恒定,即图像场景中目标的像素在帧间运动时外观上保持不变;时间连续或者运动是”小运动“,即图像的运动随时间的变化比较缓慢;空间一致,即一个场景中同一表面上邻近的点具有相似的运动。然而,对于大多数30HZ的摄像机,大而连贯的运动是普遍存在的情况,所以LK光流正因为这个原因在实际中的跟踪效果并不是很好。我们需要大的窗口来捕获大的运动,而大窗口往往违背运动连贯的假设!而图像金字塔可以解决这个问题,于是乎,金字塔Lucas-Kanade就提出来了。 
    金字塔Lucas-Kanade跟踪方法是:在图像金字塔的最高层计算光流,用得到的运动估计结果作为下一层金字塔的起始点,重复这个过程直到到达金字塔的最底层。这样就将不满足运动的假设可能性降到最小从而实现对更快和更长的运动的跟踪。


    2.cvGoodFeaturesToTrack

    函数 cvGoodFeaturesToTrack 在图像中寻找具有大特征值的角点。该函数,首先用cvCornerMinEigenVal 计算输入图像的每一个像素点的最小特征值,并将结果存储到变量 eig_image 中。然后进行非最大值抑制(仅保留3x3邻域中的局部最大值)。下一步将最小特征值小于 quality_level?max(eig_image(x,y)) 排除掉。最后,函数确保所有发现的角点之间具有足够的距离,(最强的角点第一个保留,然后检查新的角点与已有角点之间的距离大于 min_distance )。 
    C++函数代码

    void cvGoodFeaturesToTrack( 
             const CvArr* image, 
             CvArr* temp_image,
             CvPoint2D32f* corners, 
             int* corner_count,
             double quality_level, 
             double min_distance,
             const CvArr* mask=NULL,
             int block_size = NULL,
             int use_harris = 0,
             double k = 0.4
    );

    函数参数详解

    参数解释
    image输入图像,8-位或浮点32-比特,单通道
    eig_image临时浮点32-位图像,尺寸与输入图像一致
    temp_image另外一个临时图像,格式与尺寸与 eig_image 一致
    corners输出参数,检测到的角点
    corner_count输出参数,检测到的角点数目
    quality_level最大最小特征值的乘法因子。定义可接受图像角点的最小质量因子。
    min_distance限制因子。得到的角点的最小距离。使用 Euclidian 距离
    maskROI感兴趣区域。函数在ROI中计算角点,如果 mask 为 NULL,则选择整个图像。
    block_size计算导数的自相关矩阵时指定点的领域,采用小窗口计算的结果比单点(也就是block_size为1)计算的结果要好。
    use_harris标志位。当use_harris的值为非0,则函数使用Harris的角点定义;若为0,则使用Shi-Tomasi的定义。
    k当use_harris为k且非0,则k为用于设置Hessian自相关矩阵即对Hessian行列式的相对权重的权重系数

    实例代码块

    本代码参考@浅墨_毛星云的书籍《OpenCV3编程入门》,代码版权归老师所有,仅供学习借鉴只用。 

    ——博主

    @--751407505@qq.com
    // 程序描述:来自OpenCV安装目录下Samples文件夹中的官方示例程序-利用光流法进行运动目标检测
    //  描述:包含程序所使用的头文件和命名空间
    #include <opencv2/video/video.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2/core/core.hpp>
    #include <iostream>
    #include <cstdio>
    using namespace std;
    using namespace cv;
    //  描述:声明全局函数
    void tracking(Mat &frame, Mat &output);
    bool addNewPoints();
    bool acceptTrackedPoint(int i);
    //  描述:声明全局变量
    string window_name = "optical flow tracking";
    Mat gray;   // 当前图片
    Mat gray_prev;  // 预测图片
    vector<Point2f> points[2];  // point0为特征点的原来位置,point1为特征点的新位置
    vector<Point2f> initial;    // 初始化跟踪点的位置
    vector<Point2f> features;   // 检测的特征
    int maxCount = 500; // 检测的最大特征数
    double qLevel = 0.01;   // 特征检测的等级
    double minDist = 10.0;  // 两特征点之间的最小距离
    vector<uchar> status;   // 跟踪特征的状态,特征的流发现为1,否则为0
    vector<float> err;
    //输出相应信息和OpenCV版本-----
    static void helpinformation()
    {
        cout <<"\n\n\t\t\t 光流法跟踪运动目标检测\n"
             <<"\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION 
             <<"\n\n" ;
    }
    
    //main( )函数,程序入口
    int main()
    {
        Mat frame;
        Mat result;
        //加载使用的视频文件,放在项目程序运行文件下
        VideoCapture capture("1.avi");
        //显示信息函数
        helpinformation();
        // 摄像头读取文件开关
        if(capture.isOpened())  
        {
            while(true)
            {
                capture >> frame;
    
                if(!frame.empty())
                { 
                    tracking(frame, result);
                }
                else
                { 
                    printf(" --(!) No captured frame -- Break!");
                    break;
                }
                int c = waitKey(50);
                if( (char)c == 27 )
                {
                    break; 
                } 
            }
        }
        return 0;
    }
    
    // parameter: frame 输入的视频帧
    //            output 有跟踪结果的视频帧
    void tracking(Mat &frame, Mat &output)
    {
        cvtColor(frame, gray, CV_BGR2GRAY);
        frame.copyTo(output);
        // 添加特征点
        if (addNewPoints())
        {
            goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist);
            points[0].insert(points[0].end(), features.begin(), features.end());
            initial.insert(initial.end(), features.begin(), features.end());
        }
    
        if (gray_prev.empty())
        {
            gray.copyTo(gray_prev);
        }
        // l-k光流法运动估计
        calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);
        // 去掉一些不好的特征点
        int k = 0;
        for (size_t i=0; i<points[1].size(); i++)
        {
            if (acceptTrackedPoint(i))
            {
                initial[k] = initial[i];
                points[1][k++] = points[1][i];
            }
        }
        points[1].resize(k);
        initial.resize(k);
        // 显示特征点和运动轨迹
        for (size_t i=0; i<points[1].size(); i++)
        {
            line(output, initial[i], points[1][i], Scalar(0, 0, 255));
            circle(output, points[1][i], 3, Scalar(0, 255, 0), -1);
        }
    
        // 把当前跟踪结果作为下一此参考
        swap(points[1], points[0]);
        swap(gray_prev, gray);  
        imshow(window_name, output);
    }
    
    //  检测新点是否应该被添加
    // return: 是否被添加标志
    bool addNewPoints()
    {
        return points[0].size() <= 10;
    }
    
    //决定哪些跟踪点被接受
    bool acceptTrackedPoint(int i)
    {
        return status[i] && ((abs(points[0][i].x - points[1][i].x) + abs(points[0][i].y - points[1][i].y)) > 2);
    }
    

    展开全文
  • opencv视频分析光流

    2020-12-22 06:16:20
    原理2.Lucas-Kanade 3.稠密光流 1.原理 由于目标对象或者摄像机的移动,造成的图像对象在连续两帧图像中的移动被称为光流。它是一个2D 向量场,可以用来显示一个点从第一帧图像到第二帧图像之间的移动。 上图显示...
  • OpenCV:金字塔LK光流法

    千次阅读 2018-05-31 17:14:32
    金字塔LK光流法的三个假设 亮度恒定,即图像场景中目标的像素在帧间运动时外观上保持不变; 时间连续或者运动是”小运动“,即图像的运动随时间的变化比较缓慢; 空间一致,即一个场景中同一表面上邻近的点具有...
  • Opencv光流估计

    2020-01-20 14:46:45
    光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。 特点 亮度恒定:同一点随着时间的变化,其亮度不会发生改变。 小运动:...
  • 关于光流法全面的介绍和OpenCV代码,请参考:zouxy09的专栏 http://blog.csdn.net/zouxy09/article/details/8683859 本文和后续文章仅对光流法的原理进行补充。与上述参考文章里面已经介绍的内容不会重复。OpenCV...
  • 光流法_OpenCV_详解

    千次阅读 2013-11-07 15:49:37
    光流的概念是Gibson于1950年提出的。所谓光流是指图像中模式运动的速度,...因此,光流场携带了有关物体运动和景物三维结构的丰富信息,通过对速度场(光流场)的分析可以判断在检测区域内车辆的有无。 求得整个图像检测
  • OpenCV目标跟踪-LK光流法

    千次阅读 2017-03-20 19:29:01
    这几天主要看了光流的有关内容,下面就关于光流的有关内容进行个简单的总结。  所谓的光流是一种运动模式,这种运动模式即是指一个物体、表面、边缘在一个视角下由一个观察者和背景之间形成的明显移动。在如下的图...
  • 原标题:OpenCV4中DIS光流算法与应用OpenCV4中新光流算法 - DIS光流OpenCV中KLT稀疏光流算法与FB稠密光流算法都是十年前的算法,没有反应出光流算法的最新进展,这个跟OpenCV其它模块相比,光流算法模块的更新明显...
  • 光流的概念是指在连续的两帧图像当中,由于图像中的物体移动或者摄像头的移动而使得图像中的目标形成的矢量运动轨迹叫做光流。本质上光流是个向量场,表示了一个像素点从第一帧过渡到第二帧的运动过程,体现该像素点...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,219
精华内容 487
关键字:

opencv光流分析法