转自http://blog.csdn.net/xiaowei_cqu/article/details/7610665
代数运算,就是对两幅图像的点之间进行加、减、乘、除的运算。四种运算相应的公式为:
代数运算中比较常用的是图像相加和相减。图像相加常用来求平均值去除addtive噪声或者实现二次曝光(double-exposure)。图像相减用于减去背景或周期噪声,污染等。
void cvAcc( const CvArr* image,//输入图像 CvArr* sum, //累积图像 const CvArr* mask=NULL//可选的运算 );我们还需要用到一个线性变换转换函数来对相加的结果求平均
void cvConvertScale( const CvArr* src, //输入数组 CvArr* dst,//输出数组 double scale=1,//比例 double shift=0 //缩放比例,可选 ); #define cvCvtScale cvConvertScale #define cvScale cvConvertScale #define cvConvert( src, dst ) cvConvertScale( (src), (dst), 1, 0 )
int main() { CvCapture* capture=cvCaptureFromFile("media.avi"); IplImage* frame= NULL; IplImage * imgsum =NULL; int start=301; int end=304; cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, start); int count = start; while( cvGrabFrame(capture) && count <= end ) { frame = cvRetrieveFrame(capture);// 获取当前帧 if(imgsum==NULL){ imgsum=cvCreateImage(cvGetSize(frame),IPL_DEPTH_32F,3); cvZero(imgsum); } cvAcc(frame,imgsum); char testname[100]; sprintf(testname,"%s%d%s","image",count,".jpg"); cvShowImage(testname,frame); cvSaveImage(testname,frame); count++; } IplImage * imgavg = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,3); cvConvertScale(imgsum,imgavg,1.0/4.0); cvShowImage("imageavg",imgavg); cvSaveImage("imageavg_4.jpg",imgavg); cvWaitKey(0); cvReleaseCapture(&capture); return 0; }以下从左到右分别是连续两帧、四帧、八帧、十六帧求均值的结果:
//通过求平均二次曝光 int main() { IplImage* image1= cvLoadImage("psu3.jpg"); IplImage* image2= cvLoadImage("psu4.jpg"); IplImage * imgsum =cvCreateImage(cvGetSize(image1),IPL_DEPTH_32F,3); cvZero(imgsum); cvAcc(image1,imgsum); cvAcc(image2,imgsum); IplImage * imgavg = cvCreateImage(cvGetSize(image1),IPL_DEPTH_8U,3); cvConvertScale(imgsum,imgavg,1.0/2.0); cvShowImage("imageavg",imgavg); cvSaveImage("avg.jpg",imgavg); cvWaitKey(0); cvReleaseImage(&image1); cvReleaseImage(&image2); cvReleaseImage(&imgsum); cvReleaseImage(&imgavg); return 0; }下图是对同学街舞截图的“二次曝光”效果:
void cvAbsDiff( const CvArr* src1,//第一个输入数组 const CvArr* src2,//第二个输入数组 CvArr* dst//输出数组 );
//减去背景 int main() { IplImage* pFrame = NULL; IplImage* pFrImg = NULL; IplImage* pBkImg = NULL; CvMat* pFrameMat = NULL; CvMat* pFrMat = NULL; CvMat* pBkMat = NULL; CvCapture* pCapture = NULL; int nFrmNum = 0; //创建窗口 cvNamedWindow("video", 1); cvNamedWindow("background",1); cvNamedWindow("foreground",1); pCapture = cvCaptureFromFile("media.avi"); while(pFrame = cvQueryFrame( pCapture )) { nFrmNum++; //如果是第一帧,需要申请内存,并初始化 if(nFrmNum == 1) { pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1); pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1); pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); //转化成单通道图像再处理 cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY); cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); cvConvert(pFrImg, pFrameMat); cvConvert(pFrImg, pFrMat); cvConvert(pFrImg, pBkMat); } else { cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); cvConvert(pFrImg, pFrameMat); //当前帧跟背景图相减 cvAbsDiff(pFrameMat, pBkMat, pFrMat); //二值化前景图 cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY); //更新背景 cvRunningAvg(pFrameMat, pBkMat, 0.003, 0); //将背景转化为图像格式,用以显示 cvConvert(pBkMat, pBkImg); cvShowImage("video", pFrame); cvShowImage("background", pBkImg); cvShowImage("foreground", pFrImg); if( cvWaitKey(2) >= 0 ) break; } } cvDestroyWindow("video"); cvDestroyWindow("background"); cvDestroyWindow("foreground"); cvReleaseImage(&pFrImg); cvReleaseImage(&pBkImg); cvReleaseMat(&pFrameMat); cvReleaseMat(&pFrMat); cvReleaseMat(&pBkMat); cvReleaseCapture(&pCapture); return 0; }效果图: