现在的位置: 首页 > 综合 > 正文

OpenCV运动目标检测

2013年09月06日 ⁄ 综合 ⁄ 共 2805字 ⁄ 字号 评论关闭

       运动目标检测的常用方法有光流法(Optical Flow),背景减除法(Background Subtraction)和帧间差分法(Frame Difference)。其中背景减除法和帧间差分法适用于摄像头静止的情况,而光流法用于摄像头运动的情况,但计算量比较大。

       下面介绍如何运用openCV中的函数cvUpdateMotionHistory进行运动目标检测。cvUpdateMotionHistory的功能是更新运动历史图像,它的原型是:

void cvUpdateMotionHistory(
const CvArr* silhouette,
CvArr* mhi,
double timestamp,
double duration );

各个参数解释如下,

silhouette,由帧间差分得到的运动轮廓图像。

mhi,motion histoty image的缩写,表示运动历史图像。

timestamp,时间标记。

duration,发生过运动的像素所能保持的最长时间。

作为输出的运动历史图像mhi的与作为输入的运动轮廓图像silhouette的具体关系可以表达为如下三种情况:

(1)mhi(x,y) = timestamp if silhouette(x,y)!=0.即当运动轮廓图像在坐标(x,y)处不为零时,那么将mhi在(x,y)处打上时间标记timestamp.

(2)mhi(x,y) = 0 if silhouette(x, y) = 0 and mhi(x,y) < (timestamp - duration).由于timestamp是在不断随着时间增长的,所以发生过运动的像素点维持的 最长时间为duration.当mhi(x,y)保持的时间超过duration后,若在(x,y)处没有发生新的运动,就令mhi(x,y)为零。

(3)mhi(x,y) = mhi(x,y) otherwise.只要发生过运动的像素点维持的时间没有超过duration,那么令mhi(x,y)的大小维持发生运动的那个时刻的时间标记。

下面给出基于opencv2.0的代码,代码参考了opencv安装目录中的例程,并做了一些改动,方便其他项目中直接调用函数进行运动目标检测。

#include <cv.h>
#include <highgui.h>
#include <time.h>

void updateMhi(const IplImage* src_image,IplImage* binary_mhi)
{
	//运动像素维持的最大时间,单位与timestamp的单位一致
	#define MHI_DURATION 1
	//时间标记
	double timestamp = clock()/100.;
	
	//当前帧的上一帧图像
	static IplImage* last_image = NULL;
	static IplImage* color_silh = NULL;
	static IplImage* gray_silh = NULL;
	//运动历史图像
	static IplImage* mhi = NULL;
	
	if(NULL==last_image && NULL==color_silh && NULL==gray_silh && NULL==mhi)
	{
		CvSize size = cvGetSize(src_image);
		//初始分配内存,在该程序中没有释放如下图像的内存空间
		last_image = cvCreateImage(size,8,3);
		color_silh = cvCreateImage(size,8,3);
		gray_silh = cvCreateImage(size,8,1);
		mhi = cvCreateImage(size,IPL_DEPTH_32F,1);
		//初始情况下令当前帧与上一帧图像相同
		cvCopy(src_image,last_image);
		//置零初始运动历史图像
		cvZero(binary_mhi);
	}
	else
	{
		//获得帧差图像color_silh
		cvAbsDiff(src_image,last_image,color_silh);
		cvCopy(src_image,last_image);
		cvCvtColor(color_silh,gray_silh,CV_BGR2GRAY);

		cvThreshold( gray_silh, gray_silh, 30, 255, CV_THRESH_BINARY);
		//更新运动历史图像
		cvUpdateMotionHistory(gray_silh,mhi,timestamp,MHI_DURATION);
		//将浮点型的运动历史图像转换成图像binary_mhi
		cvCvtScale( mhi, binary_mhi, 255./MHI_DURATION,
				  (MHI_DURATION - timestamp)*255./MHI_DURATION );
		//二值化
		cvThreshold( binary_mhi, binary_mhi, 0, 255, CV_THRESH_BINARY );
	}

}

int main()
{
	CvCapture* capture = cvCreateFileCapture("D:\\technology\\CV\\Databases\\vedio\\motion.avi");

	if(capture)
	{
		IplImage* frame = NULL;
		int width = (int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH);
		int height = (int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT);

		CvSize frame_size = cvSize(width,height);
		IplImage* binary_mhi = cvCreateImage(frame_size,8,1);
		IplImage* src_image = cvCreateImage(frame_size,8,3);
		while(frame = cvQueryFrame(capture))
		{
			cvCopy(frame,src_image);
			updateMhi(src_image,binary_mhi);

			cvNamedWindow("src");
			cvShowImage("src",frame);

			cvNamedWindow("mhi");
			cvShowImage("mhi",binary_mhi);
			
			if(27==cvWaitKey(33))
				break;
		}
		cvReleaseCapture(&capture);
		cvDestroyWindow("src");
		cvDestroyWindow("mhi");
		cvReleaseImage(&src_image);
		cvReleaseImage(&binary_mhi);
	}


	return 0;
}

程序运行的截图如下:


抱歉!评论已关闭.