#include
//#include"stdafx.h"
#include
#include
#include
#include
#include "cvaux.h"
#include "cxmisc.h"
using namespace std;
void BackgroundDiff(IplImage* SrcImg, IplImage*FroundImg, IplImage* BackgroundImg, intnFrmNum, 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")是从文件件中读取视频。
CvCapture* pCapture = cvCreateFileCapture("E:\\Final3.avi");
int nFrmNum =0;
//创建窗口
cvNamedWindow("video",1);
cvNamedWindow("background",1);
cvNamedWindow("OTSUforeground",1);
cvNamedWindow("改进的OTSU foreground",1);
//使窗口有序排列
cvMoveWindow("video",30, 0);
cvMoveWindow("background",360, 0);
cvMoveWindow("OTSUforeground", 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("OTSUforeground", 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.2fFPS %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, intnFrmNum, 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); //浮点转化为整点
//二值化前景图
intthreshold_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;
intihist[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 { ihist[((int)(*ImgData))&255]++;//灰度统计 '&255'防止指针溢出 ImgData++;//像素遍历 } // set upeverything 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, "NOTNORMAL 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 << "OTSUthresholdValue = " << thresholdValue_temp<< ",Returned thresholdValue = "<< *thresholdValue<<'\n'< } 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);//绘制目标外接矩形 } }