基于opencv+vs视频运动区域提取

来源:互联网 发布:unity3d 烘焙 编辑:程序博客网 时间:2024/05/20 00:16

博友们:

        大家好,这是我首次写博客,之前也读过都铎博客达人们写的博客,觉得博客有很多的好处,能让自己更加的了解自己所学的,让自己更加的明白,能从中找到自己的不足,再者就是能和大家一起探讨自己所有的领域。能相互解答我们感兴趣的问题。所以前段时间开通的博客,现在我来讲述一下,最近我看的关于运动区域的提取。

        我是一个在校的研究生,由于现在手上的工作不是很多,我是做视频方向的,所以选择一家公司实习,是一家做视频监控的,我现在所做的项目是,关于烟雾方面的运动提取。由于自己是小白,什么都不懂,并且自己的码代码的能力也不足,下面我讲述的有很多的不足,希望可以有大牛们给予指点,和感兴趣的朋友一起探讨。

        不多说了,下面进入正题,由于现在是高科技发展的时代,对各种方面的检测都是运用高科技,我们是对一个含有烟雾的视频进行检测,视频是由监控摄像头来拍摄的。

        我的应用环境是vs2013+opencv2.4.9,首先我们得到的视频时给予不同位置的,主要分为两种一种是有烟雾的,一种是无烟雾的,但是拍摄的过程中由于处在高空中的原因,摄像头会由于风的干扰,又分为抖动和静止的,对于禁止的我们可以很好地操作,但是对于抖动的我到目前为止还没有想到什么好点的方法(如有人了解可以留言讨论一下)。在此之前,我参考了许多的文献,然而大部分的文献类容是给予理论上的研究,以及室内环境里面的,都是一些国家自然基金,和某某公司合作的项目,里面只是阐述的大致的内容,没有涉及具体的计算过程。这样就给我带来了很多的困难(我试着联系过吉林大学的一个博士,他就说是公司的一个项目涉及到公司利益和版权,就不了了之了),于是我就是这项分为三个步骤来进行:第一步是、将得到的视频进行预处理,然后进行运动区域检测,提取运动的目标;第二步是、将提取出来的运动区域进行烟雾分析,来去除一些不是烟雾的运动区域,得到烟雾区域或者疑似烟雾区域;第三步是、进行报警。整个烟雾检测的过程我的理解就是分成为三个部分。其中难点在于第二个部分。下面我将阐述一下第一步骤:

        从目前来看,运动不标的提取,主要有两个方面,一个是帧差,另外一个是高斯背景建模(包括背景建模),那么对已前者的话就是,利用后一帧减去前一帧,这样就可以得到运动的区域,将得到的帧差图进行二值化,显示出来,对于摄像头和背景不运动的情况下可以很好地判断出来;对于第二种的话我们采取背景建模的方法,有前后几帧的背景建模,高斯建模,混合高斯建模(就是多几个高斯模型)。我目前所做的就是第一步的所有内容,由于我们所做的是烟雾检测,包括室内室外的,例如高空中对一个烟囱的烟雾检测,那么此时摄像头会收到大风的影响,拍摄出来的画面是抖动的,此时我就是用混合高斯背景建模,再得到差值图像中,我有对其进行了处理,先腐蚀再膨胀,为什么采取这个这个处理方式?我的理解是,先腐蚀的过程是因为我要去除一些噪声干扰的因素后,在对其进行膨胀,这样得出的差值图相比较以前有了一点点的改善。(下面是我进行的代码操作)

#include <stdio.h>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <cvaux.h>//必须引此头文件
using namespace std;
using namespace cv;


int main(int argc, char ** argv)
{
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);


cvMoveWindow("video", 30, 0);
cvMoveWindow("background", 500, 0);//原始值360
cvMoveWindow("foreground", 690, 0);//原始值690


CvCapture* pCapture = cvCreateFileCapture("道窖5:比较清晰大烟囱冒烟.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);
//高斯滤波先,以平滑图像
cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);
//当前帧跟背景图相减
cvAbsDiff(pFrameMat, pBkMat, pFrMat);
//二值化前景图
cvThreshold(pFrMat, pFrImg, 8, 255, CV_THRESH_BINARY);
//进行形态学滤波,去掉噪音  
cvErode(pFrImg, pFrImg, 0, 1);
cvDilate(pFrImg, pFrImg, 0, 1);
//更新背景
cvRunningAvg(pFrameMat, pBkMat, 0.01, 0);//不同的背景更新速率产生的效果也不一样
//将背景转化为图像格式,用以显示
cvConvert(pBkMat, pBkImg);


Mat img(pFrImg, 0); //这个是将 pFrImg转换成MAT形式,由IPlImage  转换成mat形式  http://blog.sina.com.cn/s/blog_534497fd01015k7z.html 这个是两者相互转换的链接


////再进行膨胀操作
Mat outpengzhang;
Mat element2 = getStructuringElement(MORPH_RECT, Size(3, 3));//这个是核函数的参数值  调节核的大小
dilate(img, outpengzhang, element2);


//先进行腐蚀操作
Mat outfushi;
Mat element1 = getStructuringElement(MORPH_RECT, Size(20, 30));//同膨胀一样  调节核的大小
erode(outpengzhang, outfushi, element1);
//边缘检测在运动块提取的时候不需要,这个地方是在验证是否是烟雾时运用的
//canny边缘检测
/*Canny(img, img, 150, 100, 3);*/
//sobel边缘检测
//Mat grad_x, grad_y;
//Mat abs_grad_x, abs_grad_y, bianyuantupian;
//Sobel(outpengzhang, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
//convertScaleAbs(grad_x, abs_grad_x);
//Sobel(outpengzhang, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
//convertScaleAbs(grad_y, abs_grad_y);
//addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, bianyuantupian);
//显示图像
cvShowImage("video", pFrame);
cvShowImage("background", pBkImg);
imshow("foreground", outpengzhang);//imshow 输出的是mat形式(就是一个矩阵),cvShowImage是输出指针形式(IPlImage *Img)
//如果有按键事件,则跳出循环
//此等待也为cvShowImage函数提供时间完成显示
//等待时间可以根据CPU速度调整
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;


}


第二步:这个过程我还没有进行,我会在后面的博文中阐述,在这里我大致讲述一下我的思路,希望可以一起交流。首先我们将第一步得到的插值图像进行操作,大概方法有以下几个方面,第一种是,我们可以利用一些边缘算子来考虑一下,这个办法运用的是烟雾的形状特性,他是一个块状的,并且是连通的,运动区域是稳定的变化,第二种是,烟雾的特性,在生活中的大部分烟雾的运动特性是向上运动的,我们选取一个像素,来计算他的下一帧中他的运动方向或者是后面几帧中,一次来判断烟雾,当然肯定还有其他的办法,希望阅读者可以提出来方便我们一起探讨。

第三步、就是报警,当我们在第二部里面检测到的区域是可疑的火警烟雾时,我们就实施报警,我认为这一步,只要一个标志位就可以了。

我会在后续的过程中一步一步的完善这篇博文。也期待你的加入讨论和指正批评。

0 0