opencv 实践程序2——背景差分法实现前景识别
来源:互联网 发布:sql select as 编辑:程序博客网 时间:2024/06/05 03:33
程序出处:http://blog.csdn.net/cwjcwj520/article/details/7433103,感谢博主!
#include <stdio.h>//#include "stdafx.h"#include <cv.h>#include <cxcore.h>#include <highgui.h>#include <iostream>#include "cvaux.h" #include "cxmisc.h"using namespace std;void BackgroundDiff(IplImage* SrcImg, IplImage* FroundImg, IplImage* BackgroundImg, int nFrmNum, int threshold_method);void cvOtsu(IplImage *src, int *thresholdValue);void PrintVedioInfo(CvCapture* pCapture, IplImage* img);void VedioControl(); //未实现 //视频控制全局变量,// 's' 画面stop// 'q' 退出播放// 'p' 打印OTSU算法中找到的阈值char ctrl = NULL; int main( int argc, char** argv ){ //声明IplImage指针 IplImage* pFrame = NULL; IplImage* pFroundImg = NULL; IplImage* pBackgroundImg = NULL; IplImage* pFroundImg_c = NULL; IplImage* pBackgroundImg_c = NULL; //大门背景建模良好 best //CvCapture* pCapture = cvCreateFileCapture("D:\\C++ Projects\\OpenCV_project\\img_video\\video.long.mjpg.avi"); CvCapture* pCapture=cvCaptureFromCAM(0);//从摄像头读取视频。cvCaptureFromAVI("2.avi")是从文件件中读取视频。 int nFrmNum = 0; //创建窗口 cvNamedWindow("video", 1); cvNamedWindow("background",1); cvNamedWindow("OTSU foreground",1); cvNamedWindow("改进的OTSU foreground",1); //使窗口有序排列 cvMoveWindow("video", 30, 0); cvMoveWindow("background", 360, 0); cvMoveWindow("OTSU foreground", 690, 0); cvMoveWindow("改进的OTSU foreground", 690, 320); // pCapture = cvCaptureFromAVI("2.avi"); //逐帧读取视频 while(pFrame = cvQueryFrame( pCapture )) { nFrmNum++; //视频控制 if( (ctrl = cvWaitKey(1000/180)) =='s' ) cvWaitKey(); else if(ctrl == 'p') cout << "Current Frame = " << nFrmNum << endl; else if( ctrl =='q' )break; if(nFrmNum ==1) { pBackgroundImg = cvCreateImage(cvGetSize(pFrame), 8,1); pFroundImg = cvCreateImage(cvGetSize(pFrame), 8,1); pBackgroundImg_c = cvCreateImage(cvGetSize(pFrame), 8,1); //对比算法的图像 pFroundImg_c = cvCreateImage(cvGetSize(pFrame), 8,1); } BackgroundDiff(pFrame,pFroundImg,pBackgroundImg, nFrmNum, CV_THRESH_OTSU); //普通OTSU BackgroundDiff(pFrame,pFroundImg_c,pBackgroundImg_c, nFrmNum, CV_THRESH_BINARY); //阈值筛选后的OTSU //打印视频信息,画面控制 PrintVedioInfo(pCapture, pFroundImg); //显示图像 cvShowImage("video", pFrame); cvShowImage("background", pBackgroundImg); cvShowImage("OTSU foreground", pFroundImg); cvShowImage("改进的OTSU foreground", pFroundImg_c); } //while //销毁窗口 cvDestroyAllWindows(); //释放图像和矩阵 cvReleaseImage(&pFroundImg); cvReleaseImage(&pBackgroundImg); cvReleaseCapture(&pCapture); return 0;}/* *输出文字到图像 */void PrintVedioInfo(CvCapture* pCapture, IplImage* img){assert( pCapture != NULL);double frames = cvGetCaptureProperty(pCapture, CV_CAP_PROP_POS_FRAMES); //视频当前帧数 double fps = cvGetCaptureProperty(pCapture,CV_CAP_PROP_FPS); //获得视频每秒帧数 char str[255]; sprintf(str,"%4.2f FPS %4.2f frames",fps,frames); // 将浮点数转化为字符串 CvPoint location = cvPoint(20,20); // 建立字符串打印的位置 CvScalar color = cvScalar(255,255,255); CvFont font; //建立字体变量 cvInitFont(&font, CV_FONT_HERSHEY_PLAIN, 1.0,1.0); //字体设置 cvPutText(img, str, location, &font,color); //打印文本到图像}/*********背景差分函数,求前景目标*重要: 函数退出之后,函数中的动态变量会随着栈的退出全部清空.*要保存上次操作的结果,则在函数内声明为静态变量.或者在要调用的函数里先声明*********/void BackgroundDiff(IplImage* SrcImg, IplImage* FroundImg, IplImage* BackgroundImg, int nFrmNum, int threshold_method = CV_THRESH_OTSU){static IplImage* SrcImg_gray = NULL;//源图像的灰度图像static IplImage* SrcImg_grayf =NULL; //单通道浮点图像用于背景建模static IplImage* FroundImgf = NULL;static IplImage* BackgroundImgf = NULL;static IplImage* FroundImg_temp = NULL; if(nFrmNum == 1){ SrcImg_gray = cvCreateImage(cvGetSize(SrcImg), 8,1); FroundImg_temp = cvCreateImage(cvGetSize(SrcImg), 8,1); BackgroundImgf = cvCreateImage(cvGetSize(SrcImg), 32,1); //浮点图像 FroundImgf = cvCreateImage(cvGetSize(SrcImg), 32,1); SrcImg_grayf = cvCreateImage(cvGetSize(SrcImg), 32,1); //RGB图像先转化成8位单通道图像,再转化为浮点. cvCvtColor(SrcImg, BackgroundImg, CV_BGR2GRAY); cvCvtColor(SrcImg, FroundImg, CV_BGR2GRAY); cvConvert(BackgroundImg,BackgroundImgf); cvConvert(FroundImg,FroundImgf);}else{ cvCvtColor(SrcImg, SrcImg_gray, CV_BGR2GRAY); //SrcImg_gray在上次函数退出的时候被程序栈回收 cvConvert(SrcImg_gray,SrcImg_grayf); //当前帧跟背景图相减 cvAbsDiff(SrcImg_grayf, BackgroundImgf, FroundImgf);cvConvert(FroundImgf,FroundImg_temp); //浮点转化为整点 //二值化前景图 int threshold_otsu =0;cvOtsu(FroundImg_temp, &threshold_otsu); if(threshold_method == CV_THRESH_OTSU) { cvThreshold(FroundImg_temp, FroundImg, 0, 255.0, CV_THRESH_OTSU); //对比自适应阈值化 // cvAdaptiveThreshold(FroundImg_temp, FroundImg, 255.0, 0, 0, 51); //src和dst必须同时是8bit或浮点图像 } else { cvThreshold(FroundImg_temp, FroundImg, threshold_otsu, 255.0, CV_THRESH_BINARY); } cvSegmentFGMask( FroundImg ); //对前景做连通域分割 //更新背景 cvRunningAvg(SrcImg_grayf, BackgroundImgf, 0.003, 0); //必须是浮点图像,因为会有小数出现 cvConvert(BackgroundImgf,BackgroundImg);}}/******** *OTSU大津法 * thresholdValue 为使类间方差最大的阈值 * 当找到的阈值小于一个修正阈值,返回此修正阈值.防止没有前景物体时,将背景找出来 ********/void cvOtsu(IplImage *src, int *thresholdValue){ int deltaT = 0; //光照调节参数uchar grayflag =1;IplImage* gray = NULL;if(src->nChannels != 1) //检查源图像是否为灰度图像{gray = cvCreateImage(cvGetSize(src), 8, 1);cvCvtColor(src, gray, CV_BGR2GRAY);grayflag = 0;}else gray = src;uchar* ImgData=(uchar*)(gray->imageData); int thresholdValue_temp = 1; int ihist[256]; //图像直方图,256个点 int i, imgsize; //循环变量,图像尺寸 int n, n1, n2; //n 非零像素个数, n1 前景像素个数, n2 背景像素个数 double m1, m2, sum, csum, fmax, sb;//m1前景灰度均值,m2背景灰度均值 //对直方图置零 memset(ihist, 0, sizeof(ihist)); //生成直方图 imgsize = (gray->widthStep)*(gray->height);//图像数据总数 for (i=0; i<imgsize;i++) { ihist[((int)(*ImgData))&255]++;//灰度统计 '&255'防止指针溢出 ImgData++;//像素遍历 } // set up everything sum=csum=0.0; n=0; for (i=0; i<255; i++) { sum+=(double)i*(double)ihist[i]; // x*f(x)质量矩 n+= ihist[i]; //f(x)质量 像素总数 }deltaT = (int)(sum/imgsize); //像素平均灰度deltaT = deltaT>>1; //与之矫正,delatT = v*n; v=0.5 if (!n) {//图像全黑,输出警告 fprintf (stderr, "NOT NORMAL thresholdValue=160\n"); } // OTSU算法 fmax=-1.0; n1=0; for (i=0; i<255; i++) { n1+= ihist[i]; if (n1==0) {continue;} n2=n-n1; if (n2==0) {break;} csum += (double)i *ihist[i]; m1=csum/n1; m2=(sum-csum)/n2; sb=(double)n1*(double)n2*(m1-m2)*(m1-m2); //计算类间方差, 公式已简化 if (sb>fmax) { fmax=sb; thresholdValue_temp=i; //找到使类间方差最大的灰度值i } } if(thresholdValue_temp < 20)*thresholdValue = 20; //阈值筛选else *thresholdValue = thresholdValue_temp;if( ctrl == 'p') //ctrl = cvWaitKey(100),且是全局变量{ cout << "OTSU thresholdValue = " << thresholdValue_temp<<", Returned thresholdValue = " << *thresholdValue<<'\n'<<endl;}if(!grayflag) cvReleaseImage(&gray);} /************轮廓提取************/void Labeling(IplImage *src, IplImage *dst) { CvMemStorage* storage = 0; storage = cvCreateMemStorage(0); //开辟默认大小的空间 CvSeq* contour=0; cvCopy(src,dst,0); cvFindContours( dst, storage, &contour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE ); //外边缘 int num=0; for( ;contour!=0; contour=contour->h_next) { CvRect rect; rect = cvBoundingRect(contour,0);//得到目标外接矩形 num++; if((rect.height + rect.width) >= 16) cvRectangle(src,cvPoint(rect.x,rect.y),cvPoint(rect.x+rect.width,rect.y+rect.height), CV_RGB(255, 255,255),1,8);//绘制目标外接矩形// cvRectangle(dst,cvPoint(rect.x,rect.y),cvPoint(rect.x+rect.width,rect.y+rect.height), // CV_RGB(255, 255,255),1,8);//绘制目标外接矩形 }}
0 0
- opencv 实践程序2——背景差分法实现前景识别
- opencv实践程序5——最简单背景差分法
- 【OpenCV】5th-识别背景和前景
- opencv实践程序4——canny实现摄像头的边缘检测,高斯背景建模
- opencv实现图像分割,分离前景和背景(2)
- opencv实践程序6——简单(otsu)的背景差分法
- 背景差分法实现前景提取
- OpenCV实现图像物体轮廓,前景背景,标记,并保存。
- opencv实现图像分割,分离前景和背景(1)
- OpenCV 实践程序17——实现图片标注
- caffe 实践程序2——用细分的方法实现caffe中cifar100的识别
- caffe 实践程序2——用细分的方法实现caffe中cifar100的识别
- 一个去除视频前景,保留背景的 opencv 小程序 (附注释)
- 【opencv实践】人脸识别匹配——模型训练
- OpenCV实践之路——人脸识别之三识别自己的脸
- 【opencv实践】人脸识别匹配——识别自己的脸
- OpenCV实践之路——人脸识别之三识别自己的脸
- OpenCV 实践程序13——实现文件夹下图像批量归一化
- PHP之 开始篇
- php中的sprintf(),printf()
- 斯坦福机器学习-week5 学习笔记(1)——神经网络训练BP算法与Gradient checking
- Android使用https链接
- SQL技巧--------查询重复
- opencv 实践程序2——背景差分法实现前景识别
- 来自苹果、谷歌、微软等知名公司六道有趣智力面试题,试试吧!
- adb命令
- Flex 4.1 + BlazeDs + parsley框架(Demo实例)
- cocos2d-x 3.0开发笔记---物理引擎封装 Physics深入学习
- Windows无线Wifi(网络承载实现)
- QThread中的slots在那个线程中执行?
- cocos2d-x-3.0 的 lua 可以跑在 mac 上面, 2.2 版本不行
- 手把手教你做iphone的soap应用(webservice)