Opencv二帧差法检测运动目标与提取轮廓

Opencv学习之二帧差法运动目标检测与轮廓提取 ,供大家参考,具体内容如下

代码是从网上摘抄学习的,加了好多注释,感觉就像边看书边做笔记一样,给人以满足的享受。Let's do this!

#include "highgui.h"
#include "cv.h"
#include "stdio.h"
#include 
#include 
#include 

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;ih_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;
}

经过测试,这个程序能够成功检测并用红色方框圈出移动的车辆和行人。

待改进的地方有:

①视频处理速度慢,导致视频处理速度只有视频正常播放速度的二分之一。

②对于行人的检测,画出的红色方框不稳定,不是将整个行人框出,经常会分别框出一个人的几个不同部位orz。

③当两个物体稍有重叠时,会将重叠物体当作一个物体圈出。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

你可能感兴趣的:(Opencv二帧差法检测运动目标与提取轮廓)