Opencv之二帧差法运动目标检测与轮廓提取
来源:互联网 发布:java post 二进制 编辑:程序博客网 时间:2024/06/05 02:34
Opencv学习之——二帧差法运动目标检测与轮廓提取
这是我的第一篇CSDN博文。
代码是从网上摘抄学习的,加了好多注释,感觉就像边看书边做笔记一样,给人以满足的享受。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.1sconst double MAX_TIME_DELTA=0.5//最大时间增量0.5sconst double MIN_TIME_DELTA=0.05;//最小时间增量0.05sconst int N=3;const int CONTOUR_MAX_AERA=16;/*做帧差时要用到的图像缓冲*/IplImage **buf=0;int last=0;/*临时图像*/IplImage* mhi=0;//运动历史图像mhiCvConnectedComp* 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。
③当两个物体稍有重叠时,会将重叠物体当作一个物体圈出。
1 0
- Opencv之二帧差法运动目标检测与轮廓提取
- OpenCV学习之寻找轮廓实现视频流的运动目标检测
- 一种基于轮廓的运动目标检测与跟踪算法
- OpenCV之帧差法检测运动目标
- OpenCV运动目标检测
- opencv 运动目标检测
- 利用OpenCV提取目标轮廓
- 【opencv】基于opencv实现运动目标检测之帧差法
- OpenCV之轮廓检测
- opencv程序十七:运动目标检测之背景减除法
- opencv程序十八:运动目标检测之两帧差分法
- opencv程序十八:运动目标检测之三帧差分法
- OpenCV之基于GMM的运动目标检测
- opencv轮廓提取与轮廓拟合
- opencv之图像轮廓提取
- 基于运动目标轮廓的帧差法背景提取
- OpenCV成长之路:直线、轮廓的提取与描述
- OpenCV成长之路:直线、轮廓的提取与描述
- 【HDU 1863 畅通工程】
- fragment里套viewpager然后viewpager里再套fragment
- SVN系列——操作入门
- ListView控件入门
- HDU5536 Chip Factory(01字典树)
- Opencv之二帧差法运动目标检测与轮廓提取
- Java: Random.nextInt() 和Math.random()的区别
- 现阶段对数据库中知识发现KDD、数据挖掘、集成学习、深度学习、机器学习、人工智能、统计学、大数据、云计算的个人理解:
- 给自己看的NIM
- Js实现京东大的轮播图及相关动画效果
- Android Studio – Cannot resolve symbol ‘R’
- catalan数
- $_SERVER详解
- POJ-1260 Pearls (dp)