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

前面我们看到通过光流法进行运动物体跟踪的实际例子,其实现的基本原理就是: 一、获取前一帧,然后转换为灰度图,利用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**/;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 framecapture = cvCaptureFromFile( “F://BaiduYunDownload//bike.avi” );IplImage *pre_frame; //the previous frame IplImage *cur_frame; //the current frameIplImage *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);}

效果如下:

坦然接受生活给你的馈赠吧,不管是好的还是坏的。

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

相关文章:

你感兴趣的文章:

标签云: