运行环境:C++ builder 6 来自课本:opencv教程(基础篇) 例题 加上自己的注释 添加两个Button控件和一个opendialog控件 //--------------------------------------------------------------------------- //头文件 #ifndef Unit1H #define Unit1H //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <math.h> #include <time.h> #include "cv.h" #include "highgui.h" #include <Dialogs.hpp> //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: // IDE-managed Components TButton *Button1; TOpenDialog *OpenDialog1; TButton *Button2; void __fastcall Button1Click(TObject *Sender); void __fastcall Button2Click(TObject *Sender); private: // User declarations const double MHI_DURATION; const double MAX_TIME_DELTA; const double MIN_TIME_DELTA; const int N; const int CONTOUR_MAX_AERA; //ring image buffer IplImage** buf; int last; //temporary images IplImage* mhi; //MHI:motion history image CvFilter filter; CvConnectedComp* cur_comp,min_comp; CvConnectedComp comp; /*连接部件 typedef struct CvConnectedComp { double area; // 连通域的面积 float value; // 分割域的灰度缩放值 CvRect rect; // 分割域的 ROI } CvConnectedComp; */ CvMemStorage* storage; CvPoint pt[4]; public: // User declarations __fastcall TForm1(TComponent* Owner); void TForm1::update_mhi(IplImage* img,IplImage* dst,int diff_threshold); }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------- 实现文件 #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) :TForm(Owner),MHI_DURATION(0.5),MAX_TIME_DELTA(0.5),MIN_TIME_DELTA(0.05),N(3),CONTOUR_MAX_AERA(16) { buf = 0;last = 0;mhi = 0; filter = CV_GAUSSIAN_5x5; } //--------------------------------------------------------------------------- //参数:img - 输入视频帧,dst - 检测结果 void TForm1::update_mhi(IplImage* img,IplImage* dst,int diff_threshold) { double timestamp = clock()/100.; //获取当前时间,100后面的点表示浮点型,省略了0 CvSize size = cvSize(img->width,img->height); int i,j,idx1,idx2; IplImage* silh; unsigned char val; float temp; IplImage* pyr = cvCreateImage(cvSize((size.width & -2)/2,( size.height & -2)/2),8,1); /* pyr图像大小是原图像的1/2,如果你的原图像大小是奇数怎么办呢。 我觉得size.width & -2的作用就是将奇数图像长宽变成偶数。 如:5 & (-2) = 4 */ CvMemStorage* stor; CvSeq* cont,*result,*squares; //定义非固定元素序列,CvSeq是所有opencv动态数据结构的基础 CvSeqReader reader; //用来读取CvSeq结构 //初始化 if(!mhi || mhi->width != size.width || mhi->height != size.height) { if(buf == 0) { buf = (IplImage**)malloc(N * sizeof(buf[0])); memset(buf,0,N * sizeof(buf[0])); } for(i = 0;i < N;i++) { cvReleaseImage(&buf[i]); buf[i] = cvCreateImage(size,IPL_DEPTH_8U,1); cvZero(buf[i]); } cvReleaseImage(&mhi); mhi = cvCreateImage(size,IPL_DEPTH_32F,1); cvZero(mhi); } cvCvtColor(img,buf[last],CV_BGR2GRAY); idx1 = last; idx2 = (last + 1)%N; last = idx2; //做帧差 silh = buf[idx2]; //get difference between frames //cvAbsDiff( const CvArr* src1, const CvArr* src2, CvArr* dst ); //前景色与背景色相减,使图片出现0与非0元素,便于检查运动物体 cvAbsDiff(buf[idx1],buf[idx2],silh); //对差图像做二值化(src,dst,阀值,最大化值,计算方式) cvThreshold(silh,silh,30,255,CV_THRESH_BINARY); //更新运动历史图像 cvUpdateMotionHistory(silh,mhi,timestamp,MHI_DURATION); //cvCvtScale(mhi,dst,255./MHI_DURATION, // (MHI_DURATION - timestamp)*255./MHI_DURATION); //#define cvCvtScale cvConvertScale //使用线性变换转换数组,此处dst(i)=mhi(i)*255./MHI_DURATION+0 cvCvtScale(mhi,dst,255./MHI_DURATION,0); //中值滤波,消除小的噪声 cvSmooth(dst,dst,CV_MEDIAN,3,0,0,0); //向下采样,去掉噪声 图像大小为原来一半 cvPyrDown(dst,pyr,7); //做膨胀操作,消除模板的不连续空洞 cvDilate(pyr,pyr,0,1); //向上采样,图像大小为原来的两倍 cvPyrUp(pyr,dst,7); //下面的程序段用来找到轮廓 //Create dynamic structure and sequence //存储轮廓数据 stor = cvCreateMemStorage(0); //存储各个的轮廓指针的队列 cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor); // 找到所有轮廓 提取二值图像的轮廓 cvFindContours( dst, stor, &cont, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); /* for(;cont;cont = cont->h_next) { // Number point must be more than or equal to 6 (for cvFitEllipse_32f). if( cont->total < 6 ) continue; // Draw current contour. cvDrawContours(img,cont,CV_RGB(255,0,0),CV_RGB(255,0,0),0,1, 8, cvPoint(0,0)); } // end of for-loop: "cont" */ // 直接使用CONTOUR中的矩形来画轮廓 for(;cont;cont = cont->h_next) { CvRect r = ((CvContour*)cont)->rect; if(r.height * r.width > CONTOUR_MAX_AERA) // 面积小于16PX的方形抛弃掉 { cvRectangle(img, cvPoint(r.x,r.y), cvPoint(r.x + r.width, r.y + r.height), CV_RGB(255,0,0), 1, CV_AA,0); } } // free memory cvReleaseMemStorage(&stor); cvReleaseImage( &pyr ); } void __fastcall TForm1::Button1Click(TObject *Sender) { OpenDialog1->Filter = "AVI Files(*.avi)|*.avi"; if(!OpenDialog1->Execute())return; IplImage* motion = 0; CvCapture* capture = 0; //if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) // capture = cvCaptureFromCAM(0); //else if( argc == 2 ) capture = cvCaptureFromAVI( OpenDialog1->FileName.c_str()); if( capture ) { cvNamedWindow( "Motion", 1 ); for(;;) { IplImage* image; if( !cvGrabFrame( capture )) break; image = cvRetrieveFrame( capture ); if( image ) { if( !motion ) { motion = cvCreateImage( cvSize(image->width,image->height), 8, 1 ); cvZero( motion ); motion->origin = image->origin; } } update_mhi( image, motion, 60 ); cvShowImage( "Motion", image ); if( cvWaitKey(10) >= 0 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow( "Motion" ); } } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { IplImage* motion = 0; CvCapture* capture = 0; //if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) capture = cvCaptureFromCAM(0); //else if( argc == 2 ) //capture = cvCaptureFromAVI( OpenDialog1->FileName.c_str()); if( capture ) { cvNamedWindow( "Motion", 1 ); for(;;) { IplImage* image; if( !cvGrabFrame( capture )) break; image = cvRetrieveFrame( capture ); if( image ) { if( !motion ) { motion = cvCreateImage( cvSize(image->width,image->height), 8, 1 ); cvZero( motion ); motion->origin = image->origin; } } update_mhi( image, motion, 60 ); cvShowImage( "Motion", image ); if( cvWaitKey(10) >= 0 ) break; } cvReleaseCapture( &capture ); cvDestroyWindow( "Motion" ); } } //--------------------------------------------------------------------------- 载入视频,运行效果: