视频前景目标提取(一)
来源:互联网 发布:c语言单竖线 编辑:程序博客网 时间:2024/06/05 02:42
最近几天参加了一次比赛,提取监控视频前景目标,前前后后试了很多的方法,帧差法+GMM,四帧差法,改进帧差法,混合高斯模型,改进的混合高斯模型,ViBe前景目标提取,ViBe+GMM前景目标提取等等。最后也尝试了模板匹配和HOG+SVM训练样本图片提取视频目标。大概会用几篇文章介绍一下这些方法的优缺点和各自的适用情况。编程实现均在opencv2.4.13+VS2015环境。
首先介绍一下帧差法+GMM,GMM又叫混合高斯模型,在进行前景检测前,先对背景进行训练,对图像中每个背景采用一个混合高斯模型进行模拟,每个背景的混合高斯的个数可以自适应。然后在测试阶段,对新来的像素进行GMM匹配,如果该像素值能够匹配其中一个高斯,则认为是背景,否则认为是前景。由于整个过程GMM模型在不断更新学习中,所以对动态背景有一定的鲁棒性。最后通过对一个有树枝摇摆的动态背景进行前景检测,取得了较好的效果。
混合高斯模型最早在计算机视觉中的应用是用来做前景检测,主要是用于视频监控领域,这个系统和稳定且有自学能力,能在户外环境跑16个多月。KaewTraKulPong将GMM的训练过程做了改进,将训练过程分为2步进行,前L帧采用EM算法进行权值,均值,方差更新,后面的过程就采用中的方法进行更新,取得了更好的检测效果。Zivkovic et al.在中对GMM理论做了全面的论述,使得GMM理论的使用不仅金限于计算机视觉领域。并且该作者将该理论进一步具体到背景减图的前景检测中来,即加入了参数估计的先验知识,取得了很好的效果和稳定性。
实现过程
- 首先将每个高斯的均值,方差,权值都设置为0,即初始化个模型矩阵参数。
- 采用视频中的T帧用来训练GMM模型。对每一个像素而言,建立其模型个数最大GMM_MAX_COMPONT个高斯的GMM模型。当第一个像素来,单独为其在程序中设置好其固定的初始均值,方差,并且权值设置为1。
- 非第一帧训练过程中,当后面来的像素值时,与前面已有的高斯的均值比较,如果该像素点的值与其模型均值差在3倍的方差内,则任务属于该高斯。此时用如下方程进行更新:
- 当到达训练的帧数T后,进行不同像素点GMM个数自适应的选择。首先用权值除以方差对各个高斯进行从大到小排序,然后选取最前面B个高斯,使
这样就可以很好的消除训练过程中的噪声点。
5. 在测试阶段,对新来像素点的值与B个高斯中的每一个均值进行比较,如果其差值在2倍的方差之间的话,则认为是背景,否则认为是前景。并且只要其中有一个高斯分量满足该条件就认为是前景。前景赋值为255,背景赋值为0。这样就形成了一副前景二值图。
6. 由于前景二值图中含有很多噪声,所以采用了形态学的开操作将噪声缩减到0,紧接着用闭操作重建由于开操作丢失的边缘部分的信息。消除了不连通的小噪声点。
上面是该算法实现的大概流程,但是当我们在具体编程时,还是有很多细节的地方需要注意,比如有些参数值的选择。在这里,经过试验将一些常用的参数值声明如下:
- 3个参数的值的更新方差中,取其中的学习率为0.005。也就是说T等于200。
- 定义每个像素的最大混合高斯个数取7。
- 取视频的前1000帧进行训练。
- 取Cf为0.3。即满足权值大于0.7的个数为自适应高斯的个数B。
- 训练过程中,需要新建立一个高斯时,其权值取值设为与学习率大小值相等,即0.05。
- 训练过程中,需要新建立一个高斯时,取该高斯的均值为该输入像素值大小本身。方差为15。
- 训练过程中,需要新建立一个高斯时,取该高斯的方差15。
#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2\opencv.hpp>#include <vector>using namespace cv;using namespace std;int main(){//int argc, char* argv[]CvCapture *capture = cvCreateFileCapture("E:\\数学建模\\input2.avi");IplImage *img, *img_gray, *img_cny, *back, *fore;//原图像、灰度图像、边缘检测得到的图像、背景图像、前景图像CvVideoWriter *writer=NULL;double fps = cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);CvSize size = cvSize((int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH),(int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT));writer = cvCreateVideoWriter("E:\\数学建模\\input2out.avi", CV_FOURCC('M','J','P','G'), fps, size, 0);int width, height;//图像的长、宽int cnt = 0; //视频帧数img = cvQueryFrame(capture);cnt++;width = img->width; height = img->height;vector< vector<double> > mean(width*height), sd(width*height), w(width*height);img_gray = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);img_cny = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);back = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);fore = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);cvCvtColor(img, img_gray, CV_BGR2GRAY);cvCopy(img_gray, back);//初始化混合高斯背景模型int K = 5, sd_init = 16, T = 200, match = 0;//高斯分布的个数、标准差的初始值 帧数阈值 匹配参数double w_init = 0.005, D = 2.5, alph, p, threold = 0.7;//权重的初始值、置信参数、学习速率、参数更新速率、预定阈值(用于选取背景模型)for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){mean[i*width + j].push_back((uchar)img_gray->imageData[i*width + j]);sd[i*width + j].push_back(sd_init);w[i*width + j].push_back(1);}}IplImage* logpolar_frame = cvCreateImage(size, IPL_DEPTH_8U, 3);while (1){img = cvQueryFrame(capture);if (!img) break;cvCvtColor(img, img_gray, CV_BGR2GRAY);cnt++;//计算学习速率if (cnt < T) alph = (double)1 / (2 * cnt);else alph = (double)1 / (2 * T);for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){match = 0;int len = mean[i*width + j].size();for (int k = 0; k < len; k++){//判断一个像素是否与背景模型匹配if (fabs((uchar)img_gray->imageData[i*width + j] - mean[i*width + j][k]) < D*sd[i*width + j][k]){match = 1;//更新权重、均值、标准差w[i*width + j][k] = (1 - alph)*w[i*width + j][k] + alph;p = alph / w[i*width + j][k];mean[i*width + j][k] = (1 - p)*mean[i*width + j][k] + p*(uchar)img_gray->imageData[i*width + j];sd[i*width + j][k] = sqrt((1 - p)*sd[i*width + j][k] * sd[i*width + j][k] + p*pow((uchar)img_gray->imageData[i*width + j] - mean[i*width + j][k], 2));}else{w[i*width + j][k] = (1 - alph)*w[i*width + j][k];}}if (match == 0){//增加新的背景模型if (len < K){mean[i*width + j].push_back((uchar)img_gray->imageData[i*width + j]);sd[i*width + j].push_back(sd_init);w[i*width + j].push_back(w_init);}//更改权重最小的背景模型else{int min = 0;double tmp = w[i*width + j][0];for (int k = 1; k < len; k++){if (tmp > w[i*width + j][k]){min = k;tmp = w[i*width + j][k];}}mean[i*width + j][min] = (uchar)img_gray->imageData[i*width + j];sd[i*width + j][min] = sd_init;w[i*width + j][min] = w_init;}}//每隔50帧 删除权重最小的高斯分布if (cnt % 50 == 0){vector<double>::iterator it_w, it_sd, it_mean;it_w = w[i*width + j].begin();it_sd = sd[i*width + j].begin();it_mean = mean[i*width + j].begin();for (; it_w != w[i*width + j].end() && it_sd != sd[i*width + j].end() && it_mean != mean[i*width + j].end();){if (*it_w < w_init && (*it_w / *it_sd) < (w_init / sd_init)){it_w = w[i*width + j].erase(it_w);it_sd = sd[i*width + j].erase(it_sd);it_mean = mean[i*width + j].erase(it_mean);}else{it_w++;it_sd++;it_mean++;}}}//权重归一化len = mean[i*width + j].size();double tmp = 0;for (int k = 0; k < len; k++){tmp += w[i*width + j][k];}for (int k = 0; k < len; k++){w[i*width + j][k] /= tmp;}//计算各背景模型的优先级,并以从大到小的顺序排序double *rand;//优先级int *rand_ind;//排序后的优先级索引rand = (double *)malloc(sizeof(double)*len);rand_ind = (int *)malloc(sizeof(int)*len);for (int k = 0; k < len; k++){rand[k] = w[i*width + j][k] / sd[i*width + j][k];rand_ind[k] = k;}for (int k = 1; k< len; k++){for (int l = 0; l < k; l++){if (rand[k] > rand[l]){double rand_tmp = rand[k];rand[k] = rand[l];rand[l] = rand_tmp;double rand_ind_tmp = rand_ind[k];rand_ind[k] = rand_ind[l];rand_ind[l] = rand_ind_tmp;}}}double sum = 0;int B;for (int k = 0; k < len; k++){int temp = rand_ind[k];sum += w[i*width + j][temp];if (sum>threold){B = k;break;}}match = 0;back->imageData[i*width + j] = 0;//求背景模型for (int k = 0; k <= B; k++){int temp = rand_ind[k];back->imageData[i*width + j] += w[i*width + j][temp] * mean[i*width + j][temp];}/*//求前景图像for (int k = 0; k <= B; k++){int temp = rand_ind[k];if (fabs((uchar)img_gray->imageData[i*width + j] - mean[i*width + j][temp]) < D*sd[i*width + j][temp]){match = 1;break;}}if (match == 1) fore->imageData[i*width + j] = 0;else fore->imageData[i*width + j] = (uchar)img_gray->imageData[i*width + j];*/free(rand);free(rand_ind);}}cvAbsDiff(img_gray, back, fore);cvCanny(img_gray, img_cny, 40, 100,3);cvShowImage("canny", img_cny);cvAnd(img_cny, fore, fore);cvDilate(fore, fore, NULL, 3);cvErode(fore, fore, NULL, 3);cvThreshold(fore, fore, 55, 255, CV_THRESH_BINARY);cvWriteFrame(writer, fore);cvShowImage("fore", fore);cvShowImage("back", back);cvShowImage("src", img);char s = cvWaitKey(1);if (s == 27) break;}cvDestroyAllWindows();cvReleaseCapture(&capture);cvReleaseImage(&img_gray);cvReleaseImage(&fore);cvReleaseImage(&back);cvReleaseImage(&img_cny);cvReleaseVideoWriter(&writer);return (0);}
原图: 背景:前景目标:
- 视频前景目标提取(一)
- ViBe提取视频前景目标
- GMCM2017-前景目标提取
- 视频的前景目标
- 视频前景提取方法总结
- 视频前景的提取Video
- 提取视频中的前景物体
- bgslibrary视频前景提取算法之三帧差法(二)
- 目标特征提取(一):全局特征
- 视频前景提取 (I)【滑动条版本】
- 视频前景提取 (II)【IplImage版本】
- 视频前景提取 (III)【Mat版本】
- 【计算机视觉】提取视频中的前景物体
- bgslibrary视频前景提取算法之帧差法
- OpenCV学习笔记(二十九)——视频前景的提取Video
- 开源工具:实现了二十来种视频前景提取的算法(bgslibrary)
- 目标检测算法-特征提取之(一)Haar特征
- bgslibrary:实现了二十来种视频前景提取的算法
- CS231n的主讲老师Andrej说,要从底层代码开始构建神经网络,而不是仅仅使用框架
- Codeforces Round #435 (Div. 2) C. Mahmoud and Ehab and the xor
- numpy.c/numpy.r
- Groovy基本使用(6):XML 处理
- 对于static的理解
- 视频前景目标提取(一)
- What is MCPTT
- 安卓sqlite之增删改查(一)
- validator配合ajx验证,并使用servlet处理json数据
- 音频学习资料整理
- 上传图片
- C++之对象的动态创建和释放
- ubuntu环境下安装anconda
- poj1459网络流多源点多汇点模板题