转自 http://blog.youkuaiyun.com/zcube/article/details/7348113
56帧时分割出手效果
63帧时分割出手的效果
/***
平均背景法进行图像分割, 在图像背景相对稳定的情况下, 检测闯入图像的前景目标
*/
- /***
- Averaging Background Method
- We’ve just seen a simple method of learning background scenes and segmenting fore-
- ground objects. It will work well only with scenes that do not contain moving background
- components (like a waving curtain or waving trees). It also assumes that the lighting
- remains fairly constant (as in indoor static scenes).
- */
- #include "stdafx.h"
- #include "cv.h"
- #include "highgui.h"
- /***************************************************/
- //我们为需要的不同临时图像和统计属性的图像创建指针
- //Float 3-channel images
- IplImage *IavgF, *IdiffF, *IprevF, *IhiF, *IlowF;
- IplImage *Iscratch, *Iscratch2;
- //Float 1-channel images
- IplImage *Igray1, *Igray2, *Igray3;
- IplImage *Ilow1, *Ilow2, *Ilow3;
- IplImage *Ihi1, *Ihi2, *Ihi3;
- //Byte 1-channel image
- IplImage *Imaskt;
- IplImage *Imask;
- float Icount;
- /**************************************************/
- void AllocateImages(IplImage* I)
- //该函数为需要的所有临时图像分配内存,传入来自视频的首帧图像作为大小参考
- {
- CvSize sz = cvGetSize(I);
- IavgF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- IdiffF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- IprevF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- IhiF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- IlowF = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- Ilow1 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ilow2 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ilow3 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ihi1 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ihi2 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Ihi3 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- cvZero(IavgF);
- cvZero(IdiffF);
- cvZero(IprevF);
- cvZero(IhiF);
- cvZero(IlowF);
- Icount = 1e-5;
- Iscratch = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- Iscratch2 = cvCreateImage(sz, IPL_DEPTH_32F, 3);
- cvZero(Iscratch);
- cvZero(Iscratch2);
- Igray1 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Igray2 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Igray3 = cvCreateImage(sz, IPL_DEPTH_32F, 1);
- Imaskt = cvCreateImage(sz, IPL_DEPTH_8U, 1);
- Imask = cvCreateImage(sz, IPL_DEPTH_8U, 1);
- }
- void accumulateBackground(IplImage* I)
- //累积背景图像和前后帧图像差值的绝对值
- //当累积够一定数量后就将其转换成一个背景统计模型
- {
- static int first = 1;
- //局部静态变量,只初始化一次,意思就是第一次被赋值为1
- cvCvtScale(I, Iscratch, 1, 0);
- //将I指向的图像复制给Iscratch 不能用cvCopy,因为像素的位深度不同
- if (!first)
- {
- cvAcc(Iscratch, IavgF);
- //累积原始的浮点图像到IIavgF
- cvAbsDiff(Iscratch, IprevF, Iscratch2);
- //计算前后帧图像绝对差图像到Iscratch2
- cvAcc(Iscratch2, IdiffF);
- //将前后帧差值图像累加到IdiffF 中
- Icount += 1.0;
- //记录累加的次数用于背景统计时计算均值
- }
- first = 0;
- //first 为局部静态变量,以后调用该函数将不再初始化为1
- //意思就是除了第一次,以后调用该函数均进入if 语句
- cvCopy(Iscratch, IprevF);
- //IprevF用来保存前一帧图像
- }
- void setHighThreshold(float scale)
- {
- cvConvertScale(IdiffF, Iscratch, scale);
- //将统计的绝对差分图像值放大scale 倍赋给Iscratch
- cvAdd(Iscratch, IavgF, IhiF);
- //IhiF = Iscratch + IavgF
- cvSplit(IhiF, Ihi1, Ihi2, Ihi3, 0);
- //将阀值上限分割为多通道
- }
- void setLowThreshold(float scale)
- {
- cvConvertScale(IdiffF, Iscratch, scale);
- cvSub(IavgF, Iscratch, IlowF);
- //IlowF = IavgF - Iscratch
- cvSplit(IlowF, Ilow1, Ilow2, Ilow3, 0);
- //将阀值下限分割为多通道
- }
- void createModelsfromStats()
- //当累积足够多的帧图后,就将其转化成一个背景统计模型
- //该函数用于计算每个像素的均值和平均绝对差分
- {
- cvConvertScale(IavgF, IavgF, (double)(1.0/Icount));
- //计算平均原始图像到 IavgF
- cvConvertScale(IdiffF, IdiffF, (double)(1.0/Icount));
- //计算绝对差分图像到 IdiffF
- cvAddS(IdiffF, cvScalar(1.0, 1.0, 1.0), IdiffF);
- //使得到的绝对差分图像每个像素值均不为空
- setHighThreshold(7.0);
- setLowThreshold(6.0);
- //根据统计的背景模型设定一个阀值上限和下限
- //如果 IlowF <= Temp < IhiF 时认为其为背景,否则为视频中出现的运动目标物体
- }
- void backgroundDiff(IplImage* I)
- {
- cvCvtScale(I, Iscratch, 1, 0);
- //将I指向的图像复制给Iscratch 不能用cvCopy, 因为像素的位深度不同
- cvSplit(Iscratch, Igray1, Igray2, Igray3, 0);
- //得到的当前帧分割成3个单通道图像
- cvInRange(Igray1, Ilow1, Ihi1, Imask);
- // src lower upper dst
- //检查这些单通道图像是否在平均背景像素高低阀值之间
- //如果src(I)在范围内(lower <= src < upper)dst(I)被设置为0xff(每一位都是 '1')否则置0
- cvInRange(Igray2, Ilow2, Ihi2, Imaskt);
- cvOr(Imask, Imaskt, Imask);
- //计算两个数组每个元素的按位或值赋值给第三个参数
- cvInRange(Igray3, Ilow3, Ihi3, Imaskt);
- cvOr(Imask, Imaskt, Imask);
- //最后Imask 为分离出的前景二值图
- cvSubRS(Imask, cvScalar(255), Imask);
- //计算数量和数组之间的差,将Imask反相处理
- }
- void DeallocateImages()
- //解除分配的内存
- {
- cvReleaseImage(&IavgF);
- cvReleaseImage(&IdiffF);
- cvReleaseImage(&IprevF);
- cvReleaseImage(&IhiF);
- cvReleaseImage(&IlowF);
- cvReleaseImage(&Ilow1);
- cvReleaseImage(&Ilow2);
- cvReleaseImage(&Ilow3);
- cvReleaseImage(&Ihi1);
- cvReleaseImage(&Ihi2);
- cvReleaseImage(&Ihi3);
- cvReleaseImage(&Iscratch);
- cvReleaseImage(&Iscratch2);
- cvReleaseImage(&Igray1);
- cvReleaseImage(&Igray2);
- cvReleaseImage(&Igray3);
- cvReleaseImage(&Imaskt);
- cvReleaseImage(&Imask);
- }
- int main()
- {
- CvCapture* capture = cvCreateFileCapture("tree.avi");
- //初始化从文件中获取视频
- if (!capture)
- {
- printf("Couldn't Open the file.");
- return -1;
- }
- cvNamedWindow("raw");
- cvNamedWindow("avg");
- IplImage* rawImage = cvQueryFrame(capture);
- //这个函数仅仅是函数cvGrabFrame和函数cvRetrieveFrame在一起调用的组合
- cvShowImage("raw", rawImage);
- AllocateImages(rawImage);
- for (int i=0;;i++)
- {
- if (i <= 30)
- {
- accumulateBackground(rawImage);
- //前30帧用于累积计算背景图像
- if (i == 30)
- //将前30真转换成一个背景统计模型
- createModelsfromStats();
- }
- else
- //建立好背景模型后调用此函数进行图像分割
- backgroundDiff(rawImage);
- cvShowImage("avg", Imask);
- //播放分割后的目标图像结果
- if (cvWaitKey(33) == 27)
- //每33ms 播放一帧
- break;
- if (!(rawImage = cvQueryFrame(capture)))
- break;
- cvShowImage("raw", rawImage);
- //显示原图像
- if (i == 56 || i == 63)
- //56帧和63帧时暂停
- cvWaitKey();
- }
- DeallocateImages();
- return 0;
- }