void moBlobTrackerModule::applyFilter(IplImage *src) { IplImage* fg_map = NULL; assert( src != NULL ); CvSize size = cvGetSize(src); if ( src->nChannels != 1 ) { this->setError("BlobTracker input image must be a single channel binary image."); this->stop(); return; } this->tracker->Process(src, fg_map); cvSet(this->output_buffer, CV_RGB(0,0,0)); this->clearBlobs(); for ( int i = this->tracker->GetBlobNum(); i > 0; i-- ) { CvBlob* pB = this->tracker->GetBlob(i-1); int minsize = this->property("min_size").asInteger(); int maxsize = this->property("max_size").asInteger(); // Assume circular blobs if (pB->w < minsize || maxsize < pB->w || pB->h < minsize || maxsize < pB->h) continue; // draw the blob on output image if ( this->output->getObserverCount() > 0 ) { 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*this->tracker->GetState(CV_BLOB_ID(pB))); cvEllipse(this->output_buffer, p, s, 0, 0, 360, CV_RGB(c,255-c,0), cvRound(1+(3*0)/255), CV_AA, 8); } LOGM(MO_DEBUG, "Blob: id="<< pB->ID <<" pos=" << pB->x \ << "," << pB->y << "size=" << pB->w << "," << pB->h); // add the blob in data moDataGenericContainer *touch = new moDataGenericContainer(); touch->properties["type"] = new moProperty("blob"); touch->properties["id"] = new moProperty(pB->ID); touch->properties["x"] = new moProperty(pB->x / size.width); touch->properties["y"] = new moProperty(pB->y / size.height); touch->properties["w"] = new moProperty(pB->w); touch->properties["h"] = new moProperty(pB->h); this->blobs.push_back(touch); }; this->output_data->push(&this->blobs); }
void cvFindBlobsByCCClasters(IplImage* pFG, CvBlobSeq* pBlobs, CvMemStorage* storage) { /* Create contours: */ IplImage* pIB = NULL; CvSeq* cnt = NULL; CvSeq* cnt_list = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvSeq*), storage ); CvSeq* clasters = NULL; int claster_cur, claster_num; pIB = cvCloneImage(pFG); cvThreshold(pIB,pIB,128,255,CV_THRESH_BINARY); cvFindContours(pIB,storage, &cnt, sizeof(CvContour), CV_RETR_EXTERNAL); cvReleaseImage(&pIB); /* Create cnt_list. */ /* Process each contour: */ for(; cnt; cnt=cnt->h_next) { cvSeqPush( cnt_list, &cnt); } claster_num = cvSeqPartition( cnt_list, storage, &clasters, CompareContour, NULL ); for(claster_cur=0; claster_cur<claster_num; ++claster_cur) { int cnt_cur; CvBlob NewBlob; double M00,X,Y,XX,YY; /* image moments */ CvMoments m; CvRect rect_res = cvRect(-1,-1,-1,-1); CvMat mat; for(cnt_cur=0; cnt_cur<clasters->total; ++cnt_cur) { CvRect rect; CvSeq* cnt; int k = *(int*)cvGetSeqElem( clasters, cnt_cur ); if(k!=claster_cur) continue; cnt = *(CvSeq**)cvGetSeqElem( cnt_list, cnt_cur ); rect = ((CvContour*)cnt)->rect; if(rect_res.height<0) { rect_res = rect; } else { /* Unite rects: */ int x0,x1,y0,y1; x0 = MIN(rect_res.x,rect.x); y0 = MIN(rect_res.y,rect.y); x1 = MAX(rect_res.x+rect_res.width,rect.x+rect.width); y1 = MAX(rect_res.y+rect_res.height,rect.y+rect.height); rect_res.x = x0; rect_res.y = y0; rect_res.width = x1-x0; rect_res.height = y1-y0; } } if(rect_res.height < 1 || rect_res.width < 1) { X = 0; Y = 0; XX = 0; YY = 0; } else { cvMoments( cvGetSubRect(pFG,&mat,rect_res), &m, 0 ); M00 = cvGetSpatialMoment( &m, 0, 0 ); if(M00 <= 0 ) continue; X = cvGetSpatialMoment( &m, 1, 0 )/M00; Y = cvGetSpatialMoment( &m, 0, 1 )/M00; XX = (cvGetSpatialMoment( &m, 2, 0 )/M00) - X*X; YY = (cvGetSpatialMoment( &m, 0, 2 )/M00) - Y*Y; } NewBlob = cvBlob(rect_res.x+(float)X,rect_res.y+(float)Y,(float)(4*sqrt(XX)),(float)(4*sqrt(YY))); pBlobs->AddBlob(&NewBlob); } /* Next cluster. */ #if 0 { // Debug info: IplImage* pI = cvCreateImage(cvSize(pFG->width,pFG->height),IPL_DEPTH_8U,3); cvZero(pI); for(claster_cur=0; claster_cur<claster_num; ++claster_cur) { int cnt_cur; CvScalar color = CV_RGB(rand()%256,rand()%256,rand()%256); for(cnt_cur=0; cnt_cur<clasters->total; ++cnt_cur) { CvSeq* cnt; int k = *(int*)cvGetSeqElem( clasters, cnt_cur ); if(k!=claster_cur) continue; cnt = *(CvSeq**)cvGetSeqElem( cnt_list, cnt_cur ); cvDrawContours( pI, cnt, color, color, 0, 1, 8); } CvBlob* pB = pBlobs->GetBlob(claster_cur); int x = cvRound(CV_BLOB_RX(pB)), y = cvRound(CV_BLOB_RY(pB)); cvEllipse( pI, cvPointFrom32f(CV_BLOB_CENTER(pB)), cvSize(MAX(1,x), MAX(1,y)), 0, 0, 360, color, 1 ); } cvNamedWindow( "Clusters", 0); cvShowImage( "Clusters",pI ); cvReleaseImage(&pI); } /* Debug info. */ #endif } /* cvFindBlobsByCCClasters */
/* cvDetectNewBlobs * Return 1 and fill blob pNewBlob with * blob parameters if new blob is detected: */ int CvBlobDetectorCC::DetectNewBlob(IplImage* /*pImg*/, IplImage* pFGMask, CvBlobSeq* pNewBlobList, CvBlobSeq* pOldBlobList) { int result = 0; CvSize S = cvSize(pFGMask->width,pFGMask->height); /* Shift blob list: */ { int i; if(m_pBlobLists[SEQ_SIZE-1]) delete m_pBlobLists[SEQ_SIZE-1]; for(i=SEQ_SIZE-1; i>0; --i) m_pBlobLists[i] = m_pBlobLists[i-1]; m_pBlobLists[0] = new CvBlobSeq; } /* Shift blob list. */ /* Create contours and add new blobs to blob list: */ { /* Create blobs: */ CvBlobSeq Blobs; CvMemStorage* storage = cvCreateMemStorage(); if(m_Clastering) { /* Glue contours: */ cvFindBlobsByCCClasters(pFGMask, &Blobs, storage ); } /* Glue contours. */ else { /**/ IplImage* pIB = cvCloneImage(pFGMask); CvSeq* cnts = NULL; CvSeq* cnt = NULL; cvThreshold(pIB,pIB,128,255,CV_THRESH_BINARY); cvFindContours(pIB,storage, &cnts, sizeof(CvContour), CV_RETR_EXTERNAL); /* Process each contour: */ for(cnt = cnts; cnt; cnt=cnt->h_next) { CvBlob NewBlob; /* Image moments: */ double M00,X,Y,XX,YY; CvMoments m; CvRect r = ((CvContour*)cnt)->rect; CvMat mat; if(r.height < S.height*m_HMin || r.width < S.width*m_WMin) continue; cvMoments( cvGetSubRect(pFGMask,&mat,r), &m, 0 ); M00 = cvGetSpatialMoment( &m, 0, 0 ); if(M00 <= 0 ) continue; X = cvGetSpatialMoment( &m, 1, 0 )/M00; Y = cvGetSpatialMoment( &m, 0, 1 )/M00; XX = (cvGetSpatialMoment( &m, 2, 0 )/M00) - X*X; YY = (cvGetSpatialMoment( &m, 0, 2 )/M00) - Y*Y; NewBlob = cvBlob(r.x+(float)X,r.y+(float)Y,(float)(4*sqrt(XX)),(float)(4*sqrt(YY))); Blobs.AddBlob(&NewBlob); } /* Next contour. */ cvReleaseImage(&pIB); } /* One contour - one blob. */ { /* Delete small and intersected blobs: */ int i; for(i=Blobs.GetBlobNum(); i>0; i--) { CvBlob* pB = Blobs.GetBlob(i-1); if(pB->h < S.height*m_HMin || pB->w < S.width*m_WMin) { Blobs.DelBlob(i-1); continue; } if(pOldBlobList) { int j; for(j=pOldBlobList->GetBlobNum(); j>0; j--) { CvBlob* pBOld = pOldBlobList->GetBlob(j-1); if((fabs(pBOld->x-pB->x) < (CV_BLOB_RX(pBOld)+CV_BLOB_RX(pB))) && (fabs(pBOld->y-pB->y) < (CV_BLOB_RY(pBOld)+CV_BLOB_RY(pB)))) { /* Intersection detected, delete blob from list: */ Blobs.DelBlob(i-1); break; } } /* Check next old blob. */ } /* if pOldBlobList. */ } /* Check next blob. */ } /* Delete small and intersected blobs. */ { /* Bubble-sort blobs by size: */ int N = Blobs.GetBlobNum(); int i,j; for(i=1; i<N; ++i) { for(j=i; j>0; --j) { CvBlob temp; float AreaP, AreaN; CvBlob* pP = Blobs.GetBlob(j-1); CvBlob* pN = Blobs.GetBlob(j); AreaP = CV_BLOB_WX(pP)*CV_BLOB_WY(pP); AreaN = CV_BLOB_WX(pN)*CV_BLOB_WY(pN); if(AreaN < AreaP)break; temp = pN[0]; pN[0] = pP[0]; pP[0] = temp; } } /* Copy only first 10 blobs: */ for(i=0; i<MIN(N,10); ++i) { m_pBlobLists[0]->AddBlob(Blobs.GetBlob(i)); } } /* Sort blobs by size. */ cvReleaseMemStorage(&storage); } /* Create blobs. */ { /* Shift each track: */ int j; for(j=0; j<m_TrackNum; ++j) { int i; DefSeq* pTrack = m_TrackSeq+j; for(i=SEQ_SIZE-1; i>0; --i) pTrack->pBlobs[i] = pTrack->pBlobs[i-1]; pTrack->pBlobs[0] = NULL; if(pTrack->size == SEQ_SIZE)pTrack->size--; } } /* Shift each track. */ /* Analyze blob list to find best blob trajectory: */ { double BestError = -1; int BestTrack = -1;; CvBlobSeq* pNewBlobs = m_pBlobLists[0]; int i; int NewTrackNum = 0; for(i=pNewBlobs->GetBlobNum(); i>0; --i) { CvBlob* pBNew = pNewBlobs->GetBlob(i-1); int j; int AsignedTrack = 0; for(j=0; j<m_TrackNum; ++j) { double dx,dy; DefSeq* pTrack = m_TrackSeq+j; CvBlob* pLastBlob = pTrack->size>0?pTrack->pBlobs[1]:NULL; if(pLastBlob == NULL) continue; dx = fabs(CV_BLOB_X(pLastBlob)-CV_BLOB_X(pBNew)); dy = fabs(CV_BLOB_Y(pLastBlob)-CV_BLOB_Y(pBNew)); if(dx > 2*CV_BLOB_WX(pLastBlob) || dy > 2*CV_BLOB_WY(pLastBlob)) continue; AsignedTrack++; if(pTrack->pBlobs[0]==NULL) { /* Fill existed track: */ pTrack->pBlobs[0] = pBNew; pTrack->size++; } else if((m_TrackNum+NewTrackNum)<SEQ_NUM) { /* Duplicate existed track: */ m_TrackSeq[m_TrackNum+NewTrackNum] = pTrack[0]; m_TrackSeq[m_TrackNum+NewTrackNum].pBlobs[0] = pBNew; NewTrackNum++; } } /* Next track. */ if(AsignedTrack==0 && (m_TrackNum+NewTrackNum)<SEQ_NUM ) { /* Initialize new track: */ m_TrackSeq[m_TrackNum+NewTrackNum].size = 1; m_TrackSeq[m_TrackNum+NewTrackNum].pBlobs[0] = pBNew; NewTrackNum++; } } /* Next new blob. */ m_TrackNum += NewTrackNum; /* Check each track: */ for(i=0; i<m_TrackNum; ++i) { int Good = 1; DefSeq* pTrack = m_TrackSeq+i; CvBlob* pBNew = pTrack->pBlobs[0]; if(pTrack->size != SEQ_SIZE) continue; if(pBNew == NULL ) continue; /* Check intersection last blob with existed: */ if(Good && pOldBlobList) { int k; for(k=pOldBlobList->GetBlobNum(); k>0; --k) { CvBlob* pBOld = pOldBlobList->GetBlob(k-1); if((fabs(pBOld->x-pBNew->x) < (CV_BLOB_RX(pBOld)+CV_BLOB_RX(pBNew))) && (fabs(pBOld->y-pBNew->y) < (CV_BLOB_RY(pBOld)+CV_BLOB_RY(pBNew)))) Good = 0; } } /* Check intersection last blob with existed. */ /* Check distance to image border: */ if(Good) { /* Check distance to image border: */ float dx = MIN(pBNew->x,S.width-pBNew->x)/CV_BLOB_RX(pBNew); float dy = MIN(pBNew->y,S.height-pBNew->y)/CV_BLOB_RY(pBNew); if(dx < m_MinDistToBorder || dy < m_MinDistToBorder) Good = 0; } /* Check distance to image border. */ /* Check uniform motion: */ if(Good) { /* Check uniform motion: */ double Error = 0; int N = pTrack->size; CvBlob** pBL = pTrack->pBlobs; float sum[2] = {0,0}; float jsum[2] = {0,0}; float a[2],b[2]; /* estimated parameters of moving x(t) = a*t+b*/ int j; for(j=0; j<N; ++j) { float x = pBL[j]->x; float y = pBL[j]->y; sum[0] += x; jsum[0] += j*x; sum[1] += y; jsum[1] += j*y; } a[0] = 6*((1-N)*sum[0]+2*jsum[0])/(N*(N*N-1)); b[0] = -2*((1-2*N)*sum[0]+3*jsum[0])/(N*(N+1)); a[1] = 6*((1-N)*sum[1]+2*jsum[1])/(N*(N*N-1)); b[1] = -2*((1-2*N)*sum[1]+3*jsum[1])/(N*(N+1)); for(j=0; j<N; ++j) { Error += pow(a[0]*j+b[0]-pBL[j]->x,2)+ pow(a[1]*j+b[1]-pBL[j]->y,2); } Error = sqrt(Error/N); if( Error > S.width*0.01 || fabs(a[0])>S.width*0.1 || fabs(a[1])>S.height*0.1) Good = 0; /* New best trajectory: */ if(Good && (BestError == -1 || BestError > Error)) { /* New best trajectory: */ BestTrack = i; BestError = Error; } /* New best trajectory. */ } /* Check uniform motion. */ } /* Next track. */ #if 0 { /**/ printf("BlobDetector configurations = %d [",m_TrackNum); int i; for(i=0; i<SEQ_SIZE; ++i) { printf("%d,",m_pBlobLists[i]?m_pBlobLists[i]->GetBlobNum():0); } printf("]\n"); } #endif if(BestTrack >= 0) { /* Put new blob to output and delete from blob list: */ assert(m_TrackSeq[BestTrack].size == SEQ_SIZE); assert(m_TrackSeq[BestTrack].pBlobs[0]); pNewBlobList->AddBlob(m_TrackSeq[BestTrack].pBlobs[0]); m_TrackSeq[BestTrack].pBlobs[0] = NULL; m_TrackSeq[BestTrack].size--; result = 1; } /* Put new blob to output and mark in blob list to delete. */ } /* Analyze blod list to find best blob trajectory. */ { /* Delete bad tracks: */ int i; for(i=m_TrackNum-1; i>=0; --i) { /* Delete bad tracks: */ if(m_TrackSeq[i].pBlobs[0]) continue; if(m_TrackNum>0) m_TrackSeq[i] = m_TrackSeq[--m_TrackNum]; } /* Delete bad tracks: */ } #ifdef USE_OBJECT_DETECTOR if( m_split_detector && pNewBlobList->GetBlobNum() > 0 ) { int num_new_blobs = pNewBlobList->GetBlobNum(); int i = 0; if( m_roi_seq ) cvClearSeq( m_roi_seq ); m_debug_blob_seq.Clear(); for( i = 0; i < num_new_blobs; ++i ) { CvBlob* b = pNewBlobList->GetBlob(i); CvMat roi_stub; CvMat* roi_mat = 0; CvMat* scaled_roi_mat = 0; CvDetectedBlob d_b = cvDetectedBlob( CV_BLOB_X(b), CV_BLOB_Y(b), CV_BLOB_WX(b), CV_BLOB_WY(b), 0 ); m_debug_blob_seq.AddBlob(&d_b); float scale = m_param_roi_scale * m_min_window_size.height / CV_BLOB_WY(b); float b_width = MAX(CV_BLOB_WX(b), m_min_window_size.width / scale) + (m_param_roi_scale - 1.0F) * (m_min_window_size.width / scale) + 2.0F * m_max_border / scale; float b_height = CV_BLOB_WY(b) * m_param_roi_scale + 2.0F * m_max_border / scale; CvRect roi = cvRectIntersection( cvRect( cvFloor(CV_BLOB_X(b) - 0.5F*b_width), cvFloor(CV_BLOB_Y(b) - 0.5F*b_height), cvCeil(b_width), cvCeil(b_height) ), cvRect( 0, 0, pImg->width, pImg->height ) ); if( roi.width <= 0 || roi.height <= 0 ) continue; if( m_roi_seq ) cvSeqPush( m_roi_seq, &roi ); roi_mat = cvGetSubRect( pImg, &roi_stub, roi ); scaled_roi_mat = cvCreateMat( cvCeil(scale*roi.height), cvCeil(scale*roi.width), CV_8UC3 ); cvResize( roi_mat, scaled_roi_mat ); m_detected_blob_seq.Clear(); m_split_detector->Detect( scaled_roi_mat, &m_detected_blob_seq ); cvReleaseMat( &scaled_roi_mat ); for( int k = 0; k < m_detected_blob_seq.GetBlobNum(); ++k ) { CvDetectedBlob* b = (CvDetectedBlob*) m_detected_blob_seq.GetBlob(k); /* scale and shift each detected blob back to the original image coordinates */ CV_BLOB_X(b) = CV_BLOB_X(b) / scale + roi.x; CV_BLOB_Y(b) = CV_BLOB_Y(b) / scale + roi.y; CV_BLOB_WX(b) /= scale; CV_BLOB_WY(b) /= scale; CvDetectedBlob d_b = cvDetectedBlob( CV_BLOB_X(b), CV_BLOB_Y(b), CV_BLOB_WX(b), CV_BLOB_WY(b), 1, b->response ); m_debug_blob_seq.AddBlob(&d_b); } if( m_detected_blob_seq.GetBlobNum() > 1 ) { /* * Split blob. * The original blob is replaced by the first detected blob, * remaining detected blobs are added to the end of the sequence: */ CvBlob* first_b = m_detected_blob_seq.GetBlob(0); CV_BLOB_X(b) = CV_BLOB_X(first_b); CV_BLOB_Y(b) = CV_BLOB_Y(first_b); CV_BLOB_WX(b) = CV_BLOB_WX(first_b); CV_BLOB_WY(b) = CV_BLOB_WY(first_b); for( int j = 1; j < m_detected_blob_seq.GetBlobNum(); ++j ) { CvBlob* detected_b = m_detected_blob_seq.GetBlob(j); pNewBlobList->AddBlob(detected_b); } } } /* For each new blob. */ for( i = 0; i < pNewBlobList->GetBlobNum(); ++i ) { CvBlob* b = pNewBlobList->GetBlob(i); CvDetectedBlob d_b = cvDetectedBlob( CV_BLOB_X(b), CV_BLOB_Y(b), CV_BLOB_WX(b), CV_BLOB_WY(b), 2 ); m_debug_blob_seq.AddBlob(&d_b); } } // if( m_split_detector ) #endif return result; } /* cvDetectNewBlob */
/* cvDetectNewBlobs * return 1 and fill blob pNewBlob by blob parameters * if new blob is detected: */ int CvBlobDetectorSimple::DetectNewBlob(IplImage* /*pImg*/, IplImage* pFGMask, CvBlobSeq* pNewBlobList, CvBlobSeq* pOldBlobList) { int result = 0; CvSize S = cvSize(pFGMask->width,pFGMask->height); if(m_pMaskBlobNew == NULL ) m_pMaskBlobNew = cvCreateImage(S,IPL_DEPTH_8U,1); if(m_pMaskBlobExist == NULL ) m_pMaskBlobExist = cvCreateImage(S,IPL_DEPTH_8U,1); /* Shift blob list: */ { int i; if(m_pBlobLists[0]) delete m_pBlobLists[0]; for(i=1;i<EBD_FRAME_NUM;++i)m_pBlobLists[i-1]=m_pBlobLists[i]; m_pBlobLists[EBD_FRAME_NUM-1] = new CvBlobSeq; } /* Shift blob list. */ /* Create exist blob mask: */ cvCopy(pFGMask, m_pMaskBlobNew); /* Create contours and add new blobs to blob list: */ { /* Create blobs: */ CvBlobSeq Blobs; CvMemStorage* storage = cvCreateMemStorage(); #if 1 { /* Glue contours: */ cvFindBlobsByCCClasters(m_pMaskBlobNew, &Blobs, storage ); } /* Glue contours. */ #else { /**/ IplImage* pIB = cvCloneImage(m_pMaskBlobNew); CvSeq* cnts = NULL; CvSeq* cnt = NULL; cvThreshold(pIB,pIB,128,255,CV_THRESH_BINARY); cvFindContours(pIB,storage, &cnts, sizeof(CvContour), CV_RETR_EXTERNAL); /* Process each contour: */ for(cnt = cnts; cnt; cnt=cnt->h_next) { CvBlob NewBlob; /* Image moments: */ double M00,X,Y,XX,YY; CvMoments m; CvRect r = ((CvContour*)cnt)->rect; CvMat mat; if(r.height < S.height*0.02 || r.width < S.width*0.02) continue; cvMoments( cvGetSubRect(m_pMaskBlobNew,&mat,r), &m, 0 ); M00 = cvGetSpatialMoment( &m, 0, 0 ); if(M00 <= 0 ) continue; X = cvGetSpatialMoment( &m, 1, 0 )/M00; Y = cvGetSpatialMoment( &m, 0, 1 )/M00; XX = (cvGetSpatialMoment( &m, 2, 0 )/M00) - X*X; YY = (cvGetSpatialMoment( &m, 0, 2 )/M00) - Y*Y; NewBlob = cvBlob(r.x+(float)X,r.y+(float)Y,(float)(4*sqrt(XX)),(float)(4*sqrt(YY))); Blobs.AddBlob(&NewBlob); } /* Next contour. */ cvReleaseImage(&pIB); } /* One contour - one blob. */ #endif { /* Delete small and intersected blobs: */ int i; for(i=Blobs.GetBlobNum(); i>0; i--) { CvBlob* pB = Blobs.GetBlob(i-1); if(pB->h < S.height*0.02 || pB->w < S.width*0.02) { Blobs.DelBlob(i-1); continue; } if(pOldBlobList) { int j; for(j=pOldBlobList->GetBlobNum(); j>0; j--) { CvBlob* pBOld = pOldBlobList->GetBlob(j-1); if((fabs(pBOld->x-pB->x) < (CV_BLOB_RX(pBOld)+CV_BLOB_RX(pB))) && (fabs(pBOld->y-pB->y) < (CV_BLOB_RY(pBOld)+CV_BLOB_RY(pB)))) { /* Intersection is present, so delete blob from list: */ Blobs.DelBlob(i-1); break; } } /* Check next old blob. */ } /* if pOldBlobList */ } /* Check next blob. */ } /* Delete small and intersected blobs. */ { /* Bubble-sort blobs by size: */ int N = Blobs.GetBlobNum(); int i,j; for(i=1; i<N; ++i) { for(j=i; j>0; --j) { CvBlob temp; float AreaP, AreaN; CvBlob* pP = Blobs.GetBlob(j-1); CvBlob* pN = Blobs.GetBlob(j); AreaP = CV_BLOB_WX(pP)*CV_BLOB_WY(pP); AreaN = CV_BLOB_WX(pN)*CV_BLOB_WY(pN); if(AreaN < AreaP)break; temp = pN[0]; pN[0] = pP[0]; pP[0] = temp; } } /* Copy only first 10 blobs: */ for(i=0; i<MIN(N,10); ++i) { m_pBlobLists[EBD_FRAME_NUM-1]->AddBlob(Blobs.GetBlob(i)); } } /* Sort blobs by size. */ cvReleaseMemStorage(&storage); } /* Create blobs. */ /* Analyze blob list to find best blob trajectory: */ { int Count = 0; int pBLIndex[EBD_FRAME_NUM]; int pBL_BEST[EBD_FRAME_NUM]; int i; int finish = 0; double BestError = -1; int Good = 1; for(i=0; i<EBD_FRAME_NUM; ++i) { pBLIndex[i] = 0; pBL_BEST[i] = 0; } /* Check configuration exist: */ for(i=0; Good && (i<EBD_FRAME_NUM); ++i) if(m_pBlobLists[i] == NULL || m_pBlobLists[i]->GetBlobNum() == 0) Good = 0; if(Good) do{ /* For each configuration: */ CvBlob* pBL[EBD_FRAME_NUM]; int Good = 1; double Error = 0; CvBlob* pBNew = m_pBlobLists[EBD_FRAME_NUM-1]->GetBlob(pBLIndex[EBD_FRAME_NUM-1]); for(i=0; i<EBD_FRAME_NUM; ++i) pBL[i] = m_pBlobLists[i]->GetBlob(pBLIndex[i]); Count++; /* Check intersection last blob with existed: */ if(Good && pOldBlobList) { /* Check intersection last blob with existed: */ int k; for(k=pOldBlobList->GetBlobNum(); k>0; --k) { CvBlob* pBOld = pOldBlobList->GetBlob(k-1); if((fabs(pBOld->x-pBNew->x) < (CV_BLOB_RX(pBOld)+CV_BLOB_RX(pBNew))) && (fabs(pBOld->y-pBNew->y) < (CV_BLOB_RY(pBOld)+CV_BLOB_RY(pBNew)))) Good = 0; } } /* Check intersection last blob with existed. */ /* Check distance to image border: */ if(Good) { /* Check distance to image border: */ CvBlob* pB = pBNew; float dx = MIN(pB->x,S.width-pB->x)/CV_BLOB_RX(pB); float dy = MIN(pB->y,S.height-pB->y)/CV_BLOB_RY(pB); if(dx < 1.1 || dy < 1.1) Good = 0; } /* Check distance to image border. */ /* Check uniform motion: */ if(Good) { int N = EBD_FRAME_NUM; float sum[2] = {0,0}; float jsum[2] = {0,0}; float a[2],b[2]; /* estimated parameters of moving x(t) = a*t+b*/ int j; for(j=0; j<N; ++j) { float x = pBL[j]->x; float y = pBL[j]->y; sum[0] += x; jsum[0] += j*x; sum[1] += y; jsum[1] += j*y; } a[0] = 6*((1-N)*sum[0]+2*jsum[0])/(N*(N*N-1)); b[0] = -2*((1-2*N)*sum[0]+3*jsum[0])/(N*(N+1)); a[1] = 6*((1-N)*sum[1]+2*jsum[1])/(N*(N*N-1)); b[1] = -2*((1-2*N)*sum[1]+3*jsum[1])/(N*(N+1)); for(j=0; j<N; ++j) { Error += pow(a[0]*j+b[0]-pBL[j]->x,2)+ pow(a[1]*j+b[1]-pBL[j]->y,2); } Error = sqrt(Error/N); if( Error > S.width*0.01 || fabs(a[0])>S.width*0.1 || fabs(a[1])>S.height*0.1) Good = 0; } /* Check configuration. */ /* New best trajectory: */ if(Good && (BestError == -1 || BestError > Error)) { for(i=0; i<EBD_FRAME_NUM; ++i) { pBL_BEST[i] = pBLIndex[i]; } BestError = Error; } /* New best trajectory. */ /* Set next configuration: */ for(i=0; i<EBD_FRAME_NUM; ++i) { pBLIndex[i]++; if(pBLIndex[i] != m_pBlobLists[i]->GetBlobNum()) break; pBLIndex[i]=0; } /* Next time shift. */ if(i==EBD_FRAME_NUM)finish=1; } while(!finish); /* Check next time configuration of connected components. */ #if 0 {/**/ printf("BlobDetector configurations = %d [",Count); int i; for(i=0; i<EBD_FRAME_NUM; ++i) { printf("%d,",m_pBlobLists[i]?m_pBlobLists[i]->GetBlobNum():0); } printf("]\n"); } #endif if(BestError != -1) { /* Write new blob to output and delete from blob list: */ CvBlob* pNewBlob = m_pBlobLists[EBD_FRAME_NUM-1]->GetBlob(pBL_BEST[EBD_FRAME_NUM-1]); pNewBlobList->AddBlob(pNewBlob); for(i=0; i<EBD_FRAME_NUM; ++i) { /* Remove blob from each list: */ m_pBlobLists[i]->DelBlob(pBL_BEST[i]); } /* Remove blob from each list. */ result = 1; } /* Write new blob to output and delete from blob list. */ } /* Analyze blob list to find best blob trajectory. */ return result; } /* cvDetectNewBlob */
virtual void Process(IplImage* pImg, IplImage* /*pFG*/) { int i; double MinTv = pImg->width / 1440.0; /* minimal threshold for speed difference */ double MinTv2 = MinTv * MinTv; for (i = m_Tracks.GetBlobNum(); i > 0; --i) { DefTrackForDist* pF = (DefTrackForDist*)m_Tracks.GetBlob(i - 1); pF->state = 0; if (pF->LastFrame == m_Frame || pF->LastFrame + 1 == m_Frame) { /* Process one blob trajectory: */ int NumEq = 0; int it; for (it = m_TrackDataBase.GetBlobNum(); it > 0; --it) { /* Check template: */ DefTrackForDist* pFT = (DefTrackForDist*)m_TrackDataBase.GetBlob(it - 1); int Num = pF->pTrack->GetPointNum(); int NumT = pFT->pTrack->GetPointNum(); int* pPairIdx = (int*)ReallocTempData(sizeof(int) * 2 * (Num + NumT) + sizeof(DefMatch) * Num * NumT); void* pTmpData = pPairIdx + 2 * (Num + NumT); int PairNum = 0; int k; int Equal = 1; int UseVel = 0; int UsePos = 0; if (i == it) { continue; } /* Match track: */ PairNum = cvTrackMatch(pF->pTrack, m_TraceLen, pFT->pTrack, pPairIdx, pTmpData); Equal = MAX(1, cvRound(PairNum * 0.1)); UseVel = 3 * pF->pTrack->GetPointNum() > m_TraceLen; UsePos = 10 * pF->pTrack->GetPointNum() > m_TraceLen; { /* Check continues: */ float D; int DI = pPairIdx[0*2+0] - pPairIdx[(PairNum-1)*2+0]; int DIt = pPairIdx[0*2+1] - pPairIdx[(PairNum-1)*2+1]; if (UseVel && DI != 0) { D = (float)(DI - DIt) / (float)DI; if (fabs(D) > m_VelThreshold) { Equal = 0; } if (fabs(D) > m_VelThreshold * 0.5) { Equal /= 2; } } } /* Check continues. */ for (k = 0; Equal > 0 && k < PairNum; ++k) { /* Compare with threshold: */ int j = pPairIdx[k*2+0]; int jt = pPairIdx[k*2+1]; DefTrackPoint* pB = pF->pTrack->GetPoint(j); DefTrackPoint* pBT = pFT->pTrack->GetPoint(jt); double dx = pB->x - pBT->x; double dy = pB->y - pBT->y; double dvx = pB->vx - pBT->vx; double dvy = pB->vy - pBT->vy; //double dv = pB->v - pBT->v; double D = dx * dx + dy * dy; double Td = pBT->r * m_PosThreshold; double dv2 = dvx * dvx + dvy * dvy; double Tv2 = (pBT->vx * pBT->vx + pBT->vy * pBT->vy) * m_VelThreshold * m_VelThreshold; double Tvm = pBT->v * m_VelThreshold; if (Tv2 < MinTv2) { Tv2 = MinTv2; } if (Tvm < MinTv) { Tvm = MinTv; } /* Check trajectory position: */ if (UsePos && D > Td * Td) { Equal--; } else /* Check trajectory velocity. */ /* Don't consider trajectory tail because its unstable for velocity computation. */ if (UseVel && j > 5 && jt > 5 && dv2 > Tv2) { Equal--; } } /* Compare with threshold. */ if (Equal > 0) { NumEq++; pFT->close++; } } /* Next template. */ { /* Calculate state: */ float T = m_TrackDataBase.GetBlobNum() * m_AbnormalThreshold; /* calc threshold */ if (T > 0) { pF->state = (T - NumEq) / (T * 0.2f) + 0.5f; } if (pF->state < 0) { pF->state = 0; } if (pF->state > 1) { pF->state = 1; } /*if(0)if(pF->state>0) {// if abnormal blob printf("Abnormal blob(%d) %d < %f, state=%f\n",CV_BLOB_ID(pF),NumEq,T, pF->state); }*/ } /* Calculate state. */ } /* Process one blob trajectory. */ else { /* Move track to tracks data base: */ m_TrackDataBase.AddBlob((CvBlob*)pF); m_Tracks.DelBlob(i - 1); } } /* Next blob. */ if (m_Wnd) { /* Debug output: */ int i; if (m_pDebugImg == NULL) { m_pDebugImg = cvCloneImage(pImg); } else { cvCopy(pImg, m_pDebugImg); } for (i = m_TrackDataBase.GetBlobNum(); i > 0; --i) { /* Draw all elements in track data base: */ int j; DefTrackForDist* pF = (DefTrackForDist*)m_TrackDataBase.GetBlob(i - 1); CvScalar color = CV_RGB(0, 0, 0); if (!pF->close) { continue; } if (pF->close) { color = CV_RGB(0, 0, 255); } else { color = CV_RGB(0, 0, 128); } for (j = pF->pTrack->GetPointNum(); j > 0; j--) { DefTrackPoint* pB = pF->pTrack->GetPoint(j - 1); int r = 0;//MAX(cvRound(pB->r),1); cvCircle(m_pDebugImg, cvPoint(cvRound(pB->x), cvRound(pB->y)), r, color); } pF->close = 0; } /* Draw all elements in track data base. */ for (i = m_Tracks.GetBlobNum(); i > 0; --i) { /* Draw all elements for all trajectories: */ DefTrackForDist* pF = (DefTrackForDist*)m_Tracks.GetBlob(i - 1); int j; int c = cvRound(pF->state * 255); CvScalar color = CV_RGB(c, 255 - c, 0); CvPoint p = cvPointFrom32f(CV_BLOB_CENTER(pF)); int x = cvRound(CV_BLOB_RX(pF)), y = cvRound(CV_BLOB_RY(pF)); CvSize s = cvSize(MAX(1, x), MAX(1, y)); cvEllipse(m_pDebugImg, p, s, 0, 0, 360, CV_RGB(c, 255 - c, 0), cvRound(1 + (0 * c) / 255)); for (j = pF->pTrack->GetPointNum(); j > 0; j--) { DefTrackPoint* pB = pF->pTrack->GetPoint(j - 1); if (pF->pTrack->GetPointNum() - j > m_TraceLen) { break; } cvCircle(m_pDebugImg, cvPoint(cvRound(pB->x), cvRound(pB->y)), 0, color); } pF->close = 0; } /* Draw all elements for all trajectories. */ //cvNamedWindow("Tracks",0); //cvShowImage("Tracks", m_pDebugImg); } /* Debug output. */ #if 0 if (m_pDebugImg && m_pDebugAVIName) { if (m_pDebugAVI == NULL) { /* Create avi file for writing: */ m_pDebugAVI = cvCreateVideoWriter( m_pDebugAVIName, CV_FOURCC('x', 'v', 'i', 'd'), 25, cvSize(m_pDebugImg->width, m_pDebugImg->height)); if (m_pDebugAVI == NULL) { printf("WARNING!!! Can not create AVI file %s for writing\n", m_pDebugAVIName); } } /* Create avi file for writing. */ if (m_pDebugAVI) { cvWriteFrame(m_pDebugAVI, m_pDebugImg); } } /* Write debug window to AVI file. */ #endif m_Frame++; };
virtual void Process(IplImage* pImg, IplImage* pImgFG = NULL) { CvSeq* cnts; CvSeq* cnt; int i; //CvMat* pMC = NULL; if(m_BlobList.GetBlobNum() <= 0 ) return; /* Clear blob list for new blobs: */ m_BlobListNew.Clear(); assert(m_pMem); cvClearMemStorage(m_pMem); assert(pImgFG); { /* One contour - one blob: */ IplImage* pBin = cvCloneImage(pImgFG); assert(pBin); cvThreshold(pBin,pBin,128,255,CV_THRESH_BINARY); cvFindContours(pBin, m_pMem, &cnts, sizeof(CvContour), CV_RETR_EXTERNAL); /* Process each contour: */ for(cnt = cnts; cnt; cnt=cnt->h_next) { CvBlob NewBlob; /* Image moments: */ double M00,X,Y,XX,YY; CvMoments m; CvRect r = ((CvContour*)cnt)->rect; CvMat mat; if(r.height < 3 || r.width < 3) continue; cvMoments( cvGetSubRect(pImgFG,&mat,r), &m, 0 ); M00 = cvGetSpatialMoment( &m, 0, 0 ); if(M00 <= 0 ) continue; X = cvGetSpatialMoment( &m, 1, 0 )/M00; Y = cvGetSpatialMoment( &m, 0, 1 )/M00; XX = (cvGetSpatialMoment( &m, 2, 0 )/M00) - X*X; YY = (cvGetSpatialMoment( &m, 0, 2 )/M00) - Y*Y; NewBlob = cvBlob(r.x+(float)X,r.y+(float)Y,(float)(4*sqrt(XX)),(float)(4*sqrt(YY))); m_BlobListNew.AddBlob(&NewBlob); } /* Next contour. */ cvReleaseImage(&pBin); } for(i=m_BlobList.GetBlobNum(); i>0; --i) { /* Predict new blob position. */ CvBlob* pB = NULL; DefBlobTrackerCR* pBT = (DefBlobTrackerCR*)m_BlobList.GetBlob(i-1); /* Update predictor. */ pBT->pPredictor->Update(&(pBT->blob)); pB = pBT->pPredictor->Predict(); if(pB) { pBT->BlobPredict = pB[0]; } pBT->BlobPrev = pBT->blob; } /* Predict new blob position. */ if(m_BlobList.GetBlobNum()>0 && m_BlobListNew.GetBlobNum()>0) { /* Resolve new blob to old: */ int i,j; int NOld = m_BlobList.GetBlobNum(); int NNew = m_BlobListNew.GetBlobNum(); for(i=0; i<NOld; i++) { /* Set 0 collision and clear all hyp: */ DefBlobTrackerCR* pF = (DefBlobTrackerCR*)m_BlobList.GetBlob(i); pF->Collision = 0; pF->pBlobHyp->Clear(); } /* Set 0 collision. */ /* Create correspondence records: */ for(j=0; j<NNew; ++j) { CvBlob* pB1 = m_BlobListNew.GetBlob(j); DefBlobTrackerCR* pFLast = NULL; for(i=0; i<NOld; i++) { /* Check intersection: */ int Intersection = 0; DefBlobTrackerCR* pF = (DefBlobTrackerCR*)m_BlobList.GetBlob(i); CvBlob* pB2 = &(pF->BlobPredict); if( fabs(pB1->x-pB2->x)<0.5*(pB1->w+pB2->w) && fabs(pB1->y-pB2->y)<0.5*(pB1->h+pB2->h) ) Intersection = 1; if(Intersection) { if(pFLast) { pF->Collision = pFLast->Collision = 1; } pFLast = pF; pF->pBlobHyp->AddBlob(pB1); } } /* Check intersection. */ } /* Check next new blob. */ } /* Resolve new blob to old. */ for(i=m_BlobList.GetBlobNum(); i>0; --i) { /* Track each blob. */ CvBlob* pB = m_BlobList.GetBlob(i-1); DefBlobTrackerCR* pBT = (DefBlobTrackerCR*)pB; int BlobID = CV_BLOB_ID(pB); //CvBlob* pBBest = NULL; //double DistBest = -1; int j; if(pBT->pResolver) { pBT->pResolver->SetCollision(pBT->Collision); } if(pBT->Collision) { /* Tracking in collision: */ if(pBT->pResolver) { pB[0] = pBT->pResolver->Process(&(pBT->BlobPredict),pImg, pImgFG)[0]; } } /* Tracking in collision. */ else { /* Non-collision tracking: */ CvBlob NewCC = pBT->BlobPredict; if(pBT->pBlobHyp->GetBlobNum()==1) { /* One blob to one CC: */ NewCC = pBT->pBlobHyp->GetBlob(0)[0]; } else { /* One blob several CC: */ CvBlob* pBBest = NULL; double DistBest = -1; double CMax = 0; for(j=pBT->pBlobHyp->GetBlobNum();j>0;--j) { /* Find best CC: */ CvBlob* pBNew = pBT->pBlobHyp->GetBlob(j-1); if(pBT->pResolver) { /* Choose CC by confidence: */ // double dx = fabs(CV_BLOB_X(pB)-CV_BLOB_X(pBNew)); // double dy = fabs(CV_BLOB_Y(pB)-CV_BLOB_Y(pBNew)); double C = pBT->pResolver->GetConfidence(pBNew,pImg, pImgFG); if(C > CMax || pBBest == NULL) { CMax = C; pBBest = pBNew; } } else { /* Choose CC by distance: */ double dx = fabs(CV_BLOB_X(pB)-CV_BLOB_X(pBNew)); double dy = fabs(CV_BLOB_Y(pB)-CV_BLOB_Y(pBNew)); double Dist = sqrt(dx*dx+dy*dy); if(Dist < DistBest || pBBest == NULL) { DistBest = Dist; pBBest = pBNew; } } } /* Find best CC. */ if(pBBest) NewCC = pBBest[0]; } /* One blob several CC. */ pB->x = NewCC.x; pB->y = NewCC.y; pB->w = (m_AlphaSize)*NewCC.w+(1-m_AlphaSize)*pB->w; pB->h = (m_AlphaSize)*NewCC.h+(1-m_AlphaSize)*pB->h; pBT->pResolver->SkipProcess(&(pBT->BlobPredict),pImg, pImgFG); } /* Non-collision tracking. */ pBT->pResolver->Update(pB, pImg, pImgFG); CV_BLOB_ID(pB)=BlobID; } /* Track next blob. */ if(m_Wnd) { IplImage* pI = cvCloneImage(pImg); int i; for(i=m_BlobListNew.GetBlobNum(); i>0; --i) { /* Draw each new CC: */ CvBlob* pB = m_BlobListNew.GetBlob(i-1); CvPoint p = cvPointFrom32f(CV_BLOB_CENTER(pB)); int x = cvRound(CV_BLOB_RX(pB)), y = cvRound(CV_BLOB_RY(pB)); CvSize s = cvSize(MAX(1,x), MAX(1,y)); //int c = 255; cvEllipse( pI, p, s, 0, 0, 360, CV_RGB(255,255,0), 1 ); } for(i=m_BlobList.GetBlobNum(); i>0; --i) { /* Draw each new CC: */ DefBlobTrackerCR* pF = (DefBlobTrackerCR*)m_BlobList.GetBlob(i-1); CvBlob* pB = &(pF->BlobPredict); CvPoint p = cvPointFrom32f(CV_BLOB_CENTER(pB)); int x = cvRound(CV_BLOB_RX(pB)), y = cvRound(CV_BLOB_RY(pB)); CvSize s = cvSize(MAX(1,x), MAX(1,y)); cvEllipse( pI, p, s, 0, 0, 360, CV_RGB(0,0,255), 1 ); pB = &(pF->blob); p = cvPointFrom32f(CV_BLOB_CENTER(pB)); x = cvRound(CV_BLOB_RX(pB)); y = cvRound(CV_BLOB_RY(pB)); s = cvSize(MAX(1,x), MAX(1,y)); cvEllipse( pI, p, s, 0, 0, 360, CV_RGB(0,255,0), 1 ); } //cvNamedWindow("CCwithCR",0); //cvShowImage("CCwithCR",pI); cvReleaseImage(&pI); } } /* Process. */
//将所有模块连接使用的函数 //根据这个来修改自己的 int RunBlobTrackingAuto2323(CvCapture* pCap, CvBlobTrackerAuto* pTracker, char* fgavi_name , char* btavi_name ) { int OneFrameProcess = 0; int key; int FrameNum = 0; CvVideoWriter* pFGAvi = NULL; CvVideoWriter* pBTAvi = NULL; /* Main loop: */ /*OneFrameProcess =0 时,为waitkey(0) 不等待了,返回-1,waitkey(1)表示等1ms,如果按键了返回按键,超时返回-1*/ for (FrameNum = 0; pCap && (key = cvWaitKey(OneFrameProcess ? 0 : 1)) != 27;//按下esc键整个程序结束。 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)//参数设置了fg前景要保存的文件名 if (pTracker->GetFGMask())//前景的图像的mask存在的话,保存前景。画出团块 { /* Debug FG: */ IplImage* pFG = pTracker->GetFGMask();//得到前景的mask 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) //pTracker找到了blob { /* Draw detected blobs: */ int i; for (i = pTracker->GetBlobNum(); i > 0; i--) { CvBlob* pB = pTracker->GetBlob(i - 1);//得到第i-1个blob CvPoint p = cvPointFrom32f(CV_BLOB_CENTER(pB));//团块中心 //这个宏竟然是个强制转换得来的。见下行。 //#define CV_BLOB_CENTER(pB) cvPoint2D32f(((CvBlob*)(pB))->x,((CvBlob*)(pB))->y) CvSize s = cvSize(MAX(1, cvRound(CV_BLOB_RX(pB))), MAX(1, cvRound(CV_BLOB_RY(pB)))); //通过宏 获得团块的w 和h 的size 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. *///如果要保存结果,对前景保存,画出团块 //在原图上:找到的blob附近写下id /* 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); //下面代码的大概意思就是在找到的blob附近写下id 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 = MY_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)//如果这一帧存在且,你想把图像存起来,就是传过来的参数不为空例如 btavi_name=“1.avi" 就能存起来了。 { /* 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 */
/************************************************************************* Process Process the frames in a video one by one. 1) FG detection 2) Blob Detection 3) Blob Tracking and Association 4) Blob Post Processing 5) Blob Analysis 6) Store the results Exceptions None *************************************************************************/ void Camera::Process(const int startFrameIndex, const int endFrameIndex) { ASSERT_TRUE ( m_initializied ); ASSERT_TRUE ( m_pTracker != NULL ); InitializeDisplayWindows( ); LOG_CONSOLE( "Start processing " + m_videoFileName ); int key, oneFrameProcess=0, frameNum; for ( frameNum = 1; m_videoCap.grab() && ( key = cvWaitKey( oneFrameProcess ? 0 : 1 ) ) != 27 && ( frameNum <= endFrameIndex || endFrameIndex < 0 ); frameNum++ ) { if ( frameNum >= startFrameIndex ) { std::cout << "frameNum: " << frameNum << '\r'; // get the video frame m_videoCap.retrieve( m_originalFrameMat ); // downscale the image if required if ( m_downScaleImage ) { cv::resize( m_originalFrameMat, m_frame, m_frame.size() ); } else { m_frame = m_originalFrameMat; } m_frameIpl = m_frame; if ( key != -1 ) { oneFrameProcess = ( key == 'r' ) ? 0 : 1; } // Process the current frame m_pTracker->Process( &m_frameIpl, m_pFGMaskIpl); m_fgMask = m_pTracker->GetFGMask(); // Process the current video frame using the blob tracker IplImage fgMaskIpl = m_fgMask; // Save Blob Information in a file for( int i = m_pTracker->GetBlobNum(); i> 0; i-- ) { CvBlob* pBlob = m_pTracker->GetBlob(i-1); ASSERT_TRUE( pBlob != NULL ); // Save blob record SaveBlobRecord( pBlob, frameNum ); } if ( m_displayIntermediateResult || m_saveIntermediateResult ) { char tempString[128]; std::string textMessage; //display intermediate result if necessary CvFont font; CvSize TextSize; cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, 0.7, 0.7, 0, 1, CV_AA ); sprintf(tempString,"frame # %d", frameNum); textMessage = tempString; cv::putText( m_originalFrameMat, textMessage, cv::Point(10,20), CV_FONT_HERSHEY_PLAIN, 1, cv::Scalar((0,255,255))); cv::putText( m_fgMask,textMessage, cv::Point(10,20), CV_FONT_HERSHEY_PLAIN, 1, cv::Scalar((0,255,255))); cv::putText( m_frame, textMessage, cv::Point(10,20), CV_FONT_HERSHEY_PLAIN, 1, cv::Scalar((0,255,255))); //drawing blobs if any with green ellipse with m_cvBlob id displayed next to it. int c = 0; // 0: g; 255: red for ( int i = m_pTracker->GetBlobNum(); i > 0; i-- ) { CvBlob* pBlob = m_pTracker->GetBlob(i-1); ASSERT_TRUE( pBlob != NULL ); cv::Point blobCorner( cvRound( pBlob->x * 256 ), cvRound( pBlob->y * 256 ) ); CvSize blobSize = cvSize( MAX( 1, cvRound( CV_BLOB_RX(pBlob) * 256 ) ), MAX( 1, cvRound( CV_BLOB_RY(pBlob) * 256 ) ) ); cv::Scalar boundingBoxColor( c, 255-c, 0 ); if ( m_pTracker->GetState( CV_BLOB_ID( pBlob ) ) != 0 ) { boundingBoxColor = cv::Scalar( 255-c, c, 0 ); } cv::ellipse( m_frame, cv::RotatedRect( cv::Point2f( pBlob->x, pBlob->y ), cv::Size2f( pBlob->w, pBlob->h ), 0 ), cv::Scalar( c, 255-c, 0 ) ); blobCorner.x >>= 8; blobCorner.y >>= 8; blobSize.width >>= 8; blobSize.height >>= 8; blobCorner.y -= blobSize.height; sprintf( tempString, "BlobId=%03d", CV_BLOB_ID(pBlob) ); cvGetTextSize( tempString, &font, &TextSize, NULL ); cv::putText( m_frame, std::string( tempString ), blobCorner, CV_FONT_HERSHEY_PLAIN, 1, cv::Scalar( 255, 255, 0, 0 ) ); } } if ( m_displayIntermediateResult ) { cv::imshow(m_videoFileName+"_FGMask", m_fgMask); cv::imshow(m_videoFileName+"_Tracking", m_frame); } if ( m_saveIntermediateResult ) { cv::Mat tmpFrame; cv::cvtColor( m_fgMask, tmpFrame, CV_GRAY2BGR ); *m_pFGAvi << tmpFrame; *m_pBTAvi << m_frame; } }