視頻運動目標跟蹤,基於opencv , vc++

//打開視頻文件以及車輛跟蹤和識別,按鈕消息響應部分
void CTrackandIDDlg::OnStartTrackandID()
{
 // TODO: Add your control notification handler code here
    int argc=2;
 ////打開文件///////////////////////////////////////////////////
 CString FilePathName;
 CFileDialog dlg(TRUE);
 if(dlg.DoModal()==IDOK)  //
  FilePathName=dlg.GetPathName();

    IplImage* pFrame = NULL;
    IplImage* pFrImg = NULL;
    IplImage* pBkImg = NULL;
 IplImage* pFrImg1 = NULL;

    CvMat* pFrameMat = NULL;
    CvMat* pFrMat = NULL;
    CvMat* pBkMat = NULL;
 CvMat* pFrMat1 = NULL;

 CvMemStorage * storage = cvCreateMemStorage(0);//輪廓邊緣提取時的參數
    CvSeq * contour = 0;//輪廓邊緣提取時的參數
    int mode = CV_RETR_EXTERNAL;//輪廓邊緣提取時的參數
 //形態學處理時內核的大小
 IplConvKernel* Element = cvCreateStructuringElementEx(13,13,1,1,CV_SHAPE_RECT,NULL);

 CvFont font1;//初始化字體格式
 int linetype=CV_AA;
 cvInitFont(&font1, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, 8);
 //用字符串時一定要把using namespace std;寫在前面,否則不能用,下面是用於顯示的字符串
 string msg[10]={"JGD01","JGD02","JGD03","JGD04","JGD05","JGD06","JGD07","JGD08","JGD09","JGD10"};
 int No=0;//用於記錄顯示車輛
 bool FindCar=false;
 
 //在視頻中畫出感興趣的區域,怎麼樣才能沿車道畫線???????
 CvPoint pt1,pt2,pt3,pt4,pt5;
 pt1.x=292;//(視頻中左下點)
 pt1.y=100;
 pt2.x=412;//(視頻中右上點)
 pt2.y=280;
 CvRect bndRect=cvRect(0,0,0,0);//用cvBoundingRect畫出外接矩形時需要的矩形
 int avgX = 0;//The midpoint X position of the rectangle surrounding the moving objects
 int avgY = 0;//The midpoint Y position of the rectangle surrounding the moving objects
 int avgX1=0;//用來合併相近的車輛
 int avgY1=0;            
 for(int i=0;i<10;i++)
 {
  TrackBlock[i]=NULL;
  if((TrackBlock[i]=(struct AvTrackBlock *) malloc(sizeof(struct AvTrackBlock)))==NULL)
  {
   MessageBox("內存分配錯誤");
   exit(1);
  }   
 }////////////////////

    CvCapture* pCapture = NULL; 
    int nFrmNum = 0;//表示圖像的幀數

    //創建窗口
    cvNamedWindow("video", 1);
         //cvNamedWindow("background",1);
    cvNamedWindow("foreground",1);
    //使窗口有序排列
    cvMoveWindow("video", 30, 0);
        //cvMoveWindow("background", 360, 0);
    cvMoveWindow("foreground", 690, 0);

    if( argc > 2 ){
        fprintf(stderr, "Usage: bkgrd [video_file_name]/n");
        //return -1;
    }

    ////打開攝像頭///////////////////////////////////////////////////
    if (argc ==1)
        if( !(pCapture = cvCaptureFromCAM(-1))){
         fprintf(stderr, "Can not open camera./n");
         //return -2;
  }

    ///打開視頻文件//////////////////////////////////////////////////
    if(argc == 2)
        if( !(pCapture = cvCaptureFromFile(FilePathName))){
   fprintf(stderr, "Can not open video file %s/n", FilePathName);
   //return -2;
  }
 
    //逐幀讀取視頻,cvQueryFrame從攝像頭或者文件中抓取並返回一幀
    while(pFrame = cvQueryFrame(pCapture))
    {
        nFrmNum++;
        //如果是第一幀,需要申請內存,並初始化
        if(nFrmNum == 1)
  {
   pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);
   pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);

    pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
    pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
    pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
   cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);
   cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
   cvConvert(pFrImg, pFrameMat);
   cvConvert(pFrImg, pFrMat);
   cvConvert(pFrImg, pBkMat);
  }

  else if(nFrmNum == 3)
  {
   cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
   cvConvert(pFrImg, pFrameMat);
   //高斯濾波先,以平滑圖像
   cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);

   //在視頻中設置並畫出感興趣的區域
   cvRectangle(pFrame,pt1,pt2,CV_RGB(255,0,0),2, 8, 0 );

   //當前幀跟背景圖相減,cvAbsDiff計算兩個數組差的絕對值
   cvAbsDiff(pFrameMat, pBkMat, pFrMat);

   //二值化前景圖
   cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);
   
   //通過查找邊界找出ROI矩形區域內的運動車輛,建立完全目標檔案
   //cvCanny(pFrImg, pBkImg, 50, 150, 3);
   cvDilate(pFrImg,pBkImg,Element,1);
   cvFindContours(pBkImg, storage, &contour, sizeof(CvContour),
    mode, CV_CHAIN_APPROX_SIMPLE);
   //process each moving contour in the current frame用函數cvBoundingRect
   for(;contour!=0;contour=contour->h_next)
   {
    //Get a bounding rectangle around the moving object.
    bndRect = cvBoundingRect(contour, 0);
    
    //Get an average X position of the moving contour.
    avgX = (bndRect.x + bndRect.x + bndRect.width) / 2;
    avgY = (bndRect.y + bndRect.y + bndRect.height) / 2;
    pt5.x = bndRect.x;//寫字的左下角點
    pt5.y = avgY;

    //If the center of contour is within ROI than show it
    if(avgX>300 && avgX<400 && avgY<300 && avgY>80)
    {
     pt3.x = bndRect.x;
     pt3.y = bndRect.y;
     pt4.x = bndRect.x + bndRect.width;
     pt4.y = bndRect.y + bndRect.height;
     if(bndRect.height>35) //把長度小於某個閥值的干擾矩形去掉
     {
      cvRectangle(pFrame,pt3,pt4,CV_RGB(255,0,0),1, 8, 0 );
      //在車輛的中心寫編號
      cvPutText( pFrame, msg[No].c_str(), pt5, &font1, cvScalar(0,255,0));
      //把當前車輛存入跟蹤數組
      TrackBlock[No]->Direction=1;
      TrackBlock[No]->FramesTracked=nFrmNum;
      TrackBlock[No]->avgX=avgX;
      TrackBlock[No]->avgY=avgY;
      No++;
     }
    }
   }/////查找邊界的for 循環結束  
   
   //更新背景///////////////////////////////////////////////////
   cvRunningAvg(pFrameMat, pBkMat, 0.005, 0);
   //將背景轉化爲圖像格式,用以顯示
   cvConvert(pBkMat, pBkImg);

   //顯示圖像////////////////////////////////////////////////////
   cvShowImage("video", pFrame);
   //cvShowImage("background", pBkImg);
   //cvShowImage("foreground", pFrImg);

   //如果有按鍵事件,則跳出循環,此等待也爲cvShowImage函數提供時間完成顯示,等待時間可以根據CPU速度調整
   if( cvWaitKey(2) >= 0 )
    break;
  }

        else if(nFrmNum > 3)//從第三幀開始,根據完全目標檔案來新增或刪除運動車輛檔案。
  {
    cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
    cvConvert(pFrImg, pFrameMat);
   //高斯濾波先,以平滑圖像
    cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);

   //在視頻中設置並畫出感興趣的區域
   //cvSetImageROI(pFrame,rect1);
   cvRectangle(pFrame,pt1,pt2,CV_RGB(255,0,0),2, 8, 0 );

   //當前幀跟背景圖相減,cvAbsDiff計算兩個數組差的絕對值
   cvAbsDiff(pFrameMat, pBkMat, pFrMat);

   //二值化前景圖,void cvThreshold( const CvArr* src, CvArr* dst, double threshold,
            //double max_value, int threshold_type );
   cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);

   //通過查找邊界找出ROI矩形區域內的運動車輛,建立完全目標檔案
   //cvCanny(pFrImg, pBkImg, 50, 150, 3);
   cvDilate(pFrImg,pBkImg,Element,1);
   cvFindContours( pBkImg, storage, &contour, sizeof(CvContour),
    mode, CV_CHAIN_APPROX_SIMPLE);
   //process each moving contour in the current frame用函數cvBoundingRect
   for(;contour!=0;contour=contour->h_next)
   {
    //Get a bounding rectangle around the moving object.
    bndRect = cvBoundingRect(contour, 0);
    
    //Get an average X position of the moving contour.
    avgX = (bndRect.x + bndRect.x + bndRect.width) / 2;
    avgY = (bndRect.y + bndRect.y + bndRect.height) / 2;
    pt5.x=bndRect.x;//寫字的左下角點
    pt5.y=avgY;

    //If the center of contour is within ROI than show it
    if(avgX > 300 && avgX < 400 && avgY < 280 && avgY > 100)
    {
     pt3.x = bndRect.x;
     pt3.y = bndRect.y;
     pt4.x = bndRect.x + bndRect.width;
     pt4.y = bndRect.y + bndRect.height;
     if(bndRect.height>35) //把長度小於某個閥值的干擾矩形去掉
     {
      cvRectangle(pFrame,pt3,pt4,CV_RGB(255,0,0),1, 8, 0 );
      //cvPutText(pFrame,msg[No].c_str(), pt5, &font1, cvScalar(0,255,0));
      //在跟蹤數組中尋找看是否有匹配的車輛,沒有則表示是新車輛
      for(int i=0;i<10;i++)
      {
       if(TrackBlock[i]->avgX !=0 && abs(avgX-TrackBlock[i]->avgX)<20 &&
         abs(avgY-TrackBlock[i]->avgY)<50)
       {
           cvPutText(pFrame,msg[i].c_str(), pt5, &font1, cvScalar(0,255,0));
        TrackBlock[i]->FramesTracked=nFrmNum;
        TrackBlock[i]->avgX=avgX;
        TrackBlock[i]->avgY=avgY;
        i=10;//使跳出for循環
        FindCar=true;
       }
      }
      if(FindCar!=true && avgY<120)//表示沒有找到車輛
      {
       TrackBlock[No]->Direction=1;
       TrackBlock[No]->FramesTracked=nFrmNum;
       TrackBlock[No]->avgX=avgX;
       TrackBlock[No]->avgY=avgY;
       if(No==9){
        No=0;
       }
       else
        No++;
      }   
      FindCar=false;//賦值爲false爲下一次尋找車輛做準備      
     }
    }
   }//輪廓分for循環結束

   //對於沒有匹配的車輛,表示已經出了邊界,清空數組
   for(int j=0;j<10;j++)
   {
    if(TrackBlock[j]->FramesTracked != nFrmNum)
    {
     //雖然置爲零,但是可能零和當前中心的值在設定的範圍內,所以不行。
     //TrackBlock[j]=NULL;爲何用NULL不行。
     TrackBlock[j]->Direction=0;
     TrackBlock[j]->FramesTracked=0;
     TrackBlock[j]->avgX=0;
     TrackBlock[j]->avgY=0;
    }
   }

   //更新背景///////////////////////////////////////////////////
   cvRunningAvg(pFrameMat, pBkMat, 0.005, 0);
   //將背景轉化爲圖像格式,用以顯示
   cvConvert(pBkMat, pBkImg);

   //顯示圖像////////////////////////////////////////////////////
   cvShowImage("video", pFrame);
   cvShowImage("background", pBkImg);
   cvShowImage("foreground", pFrImg);

   /*if(nFrmNum/2 ==0)
   pBkMat=pFrameMat;*/
   //如果有按鍵事件,則跳出循環,此等待也爲cvShowImage函數提供時間完成顯示,等待時間可以根據CPU速度調整
   if( cvWaitKey(2) >= 0 )
    break;
  }//
    }//while循環結束

 cvReleaseStructuringElement(&Element);//刪除結構元素
    //銷燬窗口
    cvDestroyWindow("video");
    cvDestroyWindow("background");
    cvDestroyWindow("foreground");

    //釋放圖像和矩陣
    cvReleaseImage(&pFrImg);
    cvReleaseImage(&pBkImg);

    cvReleaseMat(&pFrameMat);
    cvReleaseMat(&pFrMat);
    cvReleaseMat(&pBkMat);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章