帧间差分法是一种通过对视频图像序列中相邻两帧作差分运算来获得运动目标轮廓的方法,它可以很好地适用于存在多个运动目标和摄像机移动的情况。当监控场景中出现异常物体运动时,帧与帧之间会出现较为明显的差别,两帧相减,得到两帧图像亮度差的绝对值,判断它是否大于阈值来分析视频或图像序列的运动特性,确定图像序列中有无物体运动。图像序列逐帧的差分,相当于对图像序列进行了时域下的高通滤波。
帧间差分法的优点是:
算法实现简单,程序设计复杂度低;对光线等场景变化不太敏感,能够适应各种动态环境,稳定性较好。
其缺点是:
不能提取出对象的完整区域,只能提取出边界;同时依赖于选择的帧间时间间隔。对快速运动的物体,需要选择较小的时间间隔,如果选择不合适,当物体在前后两帧中没有重叠时,会被检测为两个分开的物体:而对慢速运动的物体,应该选择较大的时间差,如果时间选择不适当,当物体在前后两帧中几乎完全重叠时,则检测不到物体。
算法描述:
(l)、对序列图像进行3×3中值滤波预处理,去掉图像随机噪声。减少以后运算的复杂度,克服噪声对图像处理结果的干扰。
(2)、从视频图像序列中选取出背景图像所阢砂,使其只包含固定的背景图像:
(3)、在视频图像序列中选取连续的两帧图像,其中前一帧图像pk-1(x,y),当前帧图像pk(x,y);
(4)、计算当前帧与背景帧的差得FD(x,y),从 图像中提取出完整的目标;
(5)、计掉当前1帧的差得FG(x,y),得到目标的变化量;
(6)、求帧差FD(x,y)与,FG(x,y)的交集得到运动目标粗糙的运动区域幽像,
(7)、数学形志学运算使得运动区域封川、连续、完整,并去掉背持中的噪声。
本文的算法并不从视频中选帧,而是直接两幅背景相同而运动物体位置不同的图像进行差分:
#include "iostream" #include "cv.h" #include "highgui.h" #include "cxcore.h" #include "ml.h" using namespace std; int main( int argc, char** argv ) { IplImage* tempFrame;//用于遍历capture中的帧,通道数为3,需要转化为单通道才可以处理 IplImage* currentFrame;//当前帧 IplImage* previousFrame;//上一帧 CvMat* tempFrameMat; CvMat* currentFrameMat; //IplImage要转成CvMat进行处理 CvMat* previousFrameMat; IplImage* tempFrame1; tempFrame1 = cvLoadImage(argv[1], 1); tempFrame = cvLoadImage(argv[2], 1); previousFrame = cvCreateImage(cvSize(tempFrame->width,tempFrame->height),IPL_DEPTH_8U,1); currentFrame = cvCreateImage(cvSize(tempFrame->width,tempFrame->height),IPL_DEPTH_8U,1); currentFrameMat = cvCreateMat(tempFrame->height, tempFrame->width, CV_32FC1); previousFrameMat = cvCreateMat(tempFrame->height, tempFrame->width, CV_32FC1); tempFrameMat = cvCreateMat(tempFrame->height, tempFrame->width, CV_32FC1); cvCvtColor(tempFrame1, previousFrame, CV_BGR2GRAY); cvNamedWindow("currentFrame", 0); cvShowImage("currentFrame",tempFrame1); cvNamedWindow("previousFrame", 0); cvShowImage("previousFrame",tempFrame1); cvCvtColor(tempFrame, currentFrame, CV_BGR2GRAY);//转化为单通道灰度图,此时currentFrame=tempFrame cvConvert(currentFrame,tempFrameMat); //cvNamedWindow("tempFrame1", 0); //cvShowImage("tempFrame1",currentFrame); cvConvert(previousFrame,previousFrameMat); cvAbsDiff(tempFrameMat,previousFrameMat,currentFrameMat);//做差求绝对值 cvThreshold(currentFrameMat,currentFrame,20,255.0,CV_THRESH_BINARY); cvDilate(currentFrame,currentFrame); //膨胀 cvErode(currentFrame,currentFrame); //腐蚀 //cvFlip(currentFrame, NULL, 0); //垂直翻转 cvNamedWindow("resultFrame", 0); cvShowImage("resultFrame",currentFrame); cvWaitKey(); //释放资源 cvReleaseImage(&tempFrame); cvReleaseImage(&previousFrame); cvReleaseImage(¤tFrame); cvReleaseMat(&previousFrameMat); cvReleaseMat(¤tFrameMat); return 0; }