下面介绍如何运用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
#include
#include
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;
}
程序运行的截图如下: