www.pudn.com > backmode824.rar > ImageProcess.cpp


// ImageProcess.cpp: implementation of the CImageProcess class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "backmodel.h" 
#include "Blob.h" 
#include "TrackObject.h" 
#include "ImageProcess.h" 
#include "Dibapi.h" 
#include "math.h" 
#include "GaussianModel.h" 
#include "cv.h" 
#include "highgui.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
#define NUM_COLORS   1   /* 0  */ 
 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CImageProcess::CImageProcess() 
{ 
	m_lpMapHeader=NULL; 
	m_lpImage=NULL; 
	m_lpBackImage=NULL; 
 
	m_lpHMap=NULL; 
	m_lpDMap=NULL; 
	m_lpSMap=NULL; 
	m_lpBitmap=NULL;	 
	m_lpPalette=NULL; 
 
	bgm=NULL; 
	srand( (unsigned)time( NULL ) ); 
	 
     
	 
     
} 
 
CImageProcess::~CImageProcess() 
{ 
    if(bgm!=NULL) 
	{ 
		delete bgm; 
		bgm=NULL; 
	} 
} 
BOOL CImageProcess::InitData(CMemory *lpmemory) 
{ 
	if(lpmemory==NULL) return FALSE; 
	if(lpmemory->m_bInitialized==FALSE) return FALSE; 
 
	m_lpMapHeader=lpmemory->m_lpMapHeader; 
	m_lpImage=lpmemory->m_lpImage; 
	m_lpBackImage=lpmemory->m_lpBackImage; 
	m_lpMask=lpmemory->m_lpMask; //new  add 
	m_lpGrayMask=lpmemory->m_lpGrayMask; //new  add809 
 
	m_lpDMap=lpmemory->m_lpDMap; 
	m_lpSMap=lpmemory->m_lpSMap; 
	m_lpHMap=lpmemory->m_lpHMap; 
	m_lpNewEdgeChain=lpmemory->m_lpNewEdgeChain; 
	m_lpOldEdgeChain=lpmemory->m_lpOldEdgeChain; 
	return TRUE; 
} 
//装入位图 
//输入:CFile类指针,图象数据指针 
//输出:成功 TRUE,失败 FALSE 
BOOL CImageProcess::LoadImage(CFile* pFile,LPBYTE lpimage) 
{ 
	SetCursor(LoadCursor(NULL,IDC_WAIT));         
    DWORD dwSize;          
    TRY 
	{ 
	// read DIB file header 
		BITMAPFILEHEADER bmfHdr; 
		pFile->Read(&bmfHdr,sizeof(BITMAPFILEHEADER)); 
	// is DIB file? 
		if (bmfHdr.bfType!=0x4d42) 
		{  
			SetCursor(LoadCursor(NULL,IDC_ARROW)); 
			return FALSE; 
		} 
		DWORD dwLength=pFile->GetLength(); 
		if (bmfHdr.bfSize!=dwLength) bmfHdr.bfSize=dwLength; 
	// read DIB buffer 
		dwSize=bmfHdr.bfSize - sizeof(BITMAPFILEHEADER); 
		if(!m_lpMapHeader) return FALSE;       
		pFile->Read((LPBYTE)m_lpMapHeader,sizeof(BITMAPINFOHEADER)); 
		if (m_lpMapHeader->biSize!= sizeof(BITMAPINFOHEADER)) 
		{   SetCursor(LoadCursor(NULL,IDC_WAIT));return FALSE;} 
		int nNumColors=(UINT)m_lpMapHeader->biClrUsed; 
		if (nNumColors == 0) 
		{ 
			//no color table for 24-bit, default size otherwise 
			if (m_lpMapHeader->biBitCount!=24) 
				nNumColors=1<biBitCount; // standard size table 
		} 
		// fill in some default values if they are zero 
		if(m_lpMapHeader->biClrUsed == 0) 
			  m_lpMapHeader->biClrUsed=nNumColors; 
		if(m_lpMapHeader->biSizeImage == 0) 
			  m_lpMapHeader->biSizeImage=((((m_lpMapHeader->biWidth*(DWORD)m_lpMapHeader->biBitCount) 
						        +31)&~31)>>3)*m_lpMapHeader->biHeight; 
 
	    pFile->Read((LPBYTE)m_lpMapHeader+m_lpMapHeader->biSize,nNumColors*sizeof(RGBQUAD)); 
	    WORD offBits=(WORD)m_lpMapHeader->biSize+nNumColors*sizeof(RGBQUAD); 
	    if(bmfHdr.bfOffBits!=0L) 
			pFile->Seek(bmfHdr.bfOffBits,CFile::begin); 
		 
	    DWORD dwCount=pFile->ReadHuge(lpimage,m_lpMapHeader->biSizeImage); 
		if(dwCount!=m_lpMapHeader->biSizeImage) 
		{	 
			SetCursor(LoadCursor(NULL,IDC_ARROW)); 
             return FALSE; 
		} 
 
 
		 
 
	} 
		 
    CATCH (CException, e)          
    {    
		SetCursor(LoadCursor(NULL,IDC_ARROW)); 
        return FALSE;   
	} 
    END_CATCH 
    //create CDib with DIB buffer  
    SetCursor(LoadCursor(NULL,IDC_ARROW));  
	BuildPalette(); 
	return BuildBitmap(lpimage);     
} 
 
//创建调色板 
//输入: 
//输出:成功 TRUE、失败 FALSE 
BOOL CImageProcess::BuildPalette() 
{ 
	if(m_lpPalette!=NULL) 
	{ 
		delete m_lpPalette; 
		m_lpPalette=NULL; 
	} 
	if(!m_lpMapHeader)	return FALSE; 
	HPALETTE hPalette=CreateDIBPalette((LPBYTE)m_lpMapHeader); 
	if(hPalette==NULL) 	return FALSE; 
	m_lpPalette=new CPalette; 
	m_lpPalette->Attach(hPalette); 
	return TRUE; 
} 
 
//创建调色板 
//输入:图象数据句柄 
//输出:成功 TRUE、失败 FALSE 
BOOL CImageProcess::BuildBitmap(LPBYTE lpimage) 
{ 
	HBITMAP hBitmap; 
	if(m_lpBitmap!=NULL) 
	{ 
		delete m_lpBitmap; 
		m_lpBitmap=NULL; 
		hBitmap=NULL; 
	} 
 
	if(!m_lpMapHeader) 	return FALSE; 
	HPALETTE hPal=CreateDIBPalette((LPBYTE)m_lpMapHeader); 
 
    HDC hDC; 
	HPALETTE hOldPal=NULL; 
 
	hDC=GetDC(NULL); 
	if(!hDC)	return 0; 
	if(hPal) 
	{ 
		hOldPal=SelectPalette(hDC,hPal,FALSE); 
		RealizePalette(hDC); 
	} 
	hBitmap=CreateDIBitmap(hDC, 
						   (LPBITMAPINFOHEADER)m_lpMapHeader, 
						   CBM_INIT, 
						   lpimage, 
						   (LPBITMAPINFO)m_lpMapHeader, 
						   DIB_RGB_COLORS); 
	if(hOldPal) 
		SelectPalette(hDC,hOldPal,FALSE); 
	ReleaseDC(NULL,hDC); 
	if(hBitmap==NULL)		return FALSE; 
	m_lpBitmap=new CBitmap; 
	m_lpBitmap->Attach(hBitmap); 
	return TRUE;	 
} 
 
//缩放显示位图      
//输入:设备句柄,目标区域,源区域,光栅操作模式 
//输出:成功 TRUE、失败 FALSE 
BOOL CImageProcess::Display(CDC* pDC,CRect rcDest,CRect rcSrc,DWORD dwRop) 
{ 
	CDC MemDC; 
    MemDC.CreateCompatibleDC(pDC); 
	CBitmap*  lpOldBmp=MemDC.SelectObject(m_lpBitmap); 
	CPalette* lpOldPal=pDC->SelectPalette(m_lpPalette,TRUE); 
    pDC->RealizePalette (); 
          
	BOOL bSuccess=pDC->StretchBlt(rcDest.left,rcDest.top, 
                                  rcDest.Width(), 
								  rcDest.Height(), 
                                  &MemDC, 
                                  rcSrc.left, rcSrc.top, 
                                  rcSrc.Width(), 
								  rcSrc.Height(), 
                                  dwRop); 
          
   MemDC.SelectObject(lpOldBmp); 
   pDC->SelectPalette(lpOldPal,TRUE); 
   return bSuccess; 
} 
 
 
void CImageProcess::simpleFrameDiff() 
{ 
	int w,h; 
	w=m_lpMapHeader->biWidth; 
	h=m_lpMapHeader->biHeight; 
 
	float hisO; 
	float hisB; 
	if(m_lpMapHeader->biBitCount==24) 
	{ 
		for(int i=0;i<3*h;i+=3)// 
			for(int j=0;j<3*w;j+=3) 
			{ 
				hisO=0.3*(*(m_lpImage+(i*w)+j+0))+ 
					0.59*(*(m_lpImage+(i*w)+j+1)) 
					+0.11*(*(m_lpImage+(i*w)+j+2)); 
				hisB=0.3*(*(m_lpBackImage+(i*w)+j+0))+ 
					0.59*(*(m_lpBackImage+(i*w)+j+1)) 
					+0.11*(*(m_lpBackImage+(i*w)+j+2)); 
 
				//aa=*(m_ImageProcess.m_lpImage+(i*w)+j+0)-*(m_ImageProcess_back.m_lpImage+(i*w)+j+0); 
			  if(fabs(hisB-hisO)>m_iThreshold) 
			  { 
				 
				*(m_lpDMap+(i*w)+j+0)=255; 
				*(m_lpDMap+(i*w)+j+1)=255; 
				*(m_lpDMap+(i*w)+j+2)=255;				 
			   
			    /*   
				*(m_lpDMap+(i*w)+j+0)=255; 
				*(m_lpDMap+(i*w)+j+1)=0; 
				*(m_lpDMap+(i*w)+j+2)=197; //粉色*/ 
			  } 
			  else 
			  { 
				/* 
				  *(m_lpDMap+(i*w)+j+0)=*(m_lpImage+(i*w)+j+0);//0; 
				*(m_lpDMap+(i*w)+j+1)=*(m_lpImage+(i*w)+j+1);//0; 
				*(m_lpDMap+(i*w)+j+2)=*(m_lpImage+(i*w)+j+2);//0;*/ 
				 
				*(m_lpDMap+(i*w)+j+0)=0;//0; 
				*(m_lpDMap+(i*w)+j+1)=0;//0; 
				*(m_lpDMap+(i*w)+j+2)=0;//0; 
 
			  } 
			} 
	} 
	else if(m_lpMapHeader->biBitCount==8) //灰度图 
	{ 
		for(int i=0;im_iThreshold) 
			  { 
				*(m_lpDMap+(i*w)+j+0)=255; 
				//*(m_lpDMap+(i*w)+j+1)=0; 
				//*(m_lpDMap+(i*w)+j+2)=197; //粉色 
			  } 
			  else 
			  { 
				*(m_lpDMap+(i*w)+j+0)=0; 
				//*(m_lpDMap+(i*w)+j+1)=*(m_lpImage+(i*w)+j+1);//0; 
				//*(m_lpDMap+(i*w)+j+2)=*(m_lpImage+(i*w)+j+2);//0; 
 
			  } 
			} 
	} 
 
/* 
	for(int i=0;i0) 
			{ 
				*(m_lpImage+(i*w+j))=255; 
				*(m_lpImage+(i*w+j)+1)=255; 
				*(m_lpImage+(i*w+j)+2)=255; 
 
			} 
			else 
			{ 
				*(m_lpImage+(i*w+j))=0; 
				*(m_lpImage+(i*w+j)+1)=0; 
				*(m_lpImage+(i*w+j)+2)=0; 
			} 
		}*/ 
} 
 
 
 
 
 
/************************************************ 
 *  函数:KCluster() 
 *  参数: 
 *  int     type          1:HS空间聚类;其它RGB空间聚类 
 *  double  *lpMeanValue //聚类中心指针 
 *  int     ClusterNum   //聚类中心数量						   
 *  int     IterativeNum //聚类迭代次数 
 *  double  error        //聚类中心值变化允许偏差 
 *  返回值: TRUE  or FALSE 
*************************************************/ 
bool   CImageProcess::KCluster(int type, 
							   double  *lpMeanValue, 
						       int     ClusterNum,						   
						       int     IterativeNum, 
						       double  error) 
{ 
    bool b;  
	SetCursor(LoadCursor(NULL,IDC_WAIT)); 
	ZeroDMemory(); 
	m_lpKCluster=new CKCluster; 
	//m_lpBackImage 
	//m_lpKCluster->InitData(m_lpMapHeader,m_lpImage,m_lpDMap,m_lpHMap,m_lpSMap); 
	m_lpKCluster->InitData(m_lpMapHeader,m_lpDMap,m_lpBackImage,m_lpHMap,m_lpSMap); 
	if(type==1)   
	    b=m_lpKCluster->KClusterHS(lpMeanValue,ClusterNum,IterativeNum,error); 
	else             
		b=m_lpKCluster->KClusterRGB(lpMeanValue,ClusterNum,IterativeNum,error); 
	SetCursor(LoadCursor(NULL,IDC_ARROW)); 
	delete m_lpKCluster; 
	return b; 
 
} 
 
/////////////////////////////////////////////////////////// 
BOOL     CImageProcess::ZeroDMemory() 
{ 
	ZeroMemory(m_lpDMap,1024*1024*2); 
	ZeroMemory(m_lpNewEdgeChain,1024*1024*2); 
	ZeroMemory(m_lpOldEdgeChain,1024*1024*2); 
	//ZeroMemory(m_lpVMap,1024*1024); 
//	ZeroMemory(m_lpSHighPassMap,1024*1024); 
 
	return TRUE; 
} 
bool CImageProcess::creatBackModel(LPBYTE pFInitial) //创建背景模型 
//以第一幅图像每点的像素值作为均值的初始化 
{ 
	if(bgm!=NULL) 
		return true; 
	bgm=new CBGModel(m_lpMapHeader->biWidth,m_lpMapHeader->biHeight); 
	bgm->ProcessFirst(pFInitial); 
		return true; 
 
} 
//============================================ 
bool CImageProcess::doGaussSub(LPBYTE m_lpImage,int Num) 
{ 
 
	int i,j;//判断是否是第一幅图像 
	i=Num; 
	IplImage*       image = NULL; 
	IplImage*       image1 = NULL; 
    IplImage*       image2[3] ;  
    IplImage*       image3 = NULL; 
	int minSize = 50;//确定无效区域的大小 
	int nBlobs=0; 
	int nTobs=0; 
	for( j = 0; jbiWidth,m_lpMapHeader->biHeight),8,3); 
        image1=cvCreateImage(cvSize(m_lpMapHeader->biWidth,m_lpMapHeader->biHeight),8,1); 
        image2[0]=cvCreateImage(cvSize(m_lpMapHeader->biWidth,m_lpMapHeader->biHeight),32,1); 
        image3=cvCreateImage(cvSize(m_lpMapHeader->biWidth,m_lpMapHeader->biHeight),8,3); 
		image->origin = 1; 
		image1->origin = 1; 
	//	image2->origin = 1; 
      	image3->origin = 1; 
	 
 
 
	if((creatBackModel(m_lpBackImage))&&(i==0)) 
		//第一次初始化背景 
	{ 
		//判断是前景还是背景 
		bgm->Process(m_lpImage,m_lpMask,i);//m_lpBackImage);//,m_lpMask);     
		i++; 
		return true; 
	}else 
	{ 
		if(i>=1) 
			//累积多次背景更新之后进行处理 
		{                                                                                                                                                                                                                                                                                                                                                      
			//判断是前景还是背景 
			bgm->Process(m_lpImage,m_lpMask,i);//m_lpBackImage);//,m_lpMask); 
 
		        //LPBYTE转换为IplImage 
 		cvSetData(image,m_lpMask,image->width*3); 
        //LPBYTE转换为IplImage 
		cvSetData(image3,m_lpImage,image3->width*3); 
 
		//rgbtogray 
		cvCvtColor(image, image1, CV_RGB2GRAY); 
		//高斯平滑 
		cvSmooth(image1,image1,CV_GAUSSIAN,3,0,0); 
		 
		//二值化前景图 
        cvThreshold(image1, image1, 60, 255.0, CV_THRESH_BINARY); 
 
        //进行形态学滤波,去掉噪音  
        cvErode(image1, image1, 0, 1); 
		 
        cvDilate(image1, image1, 0, 1); 
		//进行形态学滤波,去掉噪音  
        //cvErode(image1, image1, 0, 1); 
		 
        //cvDilate(image1, image1, 0, 1); 
	 
	 
 
			//找到二值图像的连接区域 
			if(FindConnectedComponents(image1->imageDataOrigin,image2[0]->imageDataOrigin)) 
			{ 
				// now extract blobs 
				FindBlobs(image2[0], blobs, &nBlobs, minSize); 
				MatchBlobsTobs(blobs, nBlobs, tobs, &nTobs); 
				for(int i=0; iid % NUM_COLORS]); 
					blobs[i]->RenderBB(image3, CV_RGB(0, 128, 200)); 
				} 
 
			} 
			 
 
		/*//提取目标轮廓 
		cvFindContours(image1, storage, &contours, sizeof(CvContour), 
                    CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE , cvPoint(0,0) ); 
		count = contours->total; 
        PointArray = (CvPoint *)malloc(count * sizeof(CvPoint));//数组    
		Array=new int[count*2]; 
		for(j=0;jh_next!=NULL) 
			{ 
				cvCvtSeqToArray(contours, PointArray, CV_WHOLE_SEQ);//contour转换成数组 
				*(Array+j)=PointArray->x; 
				*(Array+j+1)=PointArray->y; 
				contours=contours->h_next; 
			} 
		} 
			 
 
 
 
		//去除背景消减之后的噪声小区域,根据面积大小 
		//确定物体位置 
		 
     	//if(bgm->DivideSmallArea(image1->imageDataOrigin,m_lpGrayMask))*/ 
         
 
		cvNamedWindow( "ObjectTracking", 1 ); 
		cvNamedWindow("Raw Video",1); 
		 
		 
		cvShowImage("ObjectTracking", image1); 
	    cvShowImage("Raw Video",image3); 
		cvWaitKey(1); 
		cvReleaseImage(&image); 
        cvReleaseImage(&image1); 
		cvReleaseImage(&image2[0]); 
		image3->imageData=NULL; 
		cvReleaseImage(&image3); 
 
		 
 
		//delete [] Array; 
		return true; 
		}else 
			//先选择前五十幅图像进行背景重建 
			//进行多次背景更新 
		{ 
			//判断是前景还是背景 
		bgm->Process(m_lpImage,m_lpMask,i);//m_lpBackImage);//,m_lpMask); 
		i++; 
		return true; 
		} 
	} 
	return false; 
} 
//=============================================== 
//进行背景建模后,进行连接 
//=============================================== 
////////////////////////////////////////////////////////////////////// 
 
/* 
 Finds connected components in binary image pMask (8x1) using a 2-pass 
  method.  Stores resulting labels in pLabels (32x1) such that every pixel in 
  a blob has the same label and each blob has a unique label. 
 */ 
bool CImageProcess::FindConnectedComponents(LPBYTE pMask, LPBYTE pLabels) 
{ 
   if (!pMask || !pLabels) return false; 
    
   BYTE *mask=pMask; 
   int *id = (int*)pLabels; 
   int x, y, i, j, k, nextId; 
   int ids[4]; 
   int vw=bgm->vw; 
   int vh=bgm->vh; 
   int nPixels=vw*vh; 
   int idOfs[4] = { -vw-1, -vw, -vw+1, -1 };    
 
   // to start, every id value maps to itself 
   nextId = 1; 
   for( i = 0; i 0) 
         { 
             *id = j; 
         } 
         else  
         { 
             *id = nextId++; 
         } 
      } 
      else  
      { 
          *id = 0; 
      } 
       
      mask++; 
      id++; 
   } 
 
   // scan rest of rows 
   for(y=1; yi) 
         { 
             i = j; 
         } 
         if (i>0)  
         { 
             *id = i; 
         } 
         else  
         { 
             *id = nextId++; 
         } 
      } 
      else  
      { 
          *id = 0; 
      } 
      mask++; 
      id++; 
 
      // now check the 'middle' of the row 
      for(x=1; x j) j = ids[i]; 
            } 
 
            if (j > 0) 
            { 
               for( i = 0; i<4; i++) 
               { 
                  if (ids[i]==0 || ids[i]==j) continue; 
                  for(k=1; ki) i = j; 
          
         j = *(id - 1); 
         if (j>i) i = j; 
 
         if (i>0) 
         { 
             *id = i; 
         } 
         else  
         { 
             *id = nextId++; 
         } 
      } 
      else 
      { 
          *id = 0; 
      } 
      mask++; 
      id++; 
 
      if (nextId >= MAX_CC_IDS) 
      { 
		  CString s; 
         s.Format("Error - not enough connected component ids (%d)\n", MAX_CC_IDS); 
		 //MessageBox(s); 
         return false; 
      } 
   } 
 
   // pass 2 - update ids in label image according to equiv map 
   id = (int*)pLabels; 
 
   for( i = 0; i 0) *id = map[*id]; 
      id++; 
   } 
 
   return true; 
} 
////////////////////////////////////////////////////////////////////// 
 
/* 
 Extracts blob info from labelled connected component image 
 
 pLabels - 32x1 labelled image 
 blobs - pointer to MAX_NUM_BLOBS blob object pointers 
 nBlobs - pointer to int that will store number of valid blobs found 
 minSize - minimum size for a blob to be valid 
 */ 
////////////////////////////////////////////////////////////////////// 
bool CImageProcess::FindBlobs(IplImage *pLabels, Blob **blobs, int *nBlobs, int minSize) 
{ 
   if (!pLabels || !blobs || !nBlobs) return false; 
 
   int *id = (int*)pLabels->imageData; 
 
   int x, y, i, j, n; 
 
   int vw=bgm->vw; 
   int vh=bgm->vh; 
   int nPixels=vw*vh; 
 
   *nBlobs = 0; 
   for( i = 0; iuser will serve a dual purpose: 
      //  1) flag to say whether the blob 'grew' due to the last row 
      //  2) index into map array that references this blob 
      for( i = 0; iuser = 0; 
 
      for(x=0; x 0) 
         { 
            if (map[j] < 0) 
            { 
               if (n >= MAX_NUM_BLOBS) 
               { 
				   CString s; 
                  s.Format("error: too many blobs (%d)\n", n); 
                  *nBlobs = 0; 
                  return false; 
               } 
               else 
               { 
                  // this is a new blob 
                  map[j] = n; 
                  blobs[n]->mass = 1; 
                  blobs[n]->nHull = 0; 
                  blobs[n]->centroid.x = x; 
                  blobs[n]->centroid.y = y; 
                  blobs[n]->bbBottomRight.x = x; 
                  blobs[n]->bbBottomRight.y = y; 
                  blobs[n]->bbTopLeft.x = x; 
                  blobs[n]->bbTopLeft.y = y; 
                  blobs[n]->id = j; 
                  blobs[n]->user = j; 
                  n++; 
               } 
            } 
            else 
            { 
               // this blob already exists 
               blobs[map[j]]->user = j; 
               j = map[j]; 
               blobs[j]->mass++; 
               blobs[j]->centroid.x += x; 
               blobs[j]->centroid.y += y; 
               if (x > blobs[j]->bbBottomRight.x) blobs[j]->bbBottomRight.x = x; 
               else if (x < blobs[j]->bbTopLeft.x) blobs[j]->bbTopLeft.x = x; 
               if (y > blobs[j]->bbBottomRight.y) blobs[j]->bbBottomRight.y = y; 
               else if (y < blobs[j]->bbTopLeft.y) blobs[j]->bbTopLeft.y = y;                
            } 
         } 
 
         id++; 
      }       
 
      // check for finished blobs 
      for( i = 0; iuser == 0) && (blobs[i]->mass < minSize)) 
         { 
            // kill this blob by moving it to the end of the list and 
            //  decrement the list size 
            n--; 
 
            // we have to do a proper swap 
            Blob *tblob = blobs[i]; 
            blobs[i] = blobs[n]; 
            blobs[n] = tblob;             
 
            // we also have to update the map             
            map[blobs[i]->user] = i; 
 
            // since we changed the blob at position  we want to reprocess 
            //  it next time through the loop 
            i--; 
         } 
      } 
   } 
 
   // do some per blob post-processing 
   for( i = 0; icentroid.x /= blobs[i]->mass; 
      blobs[i]->centroid.y /= blobs[i]->mass; 
   } 
 
   *nBlobs = n; 
 
   return true; 
} 
 
////////////////////////////////////////////////////////////////////// 
 
bool CImageProcess::ColorTob(IplImage *pImg, IplImage *pLabels, 
                        TrackObject *tob, BYTE *color) 
{ 
   if (!pImg || !tob) return false; 
 
   BYTE *pi = (BYTE*)pImg->imageData; 
   int *id = (int*)pLabels->imageData; 
   int w, h, x, y, x3, pitch; 
 
   int vw=bgm->vw; 
   int vh=bgm->vh; 
   int nPixels=vw*vh; 
 
   Blob *blob = tob->blob; 
 
   w = blob->bbBottomRight.x - blob->bbTopLeft.x; 
   h = blob->bbBottomRight.y - blob->bbTopLeft.y; 
 
   x = blob->bbTopLeft.y * vw + blob->bbTopLeft.x; 
   pi += x*3; 
   id += x; 
   pitch = vw*3; 
 
   for(y=0; yid == *(id + x)) 
         { 
            *(pi + x3) = color[2]; 
            *(pi + x3 + 1) = color[1]; 
            *(pi + x3 + 2) = color[0]; 
         } 
 
         x3 += 3; 
      } 
 
      pi += pitch; 
      id += vw; 
   } 
 
   return true; 
} 
 
////////////////////////////////////////////////////////////////////// 
 
bool CImageProcess::MatchBlobsTobs(Blob **blobs, int nBlobs, 
                              TrackObject **tobs, int *nTobs) 
{ 
   if (!blobs || !tobs || !nTobs) return false; 
 
   int i; 
   int n = nBlobs; 
   if (n > MAX_NUM_TOBS) n = MAX_NUM_TOBS; 
 
   for( i = 0; iblob = blobs[i]; 
   } 
    
   *nTobs = n; 
 
   return true; 
}