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