opencv 实践程序2——背景差分法实现前景识别
2014-03-30 14:31
519 查看
程序出处: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);//从摄像头读取视频。cvCaptureFrom***I("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 = cvCaptureFrom***I("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);//绘制目标外接矩形 } }
相关文章推荐
- OpenCV 实践程序17——实现图片标注
- caffe 实践程序2——用细分的方法实现caffe中cifar100的识别
- caffe 实践程序2——用细分的方法实现caffe中cifar100的识别
- opencv实践程序6——简单(otsu)的背景差分法
- OpenCV 实践程序13——实现文件夹下图像批量归一化
- opencv实践程序4——canny实现摄像头的边缘检测,高斯背景建模
- OpenCV 实践程序17——用C++实现ip camera的视频播放
- Python+OpenCV实现车牌字符分割和识别
- 6 机器学习实践之手写数字识别-卷积神经网络实现
- python+opencv实现的简单人脸识别代码示例
- opencv实现简单手指位置识别
- opencv实现猫脸识别
- OpenCV实现屏保程序智能控制
- 微信小程序:nodejs+百度语音识别开发实践
- OpenCV编程案例:实现一个双目摄像头图像显示的程序
- 张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)
- 在WinForms程序里实现窗体传值的最佳实践
- 基于OpenCV的人脸识别算法之二---代码实现
- 基于OpenCV的 SVM算法实现数字识别(一)---理论基础
- 使用Opencv实现IOS平台下的人脸识别