aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine Villeret <avilleret@users.sourceforge.net>2012-09-22 15:06:16 +0000
committerAntoine Villeret <avilleret@users.sourceforge.net>2012-09-22 15:06:16 +0000
commit56d169c81a42f3f473b8ce53b514798685c7ea9c (patch)
treec4eab5582ef5b963766e498e239d973da9c6475d
parentd86dbe680d2a6a8998a64cdc3f3ac77b2a75897b (diff)
add a blobtracker
svn path=/trunk/externals/pix_opencv/; revision=16264
-rw-r--r--blobtrack.cpp643
-rw-r--r--blobtrack.h130
-rw-r--r--pix_opencv_blobtrack-help.pd219
-rw-r--r--pix_opencv_blobtrack.cpp556
-rw-r--r--pix_opencv_blobtrack.h104
5 files changed, 1652 insertions, 0 deletions
diff --git a/blobtrack.cpp b/blobtrack.cpp
new file mode 100644
index 0000000..431476e
--- /dev/null
+++ b/blobtrack.cpp
@@ -0,0 +1,643 @@
+/*
+ * OpenCV 2.3 - blobtrack_sample.cpp ported to Gem by Antoine Villeret - 2012
+*/
+
+#include "blobtrack.h"
+#include "opencv2/video/background_segm.hpp"
+#include "opencv2/legacy/blobtrack.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include <opencv2/imgproc/imgproc_c.h>
+
+#include <stdio.h>
+
+/* List of Blob Trajectory ANALYSIS modules: */
+/*================= END MODULES DECRIPTION ===================================*/
+
+/* Run pipeline on all frames: */
+int RunBlobTrackingAuto( CvCapture* pCap, CvBlobTrackerAuto* pTracker,char* fgavi_name = NULL, char* btavi_name = NULL )
+{
+ int OneFrameProcess = 0;
+ int key;
+ int FrameNum = 0;
+ CvVideoWriter* pFGAvi = NULL;
+ CvVideoWriter* pBTAvi = NULL;
+
+ //cvNamedWindow( "FG", 0 );
+
+ /* Main loop: */
+ for( FrameNum=0; pCap && (key=cvWaitKey(OneFrameProcess?0:1))!=27;
+ FrameNum++)
+ { /* Main loop: */
+ IplImage* pImg = NULL;
+ IplImage* pMask = NULL;
+
+ if(key!=-1)
+ {
+ OneFrameProcess = 1;
+ if(key=='r')OneFrameProcess = 0;
+ }
+
+ pImg = cvQueryFrame(pCap);
+ if(pImg == NULL) break;
+
+
+ /* Process: */
+ pTracker->Process(pImg, pMask);
+
+ if(fgavi_name)
+ if(pTracker->GetFGMask())
+ { /* Debug FG: */
+ IplImage* pFG = pTracker->GetFGMask();
+ CvSize S = cvSize(pFG->width,pFG->height);
+ static IplImage* pI = NULL;
+
+ if(pI==NULL)pI = cvCreateImage(S,pFG->depth,3);
+ cvCvtColor( pFG, pI, CV_GRAY2BGR );
+
+ if(fgavi_name)
+ { /* Save fg to avi file: */
+ if(pFGAvi==NULL)
+ {
+ pFGAvi=cvCreateVideoWriter(
+ fgavi_name,
+ CV_FOURCC('x','v','i','d'),
+ 25,
+ S );
+ }
+ cvWriteFrame( pFGAvi, pI );
+ }
+
+ if(pTracker->GetBlobNum()>0)
+ { /* Draw detected blobs: */
+ int i;
+ for(i=pTracker->GetBlobNum();i>0;i--)
+ {
+ CvBlob* pB = pTracker->GetBlob(i-1);
+ CvPoint p = cvPointFrom32f(CV_BLOB_CENTER(pB));
+ CvSize s = cvSize(MAX(1,cvRound(CV_BLOB_RX(pB))), MAX(1,cvRound(CV_BLOB_RY(pB))));
+ int c = cvRound(255*pTracker->GetState(CV_BLOB_ID(pB)));
+ cvEllipse( pI,
+ p,
+ s,
+ 0, 0, 360,
+ CV_RGB(c,255-c,0), cvRound(1+(3*c)/255) );
+ } /* Next blob: */;
+ }
+
+ cvNamedWindow( "FG",0);
+ cvShowImage( "FG",pI);
+ } /* Debug FG. */
+
+
+ /* Draw debug info: */
+ if(pImg)
+ { /* Draw all information about test sequence: */
+ char str[1024];
+ int line_type = CV_AA; // Change it to 8 to see non-antialiased graphics.
+ CvFont font;
+ int i;
+ IplImage* pI = cvCloneImage(pImg);
+
+ cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, 0.7, 0.7, 0, 1, line_type );
+
+ for(i=pTracker->GetBlobNum(); i>0; i--)
+ {
+ CvSize TextSize;
+ CvBlob* pB = pTracker->GetBlob(i-1);
+ CvPoint p = cvPoint(cvRound(pB->x*256),cvRound(pB->y*256));
+ CvSize s = cvSize(MAX(1,cvRound(CV_BLOB_RX(pB)*256)), MAX(1,cvRound(CV_BLOB_RY(pB)*256)));
+ int c = cvRound(255*pTracker->GetState(CV_BLOB_ID(pB)));
+
+ cvEllipse( pI,
+ p,
+ s,
+ 0, 0, 360,
+ CV_RGB(c,255-c,0), cvRound(1+(3*0)/255), CV_AA, 8 );
+
+ p.x >>= 8;
+ p.y >>= 8;
+ s.width >>= 8;
+ s.height >>= 8;
+ sprintf(str,"%03d",CV_BLOB_ID(pB));
+ cvGetTextSize( str, &font, &TextSize, NULL );
+ p.y -= s.height;
+ cvPutText( pI, str, p, &font, CV_RGB(0,255,255));
+ {
+ const char* pS = pTracker->GetStateDesc(CV_BLOB_ID(pB));
+
+ if(pS)
+ {
+ char* pStr = strdup(pS);
+ char* pStrFree = pStr;
+
+ while (pStr && strlen(pStr) > 0)
+ {
+ char* str_next = strchr(pStr,'\n');
+
+ if(str_next)
+ {
+ str_next[0] = 0;
+ str_next++;
+ }
+
+ p.y += TextSize.height+1;
+ cvPutText( pI, pStr, p, &font, CV_RGB(0,255,255));
+ pStr = str_next;
+ }
+ free(pStrFree);
+ }
+ }
+
+ } /* Next blob. */;
+
+ cvNamedWindow( "Tracking", 0);
+ cvShowImage( "Tracking",pI );
+
+ if(btavi_name && pI)
+ { /* Save to avi file: */
+ CvSize S = cvSize(pI->width,pI->height);
+ if(pBTAvi==NULL)
+ {
+ pBTAvi=cvCreateVideoWriter(
+ btavi_name,
+ CV_FOURCC('x','v','i','d'),
+ 25,
+ S );
+ }
+ cvWriteFrame( pBTAvi, pI );
+ }
+
+ cvReleaseImage(&pI);
+ } /* Draw all information about test sequence. */
+ } /* Main loop. */
+
+ if(pFGAvi)cvReleaseVideoWriter( &pFGAvi );
+ if(pBTAvi)cvReleaseVideoWriter( &pBTAvi );
+ return 0;
+} /* RunBlobTrackingAuto */
+
+/* Read parameters from command line
+ * and transfer to specified module:
+ */
+void set_params(int argc, char* argv[], CvVSModule* pM, const char* prefix, const char* module)
+{
+ int prefix_len = strlen(prefix);
+ int i;
+ for(i=0; i<argc; ++i)
+ {
+ int j;
+ char* ptr_eq = NULL;
+ int cmd_param_len=0;
+ char* cmd = argv[i];
+ if(MY_STRNICMP(prefix,cmd,prefix_len)!=0) continue;
+ cmd += prefix_len;
+ if(cmd[0]!=':')continue;
+ cmd++;
+
+ ptr_eq = strchr(cmd,'=');
+ if(ptr_eq)cmd_param_len = ptr_eq-cmd;
+
+ for(j=0; ; ++j)
+ {
+ int param_len;
+ const char* param = pM->GetParamName(j);
+ if(param==NULL) break;
+ param_len = strlen(param);
+ if(cmd_param_len!=param_len) continue;
+ if(MY_STRNICMP(param,cmd,param_len)!=0) continue;
+ cmd+=param_len;
+ if(cmd[0]!='=')continue;
+ cmd++;
+ pM->SetParamStr(param,cmd);
+ printf("%s:%s param set to %g\n",module,param,pM->GetParam(param));
+ }
+ }
+
+ pM->ParamUpdate();
+
+} /* set_params */
+
+/* Print all parameter values for given module: */
+void print_params(CvVSModule* pM, const char* module, const char* log_name)
+{
+ FILE* log = log_name?fopen(log_name,"at"):NULL;
+ int i;
+ if(pM->GetParamName(0) == NULL ) return;
+
+
+ printf("%s(%s) module parameters:\n",module,pM->GetNickName());
+ if(log)
+ fprintf(log,"%s(%s) module parameters:\n",module,pM->GetNickName());
+
+ for (i=0; ; ++i)
+ {
+ const char* param = pM->GetParamName(i);
+ const char* str = param?pM->GetParamStr(param):NULL;
+ if(param == NULL)break;
+ if(str)
+ {
+ printf(" %s: %s\n",param,str);
+ if(log)
+ fprintf(log," %s: %s\n",param,str);
+ }
+ else
+ {
+ printf(" %s: %g\n",param,pM->GetParam(param));
+ if(log)
+ fprintf(log," %s: %g\n",param,pM->GetParam(param));
+ }
+ }
+
+ if(log) fclose(log);
+
+} /* print_params */
+
+int main(int argc, char* argv[])
+{ /* Main function: */
+ CvCapture* pCap = NULL;
+ CvBlobTrackerAutoParam1 param = {0}; // TODO need more params
+ CvBlobTrackerAuto* pTracker = NULL;
+
+ float scale = 1;
+ const char* scale_name = NULL;
+ char* yml_name = NULL;
+ char** yml_video_names = NULL;
+ int yml_video_num = 0;
+ char* avi_name = NULL;
+ const char* fg_name = NULL;
+ char* fgavi_name = NULL;
+ char* btavi_name = NULL;
+ const char* bd_name = NULL;
+ const char* bt_name = NULL;
+ const char* btgen_name = NULL;
+ const char* btpp_name = NULL;
+ const char* bta_name = NULL;
+ char* bta_data_name = NULL;
+ char* track_name = NULL;
+ char* comment_name = NULL;
+ char* FGTrainFrames = NULL;
+ char* log_name = NULL;
+ char* savestate_name = NULL;
+ char* loadstate_name = NULL;
+ const char* bt_corr = NULL;
+ DefModule_FGDetector* pFGModule = NULL;
+ DefModule_BlobDetector* pBDModule = NULL;
+ DefModule_BlobTracker* pBTModule = NULL;
+ DefModule_BlobTrackPostProc* pBTPostProcModule = NULL;
+ DefModule_BlobTrackGen* pBTGenModule = NULL;
+ DefModule_BlobTrackAnalysis* pBTAnalysisModule = NULL;
+
+ cvInitSystem(argc, argv);
+
+ if(argc < 2)
+ { /* Print help: */
+ int i;
+ printf("blobtrack [fg=<fg_name>] [bd=<bd_name>]\n"
+ " [bt=<bt_name>] [btpp=<btpp_name>]\n"
+ " [bta=<bta_name>\n"
+ " [bta_data=<bta_data_name>\n"
+ " [bt_corr=<bt_corr_way>]\n"
+ " [btgen=<btgen_name>]\n"
+ " [track=<track_file_name>]\n"
+ " [scale=<scale val>] [noise=<noise_name>] [IVar=<IVar_name>]\n"
+ " [FGTrainFrames=<FGTrainFrames>]\n"
+ " [btavi=<avi output>] [fgavi=<avi output on FG>]\n"
+ " <avi_file>\n");
+
+ printf(" <bt_corr_way> is the method of blob position correction for the \"Blob Tracking\" module\n"
+ " <bt_corr_way>=none,PostProcRes\n"
+ " <FGTrainFrames> is number of frames for FG training\n"
+ " <track_file_name> is file name for save tracked trajectories\n"
+ " <bta_data> is file name for data base of trajectory analysis module\n"
+ " <avi_file> is file name of avi to process by BlobTrackerAuto\n");
+
+ puts("\nModules:");
+#define PR(_name,_m,_mt)\
+ printf("<%s> is \"%s\" module name and can be:\n",_name,_mt);\
+ for(i=0; _m[i].nickname; ++i)\
+ {\
+ printf(" %d. %s",i+1,_m[i].nickname);\
+ if(_m[i].description)printf(" - %s",_m[i].description);\
+ printf("\n");\
+ }
+
+ PR("fg_name",FGDetector_Modules,"FG/BG Detection");
+ PR("bd_name",BlobDetector_Modules,"Blob Entrance Detection");
+ PR("bt_name",BlobTracker_Modules,"Blob Tracking");
+ PR("btpp_name",BlobTrackPostProc_Modules, "Blob Trajectory Post Processing");
+ PR("btgen_name",BlobTrackGen_Modules, "Blob Trajectory Generation");
+ PR("bta_name",BlobTrackAnalysis_Modules, "Blob Trajectory Analysis");
+#undef PR
+ return 0;
+ } /* Print help. */
+
+ { /* Parse arguments: */
+ int i;
+ for(i=1; i<argc; ++i)
+ {
+ int bParsed = 0;
+ size_t len = strlen(argv[i]);
+#define RO(_n1,_n2) if(strncmp(argv[i],_n1,strlen(_n1))==0) {_n2 = argv[i]+strlen(_n1);bParsed=1;};
+ RO("fg=",fg_name);
+ RO("fgavi=",fgavi_name);
+ RO("btavi=",btavi_name);
+ RO("bd=",bd_name);
+ RO("bt=",bt_name);
+ RO("bt_corr=",bt_corr);
+ RO("btpp=",btpp_name);
+ RO("bta=",bta_name);
+ RO("bta_data=",bta_data_name);
+ RO("btgen=",btgen_name);
+ RO("track=",track_name);
+ RO("comment=",comment_name);
+ RO("FGTrainFrames=",FGTrainFrames);
+ RO("log=",log_name);
+ RO("savestate=",savestate_name);
+ RO("loadstate=",loadstate_name);
+#undef RO
+ {
+ char* ext = argv[i] + len-4;
+ if( strrchr(argv[i],'=') == NULL &&
+ !bParsed &&
+ (len>3 && (MY_STRICMP(ext,".avi") == 0 )))
+ {
+ avi_name = argv[i];
+ break;
+ }
+ } /* Next argument. */
+ }
+ } /* Parse arguments. */
+
+ if(track_name)
+ { /* Set Trajectory Generator module: */
+ int i;
+ if(!btgen_name)btgen_name=BlobTrackGen_Modules[0].nickname;
+
+ for(i=0; BlobTrackGen_Modules[i].nickname; ++i)
+ {
+ if(MY_STRICMP(BlobTrackGen_Modules[i].nickname,btgen_name)==0)
+ pBTGenModule = BlobTrackGen_Modules + i;
+ }
+ } /* Set Trajectory Generato module. */
+
+ /* Initialize postprocessing module if tracker
+ * correction by postprocessing is required.
+ */
+ if(bt_corr && MY_STRICMP(bt_corr,"PostProcRes")!=0 && !btpp_name)
+ {
+ btpp_name = bt_corr;
+ if(MY_STRICMP(btpp_name,"none")!=0)bt_corr = "PostProcRes";
+ }
+
+ { /* Set default parameters for one processing: */
+ if(!bt_corr) bt_corr = "none";
+ if(!fg_name) fg_name = FGDetector_Modules[0].nickname;
+ if(!bd_name) bd_name = BlobDetector_Modules[0].nickname;
+ if(!bt_name) bt_name = BlobTracker_Modules[0].nickname;
+ if(!btpp_name) btpp_name = BlobTrackPostProc_Modules[0].nickname;
+ if(!bta_name) bta_name = BlobTrackAnalysis_Modules[0].nickname;
+ if(!scale_name) scale_name = "1";
+ }
+
+ if(scale_name)
+ scale = (float)atof(scale_name);
+
+ for(pFGModule=FGDetector_Modules; pFGModule->nickname; ++pFGModule)
+ if( fg_name && MY_STRICMP(fg_name,pFGModule->nickname)==0 ) break;
+
+ for(pBDModule=BlobDetector_Modules; pBDModule->nickname; ++pBDModule)
+ if( bd_name && MY_STRICMP(bd_name,pBDModule->nickname)==0 ) break;
+
+ for(pBTModule=BlobTracker_Modules; pBTModule->nickname; ++pBTModule)
+ if( bt_name && MY_STRICMP(bt_name,pBTModule->nickname)==0 ) break;
+
+ for(pBTPostProcModule=BlobTrackPostProc_Modules; pBTPostProcModule->nickname; ++pBTPostProcModule)
+ if( btpp_name && MY_STRICMP(btpp_name,pBTPostProcModule->nickname)==0 ) break;
+
+ for(pBTAnalysisModule=BlobTrackAnalysis_Modules; pBTAnalysisModule->nickname; ++pBTAnalysisModule)
+ if( bta_name && MY_STRICMP(bta_name,pBTAnalysisModule->nickname)==0 ) break;
+
+ /* Create source video: */
+ if(avi_name)
+ pCap = cvCaptureFromFile(avi_name);
+
+ if(pCap==NULL)
+ {
+ printf("Can't open %s file\n",avi_name);
+ return -1;
+ }
+
+
+ { /* Display parameters: */
+ int i;
+ FILE* log = log_name?fopen(log_name,"at"):NULL;
+ if(log)
+ { /* Print to log file: */
+ fprintf(log,"\n=== Blob Tracking pipline in processing mode===\n");
+ if(avi_name)
+ {
+ fprintf(log,"AVIFile: %s\n",avi_name);
+ }
+ fprintf(log,"FGDetector: %s\n", pFGModule->nickname);
+ fprintf(log,"BlobDetector: %s\n", pBDModule->nickname);
+ fprintf(log,"BlobTracker: %s\n", pBTModule->nickname);
+ fprintf(log,"BlobTrackPostProc: %s\n", pBTPostProcModule->nickname);
+ fprintf(log,"BlobCorrection: %s\n", bt_corr);
+
+ fprintf(log,"Blob Trajectory Generator: %s (%s)\n",
+ pBTGenModule?pBTGenModule->nickname:"None",
+ track_name?track_name:"none");
+
+ fprintf(log,"BlobTrackAnalysis: %s\n", pBTAnalysisModule->nickname);
+ fclose(log);
+ }
+
+ printf("\n=== Blob Tracking pipline in %s mode===\n","processing");
+ if(yml_name)
+ {
+ printf("ConfigFile: %s\n",yml_name);
+ printf("BG: %s\n",yml_video_names[0]);
+ printf("FG: ");
+ for(i=1;i<(yml_video_num);++i){printf("%s",yml_video_names[i]);if((i+1)<yml_video_num)printf("|");};
+ printf("\n");
+ }
+ if(avi_name)
+ {
+ printf("AVIFile: %s\n",avi_name);
+ }
+ printf("FGDetector: %s\n", pFGModule->nickname);
+ printf("BlobDetector: %s\n", pBDModule->nickname);
+ printf("BlobTracker: %s\n", pBTModule->nickname);
+ printf("BlobTrackPostProc: %s\n", pBTPostProcModule->nickname);
+ printf("BlobCorrection: %s\n", bt_corr);
+
+ printf("Blob Trajectory Generator: %s (%s)\n",
+ pBTGenModule?pBTGenModule->nickname:"None",
+ track_name?track_name:"none");
+
+ printf("BlobTrackAnalysis: %s\n", pBTAnalysisModule->nickname);
+
+ } /* Display parameters. */
+
+ { /* Create autotracker module and its components: */
+ param.FGTrainFrames = FGTrainFrames?atoi(FGTrainFrames):0;
+
+ /* Create FG Detection module: */
+ param.pFG = pFGModule->create();
+ if(!param.pFG)
+ puts("Can not create FGDetector module");
+ param.pFG->SetNickName(pFGModule->nickname);
+ set_params(argc, argv, param.pFG, "fg", pFGModule->nickname);
+
+ /* Create Blob Entrance Detection module: */
+ param.pBD = pBDModule->create();
+ if(!param.pBD)
+ puts("Can not create BlobDetector module");
+ param.pBD->SetNickName(pBDModule->nickname);
+ set_params(argc, argv, param.pBD, "bd", pBDModule->nickname);
+
+ /* Create blob tracker module: */
+ param.pBT = pBTModule->create();
+ if(!param.pBT)
+ puts("Can not create BlobTracker module");
+ param.pBT->SetNickName(pBTModule->nickname);
+ set_params(argc, argv, param.pBT, "bt", pBTModule->nickname);
+
+ /* Create blob trajectory generation module: */
+ param.pBTGen = NULL;
+ if(pBTGenModule && track_name && pBTGenModule->create)
+ {
+ param.pBTGen = pBTGenModule->create();
+ param.pBTGen->SetFileName(track_name);
+ }
+ if(param.pBTGen)
+ {
+ param.pBTGen->SetNickName(pBTGenModule->nickname);
+ set_params(argc, argv, param.pBTGen, "btgen", pBTGenModule->nickname);
+ }
+
+ /* Create blob trajectory post processing module: */
+ param.pBTPP = NULL;
+ if(pBTPostProcModule && pBTPostProcModule->create)
+ {
+ param.pBTPP = pBTPostProcModule->create();
+ }
+ if(param.pBTPP)
+ {
+ param.pBTPP->SetNickName(pBTPostProcModule->nickname);
+ set_params(argc, argv, param.pBTPP, "btpp", pBTPostProcModule->nickname);
+ }
+
+ param.UsePPData = (bt_corr && MY_STRICMP(bt_corr,"PostProcRes")==0);
+
+ /* Create blob trajectory analysis module: */
+ param.pBTA = NULL;
+ if(pBTAnalysisModule && pBTAnalysisModule->create)
+ {
+ param.pBTA = pBTAnalysisModule->create();
+ param.pBTA->SetFileName(bta_data_name);
+ }
+ if(param.pBTA)
+ {
+ param.pBTA->SetNickName(pBTAnalysisModule->nickname);
+ set_params(argc, argv, param.pBTA, "bta", pBTAnalysisModule->nickname);
+ }
+
+ /* Create whole pipline: */
+ pTracker = cvCreateBlobTrackerAuto1(&param);
+ if(!pTracker)
+ puts("Can not create BlobTrackerAuto");
+ }
+
+ { /* Load states of each module from state file: */
+ CvFileStorage* fs = NULL;
+ if(loadstate_name)
+ fs=cvOpenFileStorage(loadstate_name,NULL,CV_STORAGE_READ);
+ if(fs)
+ {
+ printf("Load states for modules...\n");
+ if(param.pBT)
+ {
+ CvFileNode* fn = cvGetFileNodeByName(fs,NULL,"BlobTracker");
+ param.pBT->LoadState(fs,fn);
+ }
+
+ if(param.pBTA)
+ {
+ CvFileNode* fn = cvGetFileNodeByName(fs,NULL,"BlobTrackAnalyser");
+ param.pBTA->LoadState(fs,fn);
+ }
+
+ if(pTracker)
+ {
+ CvFileNode* fn = cvGetFileNodeByName(fs,NULL,"BlobTrackerAuto");
+ pTracker->LoadState(fs,fn);
+ }
+
+ cvReleaseFileStorage(&fs);
+ printf("... Modules states loaded\n");
+ }
+ } /* Load states of each module. */
+
+ { /* Print module parameters: */
+ struct DefMMM
+ {
+ CvVSModule* pM;
+ const char* name;
+ } Modules[] = {
+ {(CvVSModule*)param.pFG,"FGdetector"},
+ {(CvVSModule*)param.pBD,"BlobDetector"},
+ {(CvVSModule*)param.pBT,"BlobTracker"},
+ {(CvVSModule*)param.pBTGen,"TrackGen"},
+ {(CvVSModule*)param.pBTPP,"PostProcessing"},
+ {(CvVSModule*)param.pBTA,"TrackAnalysis"},
+ {NULL,NULL}
+ };
+ int i;
+ for(i=0; Modules[i].name; ++i)
+ {
+ if(Modules[i].pM)
+ print_params(Modules[i].pM,Modules[i].name,log_name);
+ }
+ } /* Print module parameters. */
+
+ /* Run pipeline: */
+ RunBlobTrackingAuto( pCap, pTracker, fgavi_name, btavi_name );
+
+ { /* Save state and release modules: */
+ CvFileStorage* fs = NULL;
+ if(savestate_name)
+ {
+ fs=cvOpenFileStorage(savestate_name,NULL,CV_STORAGE_WRITE);
+ }
+ if(fs)
+ {
+ cvStartWriteStruct(fs,"BlobTracker",CV_NODE_MAP);
+ if(param.pBT)param.pBT->SaveState(fs);
+ cvEndWriteStruct(fs);
+ cvStartWriteStruct(fs,"BlobTrackerAuto",CV_NODE_MAP);
+ if(pTracker)pTracker->SaveState(fs);
+ cvEndWriteStruct(fs);
+ cvStartWriteStruct(fs,"BlobTrackAnalyser",CV_NODE_MAP);
+ if(param.pBTA)param.pBTA->SaveState(fs);
+ cvEndWriteStruct(fs);
+ cvReleaseFileStorage(&fs);
+ }
+ if(param.pBT)cvReleaseBlobTracker(&param.pBT);
+ if(param.pBD)cvReleaseBlobDetector(&param.pBD);
+ if(param.pBTGen)cvReleaseBlobTrackGen(&param.pBTGen);
+ if(param.pBTA)cvReleaseBlobTrackAnalysis(&param.pBTA);
+ if(param.pFG)cvReleaseFGDetector(&param.pFG);
+ if(pTracker)cvReleaseBlobTrackerAuto(&pTracker);
+
+ } /* Save state and release modules. */
+
+ if(pCap)
+ cvReleaseCapture(&pCap);
+
+ return 0;
+
+} /* main() */
+
+
+q
diff --git a/blobtrack.h b/blobtrack.h
new file mode 100644
index 0000000..14c5df7
--- /dev/null
+++ b/blobtrack.h
@@ -0,0 +1,130 @@
+#include "opencv2/video/background_segm.hpp"
+#include "opencv2/legacy/blobtrack.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include <opencv2/imgproc/imgproc_c.h>
+
+#include <stdio.h>
+
+/* Select appropriate case insensitive string comparison function: */
+#if defined WIN32 || defined _MSC_VER
+ #define MY_STRNICMP strnicmp
+ #define MY_STRICMP stricmp
+#else
+ #define MY_STRNICMP strncasecmp
+ #define MY_STRICMP strcasecmp
+#endif
+
+/* List of foreground (FG) DETECTION modules: */
+static CvFGDetector* cvCreateFGDetector0 () { return cvCreateFGDetectorBase(CV_BG_MODEL_FGD, NULL); }
+static CvFGDetector* cvCreateFGDetector0Simple() { return cvCreateFGDetectorBase(CV_BG_MODEL_FGD_SIMPLE, NULL); }
+static CvFGDetector* cvCreateFGDetector1 () { return cvCreateFGDetectorBase(CV_BG_MODEL_MOG, NULL); }
+
+typedef struct DefModule_FGDetector
+{
+ CvFGDetector* (*create)();
+ const char* nickname;
+ const char* description;
+} DefModule_FGDetector;
+
+DefModule_FGDetector FGDetector_Modules[] =
+{
+ {cvCreateFGDetector0,"FG_0","Foreground Object Detection from Videos Containing Complex Background. ACM MM2003."},
+ {cvCreateFGDetector0Simple,"FG_0S","Simplified version of FG_0"},
+ {cvCreateFGDetector1,"FG_1","Adaptive background mixture models for real-time tracking. CVPR1999"},
+ {NULL,NULL,NULL}
+};
+
+/* List of BLOB DETECTION modules: */
+typedef struct DefModule_BlobDetector
+{
+ CvBlobDetector* (*create)();
+ const char* nickname;
+ const char* description;
+} DefModule_BlobDetector;
+
+DefModule_BlobDetector BlobDetector_Modules[] =
+{
+ {cvCreateBlobDetectorCC,"BD_CC","Detect new blob by tracking CC of FG mask"},
+ {cvCreateBlobDetectorSimple,"BD_Simple","Detect new blob by uniform moving of connected components of FG mask"},
+ {NULL,NULL,NULL}
+};
+
+/* List of BLOB TRACKING modules: */
+typedef struct DefModule_BlobTracker
+{
+ CvBlobTracker* (*create)();
+ const char* nickname;
+ const char* description;
+} DefModule_BlobTracker;
+
+DefModule_BlobTracker BlobTracker_Modules[] =
+{
+ {cvCreateBlobTrackerCCMSPF,"CCMSPF","connected component tracking and MSPF resolver for collision"},
+ {cvCreateBlobTrackerCC,"CC","Simple connected component tracking"},
+ {cvCreateBlobTrackerMS,"MS","Mean shift algorithm "},
+ {cvCreateBlobTrackerMSFG,"MSFG","Mean shift algorithm with FG mask using"},
+ {cvCreateBlobTrackerMSPF,"MSPF","Particle filtering based on MS weight"},
+ {NULL,NULL,NULL}
+};
+
+/* List of BLOB TRAJECTORY GENERATION modules: */
+typedef struct DefModule_BlobTrackGen
+{
+ CvBlobTrackGen* (*create)();
+ const char* nickname;
+ const char* description;
+} DefModule_BlobTrackGen;
+
+DefModule_BlobTrackGen BlobTrackGen_Modules[] =
+{
+ {cvCreateModuleBlobTrackGenYML,"YML","Generate track record in YML format as synthetic video data"},
+ {cvCreateModuleBlobTrackGen1,"RawTracks","Generate raw track record (x,y,sx,sy),()... in each line"},
+ {NULL,NULL,NULL}
+};
+
+/* List of BLOB TRAJECTORY POST PROCESSING modules: */
+typedef struct DefModule_BlobTrackPostProc
+{
+ CvBlobTrackPostProc* (*create)();
+ const char* nickname;
+ const char* description;
+} DefModule_BlobTrackPostProc;
+
+DefModule_BlobTrackPostProc BlobTrackPostProc_Modules[] =
+{
+ {cvCreateModuleBlobTrackPostProcKalman,"Kalman","Kalman filtering of blob position and size"},
+ {NULL,"None","No post processing filter"},
+// {cvCreateModuleBlobTrackPostProcTimeAverRect,"TimeAverRect","Average by time using rectangle window"},
+// {cvCreateModuleBlobTrackPostProcTimeAverExp,"TimeAverExp","Average by time using exponential window"},
+ {NULL,NULL,NULL}
+};
+
+/* List of BLOB TRAJECTORY ANALYSIS modules: */
+CvBlobTrackAnalysis* cvCreateModuleBlobTrackAnalysisDetector();
+
+typedef struct DefModule_BlobTrackAnalysis
+{
+ CvBlobTrackAnalysis* (*create)();
+ const char* nickname;
+ const char* description;
+} DefModule_BlobTrackAnalysis;
+
+DefModule_BlobTrackAnalysis BlobTrackAnalysis_Modules[] =
+{
+ {cvCreateModuleBlobTrackAnalysisHistPVS,"HistPVS","Histogram of 5D feature vector analysis (x,y,vx,vy,state)"},
+ {NULL,"None","No trajectory analiser"},
+ {cvCreateModuleBlobTrackAnalysisHistP,"HistP","Histogram of 2D feature vector analysis (x,y)"},
+ {cvCreateModuleBlobTrackAnalysisHistPV,"HistPV","Histogram of 4D feature vector analysis (x,y,vx,vy)"},
+ {cvCreateModuleBlobTrackAnalysisHistSS,"HistSS","Histogram of 4D feature vector analysis (startpos,endpos)"},
+ {cvCreateModuleBlobTrackAnalysisTrackDist,"TrackDist","Compare tracks directly"},
+ {cvCreateModuleBlobTrackAnalysisIOR,"IOR","Integrator (by OR operation) of several analysers "},
+ {NULL,NULL,NULL}
+};
+
+/*
+class blobtracker {
+ int RunBlobTrackingAuto( CvCapture* pCap, CvBlobTrackerAuto* pTracker,char* fgavi_name = NULL, char* btavi_name = NULL );
+ void print_params(CvVSModule* pM, const char* module, const char* log_name);
+ void set_params(int argc, char* argv[], CvVSModule* pM, const char* prefix, const char* module);
+};
+*/
diff --git a/pix_opencv_blobtrack-help.pd b/pix_opencv_blobtrack-help.pd
new file mode 100644
index 0000000..331c272
--- /dev/null
+++ b/pix_opencv_blobtrack-help.pd
@@ -0,0 +1,219 @@
+#N canvas 259 343 818 435 10;
+#X obj 7 200 cnv 15 430 230 empty empty empty 20 12 0 14 -233017 -66577
+0;
+#X obj 7 156 cnv 15 430 40 empty empty empty 20 12 0 14 -195568 -66577
+0;
+#X text 16 160 Arguments:;
+#X obj 7 60 cnv 15 430 90 empty empty empty 20 12 0 14 -233017 -66577
+0;
+#X obj 443 10 cnv 15 320 420 empty empty empty 20 12 0 14 -228992 -66577
+0;
+#X text 50 19 Synopsis: [pix_opencv_blobtrack];
+#X text 71 38 Class: pix_opencv;
+#X text 17 63 Description: all-in-one blobtracker;
+#X text 28 86 [pix_opencv_blobtrack] implements a blobtracking pipeline.
+This is made by a foreground detector \, a blob detector \, a blob
+tracker and a trajectory post processor.;
+#X text 30 173 none;
+#X obj 450 216 cnv 15 250 120 empty empty empty 20 12 0 14 -4034 -66577
+0;
+#X obj 656 363 cnv 15 100 60 empty empty empty 20 12 0 14 -195568 -66577
+0;
+#N canvas 1 98 450 300 gemwin 0;
+#X obj 132 136 gemwin;
+#X obj 67 89 outlet;
+#X obj 67 10 inlet;
+#X obj 67 41 route create;
+#X msg 67 70 set destroy;
+#X msg 142 68 set create;
+#X msg 132 112 create \, 1;
+#X msg 198 112 destroy;
+#X msg 234 221 dimen 500 500;
+#X obj 295 164 loadbang;
+#X msg 279 190 dimen 640 480;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 3 0 6 0;
+#X connect 3 1 5 0;
+#X connect 3 1 7 0;
+#X connect 4 0 1 0;
+#X connect 5 0 1 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 10 0;
+#X connect 10 0 0 0;
+#X restore 661 402 pd gemwin;
+#X msg 661 383 destroy;
+#X text 657 362 Create window:;
+#X obj 454 364 pix_texture;
+#X obj 454 30 gemhead;
+#X msg 520 45 auto 1;
+#X obj 520 18 loadbang;
+#X obj 606 295 print dumpout;
+#X floatatom 501 293 5 0 0 0 - - -;
+#X obj 501 274 route blobnum blob;
+#N canvas 1087 211 709 722 showblob 0;
+#X obj 187 13 inlet blobinformation;
+#X obj 279 316 gemlist;
+#X obj 279 296 t b a;
+#X obj 291 50 gemhead 70;
+#X obj 129 258 list append;
+#X obj 124 140 list split 2;
+#X obj 124 114 list append;
+#X obj 291 73 t b a;
+#X obj 158 232 t b a;
+#X obj 279 506 translateXYZ;
+#X msg 420 349 \$2;
+#X obj 279 356 alpha 1;
+#X obj 279 466 translateXYZ -0.5 -0.5 0;
+#X obj 279 530 scaleXYZ 0.125 0.25 0;
+#X msg 459 349 \$3;
+#X msg 420 499 \$4;
+#X msg 459 499 \$5;
+#X obj 463 328 t a a;
+#X obj 279 576 circle 0.5;
+#X obj 279 426 color 1 0 0 0.2;
+#X obj 279 336 separator;
+#X msg 499 499 \$1;
+#X obj 279 676 text2d;
+#X obj 279 616 color 1 1 0 1;
+#X obj 158 198 list split 6;
+#X msg 124 167 \$2;
+#X obj 366 622 loadbang;
+#X msg 366 641 12;
+#X msg 521 377 \$6;
+#X obj 521 399 > 0;
+#X obj 521 420 sel 1 0;
+#X msg 520 441 1 0 0 0.2;
+#X msg 540 461 0 1 0 0.2;
+#X obj 279 596 translateXYZ 0.2 0.2 0;
+#X obj 279 446 scaleXYZ 10.666 -8 0;
+#X text 336 194 here is an example on how to display blobs with Gem
+;
+#X connect 0 0 6 1;
+#X connect 1 0 20 0;
+#X connect 2 0 1 0;
+#X connect 2 1 17 0;
+#X connect 3 0 7 0;
+#X connect 4 0 24 0;
+#X connect 5 0 25 0;
+#X connect 5 1 24 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
+#X connect 7 1 1 1;
+#X connect 8 0 4 0;
+#X connect 8 1 2 0;
+#X connect 9 0 13 0;
+#X connect 10 0 9 1;
+#X connect 11 0 19 0;
+#X connect 12 0 9 0;
+#X connect 13 0 18 0;
+#X connect 14 0 9 2;
+#X connect 15 0 13 1;
+#X connect 16 0 13 2;
+#X connect 17 0 14 0;
+#X connect 17 0 10 0;
+#X connect 17 1 16 0;
+#X connect 17 1 15 0;
+#X connect 17 1 21 0;
+#X connect 17 1 28 0;
+#X connect 18 0 33 0;
+#X connect 19 0 34 0;
+#X connect 20 0 11 0;
+#X connect 21 0 22 0;
+#X connect 23 0 22 0;
+#X connect 24 0 8 0;
+#X connect 24 1 4 1;
+#X connect 25 0 24 1;
+#X connect 26 0 27 0;
+#X connect 27 0 22 1;
+#X connect 28 0 29 0;
+#X connect 29 0 30 0;
+#X connect 30 0 31 0;
+#X connect 30 1 32 0;
+#X connect 31 0 19 1;
+#X connect 32 0 19 1;
+#X connect 33 0 23 0;
+#X connect 34 0 12 0;
+#X restore 553 315 pd showblob;
+#X obj 454 395 rectangle 5.333 4;
+#X obj 454 124 pix_resize 320 240;
+#X obj 454 255 pix_opencv_blobtrack;
+#X obj 454 173 pix_rgba;
+#X obj 471 227 r \$0-properties;
+#X text 464 153 input format : rgba or grey;
+#N canvas 699 185 544 482 properties 0;
+#X msg 290 314 monitorStage \$1;
+#X msg 4 21 getModule;
+#X msg 4 41 getModule fg;
+#X msg 4 61 getModule bd;
+#X msg 4 81 getModule bt;
+#X msg 4 101 getModule btpp;
+#X obj 12 142 loadbang;
+#X msg 260 194 setModule bd BD_CC;
+#X msg 27 194 setModule fg FG_0S;
+#X msg 147 194 setModule fg FG_1;
+#X text 289 249 monitoring stage :;
+#X obj 290 266 vradio 15 1 0 3 empty empty empty 0 -8 0 10 -262144
+-1 -1 0;
+#X text 308 265 input image;
+#X text 307 281 foreground mask;
+#X text 307 296 diplsay blobs;
+#X obj -35 433 s \$0-properties;
+#X obj -35 353 t a;
+#X msg 287 380 fgTrainFrames \$1;
+#X floatatom 287 353 5 0 0 0 - - -;
+#X text 72 20 post all accessibles modules and their nickname;
+#X text 108 56 post information of specific module and get the avaiblable
+variant to load;
+#X msg 12 160 setModule fg FG_1 \, setModule bd BD_Simple \, setModule
+bt CC \, setModule btpp none \, setModule bta none;
+#X connect 0 0 15 0;
+#X connect 1 0 16 0;
+#X connect 2 0 16 0;
+#X connect 3 0 16 0;
+#X connect 4 0 16 0;
+#X connect 5 0 16 0;
+#X connect 6 0 21 0;
+#X connect 7 0 16 0;
+#X connect 8 0 16 0;
+#X connect 9 0 16 0;
+#X connect 11 0 0 0;
+#X connect 16 0 15 0;
+#X connect 17 0 15 0;
+#X connect 18 0 17 0;
+#X connect 21 0 16 0;
+#X restore 610 222 pd properties;
+#X obj 454 70 pix_film;
+#X text 459 96 the bigger the image is \, the more CPU expensive the
+algo will be;
+#X text 16 202 Inlet 1 accepts a lot of messages \, here are the most
+usefull ones \, see [pd properties] for details.;
+#X text 26 232 getModule : get information about loaded modules.;
+#X text 26 252 setModule : set algorythm to use in each module.;
+#X text 26 272 monitoringStage : set the location where output image
+is taken (input \, foreground mask or input with tracking information)
+;
+#X obj 580 51 openpanel;
+#X obj 583 24 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X msg 580 72 open \$1;
+#X connect 12 0 13 0;
+#X connect 13 0 12 0;
+#X connect 15 0 23 0;
+#X connect 16 0 30 0;
+#X connect 17 0 30 0;
+#X connect 18 0 17 0;
+#X connect 21 0 20 0;
+#X connect 21 1 22 0;
+#X connect 21 2 19 0;
+#X connect 24 0 26 0;
+#X connect 25 0 15 0;
+#X connect 25 1 21 0;
+#X connect 26 0 25 0;
+#X connect 27 0 25 0;
+#X connect 30 0 24 0;
+#X connect 36 0 38 0;
+#X connect 37 0 36 0;
+#X connect 38 0 30 0;
diff --git a/pix_opencv_blobtrack.cpp b/pix_opencv_blobtrack.cpp
new file mode 100644
index 0000000..d2ed9ed
--- /dev/null
+++ b/pix_opencv_blobtrack.cpp
@@ -0,0 +1,556 @@
+////////////////////////////////////////////////////////
+//
+// GEM - Graphics Environment for Multimedia
+//
+// zmoelnig@iem.kug.ac.at
+//
+// Implementation file
+//
+// Copyright (c) 1997-2000 Mark Danks.
+// Copyright (c) Günther Geiger.
+// Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM
+// Copyright (c) 2002 James Tittle & Chris Clepper
+// For information on usage and redistribution, and for a DISCLAIMER OF ALL
+// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
+//
+/////////////////////////////////////////////////////////
+// based on code written by Lluis Gomez i Bigorda ( lluisgomez _at_ hangar _dot_ org ) (pix_opencv)
+// mainly copy and paste from blobtracker_sample.cpp provided by OpenCV 2.3 SVN rev7875
+
+#include "pix_opencv_blobtrack.h"
+#include <stdio.h>
+#include <RTE/MessageCallbacks.h>
+
+
+CPPEXTERN_NEW(pix_opencv_blobtrack)
+
+/////////////////////////////////////////////////////////
+//
+// pix_opencv_blobtrack
+//
+/////////////////////////////////////////////////////////
+// Constructor
+//
+/////////////////////////////////////////////////////////
+
+pix_opencv_blobtrack :: pix_opencv_blobtrack() : m_fg_name(FGDetector_Modules[0].nickname), \
+ m_bd_name(BlobDetector_Modules[0].nickname), \
+ m_bt_name(BlobTracker_Modules[0].nickname), \
+ m_btpp_name(BlobTrackPostProc_Modules[0].nickname), \
+ m_bta_name(BlobTrackAnalysis_Modules[0].nickname), \
+ m_bt_corr("none"), \
+ m_FGTrainFrames(6), \
+ m_monitoring_stage(0), \
+ m_tracker(NULL)
+{
+ m_param.pBT=NULL;
+ m_param.pBD=NULL;
+ m_param.pBTGen=NULL;
+ m_param.pBTA=NULL;
+ m_param.pFG=NULL;
+ m_dataout = outlet_new(this->x_obj, 0);
+ setupModules();
+ createModules();
+ printParamsMess();
+}
+
+/////////////////////////////////////////////////////////
+// Destructor
+//
+/////////////////////////////////////////////////////////
+pix_opencv_blobtrack :: ~pix_opencv_blobtrack()
+{
+ releaseModules();
+}
+
+/////////////////////////////////////////////////////////
+// processImage
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_blobtrack :: processRGBAImage(imageStruct &image)
+{
+ cv::Mat imgMat( image.ysize, image.xsize, CV_8UC4, image.data, image.csize*image.xsize); // just transform imageStruct to IplImage without copying data
+ IplImage img = imgMat; // convert cv::Mat to IplImage
+ RunBlobTrackingAuto( &img );
+}
+
+void pix_opencv_blobtrack :: processRGBImage(imageStruct &image) {
+ cv::Mat imgMat( image.ysize, image.xsize, CV_8UC3, image.data, image.csize*image.xsize); // just transform imageStruct to IplImage without copying data
+ IplImage img = imgMat;
+ RunBlobTrackingAuto( &img );
+}
+
+void pix_opencv_blobtrack :: processYUVImage(imageStruct &image) {
+
+ error("YVU format not supported");
+}
+
+void pix_opencv_blobtrack :: processGrayImage(imageStruct &image)
+{
+ cv::Mat imgMat( image.ysize, image.xsize, CV_8UC1, image.data, image.csize*image.xsize); // convert imageStruct to cv::Mat without copying data
+ IplImage img = imgMat; // convert cv::Mat to IplImage
+ RunBlobTrackingAuto( &img );
+}
+
+void pix_opencv_blobtrack :: RunBlobTrackingAuto( IplImage* img )
+{
+ IplImage* pMask = NULL;
+ IplImage* imgRGB = NULL;
+
+ if ( x_size != img->width || y_size != img->height ){
+ releaseModules();
+ createModules();
+ x_size = img->width;
+ y_size = img->height;
+ }
+
+ imgRGB = cvCreateImage(cvSize(img->width,img->height),img->depth,3);
+ switch (img->nChannels){
+ case 1:
+ cvCvtColor(img, imgRGB, CV_GRAY2RGB);
+ break;
+ case 4:
+ cvCvtColor(img, imgRGB, CV_RGBA2RGB);
+ break;
+ }
+
+ /* Process: */
+ m_tracker->Process(imgRGB, pMask);
+
+ //~ t_atom blob_num;
+ //~ SETFLOAT(&blob_num, m_tracker->GetBlobNum());
+ //~ outlet_anything(m_dataout, gensym("blobnum"), 1, &blob_num);
+
+ int blob_atom_size = 2+m_tracker->GetBlobNum()*6;
+
+ t_atom* blob_atom = new t_atom[blob_atom_size];
+ SETFLOAT(&blob_atom[0], m_tracker->GetBlobNum());
+ SETFLOAT(&blob_atom[1], 6);
+
+ for(int i=0; i<m_tracker->GetBlobNum(); i++){
+ CvBlob* blob = m_tracker->GetBlob(i);
+ SETFLOAT(&blob_atom[2+i*6], blob->ID);
+ SETFLOAT(&blob_atom[3+i*6], blob->x/img->width);
+ SETFLOAT(&blob_atom[4+i*6], blob->y/img->height);
+ SETFLOAT(&blob_atom[5+i*6], blob->w/img->width);
+ SETFLOAT(&blob_atom[6+i*6], blob->h/img->height);
+ SETFLOAT(&blob_atom[7+i*6], m_tracker->GetState(blob->ID));
+ //~ t_atom *ap=blob_atom+2+6*i;
+ //~ SETFLOAT(ap++, blob->ID);
+ //~ SETFLOAT(ap++, blob->x/img->width);
+ //~ SETFLOAT(ap++, blob->y/img->height);
+ //~ SETFLOAT(ap++, blob->w/img->width);
+ //~ SETFLOAT(ap++, blob->h/img->height);
+ //~ SETFLOAT(ap++, m_tracker->GetState(blob->ID));
+ }
+
+ outlet_anything(m_dataout, gensym("blob"), blob_atom_size, blob_atom);
+
+ if(blob_atom) delete blob_atom;
+ blob_atom = NULL;
+
+ if ( m_monitoring_stage == 1 ) { // show foreground
+ IplImage* fg = m_tracker->GetFGMask();
+ switch (img->nChannels){
+ case 1:
+ cvCopy(fg, img);
+ break;
+ case 4:
+ cvCvtColor(fg, img, CV_GRAY2RGBA);
+ break;
+ }
+ }
+
+ if ( m_monitoring_stage == 2 ) {
+ /* Draw all information about test sequence: */
+ char str[1024];
+ int line_type = CV_AA; // Change it to 8 to see non-antialiased graphics.
+ CvFont font;
+ int i;
+
+ cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, 0.7, 0.7, 0, 1, line_type );
+
+ for(i=m_tracker->GetBlobNum(); i>0; i--)
+ {
+ CvSize TextSize;
+ CvBlob* pB = m_tracker->GetBlob(i-1);
+ CvPoint p = cvPoint(cvRound(pB->x*256),cvRound(pB->y*256));
+ CvSize s = cvSize(MAX(1,cvRound(CV_BLOB_RX(pB)*256)), MAX(1,cvRound(CV_BLOB_RY(pB)*256)));
+ int c = cvRound(255*m_tracker->GetState(CV_BLOB_ID(pB)));
+
+ cvEllipse( imgRGB,
+ p,
+ s,
+ 0, 0, 360,
+ CV_RGB(c,255-c,0), cvRound(1+(3*0)/255), CV_AA, 8 );
+
+ p.x >>= 8;
+ p.y >>= 8;
+ s.width >>= 8;
+ s.height >>= 8;
+ sprintf(str,"%03d",CV_BLOB_ID(pB));
+ cvGetTextSize( str, &font, &TextSize, NULL );
+ p.y -= s.height;
+ cvPutText( imgRGB, str, p, &font, CV_RGB(0,255,255));
+ {
+ const char* pS = m_tracker->GetStateDesc(CV_BLOB_ID(pB));
+
+ if(pS)
+ {
+ char* pStr = strdup(pS);
+ char* pStrFree = pStr;
+
+ while (pStr && strlen(pStr) > 0)
+ {
+ char* str_next = strchr(pStr,'\n');
+
+ if(str_next)
+ {
+ str_next[0] = 0;
+ str_next++;
+ }
+
+ p.y += TextSize.height+1;
+ cvPutText( imgRGB, pStr, p, &font, CV_RGB(0,255,255));
+ pStr = str_next;
+ }
+ free(pStrFree);
+ }
+ }
+
+ } /* Next blob. */;
+ switch (img->nChannels){
+ case 1:
+ cvCvtColor(imgRGB, img, CV_RGB2GRAY);
+ break;
+ case 4:
+ cvCvtColor(imgRGB, img, CV_RGB2RGBA);
+ break;
+ }
+
+ }/* Draw all information about test sequence. */
+ cvReleaseImage(&imgRGB);
+ imgRGB = NULL;
+
+} /* RunBlobTrackingAuto */
+
+/////////////////////////////////////////////////////////
+// static member function
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_blobtrack :: obj_setupCallback(t_class *classPtr)
+{
+ CPPEXTERN_MSG1(classPtr, "monitorStage", monitorStageMess, int);
+ CPPEXTERN_MSG1(classPtr, "fgTrainFrames", fgTrainFramesMess, int);
+ CPPEXTERN_MSG (classPtr, "getParam", getParamMess);
+ CPPEXTERN_MSG (classPtr, "setParam", setParamMess);
+ CPPEXTERN_MSG (classPtr, "getModule", getModuleMess);
+ CPPEXTERN_MSG (classPtr, "setModule", setModuleMess);
+}
+
+/////////////////////////////////////////////////////////
+// private function
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_blobtrack :: setupModules()
+{
+ const char* fg_name = m_fg_name.c_str();
+ const char* bd_name = m_bd_name.c_str();
+ const char* bt_name = m_bt_name.c_str();
+ const char* btpp_name = m_btpp_name.c_str();
+ const char* bta_name = m_bta_name.c_str();
+
+ for(m_FGModule=FGDetector_Modules; m_FGModule->nickname; ++m_FGModule)
+ if( fg_name && MY_STRICMP(fg_name,m_FGModule->nickname)==0 ) break;
+ if ( m_FGModule->nickname == NULL ){
+ error("FG Module %s doesn't exist, swith to default one", fg_name);
+ m_FGModule=FGDetector_Modules;
+ }
+
+ for(m_BDModule=BlobDetector_Modules; m_BDModule->nickname; ++m_BDModule)
+ if( bd_name && MY_STRICMP(bd_name,m_BDModule->nickname)==0 ) break;
+ if ( m_BDModule->nickname == NULL ){
+ error("BD Module %s doesn't exist, swith to default one", bd_name);
+ m_BDModule=BlobDetector_Modules;
+ }
+
+ for(m_BTModule=BlobTracker_Modules; m_BTModule->nickname; ++m_BTModule)
+ if( bt_name && MY_STRICMP(bt_name,m_BTModule->nickname)==0 ) break;
+ if ( m_BTModule->nickname == NULL ){
+ error("BT Module %s doesn't exist, swith to default one", bt_name);
+ m_BTModule=BlobTracker_Modules;
+ }
+
+ for(m_BTPostProcModule=BlobTrackPostProc_Modules; m_BTPostProcModule->nickname; ++m_BTPostProcModule)
+ if( btpp_name && MY_STRICMP(btpp_name,m_BTPostProcModule->nickname)==0 ) break;
+ if ( m_BTPostProcModule->nickname == NULL ){
+ error("BTPP Module %s doesn't exist, swith to default one", btpp_name);
+ m_BTPostProcModule=BlobTrackPostProc_Modules;
+ }
+
+ for(m_BTAnalysisModule=BlobTrackAnalysis_Modules; m_BTAnalysisModule->nickname; ++m_BTAnalysisModule)
+ if( bta_name && MY_STRICMP(bta_name,m_BTAnalysisModule->nickname)==0 ) break;
+ if ( m_BTAnalysisModule->nickname == NULL ){
+ error("BTA Module %s doesn't exist, swith to default one", bta_name);
+ m_BTAnalysisModule=BlobTrackAnalysis_Modules;
+ }
+} /* setupModules */
+
+void pix_opencv_blobtrack :: createModules()
+{ /* Create autotracker module and its components: */
+
+ m_param.FGTrainFrames = m_FGTrainFrames;
+ /* Create FG Detection module: */
+ m_param.pFG = m_FGModule->create();
+ if(!m_param.pFG){
+ error("Can not create FGDetector module");
+ return;
+ }
+ m_param.pFG->SetNickName(m_FGModule->nickname);
+ //~ set_params(argc, argv, m_param.pFG, "fg", m_FGModule->nickname);
+ /* Create Blob Entrance Detection module: */
+ m_param.pBD = m_BDModule->create();
+ if(!m_param.pBD){
+ error("Can not create BlobDetector module");
+ return;
+ }
+ m_param.pBD->SetNickName(m_BDModule->nickname);
+ //~ set_params(argc, argv, m_param.pBD, "bd", m_BDModule->nickname);
+
+ /* Create blob tracker module: */
+ m_param.pBT = m_BTModule->create();
+ if(!m_param.pBT){
+ error("Can not create BlobTracker module");
+ }
+ m_param.pBT->SetNickName(m_BTModule->nickname);
+ //~ set_params(argc, argv, m_param.pBT, "bt", m_BTModule->nickname);
+
+ /* Create blob trajectory generation module: */
+ /*
+ m_param.pBTGen = NULL;
+ if(m_BTGenModule && track_name && m_BTGenModule->create)
+ {
+ m_param.pBTGen = m_BTGenModule->create();
+ m_param.pBTGen->SetFileName(track_name);
+ }
+ if(m_param.pBTGen)
+ {
+ m_param.pBTGen->SetNickName(m_BTGenModule->nickname);
+ //~ set_params(argc, argv, m_param.pBTGen, "btgen", m_BTGenModule->nickname);
+ }
+ */
+
+ /* Create blob trajectory post processing module: */
+ m_param.pBTPP = NULL;
+ if(m_BTPostProcModule && m_BTPostProcModule->create)
+ {
+ m_param.pBTPP = m_BTPostProcModule->create();
+ }
+ if(m_param.pBTPP)
+ {
+ m_param.pBTPP->SetNickName(m_BTPostProcModule->nickname);
+ //~ set_params(argc, argv, m_param.pBTPP, "btpp", pBTPostProcModule->nickname);
+ }
+
+ const char * bt_corr = m_bt_corr.c_str();
+
+ m_param.UsePPData = (bt_corr && MY_STRICMP(bt_corr,"PostProcRes")==0);
+
+ /* Create blob trajectory analysis module: */
+ m_param.pBTA = NULL;
+ if(m_BTAnalysisModule && m_BTAnalysisModule->create)
+ {
+ m_param.pBTA = m_BTAnalysisModule->create();
+ //~ m_param.pBTA->SetFileName(bta_data_name);
+ }
+ if(m_param.pBTA)
+ {
+ m_param.pBTA->SetNickName(m_BTAnalysisModule->nickname);
+ //~ set_params(argc, argv, m_param.pBTA, "bta", m_BTAnalysisModule->nickname);
+ }
+
+ /* Create whole pipline: */
+ m_tracker = cvCreateBlobTrackerAuto1(&m_param);
+ if(!m_tracker)
+ error("Can not create BlobTrackerAuto");
+} /* createModules */
+
+void pix_opencv_blobtrack :: releaseModules(void)
+{
+ if(m_param.pBT)cvReleaseBlobTracker(&m_param.pBT);
+ if(m_param.pBD)cvReleaseBlobDetector(&m_param.pBD);
+ if(m_param.pBTGen)cvReleaseBlobTrackGen(&m_param.pBTGen);
+ if(m_param.pBTA)cvReleaseBlobTrackAnalysis(&m_param.pBTA);
+ if(m_param.pFG)cvReleaseFGDetector(&m_param.pFG);
+ if(m_tracker)cvReleaseBlobTrackerAuto(&m_tracker);
+} /* releaseModules */
+
+void pix_opencv_blobtrack :: print_params(CvVSModule* pM, const char* module)
+{
+ int i;
+ if(pM->GetParamName(0) == NULL ) return;
+
+
+ post("%s(%s) module parameters:",module,pM->GetNickName());
+
+ for (i=0; ; ++i)
+ {
+ const char* param = pM->GetParamName(i);
+ const char* str = param?pM->GetParamStr(param):NULL;
+ if(param == NULL)break;
+ if(str)
+ {
+ post(" %s: %s",param,str);
+ }
+ else
+ {
+ post(" %s: %g",param,pM->GetParam(param));
+ }
+ }
+} /* print_params */
+
+/////////////////////////////////////////////////////////
+// messages handling
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_blobtrack :: monitorStageMess(int arg)
+{
+ m_monitoring_stage = int(arg);
+ t_atom data_out;
+ SETFLOAT(&data_out, m_monitoring_stage);
+ outlet_anything( m_dataout, gensym("monitorStage"), 1, &data_out);
+}
+
+void pix_opencv_blobtrack :: fgTrainFramesMess(int arg)
+{
+ //~ m_FGTrainFrames = int(arg);
+ t_atom data_out;
+ SETFLOAT(&data_out, m_FGTrainFrames);
+ outlet_anything( m_dataout, gensym("FGTrainFrames"), 1, &data_out);
+}
+
+void pix_opencv_blobtrack :: printParamsMess(void)
+{ /* Print module parameters: */
+ struct DefMMM
+ {
+ CvVSModule* pM;
+ const char* name;
+ } Modules[] = {
+ {(CvVSModule*)m_param.pFG,"FGdetector"},
+ {(CvVSModule*)m_param.pBD,"BlobDetector"},
+ {(CvVSModule*)m_param.pBT,"BlobTracker"},
+ {(CvVSModule*)m_param.pBTGen,"TrackGen"},
+ {(CvVSModule*)m_param.pBTPP,"PostProcessing"},
+ {(CvVSModule*)m_param.pBTA,"TrackAnalysis"},
+ {NULL,NULL}
+ };
+ int i;
+ for(i=0; Modules[i].name; ++i)
+ {
+ if(Modules[i].pM)
+ print_params(Modules[i].pM,Modules[i].name);
+ }
+} /* Print module parameters. */
+
+void pix_opencv_blobtrack :: getParamMess(t_symbol*s, int argc, t_atom*argv)
+{
+ // TODO
+}
+
+void pix_opencv_blobtrack :: setParamMess(t_symbol*s, int argc, t_atom*argv)
+{
+ // TODO
+}
+
+void pix_opencv_blobtrack :: getModuleMess(t_symbol*s, int argc, t_atom*argv)
+{
+ if ( argc == 0 ){ // no args : print all modules in pipeline
+ post("avaible modules in pipeline :\n \
+ fg : ForeGround detector\n \
+ bd : Blob Detector\n \
+ bt : Blob Tracker\n \
+ btpp : Blob Tracker Post Processing\n \
+ bta : Blob Tracker Analysis");
+
+ t_atom module_list[5];
+ SETSYMBOL(&module_list[0], gensym("fg"));
+ SETSYMBOL(&module_list[1], gensym("bd"));
+ SETSYMBOL(&module_list[2], gensym("bt"));
+ SETSYMBOL(&module_list[3], gensym("btpp"));
+ SETSYMBOL(&module_list[4], gensym("bta"));
+ outlet_anything(m_dataout, gensym("modulelist"), 5, module_list);
+
+ } else if ( argc == 1 ) { // one arg : print available algo for specified module
+ if ( argv[0].a_type == A_SYMBOL ) {
+ t_atom algo_list[512];
+ int i;
+ if ( std::string(argv[0].a_w.w_symbol->s_name) == "fg" ){
+ post("available foreground detector algo :");
+ for (i = 0 ; FGDetector_Modules[i].nickname!=NULL ; i++){
+ post("\t%s : %s", FGDetector_Modules[i].nickname, FGDetector_Modules[i].description);
+ SETSYMBOL(&algo_list[i],gensym(FGDetector_Modules[i].nickname));
+ }
+ outlet_anything(m_dataout, gensym("fg_algo"), i, algo_list);
+ } else if ( std::string(argv[0].a_w.w_symbol->s_name) == "bd" ){
+ post("available blob detector algo :");
+ for (i = 0 ; BlobDetector_Modules[i].nickname!=NULL ; i++){
+ post("\t%s : %s", BlobDetector_Modules[i].nickname, BlobDetector_Modules[i].description);
+ SETSYMBOL(&algo_list[i],gensym(BlobDetector_Modules[i].nickname));
+ }
+ outlet_anything(m_dataout, gensym("bd_algo"), i, algo_list);
+ } else if ( std::string(argv[0].a_w.w_symbol->s_name) == "bt" ){
+ post("available blob tracker algo :");
+ for (i = 0 ; BlobTracker_Modules[i].nickname!=NULL ; i++){
+ post("\t%s : %s", BlobTracker_Modules[i].nickname, BlobTracker_Modules[i].description);
+ SETSYMBOL(&algo_list[i],gensym(BlobTracker_Modules[i].nickname));
+ }
+ outlet_anything(m_dataout, gensym("bt_algo"), i, algo_list);
+ } else if ( std::string(argv[0].a_w.w_symbol->s_name) == "btpp" ){
+ post("available blob tracker post processing algo :");
+ for (i = 0 ; BlobTrackPostProc_Modules[i].nickname!=NULL ; i++){
+ post("\t%s : %s", BlobTrackPostProc_Modules[i].nickname, BlobTrackPostProc_Modules[i].description);
+ SETSYMBOL(&algo_list[i],gensym(BlobTrackPostProc_Modules[i].nickname));
+ }
+ outlet_anything(m_dataout, gensym("btpp_algo"), i, algo_list);
+ } else if ( std::string(argv[0].a_w.w_symbol->s_name) == "bta" ){
+ post("available blob tracker analysis algo :");
+ for (i = 0 ; BlobTrackAnalysis_Modules[i].nickname!=NULL ; i++){
+ post("\t%s : %s", BlobTrackAnalysis_Modules[i].nickname, BlobTrackAnalysis_Modules[i].description);
+ SETSYMBOL(&algo_list[i],gensym(BlobTrackAnalysis_Modules[i].nickname));
+ }
+ outlet_anything(m_dataout, gensym("bd_algo"), i, algo_list);
+ }
+ } else error("getModules <symbol> [<symbol>]");
+ } else error("getModules <symbol> [<symbol>] : need 1 or 2 args");
+}
+
+void pix_opencv_blobtrack :: setModuleMess(t_symbol*s, int argc, t_atom*argv)
+{
+ if ( argc != 2 ){
+ error("use : setModule <module> <module_name>");
+ error("try getModule to get available module list");
+ return;
+ }
+
+ if ( argv[0].a_type == A_SYMBOL ) {
+ if (std::string(argv[0].a_w.w_symbol->s_name) == "fg") {
+ m_fg_name = argv[1].a_w.w_symbol->s_name;
+ }
+ else if (std::string(argv[0].a_w.w_symbol->s_name) == "bd") {
+ m_bd_name = argv[1].a_w.w_symbol->s_name;
+ }
+ else if (std::string(argv[0].a_w.w_symbol->s_name) == "bt") {
+ m_bt_name = argv[1].a_w.w_symbol->s_name;
+ }
+ else if (std::string(argv[0].a_w.w_symbol->s_name) == "btpp") {
+ m_btpp_name = argv[1].a_w.w_symbol->s_name;
+ }
+ else if (std::string(argv[0].a_w.w_symbol->s_name) == "bta") {
+ m_bta_name = argv[1].a_w.w_symbol->s_name;
+ }
+ releaseModules();
+ setupModules();
+ createModules();
+ printParamsMess();
+ }
+}
diff --git a/pix_opencv_blobtrack.h b/pix_opencv_blobtrack.h
new file mode 100644
index 0000000..66c9d4f
--- /dev/null
+++ b/pix_opencv_blobtrack.h
@@ -0,0 +1,104 @@
+/*-----------------------------------------------------------------
+LOG
+ GEM - Graphics Environment for Multimedia
+
+ Threshold filter
+
+ Copyright (c) 1997-1999 Mark Danks. mark@danks.org
+ Copyright (c) Günther Geiger. geiger@epy.co.at
+ Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM. zmoelnig@iem.kug.ac.at
+ Copyright (c) 2002 James Tittle & Chris Clepper
+ For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
+
+-----------------------------------------------------------------*/
+
+#ifndef INCLUDE_PIX_OPENCV_BLOBTRACK_H_
+#define INCLUDE_PIX_OPENCV_BLOBTRACK_H_
+
+#ifndef _EiC
+#include "opencv2/video/background_segm.hpp"
+#include "opencv2/legacy/blobtrack.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include <opencv2/imgproc/imgproc_c.h>
+#endif
+
+#include "blobtrack.h"
+
+#include "Base/GemPixObj.h"
+
+/*-----------------------------------------------------------------
+-------------------------------------------------------------------
+CLASS
+ pix_opencv_blobtrack
+
+ square pattern detector
+
+KEYWORDS
+ pix
+
+DESCRIPTION
+
+-----------------------------------------------------------------*/
+class GEM_EXTERN pix_opencv_blobtrack : public GemPixObj
+{
+ CPPEXTERN_HEADER(pix_opencv_blobtrack, GemPixObj)
+
+ public:
+
+ //////////
+ // Constructor
+ pix_opencv_blobtrack();
+
+ protected:
+
+ //////////
+ // Destructor
+ virtual ~pix_opencv_blobtrack();
+
+ //////////
+ // Do the processing
+ virtual void processRGBAImage(imageStruct &image);
+ virtual void processRGBImage(imageStruct &image);
+ virtual void processYUVImage(imageStruct &image);
+ virtual void processGrayImage(imageStruct &image);
+ void RunBlobTrackingAuto( IplImage* img );
+
+ //////////
+ // Messages handling
+ void monitorStageMess(int arg);
+ void fgTrainFramesMess(int arg);
+ void printParamsMess(void);
+ void getParamMess(t_symbol*s, int argc, t_atom*argv); // get available params or param value
+ void setParamMess(t_symbol*s, int argc, t_atom*argv); // set param
+ void getModuleMess(t_symbol*s, int argc, t_atom*argv); // list available and currently used modules
+ void setModuleMess(t_symbol*s, int argc, t_atom*argv); // set selected modules
+
+ // Members
+ std::string m_fg_name, m_bd_name, m_bt_name, m_btgen_name, m_btpp_name, m_bta_name, m_bt_corr;
+ int m_FGTrainFrames;
+ int m_monitoring_stage; // 0 : input image, 1 : FG 3 : input with trackng info
+ int x_size, y_size;
+
+
+ CvBlobTrackerAuto* m_tracker;
+ CvBlobTrackerAutoParam1 m_param;
+
+ DefModule_FGDetector* m_FGModule;
+ DefModule_BlobDetector* m_BDModule;
+ DefModule_BlobTracker* m_BTModule;
+ DefModule_BlobTrackPostProc* m_BTPostProcModule;
+ DefModule_BlobTrackGen* m_BTGenModule;
+ DefModule_BlobTrackAnalysis* m_BTAnalysisModule;
+
+
+ private:
+
+ void setupModules();
+ void createModules();
+ void releaseModules(void);
+ void print_params(CvVSModule* pM, const char* module);
+ t_outlet *m_dataout; // info outlet
+
+};
+#endif // for header file