光流法原理与实现「建议收藏」

光流法原理与实现「建议收藏」以下内容摘自一篇硕士论文《视频序列中运动目标检测与跟踪算法的研究》:1950年Gibson首先提出了光流的概念,光流(opticalflow)法是空间运动物体在观测成像面上的像素运动的瞬时速度。物体在运动的时候,它在图像上对应点的亮度模式也在做相应的运动,这种图像亮度模式的表观运动就是光流。光流的研究就是利用图像序列中像素的强度数据的时域变化和相关性来确定各自像素位置的“运动”。光流表达

大家好,又见面了,我是你们的朋友全栈君。

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

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 需要确定特征点。

本程序,通过帧差获得运动的点作为特征点。

本程序原本的目的是计算运动点的速度,通过修正可以进行运动跟踪。

 

#include <cv.h>

#include <highgui.h>

#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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/163535.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • 光纤交换机zone配置

    光纤交换机zone配置一、CentOS下查看PortName1、命令cat/sys/class/fc_host/host[N]/port_state,显示online则证明链路状态正常2、命令cat/sys/class/fc_host/host[N]/port_name,获取客户端HBA卡PortName二、AIX下查看WWNName1、查看系统中有效的光纤卡$lsdev-Ccadapter-Sa|grepfcs3、查看光纤卡WWNName$ls…

    2022年5月11日
  • 基于matlab的语音信号频谱分析_声音信号的数字化过程

    基于matlab的语音信号频谱分析_声音信号的数字化过程1.概述随着软硬件技术的发展,仪器的智能化与虚拟化已成为未来实验室及研究机构的发展方向[1]。虚拟仪器技术的优势在于可由用户定义自己的专用仪器系统,且功能灵活,很容易构建,所以应用面极为广泛。基于计算机软硬件平台的虚拟仪器可代替传统的测量仪器,如示波器、逻辑分析仪、信号发生器、频谱分析仪等[2]。从发展史看,电子测量仪器经历了由模拟仪器、智能仪器到虚拟仪器,由于计算机性能的飞速发展,已把传

    2022年8月11日
  • NLP关键词提取方法总结及实现

    NLP关键词提取方法总结及实现目录一、关键词提取概述二、TF-IDF关键词提取算法及实现三、TextRank关键词提取算法实现四、LDA主题模型关键词提取算法及实现五、Word2Vec词聚类的关键词提取算法及实现六、信息增益关键词提取算法及实现七、互信息关键词提取算法及实现八、卡方检验关键词提取算法及实现九、基于树模型的关键词提取算法及实现十、总结一、关键词提取概述关键词是能够表…

    2022年10月23日
  • 操作系统中 heap 和 stack 的区别

    操作系统中 heap 和 stack 的区别 操作系统中 heap 和 stack 的区别(2016年腾讯校招笔试)概念:   堆栈是两种数据结构,是一种数据项按序排列的数据结构,只能在一端进行插入和删除操作。堆为队列优先,先进先出(FIFO)。栈为先进后出(FILO)。区别:一、空间区别:    1.堆(操作系统):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表。PS:java中都是…

    2022年6月13日
  • 用git将项目文件上传至github

    用git将项目文件上传至github1,新建文件夹,在文件夹中新增txt文件2,下载githttps://git-scm.com/download/win3,点击文件右键(gitbasehere)打开git客户端4,根据https://jingyan.baidu.com/article/295430f18d33490c7e0050e4.html步骤安装直到出现登录github账号5,将需要上传的项目文件拖至新建的文件…

    2022年7月16日
  • 授权使用微信登陆第三方_微信图标改成WeChat

    授权使用微信登陆第三方_微信图标改成WeChat第三方平台系列文章,今天终于又开始更新了,今天继续学习微信(wechat)授权第三方登录一、准备工作1、申请微信公众测试号由于我们是个人开发者,我们需要去注册申请一个微信公众平台的测试号https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login我们使用微信扫码登录后,我们可以拿到appID和appsecret2、关注公众测试号3、配置回调域名在“网页服务”中找到“网页账号”,修改“网页授权获取用户基本信息”接口的

    2022年10月22日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号