Opencv 2フレーム差分法により、動きターゲットと抽出プロファイルを検出する。


Opencv学習の二フレーム差分運動目標検出とアウトライン抽出は、以下の通りです。
コードはネットから抜粋して勉強しています。注釈をたくさんつけています。まるで本を読みながらメモを取るように、満足できるような感じがします。Let's do this

#include "highgui.h"
#include "cv.h"
#include "stdio.h"
#include <time.h>
#include <math.h>
#include <string.h>

const double MHI_DURATION=0.1;//           0.1s
const double MAX_TIME_DELTA=0.5//      0.5s
const double MIN_TIME_DELTA=0.05;//      0.05s
const int N=3;
const int CONTOUR_MAX_AERA=16;

/*            */
IplImage **buf=0;
int last=0;
/*    */
IplImage* mhi=0;//      mhi

CvConnectedComp* cur_comp,mincomp;
/*typedef struct CvConnectedComp 
 {
 double area; //     
 CvScalar value; //        
 CvRect rect; //          
 CvSeq * contour; //          
 };*/
/*         */
CvMemStorage* storage;
/*        ,     ,   0    , x、y  */
CvPoint pt[4];

/*      */
int nCurFrameIndex=0;

/*               */
/*img-     ;dst-    */
void update(IplImage *img,IplImage *dst,int diff_threshold)
{
 /*      ,    */
 double timestamp=clock()/100;
 /*          ,   size */
 CvSize size=cvSize(img->width,img->height);
 /*           */
 int i,idx1,idx2;
 /*            ,          nimg */
 IplImage* nimg;
 /*       - -!*/
 IplImage* pyr=cvCreateImage(cvSize((size.width&-2)/2,(size.height&-2)/2),8,1);
 /*         */
 CvMemStorage* stor;
 /*          seq*/
 CvSeq* seq;

 /*         */
 /*        ,                    (           ?)*/
 if(!mhi||mhi->width!=size.width||mhi->height!=size.height)
 {
 /*  buf     ,  buf    */
 if(buf==0)
 {
  /*N=3*/
  buf=(IplImage**)malloc(N*sizeof(buf[0]));
  /*   s                       ch   ASCII ,            :memset(void *s,char ch,unsigned n)。        buf        */
  memset(buf,0,N*sizeof(buf[0]));
 }
 /* buf      ,  buf  */
 for(i=0;i<N;i++)
 {
  cvReleaseImage(&buf[i]);
  buf[i]=cvCreateImage(size,IPL_DEPTH_8U,1);
  cvZero(buf[i]);
 }
 /*           mhi*/
 cvReleaseImage(&mhi);
 mhi=cvCreateImage(size,IPL_DEPTH_32F,1);
 cvZero(mhi);
 }

 /*              ,  buf     */
 cvCvtColor(img,buf[last],CV_BGR2GRAY);
 /*         , buf[idx1]         ,buf[idx2]     */
 idx1=last;
 idx2=(last+1)%N;
 last=idx2;
 /*   ,   cvAbsDiff            */
 nimg=buf[idx2];
 cvAbsDiff(buf[idx1],buf[idx2],nimg);
 /*    ,         */
 cvThreshold(nimg,nimg,50,255,CV_THRESH_BINARY);
 /*                */
 cvUpdateMotionHistory(nimg,mhi,timestamp,MHI_DURATION);
 cvConvert(mhi,dst);
 /*    ,      
   cvPyrDown  Gaussian              ,    ,           
   cvDialate     ,          
   cvPyrUp  Gaussian              ,    ,         */
 cvSmooth(dst,dst,CV_MEDIAN,3,0,0,0);
 cvPyrDown(dst,pyr,CV_GAUSSIAN_5x5);
 cvDilate(pyr,pyr,0,1);
 cvPyrUp(pyr,dst,CV_GAUSSIAN_5x5);

 /*    */
 stor=cvCreateMemStorage(0);
 seq=cvCreateSeq(CV_SEQ_ELTYPE_POINT,//                  
 sizeof(CvSeq),//            ;       sizeof(CvSeq)
 /*           ,    。           ( seq_flags  )   ,  ,        ,     CV_SEQ_ELTYPE_POINT     ,  elem_size     sizeof(CvPoint)。
*/
 sizeof(CvPoint),
 stor);//               

 /*      */
 cvFindContours(dst,//     
 stor,//       
 &seq,//    ,          。
 sizeof(CvContour),
 CV_RETR_EXTERNAL,//mode:EXTERNAL――        
 CV_CHAIN_APPROX_NONE,//       ,       - -
 cvPoint(0,0));

 /*   CONTOUR        */
 /*  seq  */
 for(;seq;seq=seq->h_next)
 {
 /*         ,  rect    x、y      ,      */
 CvRect r=((CvContour*)cont)->rect;//               ?
 /*             ,  ;         */
 if((r.height*r.width>CONTOUR_MAX_AERA)&&(r.height*r.width>2560))
 {
  /*cvRectangle           ,    */
  cvRectangle(img,//  
  cvPoint(r.x,r.y),//    
  cvPoint(r.x + r.width, r.y + r.height),//     
  CV_RGB(255,0,0),//    
  1,//      
  CV_AA,//    
  0); //         
 }
 }

 /*      ,    */
 cvReleaseMemStorage(&stor);
 cvReleaseImage(&pyr);
}

/    ,   /
int main(int argc,char**argv)
{
 IplImage *motion=0;
 CvCapture *capture=0;
 /*     */
 capture=cvCaptureFromFile("D:\\  \\01.mp4");
 if(capture)
 {
 cvNamedWindow("Motion",1);
 for(;;)
 {
  IplImage *image;
  /*  cvGrabFrame     */
  if(!cvGrabFrame(capture))
  break;
  /*  cvRetrieveFrame     cvGrabFrame    */
  image=cvRetrieveFrame(capture);
  if(image)
  {
  /*  motion     ,       。   motion   */
  if(!motion)
  {
   motion=cvCreateImage(cvSize(image->width,image->height),8,1);
   cvZero(motion);
   /*                  */
   motion->origin=image->origin;
  }
  }
  /*        ,  motion   ,     */
  update(image,motion,10);
  /*        */
  cvShowImage("Motion",image);

  /*10ms           ,   */
  if(cvWaitKey(10)>=0)
  break;
 }
 /*     for       ,                     */
 cvReleaseCapture(&capture);
 cvDestroyWindow("Motion");
 }
 return 0;
}
テストを経て、このプログラムは正常に検出され、赤い枠で移動する車両と歩行者を囲むことができます。
改善すべきところはあります。
①映像の処理速度が遅いため、映像の処理速度は動画の正常再生速度の2分の1しかない。
②歩行者の測定に対して、赤い枠が不安定であり、歩行者全体を枠ではなく、人のいくつかの異なる部分をそれぞれ枠で囲んでいることが多いorz。
③二つの物体が少し重なったら、重なりの物体を一つの物体として囲みます。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。