OpenCV圖像識別、移動偵測、邊緣檢測實現及 cvCopy()和cvCloneImage()的區別

#include <stdio.h>
#include <time.h>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>網絡

int main( int argc, char** argv )
{
//聲明IplImage指針
  IplImage* pFrame = NULL;     //pFrame爲視頻截取的一幀
  IplImage* pFrame1 = NULL;      //第一幀
  IplImage* pFrame2 = NULL;//第二幀
  IplImage* pFrame3 = NULL;//第三幀ide

  IplImage* pFrImg = NULL;     //pFrImg爲當前幀的灰度圖
  IplImage* pBkImg = NULL;     //pBkImg爲當前背景的灰度圖
  IplImage* pBkImgTran = NULL;//pBkImgTran爲當前背景處理過的圖像
  IplImage* pFrImgTran = NULL;//pFrImgTran爲當前背景處理過的圖像函數

  CvMat* pFrameMat = NULL;     //pFrameMat爲當前灰度矩陣
  CvMat* pFrMat = NULL;      //pFrMat爲當前前景圖矩陣,當前幀減去背景圖
  CvMat* bg1 = NULL;
  CvMat* bg2 = NULL;
  CvMat* bg3 = NULL;
  CvMat* pFrMatB = NULL;     //pFrMatB爲二值化(0,1)的前景圖
  CvMat* pBkMat = NULL;
  CvMat* pZeroMat = NULL;               //用於計算bg1 - bg2 的值
  CvMat* pZeroMatB = NULL;//用於計算 pZeroMat閾值化後來判斷有多少個零的臨時矩陣ui

  CvCapture* pCapture = NULL;指針

  int warningNum = 0;      //檢測到有異物入侵的次數
  int nFrmNum = 0;//幀計數
  int status = 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(argv[1])))
      {
        fprintf(stderr, "Can not open video file %s\n", argv[1]);
        return -2;
      }it


//開始計時
  time_t start,end;
  time(&start);        //time() 返回從1970年1月1號00:00:00開始以來到如今的秒數(有10爲數字)。
  printf("%d\n",start);
//逐幀讀取視頻
  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);
          pBkImgTran = cvCreateImage(cvSize(pFrame->width,pFrame->height), IPL_DEPTH_8U,1);
          pFrImgTran = cvCreateImage(cvSize(pFrame->width,pFrame->height), IPL_DEPTH_8U,1);

          pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
          pZeroMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
          pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
          pFrMatB = cvCreateMat(pFrame->height, pFrame->width, CV_8UC1);
          pZeroMatB = cvCreateMat(pFrame->height, pFrame->width, CV_8UC1);
          pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
          cvZero(pZeroMat);
          //轉化成單通道圖像再處理
          cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);
          //轉換爲矩陣
          cvConvert(pFrImg, pBkMat);
        }
      else /* 不是第一幀的就這樣處理 */
        {
          //pFrImg爲當前幀的灰度圖
          cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);

          //pFrameMat爲當前灰度矩陣
          cvConvert(pFrImg, pFrameMat);

          //pFrMat爲前景圖矩陣,當前幀減去背景圖
          cvAbsDiff(pFrameMat, pBkMat, pFrMat);

          //pFrMatB爲二值化(0,1)的前景圖
          cvThreshold(pFrMat,pFrMatB, 60, 1, CV_THRESH_BINARY);

          //將圖像矩陣轉化爲圖像格式,用以顯示
          cvConvert(pBkMat, pBkImgTran);   
          cvConvert(pFrMat, pFrImgTran);  

          //顯示圖像
          cvShowImage("video", pFrame);
          cvShowImage("background", pBkImgTran); //顯示背景
          cvShowImage("foreground", pFrImgTran); //顯示前景


          //以上是每抓取一幀都要作的工做,下面進行危險檢測
          if (cvCountNonZero(pFrMatB) > 10000 && status == 0) //表示是第一幀的異物大於1W個像數點
            {/* 則須要將當前幀存儲爲第一幀 */
              pFrame1 = cvCloneImage(pFrame);
              bg1 = cvCloneMat(pFrMat);
              status = 1;      //繼續採集第2幀
            }
          else if (cvCountNonZero(pFrMatB) < 10000 && status == 1) // 表示第一幀的異物大於1W個像數點,而第二幀沒有,則報警
            {
              printf("NO.%d warning!!!!\n\n",warningNum++);
              status = 0;
            }
          else if (cvCountNonZero(pFrMatB) > 10000 && status == 1)// 表示第一幀和第二幀的異物都大於1W個像數點
            {
              pFrame2 = cvCloneImage(pFrame);
              bg2 = cvCloneMat(pFrMat);

              cvAbsDiff(bg1, bg2, pZeroMat);
              cvThreshold(pZeroMat,pZeroMatB, 20, 1, CV_THRESH_BINARY);
              if (cvCountNonZero(pZeroMatB) > 3000 ) //表示他們不連續,這樣的話要報警
                {
                  printf("NO.%d warning!!!!\n\n",warningNum++);
                  status = 0;
                }
              else
                {
                  status = 2;                   //繼續採集第3幀
                }
            }
          else if (cvCountNonZero(pFrMatB) < 10000 && status == 2)//表示第一幀和第二幀的異物都大於1W個像數點,而第三幀沒有
            {
              //報警
              printf("NO.%d warning!!!!\n\n",warningNum++);
              status = 0;
            }
          else if (cvCountNonZero(pFrMatB) > 10000 && status == 2)//表示連續3幀的異物都大於1W個像數點
            {
              pFrame3 = cvCloneImage(pFrame);
              bg3 = cvCloneMat(pFrMat);

              cvAbsDiff(bg2, bg3, pZeroMat);
              cvThreshold(pZeroMat,pZeroMatB, 20, 1, CV_THRESH_BINARY);
              if (cvCountNonZero(pZeroMatB) > 3000 ) //表示他們不連續,這樣的話要報警
                {
                  printf("NO.%d warning!!!!\n\n",warningNum++);
                }
              else //表示bg2,bg3連續
                {
                  cvReleaseMat(&pBkMat);
                  pBkMat = cvCloneMat(pFrameMat); //更新背景
                }
                status = 0;                //進入下一次採集過程
            }

          //若是有按鍵事件,則跳出循環
          //此等待也爲cvShowImage函數提供時間完成顯示
          //等待時間能夠根據CPU速度調整
          if ( cvWaitKey(2) >= 0 )
            break;
        }/* The End of the else */
    }/* The End of th while */

//銷燬窗口
    cvDestroyWindow("video");
    cvDestroyWindow("background");
    cvDestroyWindow("foreground");

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

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

    cvReleaseCapture(&pCapture);

  return 0;
}

 

 

所研究的運動檢測和背景更新方法實現的步驟以下:

(1)開闢靜態內存,對圖像進行初始化準備採集;

(2)採集圖像,定義參數k,做爲圖像序列計數。採集第1幅圖像時,則根據第一幀的大小信息進行矩陣、圖像的初始化,而且將第一幀圖像進行灰度化處理,並轉化爲矩陣,做爲背景圖像及矩陣;若是k不等於1則把當前幀進行灰度化處理,並轉化爲矩陣,做爲當前幀的圖像及矩陣。用當前幀的圖像矩陣和背景幀的圖像矩陣作差算出前景圖矩陣並對其進行二值化以便計算它與背景幀差異較大的像素個數,也就是二值化後零的個數。

當第一幀的異物大於1W個像數點則須要將當前幀存儲爲第一幀,而且將系統的狀態轉爲1——採集第二幀;

第一幀和第二幀的異物都大於1W個像數點時,將當前幀存儲爲第二幀,經過判斷第一幀和第二幀的差值來肯定兩幀是否連續,若連續則將系統狀態轉爲2——採集第三幀,若不連續則報警,並把系統狀態轉爲0——採集背景幀;

當第一幀和第二幀的異物都大於1W個像數點,而第三幀沒有時則報警;

若連續3幀的異物都大於1W個像數點時,將當前幀存儲爲第三幀,經過判斷第二幀和第三幀的差值來肯定兩幀是否連續,若連續則將更新背景,若不連續則報警。而後把系統狀態轉爲0——採集背景幀。

注意其中有一個0-1-2-0....的狀態機。

cvCopy的原型是:
void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask=NULL );
在使用這個函數以前,你必須用cvCreateImage()一類的函數先開一段內存,而後傳遞給dst。cvCopy會把src中的數據複製到dst的內存中。

cvCloneImage的原型是:
IplImage* cvCloneImage( const IplImage* image );
在使用函數以前,不用開闢內存。該函數會本身開一段內存,而後複製好image裏面的數據,而後把這段內存中的數據返回給你。

clone是把全部的都複製過來,也就是說不論你是否設置Roi,Coi等影響copy的參數,clone都會原封不動的克隆過來。 copy就不同,只會複製ROI區域等。

相關文章
相關標籤/搜索