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

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

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

待改进的地方有:

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

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持<计算机技术网(www.ctvol.com)!!>。

—-想了解Opencv二帧差法检测运动目标与提取轮廓分享!全部内容且更多的C语言教程关注<计算机技术网(www.ctvol.com)!!>

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/484285.html

(0)
上一篇 2020年11月10日
下一篇 2020年11月10日

精彩推荐