码迷,mamicode.com
首页 > 其他好文 > 详细

OpenCv_背景差分结合LK金字塔进行运动物体跟踪

时间:2015-03-09 22:31:20      阅读:342      评论:0      收藏:0      [点我收藏+]

标签:opencv   运动物体跟踪   角点   差分背景   

前面我们看到通过光流法进行运动物体跟踪的实际例子,其实现的基本原理就是:
一、获取前一帧,然后转换为灰度图,利用cvGoodFeaturesToTrack 函数寻找这一帧视频流的强角点
二、获取当前帧,然后转换为灰度图,利用LK金字塔算法 cvCalcOpticalFlowPyrLK 函数结合第一帧寻找到的角点A,寻找当前帧的角点B
三、画出角点和运动轨迹

背景差分法进行运动物体检测的基本原理就是:
一、取前一帧的视频流作为运动背景
二、将当前帧的视频流中的每个像素与前一帧的每个像素做差,得出每个像素点前后两帧的值的差
三、判断每个像素点的前后两帧的差值是否大于某个阈值,是则判断为运动

关于 cvGoodFeaturesToTrack 的原理,不清楚的可以参考博客:
OpenCv目标跟踪_cvGoodFeaturesToTrack()寻找角点

其基本原理也就是,强角点所在的位置在图像中一般在两个正交方向上都有明显的倒数,该点在图像中我们认为是独一无二的。

而差分背景法的基本原理,我们从另一个角度上来看,其实也是寻找角点的过程,它在前后两帧图像的每个像素作对比的过程中,过滤掉了像素值变化小的点,变化大的点被认为是运动的,其实这些运动的点从某个意义上也就是我们想要找的角点。

接下来我们来实现这样的思路:
先运用差分背景法,找出前一帧中我们认为是运动的角点,将这些角点保存起来,再结合这些找到的角点运用LK金字塔算法计算出光流,从而实现基于背景差分法的运动物体检测跟踪。

看代码:

/*
* Description : Tracking Moving object based on background subtraction
* Author : Liulongpo
* Date : 2015年3月9日21:24:56
*
*/


#include <cv.h>
#include <highgui.h>
#include <iostream>
using namespace std;

bool acceptTrackedPoint(int i);

int const MAX_CORNERS = 200;
CvPoint2D32f * cornerA;
CvPoint2D32f * cornerB;


int main (int argc, char **argv)
{  
    CvCapture* capture = 0;
    //capture = cvCaptureFromCAM(  CV_CAP_ANY );  //get frame
    capture = cvCaptureFromFile( "F://BaiduYunDownload//bike.avi" );

    IplImage *pre_frame;  //the previous frame 
    IplImage *cur_frame;  //the current frame
    IplImage *dst_img;   //the result 
    IplImage *cur_img;   
    IplImage *pre_img;

    cornerA = new CvPoint2D32f[ MAX_CORNERS];
    cornerB = 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); 
    // 获取前一帧
    pre_frame = cvQueryFrame(capture);

    while(1)
    {
        // 获取当前帧
        cur_frame = cvQueryFrame(capture);
        if (!cur_frame)
        {
            cout<<"No frame is captured ! \n";
            break;
        }
        int i,j;
        int point_number = 0;
        int rows, cols;
        int countn = MAX_CORNERS;   

        CvSize img_sz = cvGetSize(cur_frame); 
        pre_img = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
        cvCvtColor(pre_frame,pre_img, CV_RGB2GRAY);

        cur_img = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
        cvCvtColor(cur_frame,cur_img , CV_RGB2GRAY);
        dst_img = (IplImage *)cvClone(cur_frame);

        IplImage *move_img = cvCreateImage(img_sz, IPL_DEPTH_8U, 1);
        cvZero(move_img);
        //cvAbsDiff(src_img1, src_img2,move_img);
        cols = cur_frame->width;  
        rows = cur_frame->height; 
        for (i = 0; i <cols; i++)
        {
            for (j = 0; j<rows; j++)
            {
                // 如果前后两帧的同一个像素点的值之差大于阈值,则认为该像素运动了
                double a = abs(cvGet2D(pre_img, j, i).val[0]-cvGet2D(cur_img, j, i).val[0]);
                CvScalar b = cvScalar(a, 0, 0,0);
                // 设置灰度图像
                cvSet2D(move_img, j, i,b);
                if (a>40)
                {
                    if (point_number<MAX_CORNERS-1)
                    {
                        cornerA[++point_number].x = i;
                        cornerA[point_number].y = j;
                    }
                }
            }
        }

        cvNamedWindow("moving object", 0);
        cvShowImage("moving object", move_img);

        CvSize Pyrsize = cvSize(pre_img->width +8, pre_img->height/3);
        IplImage * pyrA = cvCreateImage(Pyrsize, IPL_DEPTH_32F, 1); 
        IplImage * pyrB = cvCreateImage(Pyrsize, IPL_DEPTH_32F, 1);

        cvCalcOpticalFlowPyrLK(pre_img,cur_img,pyrA,pyrB,cornerA,cornerB,countn,
            cvSize(10, 10),3,features_found,features_error,criteria,0);
        for (i = 0; i < countn; i++)
        {   
            if (features_found[i] && acceptTrackedPoint(i))
            {
                cvLine (dst_img, cvPointFrom32f (cornerA[i]), cvPointFrom32f (cornerB[i]), CV_RGB (0, 255, 0), 1, CV_AA, 0); 
                //cvCircle(dst_img,cvPointFrom32f (cornerB[i]), 3,  CV_RGB (255, 0, 0), -1);
            }
            // 交换角点数据
            cornerA[i] = cornerB[i];
        }
        // 当前帧交换到前一帧
        pre_frame = (IplImage *)cvClone(cur_frame);
        cvNamedWindow ("ImagePyrLK", 0);  
        cvShowImage ("ImagePyrLK", dst_img); 
        cvWaitKey (1);
        cvReleaseImage (&dst_img);
        cvReleaseImage(&pyrA);
        cvReleaseImage(&pyrB);
        cvReleaseImage(&move_img);


    }

    cvDestroyWindow("moving object");
    cvDestroyWindow ("ImagePyrLK");  
    cvReleaseImage (&pre_frame); 
    cvReleaseImage (&cur_frame);

    cvReleaseImage (&pre_img); 
    cvReleaseImage (&cur_img);

    return 0;
}
// 通过设定之前点与当前点的距离来判断特征点是否可以获取
bool acceptTrackedPoint(int i)
{
    //cout<<abs(cornerA[i].x - cornerB[i].x)<< " ";
    return ((abs(cornerA[i].x - cornerB[i].x) + abs(cornerA[i].y - cornerB[i].y)) > 3);
}

效果如下:

技术分享

技术分享

OpenCv_背景差分结合LK金字塔进行运动物体跟踪

标签:opencv   运动物体跟踪   角点   差分背景   

原文地址:http://blog.csdn.net/llp1992/article/details/44160695

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!