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。

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

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

(0)

相关推荐

  • C语言实现opencv提取直线、轮廓及ROI实例详解

    一.Canny检测轮廓 在上一篇文章中有提到sobel边缘检测,并重写了soble的C++代码让其与matlab中算法效果一致,而soble边缘检测是基于单一阈值的,我们不能兼顾到低阈值的丰富边缘和高阈值时的边缘缺失这两个问题.而canny算子则很好的弥补了这一不足,从目前看来,canny边缘检测在做图像轮廓提取方面是最优秀的边缘检测算法. canny边缘检测采用双阈值值法,高阈值用来检测图像中重要的.显著的线条.轮廓等,而低阈值用来保证不丢失细节部分,低阈值检测出来的边缘更丰富,但是很多边缘并

  • Opencv实现轮廓提取功能

    轮廓:一个轮廓代表一系列的点(像素),这一系列的点构成一个有序的点集,所以可以把一个轮廓理解为一个有序的点集. 在opencv中,提供了一个函数返回一个有序的点集或者有序的点集的集合(指多个有序的点集),函数findContour是从二值图像中来计算轮廓的,一般使用Canny()函数处理后的图像,因为这样的图像含有边缘像素. 寻找轮廓的API函数: findContours(image,vector<vector<Point>> contours,vector<Vec4i&g

  • opencv3/C++轮廓的提取与筛选方式

    轮廓提取 findContours发现轮廓 findContours( InputOutputArray binImg, //输入8bit图像,0值像素值不变,非0的像素看成1:(变为二值图像) OutputArrayOfArrays contours,//输出找到的轮廓对象 OutputArray, hierachy// 图像的拓扑结构 int mode, //轮廓返回的模式(RETR_TREE等) int method,//发现方法(CHAIN_APPROX_SIMPLE等) Point o

  • opencv提取外部轮廓并在外部加矩形框

    这段时间一直在用opencv搞图像处理的问题,发现虽然可调用的函数多,但是直接找相应代码还是很困难,就行寻找连通域,并在连通域外侧加框,对于习惯使用Mat矩形操作的我,真心感觉代码少之又少,为防止以后自己还会用到,特在此记录一下. 要对下面的图像进行字符的边缘检测. 程序中具体的步骤为: (1)灰度化.二值化 (2)图像膨胀 (3)检测膨胀图像的边缘并叫外矩形框 实现代码如下: #include "stdafx.h" #include "stdio.h" #incl

  • Opencv处理图像之轮廓提取

    本文实例为大家分享了Opencv处理图像之轮廓提取,使用cvfindContours对图像进行轮廓检测,供大家参考,具体内容如下 #include<iostream> #include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> int main() { IplImage* img = cvLoadImage("E:\\test.bmp",0); IplImage* img

  • opencv提取轮廓大于某个阈值的图像

    本文实例为大家分享了opencv提取轮廓大于某个阈值的图像,供大家参考,具体内容如下 #include "stdafx.h" #include "cv.h" #include "highgui.h" #include "stdio.h" #include"core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include &quo

  • Opencv提取连通区域轮廓的方法

    本文实例为大家分享了Opencv提取连通区域轮廓的具体代码,供大家参考,具体内容如下 在进行图像分割后,可能需要对感兴趣的目标区域进行提取,比较常用的方法是计算轮廓. 通过轮廓可以获得目标的一些信息: (1)目标位置 (2)目标大小(即面积) (3)目标形状(轮廓矩) 当然,轮廓不一定代表希望目标区域,阈值分割时可能造成一部分信息丢失,因此可以计算轮廓的质心坐标,再进行漫水填充. 程序中有寻找质心+填充,但效果不好,因此就不放填充后的图了. 实验结果: #include "opencv2/img

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

    Opencv学习之二帧差法运动目标检测与轮廓提取 ,供大家参考,具体内容如下 代码是从网上摘抄学习的,加了好多注释,感觉就像边看书边做笔记一样,给人以满足的享受.Let's do this! #include "highgui.h" #include "cv.h" #include "stdio.h" #include <time.h> #include <math.h> #include <string.h>

  • OpenCV实现帧差法检测运动目标

    今天的目标是用OpenCV实现对运动目标的检测,这里选用三帧帧差法.代码如下: #include <opencv2/opencv.hpp> #include <cv.h> #include <highgui.h> #include <stdio.h> #include <ctype.h> double Threshold_index=0; const int CONTOUR_MAX_AERA = 200; void trackbar(int po

  • Qt+OpenCV利用帧差法实现车辆识别

    目录 一.目标 二.使用Qt界面 三.代码实现 一.目标 Qt界面实现 点击 线程启动按钮播放视频 左边界面显示原视频 右边界面显示车辆识别视频 结果展示如下: 初始界面 点击线程启动后,即可车辆识别 二.使用Qt界面 设计好界面后最好先保存 对按钮设置槽函数 三.代码实现 难点在于:线程同步问题 需要使用到connect函数中的第五个参数[第五个参数 具体说明如下] 1 AutoConnection 为默认参数,由发送信号决定,如果发送信号和接受信号是同一个线程,则调用DirectConnec

  • opencv实现三帧差法解析

    今天和大家谈谈三帧差法来实现运动目标检测吧,其中运动检测画框实现追踪方法多种多样,大家可以自行百度,后面我也会一一实现,今天我先给大家玩玩三帧差法吧::::(注释非常清楚哦,程序也极其简单的) 帧差法是最为常用的运动目标检测和分割方法之一,基本原理就是在图像序列相邻两帧或三帧间采用基于像素的时间差分通过闭值化来提取出图像中的运动区域.首先,将相邻帧图像对应像素值相减得到差分图像,然后对差分图像二值化,在环境亮度变化不大的情况下,如果对应像素值变化小于事先确定的阂值时,可以认为此处为背景像素:如果

  • python+opencv实现移动侦测(帧差法)

    本文实例为大家分享了python+opencv实现移动侦测的具体代码,供大家参考,具体内容如下 1.帧差法原理 移动侦测即是根据视频每帧或者几帧之间像素的差异,对差异值设置阈值,筛选大于阈值的像素点,做掩模图即可选出视频中存在变化的桢.帧差法较为简单的视频中物体移动侦测,帧差法分为:单帧差.两桢差.和三桢差.随着帧数的增加是防止检测结果的重影. 2.算法思路 文章以截取视频为例进行单帧差法移动侦测 3.python实现代码 def threh(video,save_video,thres1,ar

  • opencv帧差法找出相差大的图像

    本文实例为大家分享了opencv帧差法找出相差大的图像,供大家参考,具体内容如下 #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <iostream> #include <fstream> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp>

  • OpenCV实现帧间差分法详解

    本文实例为大家分享了OpenCV实现帧间差分法的具体方法,供大家参考,具体内容如下 一.基本概念 基于视频的车辆检测算法种类很多:光流法检测,帧差法,背景消除法(其中包括:直方图法,平均值法,单分布和混合高斯分布背景模型,Kalman滤波等),边缘检测法,运动矢量检测法...下面分享的是运动目标检测算法中最基本的方法-帧间差分法. 相邻帧间图像差分思想:检测出了相邻两帧图像中发生变化的区域.该方法是用图像序列中的连续两帧图像进行差分,然后二值化该灰度差分图像来提取运动信息.由帧间变化区域检测分割

  • C++使用opencv处理两张图片的帧差

    本文为大家分享了使用opencv处理两张图片帧差的具体代码,供大家参考,具体内容如下 这个程序是两张图片做帧差,用C++实现的,把不同的地方用框框起来,仔细读一下程序,应该还是蛮简单的哈哈,opencv处理图片的基础. opencv配置不用我说了吧,源码cmake编译,然后导入vs即可. #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int mai

  • Python OpenCV学习之特征点检测与匹配详解

    目录 背景 一.Harris角点 二.Shi-Tomasi角点检测 三.SIFT关键点 四.SIFT描述子 五.SURF 六.ORB 七.暴力特征匹配(BF) 八.FLANN特征匹配 九.图像查找 总结 背景 提取图像的特征点是图像领域中的关键任务,不管在传统还是在深度学习的领域中,特征代表着图像的信息,对于分类.检测任务都是至关重要的: 特征点应用的一些场景: 图像搜索:以图搜图(电商.教育领域) 图像拼接:全景拍摄(关联图像拼接) 拼图游戏:游戏领域 一.Harris角点 哈里斯角点检测主要

  • Python基于OpenCV实现视频的人脸检测

    本文实例为大家分享了基于OpenCV实现视频的人脸检测具体代码,供大家参考,具体内容如下 前提条件 1.摄像头 2.已安装Python和OpenCV3 代码 import cv2 import sys import logging as log import datetime as dt from time import sleep cascPath = "haarcascade_frontalface_default.xml" faceCascade = cv2.CascadeCla

随机推荐