opencv视频处理和检测学习总结

基于opencv的视频处理——基础数据结构



   在一个封装的还算比较好的库中,一般都不会直接采用那些基本的数据结构像char, int 之类,一是


不具有可读性,二是不方便修改移植。通常是通过typedef 来改变。下面介绍opencv中基础数据结构。
     先介绍点,CvPoint, CvPoint2D32f, CvPoint3D32f,下面给出原型。


二维坐标系下的点,类型为整型 
typedef struct CvPoint
{
  int x; /* X坐标, 通常以0为基点 */
  int y; /* y坐标, 通常以0为基点 */
}
CvPoint;

二维坐标下的点,类型为浮点 
typedef struct CvPoint2D32f
{
  float x; /* X坐标, 通常以0为基点*/
  float y; /* Y坐标, 通常以0为基点*/
}
CvPoint2D32f;


三维坐标下的点,类型为浮点 
typedef struct CvPoint3D32f
{
  float x; /* x-坐标, 通常基于0 */
  float y; /* y-坐标, 通常基于0 */
  float z; /* z-坐标, 通常基于0 */
}
CvPoint3D32f;
    
    大家很明显可以看出来,这些点还是由基本的数据类型构成的。下面再顺便提一下相应类型的构造函数


CvPoint 型
inline CvPoint cvPoint( int x, int y );

CvPoint2D32f型
inline CvPoint2D32f cvPoint2D32f( double x, double y );

CvPoint3D32f型
inline CvPoint3D32f cvPoint3D32f( double x, double y, double z );


下面再介绍几个简单的

CvSize
矩形框大小,以像素为精度

typedef struct CvSize
{
  int width; /* 矩形宽 */
  int height; /* 矩形高 */
}
CvSize;

CvSize2D32f

以亚像素精度标量矩形框大小

typedef struct CvSize2D32f
{
   float width; /* 矩形宽 */
   float height; /* 矩形高 */
}
CvSize2D32f;

CvRect

矩形框的偏移和大小


typedef struct CvRect
{
  int x; /* 方形的最左角的x-坐标 */
  int y; /* 方形的最上或者最下角的y-坐标 */
  int width; /* 宽 */
  int height; /* 高 */
}
CvRect;

CvScalar

可存放在1-,2-,3-,4-TUPLE类型的捆绑数据的容器

typedef struct CvScalar
{
  double val[4]
}
CvScalar;
    
    具体用法会在后续文章中说到,
    现在介绍点重要的

IplImage

IPL 图像头

typedef struct _IplImage
    {
        int nSize; /* IplImage大小,=sizeof(IplImage)*/
        int ID; /* 版本 (=0)*/
        int nChannels; /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */
        int alphaChannel; /* 被OpenCV忽略 */
        int depth; /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,IPL_DEPTH_16S, 

IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */
        char colorModel[4]; /* 被OpenCV忽略 */
        char channelSeq[4]; /* 被OpenCV忽略 */
        int dataOrder; /* 0 - 交叉存取颜色通道,对三通道RGB图像,像素存储顺序为BGR BGR BGR 

... BGR;1 - 分开的颜色通道,对三通道RGB图像,像素存储顺序为RRR...R GGG...G BBB...B。

cvCreateImage只能创建交叉存取图像 */
        int origin; /* 0 - 顶—左结构, 1 - 底—左结构 (Windows bitmaps 风格) */
        int align; /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */
        int width; /* 图像宽像素数 */
        int height; /* 图像高像素数*/
        struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理 */
        struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */
        void *imageId; /* 同上*/
        struct _IplTileInfo *tileInfo; /*同上*/
        int imageSize; /* 图像数据大小(在交叉存取格式下imageSize=image->height*image-


>widthStep),单位字节*/
        char *imageData; /* 指向排列的图像数据 */
        int widthStep; /* 排列的图像行大小,以字节为单位 */
        int BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */
        int BorderConst[4]; /* 同上 */
        char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */
    }
    IplImage;


IplImage结构来自于 Intel Image Processing Library(是其本身所具有的)。OpenCV 只支持其中的一个子集:


    * alphaChannel 在OpenCV中被忽略。
    * colorModel 和channelSeq 被OpenCV忽略。OpenCV颜色转换的唯一函数 cvCvtColor把原图像的颜

色空间的目标图像的颜色空间作为一个参数。
    * dataOrder 必须是IPL_DATA_ORDER_PIXEL (颜色通道是交叉存取),然而平面图像的被选择通道可

以被处理,就像COI(感兴趣的通道)被设置过一样。
    * align 是被OpenCV忽略的,而用 widthStep 去访问后继的图像行。
    * 不支持maskROI 。处理MASK的函数把他当作一个分离的参数。MASK在 OpenCV 里是 8-bit,然而在 

IPL他是 1-bit。
    * tileInfo 不支持。
    * BorderMode和BorderConst是不支持的。每个 OpenCV 函数处理像素的邻近的像素,通常使用单一的固定代码边际模式。 


除了上述限制,OpenCV处理ROI有不同的要求。要求原图像和目标图像的尺寸或 ROI的尺寸必须(根据不同的操作,

例如cvPyrDown 目标图像的宽(高)必须等于原图像的宽(高)除以2 ±1)精确匹配,而IPL

处理交叉区域,如图像的大小或ROI大小可能是完全独立的。

    这是一个很重要的数据结构,处理图像时传入的就是IplImage *Img. 对于初学者来说,首先要关注
的是成员width, height, widthstep和imageDate,比如说做一个遍历的话

int i, j;
char *data = NULL;
for(i=0; iwidth; i++)
{
   for(j=0; jheight; j++)
  {
       data = Img->imageData + i*widthStep + j;  //取图片相应点的数据,要知道图片的存储是以

一个矩阵的形式
       statement
  }
}

最后还有一个比较重要的

CvMat

多通道矩阵

typedef struct CvMat
{
  int type; /* CvMat 标识 (CV_MAT_MAGIC_VAL), 元素类型和标记 */
  int step; /* 以字节为单位的行数据长度*/
  int* refcount; /* 数据引用计数 */
  union
  {
    uchar* ptr;
    short* s;
    int* i;
    float* fl;
    double* db;
  } data; /* data 指针 */
  #ifdef __cplusplus
  union
   {
     int rows;
     int height;
   };
  union
   {
     int cols;
     int width;
   };
  #else
   int rows; /* 行数 */
   int cols; /* 列数*/
  #endif
} CvMat;

========

OpenCV成长之路 视频的处理

视频中包含的信息量要远远大于图片,对视频的处理分析也越来越成为计算机视觉的主流,而本质上视频
是由一帧帧的图像组成,所以视频处理最终还是要归结于图像处理,但在视频处理中,有更多的时间维的
信息可以利用。本文主要介绍OpenCV在处理视频时的一些基本函数。

一、视频帧的读取

OpenCV为视频的读入提供了一个类VideoCapture,下面我们说明一下类的几个重要的方法:

1,打开一段视频或默认的摄像头

有两种方法,一种是在定义类的时候,一种是用open()方法。

VideoCapture capture("../video.avi"); 
// 方法1
capture.open("../video.avi"); 
// 方法2
如果把文件名换为设置ID,则可打开摄像头,默认摄像头为0。

2,获取视频帧

获取视频帧可以有多种方法

// 方法一
capture.read(frame);
// 方法二
capture.grab();
capture.retrieve(frame);
// 方法三
capture>>frame;
3,获取视频的参数

一个视频有很多参数,比如:帧率、总帧数、尺寸、格式等,VideoCapture的get方法可以获取大量这些参数。


double rate=capture.get(CV_CAP_PROP_FPS); 
// 获取
long nFrame=static_cast(capture.get(CV_CAP_PROP_FRAME_COUNT)); 
// 获取总帧数
更加相关的参数可以参考手册。


4,设置视频帧的读取位置


VideoCapture类的set方法可以允许我们取出视频中某个位置的帧,它有一些参数,可以按时间,也可以


按帧号,还可以按视频长短的比例。


// 第100帧
double position=100.0;
capture.set(CV_CAP_PROP_POS_FRAMES,position);
// 第1e6毫秒
double position=1e6;
capture.set(CV_CAP_PROP_POS_MSEC,position);
// 视频1/2位置
double position=0.5;
capture.set(CV_CAP_PROP_POS_AVI_RATIO,position);
当然,set方法仅用于取视频帧的位置,还可以设置视频的帧率、亮度。


下面是一个将canny边缘检测应用于视频的程序:


int main()
{
    VideoCapture capture("../track.avi"); 
    if(!capture.isOpened())
        return 1;
    double rate=capture.get(CV_CAP_PROP_FPS);
    bool stop(false);
    Mat frame;
 
    namedWindow("Canny Video");
    int delay=1000/rate;
 
    while(!stop)
    {
        if(!capture.read(frame))
            break;
        Mat result;
        Canny(frame,result,100,200);
        threshold(result,result,128,255,THRESH_BINARY);
        imshow("Canny Video",result);
 
        if(waitKey(delay)>=0)
            stop=true;
    }
    capture.release();
}
二、视频的写入


视频的写入与读取类似,OpenCV中是使用VideoWriter类来实现的,这个类有几个方法,都很简单。除了

构造函数外,提供了open、IsOpen、write、和重载操作符<<

值得注意的是OpenCV里对视频的编码解码等支持并不是很良好,所以不要希望用这个类去实现摄像头图像

的获取与转码,有兴趣的可以参考FFmpeg库。

VideoWriter::VideoWriter(const string& filename, int fourcc, double fps, Size frameSize, 
bool isColor=true);
bool VideoWriter::open(const string& filename, int fourcc, double fps, Size frameSize, bool 
isColor=true);
上面是类的构造函数与open方法,它们的参数相同,首先指定文件名,第二个参数是编码格式,OpenCV里
提供了很多种的编码格式,如CV_FOURCC(‘P’,’I’,’M’,’1’)是MPEG-1格式,CV_FOURCC(‘M’,’
G’,’P’,’G’)为motion-jpeg格式。


第三个参数为帧率,第4个参数为视频的尺寸大小。

VideoCapture capture("../track.avi"); 
double rate=capture.get(CV_CAP_PROP_FPS);
Size videoSize(capture.get(CV_CAP_PROP_FRAME_WIDTH),
               capture.get(CV_CAP_PROP_FRAME_HEIGHT));
VideoWriter writer;
writer.open("../result.avi",CV_FOURCC('P','I','M','1'),rate, videoSize);
Mat frame;
capture>>frame;
writer<  
========

OpenCV视频处理相关编程总结


     高级语言自带的播放视频的API多是把视频当成一个整体的文件进行读取,但是实际上视频文件时由

图片按帧排列而成,中间加上时间戳,普通的这种视频读取方法不利用按帧进行图像处理,然后适时播放

。譬如我们要写一个程序,detect这个视频中出现的某一个人,当这个人出现的时候,在视频中把这个人

的位置画出来。普通的视频读取方法无法完成这一功能。幸运的是,作为一个强大的图像处理工具包,

OpenCV提供了一套按帧读取的开放API,本文主要介绍OpenCV在视频处理中常用的一些方法。

(1)按帧读取视频的例子程序
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include

using namespace std;
using namespace cv;

int main()
{
     // Open the video file
     cv::VideoCapture capture("F:/Output.avi");
     // check if video successfully opened
     if (!capture.isOpened())
          return 1;
     // Get the frame rate
     double rate= capture.get(CV_CAP_PROP_FPS);
     bool stop(false);
     cv::Mat frame; // current video frame
     cv::namedWindow("Extracted Frame");
     // Delay between each frame in ms
     // corresponds to video frame rate
     long frames= static_cast(
     capture.get(CV_CAP_PROP_FRAME_COUNT));
     cout<<"rate="<      cout<<"Frames="<
     int delay= 1000/rate;
     cout<<"delay="<      // for all frames in video
     //while (!stop) {
          // // read next frame if any
          // if (!capture.read(frame))
          // break;
          // cv::imshow("Extracted Frame",frame);
          // // introduce a delay
          // // or press key to stop
          // if (cv::waitKey(delay)>=0)
          // stop= true;
     //}
     // Close the video file.
     // Not required since called by destructor

     //read the video by for-loop
     for(int i=1;i      {
          double position= double(i);
          capture.set(CV_CAP_PROP_POS_FRAMES, position);
          capture.read(frame);
          imshow("Extracted Frame",frame);
          waitKey(100);//define the dalay time
     }
     capture.release();
}
(2)在Android编程中使用OpenCV
http://underthehood.blog.51cto.com/2531780/670169

(3).hpp和.h的区别
 hpp实质上就是将.cpp的实现代码混入.h头文件当中,定义与实现都包含在同一文件。

(4)初始化一个矩阵
Mat img=Mat::zeros(53,21,CV_8U);//uchar类型的矩阵

(5)OpenCV与彩色图像
int main()
{
     Mat img=imread("data/test.jpg",1);
     for(int i=0;i      {
          for(int j=0;j           {
               img.ptr>(i,j)->x=0;
               img.ptr>(i,j)->y=0;
               img.ptr>(i,j)->z=255;
          }
     }

     imshow("img",img);
     waitKey(0);

     return 0;
}

========

基于opencv的视频处理——高斯背景建模

   
    运动检测的一般方法
    目前,运动物体检测的问题主要分为两类,摄像机固定和摄像机运动。对于摄像机运动的运动物体检

测问题,比较著名的解决方案是光流法,通过求解偏微分方程求 的图像序列的光流场,从而预测摄像机

的运动状态。对于摄像机固定的情形,当然也可以用光流法,但是由于光流法的复杂性,往往难以实时的

计算,所以我采用高 斯背景模型。因为,在摄像机固定的情况下,背景的变化是缓慢的,而且大都是光

照,风等等的影响,通过对背景建模,对一幅给定图像分离前景和背景,一般来 说,前景就是运动物体

,从而达到运动物体检测的目的。

    在这里我要介绍的是摄像机固定的情况,分离图像的前景和背景,之前的想法很天真----帧差法。就

是取含有目标物体的当前帧去减背景,现在想想真的很天真,这就是没有文化不知道害怕啊!完全没有图

像处理的理论基础啊,完全不顾噪音等的影响。亏我认真的去调程序,可结果让我咋舌阿!

    然后知道了高斯背景建模的处理方法,高斯处理的还不错,我又加了平滑处理,代码如下


#include
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include "cxtypes.h"
//#include "function.h"


#include "cvaux.h"


int cvSumImage(IplImage *Img)
{
    int sum = 0;
    int i, j;
    int width = Img->width;
    int height = Img->height;
    int step = Img->widthStep;
    unsigned char *data = (unsigned char*)Img->imageData;


    for(i=0; i      for(j=0; j      {
         if(data[i*step+j]) 
            sum ++;
     }
    
    return sum;
}


int main(int argc, char **argv)
{
    IplImage* pFrame = NULL;
    IplImage* pFrImg = NULL;
    IplImage* pBkImg = NULL;
    IplImage* Img0 = NULL;
    IplImage* DiffImg = NULL;
    IplImage* SumImg = NULL;
    IplImage* FirstImg = NULL;
    
    CvCapture* pCapture = NULL;
    int nFrmNum = 0;


    cvNamedWindow("video", 1);
    cvNamedWindow("background", 1);
    cvNamedWindow("foreground", 1);
    cvMoveWindow("video", 30, 0);
    cvMoveWindow("background", 360, 0);
    cvMoveWindow("foreground", 690, 0);


    if(argc > 3)
    {
        fprintf(stderr, "Usage: bkgrd [video_file_name\n]");
        return -1;
    }

    if(argc == 2)
     if( !(pCapture = cvCaptureFromFile(argv[1])))
     {
         fprintf(stderr, "Can not open video file %s\n", argv[1]);
         return -1;
     }

    if(argc == 3)
     if( !(pCapture = cvCaptureFromCAM(-1)))
     {
         fprintf(stderr, "Can not open camera.\n");
         return -2;
     }

    CvGaussBGModel* bg_model = NULL;

    while( pFrame=cvQueryFrame( pCapture ))
    {
        nFrmNum ++;
        if( nFrmNum == 1)
        {
            pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 3);
            pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 1);
            FirstImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 
1);
//            cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);

//            cvSaveImage("1.jpg",pFrImg);

            CvGaussBGStatModelParams params;
            params.win_size = 200;
            params.bg_threshold = 0.7;
            params.std_threshold = 2.5;
            params.weight_init = 0.05;
            params.variance_init = 30*30;
            params.minArea = 15.f;
            params.n_gauss = 5;

            bg_model = (CvGaussBGModel*) cvCreateGaussianBGModel(pFrame, 0);
        }
        else
        {
            int regioncount = 0;

            int totalNum = pFrImg->width * pFrImg->height;
//            regioncount = icvUpdateGaussianBGModel(pFrame, bg_model);

            cvUpdateBGStatModel(pFrame, (CvBGStatModel *)bg_model);
            cvCopy(bg_model->foreground, pFrImg, 0);
            cvCopy(bg_model->background, pBkImg, 0);
            cvErode(pFrImg, pFrImg, NULL, 1);
            cvDilate(pFrImg, pFrImg, 0, 1);
            cvSmooth(pFrImg, pFrImg, CV_GAUSSIAN, 3, 0, 0, 0);
//            cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);

//            cvSaveImage("2.jpg", pFrImg);

            //把图像正过来


            pBkImg->origin = 1;
            pFrImg->origin = 1;

            cvShowImage("video", pFrame);
            cvShowImage("background", pBkImg);
            cvShowImage("foreground", pFrImg);
//            printf("number is %d\n", cvSumImage(pFrImg));
//       取目标帧
            if(nFrmNum > 10 && (double)cvSumImage(pFrImg) > 0.3*totalNum )
            {
                int first, next;
                first = cvSumImage(FirstImg);
                next = cvSumImage( pFrImg );

                printf("number is %d\n", next);
                if(next < first)
                {
                    break;
                }
                cvCopy(pFrImg, FirstImg, 0);
            }

            cvCopy(pFrImg, FirstImg, 0);
            if( cvWaitKey(2)>=0)
             break;

        }
    }
    printf("%d\n", pFrImg->width*pFrImg->height);

    cvReleaseBGStatModel((CvBGStatModel**)&bg_model);
    
    cvDestroyWindow("video");
    cvDestroyWindow("background");
    cvWaitKey(0);
    cvDestroyWindow("foreground");

    cvReleaseImage(&pFrImg);
    cvReleaseImage(&pBkImg);
    cvReleaseImage(&FirstImg);
    cvReleaseCapture(&pCapture);

    return 0;
}

========

 基于opencv的视频处理——图像轮廓边缘检测Canny算法


    在数字图像处理中有一个重要的内容就是边缘检测。先说下边缘检测的原理吧!
    边缘检测实际上就是标记图像中变化梯度比较大的点,这时大家应该想到倒数了。


    下面附上程序,挺简单的一个程序。具体细节以后再说


#include
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
//#include "tklopencv.h"

int main(int argc, char **argv)
{
    int i,j;
    char *p = NULL;
    IplImage *pImg = NULL;
    IplImage *pCannyImg = NULL;
    IplImage *ReImg = NULL;

    if(argc == 2 && (pImg = cvLoadImage(argv[1],0)) != 0)
    {
        int width = pImg->width;
        int height = pImg->height;

        pCannyImg = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1);
        ReImg = cvCreateImage(cvSize(800,640), IPL_DEPTH_8U, 1);
        printf("%d\t%d\n", pImg->width, pImg->widthStep);

        cvCanny(pImg, pCannyImg, 50, 159, 3);        //设定阈值并检测

        cvErode(pCannyImg, pCannyImg, NULL, 1);
        cvDilate(pCannyImg, pCannyImg, 0, 1);
        cvSmooth(pCannyImg, pCannyImg, CV_GAUSSIAN, 3, 0, 0, 0);

        cvNamedWindow("src", 1);
        cvNamedWindow("canny", 1);
//        cvNamedWindow("Reset", 1);

        cvShowImage("src", pImg);
        cvShowImage("canny", pCannyImg);
//        cvShowImage("Reset", ReImg);

        cvWaitKey(0);

        cvDestroyWindow("src");
        cvDestroyWindow("canny");
//        cvDestroyWindow("Reset");

        cvReleaseImage(&pImg);
        cvReleaseImage( &pCannyImg);
        cvReleaseImage(&ReImg);
        return 0;
    }
    printf("Error!\n");
    return -1;


}

========

OpenCV2学习笔记:视频流读取与处理


由于项目需要,计划实现九路视频拼接,因此必须熟悉OpenCV对视频序列的处理。视频信号处理是图像处

理的一个延伸,所谓的视频序列是由按一定顺序进行排放的图像组成,即帧(Frame)。在这里,主要记录

下如何使用Qt+OpenCV读取视频中的每一帧,之后,在这基础上将一些图像处理的算法运用到每一帧上(

如使用Canny算子检测视频中的边缘)。

一. 读取视频序列

OpenCV提供了一个简便易用的框架以提取视频文件和USB摄像头中的图像帧,如果只是单单想读取某个视

频,你只需要创建一个cv::VideoCapture实例,然后在循环中提取每一帧。新建一个Qt控制台项目,直接

在main函数添加:

#include
#include
#include
#include
#include

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 读取视频流
    cv::VideoCapture capture("e:/BrokeGirls.mkv");
    // 检测视频是否读取成功
    if (!capture.isOpened())
    {
        qDebug() << "No Input Image";
        return 1;
    }

    // 获取图像帧率
    double rate= capture.get(CV_CAP_PROP_FPS);
    bool stop(false);
    cv::Mat frame; // 当前视频帧
    cv::namedWindow("Extracted Frame");

    // 每一帧之间的延迟
    int delay= 1000/rate;

    // 遍历每一帧
    while (!stop)
    {
        // 尝试读取下一帧
        if (!capture.read(frame))
            break;
        cv::imshow("Extracted Frame",frame);
        // 引入延迟
        if (cv::waitKey(delay)>=0)
                stop= true;
    }
        return a.exec();
}
(注意:要正确打开视频文件,计算机中必须安装有对应的解码器,否则cv::VideoCapture无法理解视频

格式!)运行后,将出现一个窗口,播放选定的视频(需要在创建cv::VideoCapture对象时指定视频的文

件名)。

二. 处理视频帧

为了对视频的每一帧进行处理,这里创建自己的类VideoProcessor,其中封装了OpenCV的视频获取框架,

该类允许我们指定每帧调用的处理函数。

首先,我们希望指定一个回调处理函数,每一帧中都将调用它。该函数接受一个cv::Mat对象,并输出处

理后的cv::Mat对象,其函数签名如下:

void processFrame(cv::Mat& img, cv::Mat& out);
作为这样一个处理函数的例子,以下的Canny函数计算图像的边缘:

    // 对视频的每帧做Canny算子边缘检测
void canny(cv::Mat& img, cv::Mat& out) 
{
    // 先要把每帧图像转化为灰度图
    cv::cvtColor(img,out,CV_BGR2GRAY);
    // 调用Canny函数
    cv::Canny(out,out,100,200);
    // 对像素进行翻转
    cv::threshold(out,out,128,255,cv::THRESH_BINARY_INV);
}
定义好一个视频处理类,它将与一个回调函数相关联。使用该类,可以创建一个实例,指定输入的视频文
件,绑定回调函数,然后开始对每一帧进行处理,要调用这个视频处理类,只需在main函数中添加:

    // 定义一个视频处理类处理视频帧
    // 首先创建实例
    VideoProcessor processor;
    // 打开视频文件
    processor.setInput("e:/BrokeGirls.mkv");
    // 声明显示窗口
    // 分别为输入和输出视频
    processor.displayInput("Input Video");
    processor.displayOutput("Output Video");
    // 以原始帧率播放视频
    processor.setDelay(1000./processor.getFrameRate());
    // 设置处理回调函数
    processor.setFrameProcessor(canny);
    // 开始帧处理过程
    processor.run();
    cv::waitKey();
未完待续…

========

视频加载、处理、输出

 一、加载播放视频

#include "stdafx.h"  
using namespace std;  
using namespace cv;  
  
int main()  
{     
    //下面两种方法都可以打开视频  
    VideoCapture capture("../1.avi");  
    /*2、VideoCapture capture; 
    capture.open("../1.avi");*/  
    if(!capture.isOpened())  
        return 1;  
    double rate = capture.get(CV_CAP_PROP_FPS);  
    bool stop(false);  
    Mat frame;  
    namedWindow("Extracted Frame");  
    //这个delay的单位是ms,若是秒,则delay为1/rate。  
    //rate为每秒播放的帧数  
    int delay = 1000/rate;  
    //用于设置直接播放哪一帧  
    double position= 0.0;   
    capture.set(CV_CAP_PROP_POS_FRAMES, position);  
    while(!stop)  
    {  
        //以下三种方法都可以读取视频  
        if(!capture.read(frame))  
            break;  
        /*2、capture>>frame;*/  
        /*3、capture.grab(); 
        capture.retrieve(frame);*/  
        imshow("Extracted Frame",frame);
 
       
if(waitKey(delay) >= 0)  
            stop = true;//

delay==0时,将会暂停在该帧,不再执行下去,
若不是0,则会等

待键盘的消息输入,则结束
 
    }  
    //
关闭视频文件,但是不

是必须的,VideoCapture构造函数会默认调用它  
capture.release();  
}  
 
 
二、对视频读入、处理、输出进行的封装
头文件代码:


#pragma once  
using namespace cv;  
class VideoProcessor  
{  
private://用于打开处理视频  
    //opencv 视频捕捉对象  
    VideoCapture capture;  
    //回调函数将调用每帧处理函数  
    void (*process)(Mat&,Mat&);  
    //是否调用回调函数的开关  
    bool callIt;  
    //输入视频的播放窗口名字  
    string windowNameInput;  
    //输入视频的播放窗口名字  
    string windowNameOutput;  
    //播放每帧之间的暂停间隔  
    int delay;  
    //已处理的帧数  
    long fnumber;  
    //停止在某一帧  
    long frameToStop;  
    //停止处理的开关  
    bool stop;  
    //存储获得的视频每帧  
    Mat image;  
public:  
    //设置回调函数,用于处理帧  
    void setFrameProcessor(  
        void (*frameProcessingCallback)(Mat&,Mat&))  
    {  
        process = frameProcessingCallback;  
    }  
    //打开一个视频文件  
    bool setInput(string filename);  
    //创建一个窗口显示输入帧  
    void displayInput(string wn);  
    //创建一个窗口显示输出帧  
    void displayOutput(string wn);  
    //不显示帧  
    void dontDisplay(void);  
    //抓取或处理帧序列  
    void run(void);  
    //捕捉设备是否打开  
    bool isOpened(){ return capture.isOpened() || !images.empty();}  
    //是否停止处理  
    bool isStopped(){ return stop; }  
    //停止处理  
    void stopIt(){ stop = true; }  
    //从视频或摄像头或图片文件读取下一帧  
    bool readNextFrame(Mat& frame);  
    //设置播放延时  
    void setDelay(int d){ delay = d;}  
    //设置调用回调函数  
    void callProcess(){ callIt = true; }  
    //设置不调用回调函数  
    void dontCallProcess(){ callIt = false;}  
    //设置停留在某帧  
    void stopAtFrameNo(long frame){ frameToStop = frame;}  
    //返回视频总帧数  
    long getFrameNumber(void);  
    //返回输入视频的帧频  
    long  getFrameRate(){ return capture.get(CV_CAP_PROP_FPS); }  
  
private://用于输出视频或图片文件  
    //opencv用于视频输出类对象  
    VideoWriter writer;  
    //输出文件名  
    string outputFile;  
    //输出图片的当前索引值  
    int currentIndex;  
    //输出图像的数字编号的位数  
    int digits;  
    //扩展名  
    string extension;  
    //保存图片文件名  
    vector images;  
    //遍历图片vector的迭代器  
    vector::const_iterator itImg;  
  
public:  
    //输出视频文件以原视频相同的参数  
    //还不能正确得到输入视频的codec格式,只能在codec==-1时,输出视频  
    bool setOutput(const string& filename, int codec=-1, double framerate=0.0, bool 


isColor=true);  
    //用于输出每一帧  
    void writeNextFrame(Mat& frame);  
    //用于以图片格式输出  
    bool setOutput(const string &filename,const string &ext,int numberOfDigits=3, int 


startIndex=0);  
    //获得输入视频的编码格式  
    int getCodec(char codec[4]);  
    //获得图片大小  
    cv::Size getFrameSize()  
    {   
        cv::Size S ;  
        return S = Size((int) capture.get(CV_CAP_PROP_FRAME_WIDTH),    //获取输入尺寸  
              (int) capture.get(CV_CAP_PROP_FRAME_HEIGHT));   
    }  
public:  
    VideoProcessor(void);  
    ~VideoProcessor(void);  
      
    //设置输入图片向量  
    bool setInput(const vector& imgs);  
};  
  
 
 
相应cpp文件:


#include "StdAfx.h"  
#include "VideoProcessor.h"  
  
  
VideoProcessor::VideoProcessor(void):  
    callIt(true),  
    delay(0),  
    fnumber(0),  
    stop(false),  
    frameToStop(-1),  
    currentIndex(0),  
    digits(0)  
{  
}  
    
VideoProcessor::~VideoProcessor(void)  
{  
}  
    
bool VideoProcessor::setInput(string filename)  
{  
    fnumber = 0;  
    //万一该VideoCapture对象已经关联了一个资源  
    capture.release();  
    //images.clear();  
    //打开视频文件  
    return capture.open(filename);  
      
}  
  
  void VideoProcessor::displayInput(string wn)  
{  
    windowNameInput = wn;  
    namedWindow(windowNameInput);  
}  
  
  void VideoProcessor::displayOutput(string wn)  
{  
    windowNameOutput = wn;  
    namedWindow(windowNameOutput);  
}  
    
void VideoProcessor::dontDisplay(void)  
{  
    destroyWindow(windowNameInput);  
    destroyWindow(windowNameOutput);  
    windowNameInput.clear();  
    windowNameOutput.clear();  
}  
   
void VideoProcessor::run(void)  
{  
    //当前帧  
    Mat frame;  
    //输出帧  
    Mat output;  
    //判断是否打开成功  
    if(!isOpened())  
        return;  
    stop = false;  
    while(!isStopped())  
    {  
        //若存在视频下一帧,则读取  
        if(!readNextFrame(frame))  
            break;  
        //将当前帧存于image中  
        image = frame;  
        //frame.copyTo(image);  
        //显示输入帧  
        if(windowNameInput.length() != 0)  
            imshow(windowNameInput,frame);  
        //调用处理函数  
        if(callIt)  
        {  
            process(frame,output);  
            fnumber++;  
        }else{  
            output = frame;  
        }  
        //**写输出序列  
        if(outputFile.length() != 0)  
            writeNextFrame(output);  
        //显示输出帧  
        if(windowNameOutput.length() != 0)  
            imshow(windowNameOutput,output);  
        //延时  
        if(delay >= 0 && waitKey(delay) >= 0)  
            stopIt();  
        if(frameToStop >= 0 && getFrameNumber() == frameToStop)  
            stopIt();  
    }  
}  
    
bool VideoProcessor::readNextFrame(Mat& frame)  
{  
    if(images.size() == 0)  
        return capture.read(frame);  
    else{  
        if(itImg != images.end())  
        {  
            frame = imread(*itImg);  
            itImg++;  
            return frame.data != 0;  
        }else{  
            return false;  
        }  
    }  
}  
    
long VideoProcessor::getFrameNumber(void)  
{  
    long fnumber = static_cast(capture.get(CV_CAP_PROP_POS_FRAMES));  
    return fnumber;  
}  
    
bool VideoProcessor::setOutput(const string& filename, int codec, double framerate, bool 
isColor)  
{  
    outputFile = filename;  
    extension.clear();  
    if(framerate == 0.0)  
        framerate = getFrameRate();  
    char c[4];  
    //使用与输出视频相同的编码方式  
    if(codec == 0)  
    {  
        codec = getCodec(c);  
    }  
      
    writer.open(outputFile,  
        codec=-1,  
        framerate,  
        getFrameSize(),  
        isColor);  
    if(writer.isOpened()) std::cout<<"dai kai cheng gong"<     return true;  
}  
    
void VideoProcessor::writeNextFrame(Mat& frame)  
{  
    if(extension.length())  
    {  
        std::stringstream ss;  
        //构成输出文件名  
        ss<             <             <         imwrite(ss.str(),frame);  
    }else//否则以视频格式写出  
    {  
        writer.write(frame);  
    }  
}  
    
bool VideoProcessor::setOutput(const string &filename,//文件前缀  
    const string& ext,//图片文件的扩展名  
    int numberOfDigits,//数据位  
    int startIndex) //开始索引值  
{  
    //数字必须为正  
    if(numberOfDigits<0)  
    return false;  
    //文件名及其扩展名  
    outputFile = filename;  
    extension = ext;  
    //输出图片的编号  
    digits = numberOfDigits;  
    //图片数字编号的起始值  
    currentIndex = startIndex;  
    return true;  
}  
    
int VideoProcessor::getCodec(char codec[4])  
{  
    //  
    if(images.size() != 0)  
        return -1;  
    union{//4-char编码的数据结构  
        int value;  
        char code[4];  
    }returned;  
    //获得编码方式  
    returned.value = static_cast(  
        capture.get(CV_CAP_PROP_FOURCC));  
    //获得四个字符  
    codec[0] = returned.code[0];  
    codec[1] = returned.code[1];  
    codec[2] = returned.code[2];  
    codec[3] = returned.code[3];  
    /*std::cout << "Codec: " << codec[0] << codec[1]   
             << codec[2] << codec[3] << std::endl;*/  
    return returned.value;  
}  
    
bool VideoProcessor::setInput(const vector& imgs)  
{  
    fnumber = 0;  
    capture.release();  
    //将输入图片放入iamges中  
    images = imgs;  
    itImg = images.begin();  
    return true;  
}  
 
 
主函数对这个类的引用:

#include "stdafx.h"  
  
#include "VideoProcessor.h"  
  
using namespace std;  
using namespace cv;  
  
void canny(cv::Mat& img, cv::Mat& out) {  
   // Convert to gray  
   if (img.channels()==3)  
      cv::cvtColor(img,out,CV_BGR2GRAY);  
   // Compute Canny edges  
   cv::Canny(out,out,100,200);  
   // Invert the image  
   cv::threshold(out,out,128,255,cv::THRESH_BINARY_INV);  
}  
int main()  
{     
    VideoProcessor processor;  
    processor.setInput("../1.avi");  
    processor.displayInput("Current Frame");  
    processor.displayOutput("Output Frame");  
    processor.setDelay(1000./processor.getFrameRate());  
    processor.setFrameProcessor(canny);  
    processor.setOutput("../laneout.avi");  
    //processor.setOutput("../laneout",".bmp");  
    processor.stopAtFrameNo(300);  
    processor.run();  
}
 
代码注释:输出视频和输出图片一次只能设置一个。具体应用时,对处理函数的形式进行修改,使其适合

相应程序的要求。

========

使用OpenCV 读取和处理任意格式视频文件


 记得几个月前,使用OpenCV 做背景分割时使用它 很多视频都不能处理。所以投靠了 directshow,这个
超级复杂的东西。虽然说已经用 directshow 写了一个几万行的商业软件,说实话对它还是想敬而远之。
今天在测一段网上的代码时,竟然都通了。我想这也可能和我在编译器里链接了directshow 的东西吧!
下面贴一段代码
int main( int argc, char** argv )
{
 //声明IplImage指针
 IplImage* pFrame = NULL;
 IplImage* pFrImg = NULL;
 IplImage* pBkImg = NULL;
 CvMat* pFrameMat = NULL;
 CvMat* pFrMat = NULL;
 CvMat* pBkMat = NULL;
 CvCapture* pCapture = NULL;
 int nFrmNum = 0;
 //创建窗口
 cvNamedWindow("video", 1);
 cvNamedWindow("background",1);
 cvNamedWindow("foreground",1);
 //使窗口有序排列
 cvMoveWindow("video", 30, 0);
 cvMoveWindow("background", 360, 0);
 cvMoveWindow("foreground", 690, 0);
 //if( argc > 2 )
 //{
 // fprintf(stderr, "Usage: bkgrd [video_file_name]\n");
 // return -1;
 //}
 ////打开摄像头
 //if (argc ==1)
 // if( !(pCapture = cvCaptureFromCAM(-1)))
 // {
 //  fprintf(stderr, "Can not open camera.\n");
 //  return -2;
 // }
 //打开视频文件
 //if(argc == 2)
 //if( !(pCapture = cvCaptureFromFile(argv[1])))
 if( !(pCapture = cvCaptureFromFile(videoname2)))
 {
  fprintf(stderr, "Can not open video file %s\n", argv[1]);
  return -2;
 }
 //逐帧读取视频
 while(pFrame = cvQueryFrame( pCapture ))
 {
  nFrmNum++;
  //如果是第一帧,需要申请内存,并初始化
  if(nFrmNum == 1)
  {
   pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);
   pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);
   pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
   pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
   pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
   //转化成单通道图像再处理
   cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);
   cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
   cvConvert(pFrImg, pFrameMat);
   cvConvert(pFrImg, pFrMat);
   cvConvert(pFrImg, pBkMat);
  }
  else
  {
   cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
   cvConvert(pFrImg, pFrameMat);
   //高斯滤波先,以平滑图像
   //cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);
   //当前帧跟背景图相减
   cvAbsDiff(pFrameMat, pBkMat, pFrMat);
   //二值化前景图
   cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);
   //进行形态学滤波,去掉噪音 
   //cvErode(pFrImg, pFrImg, 0, 1);
   //cvDilate(pFrImg, pFrImg, 0, 1);
   //更新背景
   cvRunningAvg(pFrameMat, pBkMat, 0.003, 0);
   //将背景转化为图像格式,用以显示
   cvConvert(pBkMat, pBkImg);
   //显示图像
   cvShowImage("video", pFrame);
   cvShowImage("background", pBkImg);
   cvShowImage("foreground", pFrImg);
   //如果有按键事件,则跳出循环
   //此等待也为cvShowImage函数提供时间完成显示
   //等待时间可以根据CPU速度调整
   if( cvWaitKey(2) >= 0 )
    break;
  }
 }
 //销毁窗口
 cvDestroyWindow("video");
 cvDestroyWindow("background");
 cvDestroyWindow("foreground");
 //释放图像和矩阵
 cvReleaseImage(&pFrImg);
 cvReleaseImage(&pBkImg);
 cvReleaseMat(&pFrameMat);
 cvReleaseMat(&pFrMat);
 cvReleaseMat(&pBkMat);
 cvReleaseCapture(&pCapture);
 return 0;
}


========

 OpenCV读视频文件和运动物体检测


简要说明:本程序 尝试打开本电脑上的摄像头作为视频输入设备,或者将命令行的输入参数作为文件名

来打开的视频文件。不管是哪一种方法,最后都是不断的循环处理一帧一帧地处理,涉及到的图像处理有 

背景擦除,平滑滤波,二值化等。

有微小调整。在VS2005+OpenCV下调试通过。
 
#include  
#include  
#include  
#include  
#include  
  
int main( int argc, char** argv ) 

    //声明IplImage指针 
    IplImage* pFrame = NULL;  
    IplImage* pFrImg = NULL; 
    IplImage* pBkImg = NULL; 
 
    CvMat* pFrameMat = NULL; 
    CvMat* pFrMat = NULL; 
    CvMat* pBkMat = NULL; 
 
    CvCapture* pCapture = NULL; 
 
    int nFrmNum = 0; 
 
    //创建窗口 
    cvNamedWindow("video", 1); 
    cvNamedWindow("background",1); 
    cvNamedWindow("foreground",1); 
    //使窗口有序排列 
    cvMoveWindow("video", 30, 0); 
    cvMoveWindow("background", 360, 0); 
    cvMoveWindow("foreground", 690, 0); 
 
 
    if( argc > 2 ) 
    { 
        fprintf(stderr, "Usage: bkgrd [video_file_name]\n"); 
        return -1; 
    } 
 
    //打开摄像头 
    if (argc ==1) 
    { 
        if( !(pCapture = cvCaptureFromCAM(0))) 
        { 
            fprintf(stderr, "Can not open camera.\n"); 
            return -2; 
        } 
    } 
    //打开视频文件 
    if(argc == 2) 
    { 
        if( !(pCapture = cvCaptureFromFile(argv[1]))) 
        { 
            fprintf(stderr, "Can not open video file %s\n", argv[1]); 
            return -2; 
        } 
    } 
    //逐帧读取视频 
    while(pFrame = cvQueryFrame( pCapture )) 
    { 
        nFrmNum++; 
 
        //如果是第一帧,需要申请内存,并初始化 
        if(nFrmNum == 1) 
        { 
            pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1); 
            pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1); 
 
            pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); 
            pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); 
            pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); 
 
            //转化成单通道图像再处理 
            cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY); 
            cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); 
 
            cvConvert(pFrImg, pFrameMat); 
            cvConvert(pFrImg, pFrMat); 
            cvConvert(pFrImg, pBkMat); 
        } 
        else 
        { 
            cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); 
            cvConvert(pFrImg, pFrameMat); 
            //高斯滤波先,以平滑图像 
            //cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0); 
 
            //当前帧跟背景图相减 
            cvAbsDiff(pFrameMat, pBkMat, pFrMat); 
 
            //二值化前景图 
            cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY); 
 
            //进行形态学滤波,去掉噪音   
            //cvErode(pFrImg, pFrImg, 0, 1); 
            //cvDilate(pFrImg, pFrImg, 0, 1); 
 
            //更新背景 
            cvRunningAvg(pFrameMat, pBkMat, 0.003, 0); 
            //将背景转化为图像格式,用以显示 
            cvConvert(pBkMat, pBkImg); 
 
            //显示图像 
            cvShowImage("video", pFrame); 
            cvShowImage("background", pBkImg); 
            cvShowImage("foreground", pFrImg); 
 
            //如果有按键事件,则跳出循环 
            //此等待也为cvShowImage函数提供时间完成显示 
            //等待时间可以根据CPU速度调整 
            if( cvWaitKey(2) >= 0 ) 
                break; 
        } 
    } 
     
    //销毁窗口 
    cvDestroyWindow("video"); 
    cvDestroyWindow("background"); 
    cvDestroyWindow("foreground"); 
 
    //释放图像和矩阵 
    cvReleaseImage(&pFrImg); 
    cvReleaseImage(&pBkImg); 
 
    cvReleaseMat(&pFrameMat); 
    cvReleaseMat(&pFrMat); 
    cvReleaseMat(&pBkMat); 
 
    cvReleaseCapture(&pCapture); 
 
    return 0; 


========

基于轮廓寻找的视频流运动检测

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


// various tracking parameters (in seconds) //跟踪的参数(单位为秒)
const double MHI_DURATION = 0.5;//0.5s为运动跟踪的最大持续时间
const double MAX_TIME_DELTA = 0.5;
const double MIN_TIME_DELTA = 0.05;
const int N = 3;
//
const int CONTOUR_MAX_AERA = 1000;
// ring image buffer 圈出图像缓冲
IplImage **buf = 0;//指针的指针
int last = 0;
// temporary images临时图像
IplImage *mhi = 0; // MHI: motion history image
CvFilter filter = CV_GAUSSIAN_5x5;
CvConnectedComp *cur_comp, min_comp;
CvConnectedComp comp;
CvMemStorage *storage;
CvPoint pt[4];
//  参数:
//  img – 输入视频帧
//  dst – 检测结果
void  update_mhi( IplImage* img, IplImage* dst, int diff_threshold )
{
    double timestamp = clock()/100.; // get current time in seconds 时间戳
    CvSize size = cvSize(img->width,img->height);
    // get current frame size,得到当前帧的尺寸
    int i, idx1, idx2;
    IplImage* silh;
    IplImage* pyr = cvCreateImage( cvSize((size.width & -2)/2, (size.height & -2)/2), 8, 1 


);
    CvMemStorage *stor;
    CvSeq *cont;


    /*先进行数据的初始化*/
    if( !mhi || mhi->width != size.width || mhi->height != size.height )
    {
        if( buf == 0 ) //若尚没有初始化则分配内存给他
        {
            buf = (IplImage**)malloc(N*sizeof(buf[0]));
            memset( buf, 0, N*sizeof(buf[0]));
        }
        
        for( i = 0; i < N; i++ )
        {
            cvReleaseImage( &buf[i] );
            buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
            cvZero( buf[i] );// clear Buffer Frame at the beginning
        }
        cvReleaseImage( &mhi );
        mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );
        cvZero( mhi ); // clear MHI at the beginning
    } // end of if(mhi)
    /*将当前要处理的帧转化为灰度放到buffer的最后一帧中*/
    cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale
    /*设定帧的序号*/
    /*
    last---->idx1
     ^
     |
     |
     |
    idx2<-----(last+1)%3
    */
    
    idx1 = last;
    idx2 = (last + 1) % N; // index of (last - (N-1))th frame
    last = idx2;
    // 做帧差
    silh = buf[idx2];//差值的指向idx2 |idx2-idx1|-->idx2(<-silh)
    cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames
    
    // 对差图像做二值化
    cvThreshold( silh, silh, 30, 255, CV_THRESH_BINARY ); //threshold it,二值化
    
    cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI
 
    cvConvert( mhi, dst );//将mhi转化为dst,dst=mhi   
    
    // 中值滤波,消除小的噪声
    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 );// 向上采样,恢复图像,图像是原图像的四倍
    //
    // 下面的程序段用来找到轮廓
    //
    // Create dynamic structure and sequence.
    stor = cvCreateMemStorage(0);
    cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint) , stor);
    
    // 找到所有轮廓
    cvFindContours( dst, stor, &cont, sizeof(CvContour),
                    CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
    // 直接使用CONTOUR中的矩形来画轮廓
    for(;cont;cont = cont->h_next)
    {
              CvRect r = ((CvContour*)cont)->rect;
              if(r.height * r.width > CONTOUR_MAX_AERA) // 面积小的方形抛弃掉
              {
                  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);
              }
    }
    // free memory
    cvReleaseMemStorage(&stor);
    cvReleaseImage( &pyr );
}
int main(int argc, char** argv)
{
    IplImage* motion = 0;
    CvCapture* capture = 0;
    
    if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
        capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );//摄像头为视频来源
    else if( argc == 2 )
        capture = cvCaptureFromAVI( argv[1] );//AVI为视频来源
    if( capture )
    {
        cvNamedWindow( "Motion", 1 );//建立窗口
        for(;;)
        {
            IplImage* image;
            if( !cvGrabFrame( capture ))//捕捉一桢
                break;
            image = cvRetrieveFrame( capture );//取出这个帧
            if( image )//若取到则判断motion是否为空
            {
                if( !motion )
                {
                    motion = cvCreateImage( cvSize(image->width,image->height), 8, 1 );
                    //创建motion帧,八位,一通道
                    cvZero( motion );
                    //零填充motion
                    motion->origin = image->origin;
                    //内存存储的顺序和取出的帧相同
                }
            }
            update_mhi( image, motion, 60 );//更新历史图像
            cvShowImage( "Motion", image );//显示处理过的图像
            if( cvWaitKey(10) >= 0 )//10ms中按任意键退出
                break;
        }
        cvReleaseCapture( &capture );//释放设备
        cvDestroyWindow( "Motion" );//销毁窗口
    }
    return 0;

========

 OpenCV读视频文件和运动问题检测

下面这个程序 来自于仕琪的讲稿 《使用OpenCV进行图像处理》]中的例程:

cvRunningAvg

  opencv中的函数,用来更新移动平均。用法:

  void cvRunningAvg(const CvArr * image,

  CvArr* acc,

  double alpha,

  const CvArr* mask=NULL)

  image:输入图像,1或3通道,8比特或32比特的float型

  acc:累加器,和image一样大小

  alpha:更新时,image所占的权重

  mask:操作符掩码

  if mask(x,y)!= 0 (1-alpha)*acc(x,y)+alpha*image(x,y) =>acc(x,y)

#if 0  
#include  
 #include  
#include  
#include  
  
#pragma comment(lib, "cv.lib")  
#pragma comment(lib, "cxcore.lib")  
#pragma comment(lib, "highgui.lib")  
  
int main( int argc, char** argv )  
{  
    //声明IplImage指针  
    IplImage* pFrame = NULL;   
    IplImage* pFrImg = NULL;  
    IplImage* pBkImg = NULL;  
  
    CvMat* pFrameMat = NULL;  
    CvMat* pFrMat = NULL;  
    CvMat* pBkMat = NULL;  
  
    CvCapture* pCapture = NULL;  
  
    int nFrmNum = 0;  
  
    //创建窗口  
    cvNamedWindow("video", 1);  
    cvNamedWindow("background",1);  
    cvNamedWindow("foreground",1);  
    //使窗口有序排列  
    cvMoveWindow("video", 30, 0);  
    cvMoveWindow("background", 360, 0);  
    cvMoveWindow("foreground", 690, 0);  
  
  
    if( !(pCapture = cvCaptureFromAVI(".\\test.avi")))  
    {  
        //pCapture = cvCaptureFromCAM(-1))  
        fprintf(stderr, "Can not open camera.\n");  
        return -2;  
    }  
  
    //逐帧读取视频  
    while(pFrame = cvQueryFrame( pCapture ))  
    {  
        nFrmNum++;  
  
        //如果是第一帧,需要申请内存,并初始化  
        if(nFrmNum == 1)  
        {  
            pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);  
            pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height),  IPL_DEPTH_8U,1);  
  
            pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);  
            pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);  
            pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);  
  
            //转化成单通道图像再处理  
            cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);  
            cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);  
  
            cvConvert(pFrImg, pFrameMat);  
            cvConvert(pFrImg, pFrMat);  
            cvConvert(pFrImg, pBkMat);  
        }  
        else  
        {  
            cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);  
            cvConvert(pFrImg, pFrameMat);  
            //高斯滤波先,以平滑图像  
            //cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);  
  
            //当前帧跟背景图相减  
            cvAbsDiff(pFrameMat, pBkMat, pFrMat);  
  
            //二值化前景图  
            cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);  
  
            //进行形态学滤波,去掉噪音    
            //cvErode(pFrImg, pFrImg, 0, 1);  
            //cvDilate(pFrImg, pFrImg, 0, 1);  
  
            //更新背景  
            cvRunningAvg(pFrameMat, pBkMat, 0.003, 0);  
            //将背景转化为图像格式,用以显示  
            cvConvert(pBkMat, pBkImg);  
  
            //显示图像  
            cvShowImage("video", pFrame);  
            cvShowImage("background", pBkImg);  
            cvShowImage("foreground", pFrImg);  
  
            //如果有按键事件,则跳出循环  
            //此等待也为cvShowImage函数提供时间完成显示  
            //等待时间可以根据CPU速度调整  
            if( cvWaitKey(20) >= 0 )  
            {  
                break;  
            }  
        }  
    }  
    cvWaitKey();  
  
    //销毁窗口  
    cvDestroyWindow("video");  
    cvDestroyWindow("background");  
    cvDestroyWindow("foreground");  
  
    //释放图像和矩阵  
    cvReleaseImage(&pFrImg);  
    cvReleaseImage(&pBkImg);  
  
    cvReleaseMat(&pFrameMat);  
    cvReleaseMat(&pFrMat);  
    cvReleaseMat(&pBkMat);  
  
    cvReleaseCapture(&pCapture);  
  
    return 0;  
}  
#else  
#include  
#include  
  
#pragma comment(lib, "cv.lib")  
#pragma comment(lib, "cxcore.lib")  
#pragma comment(lib, "highgui.lib")  
  
int main( int argc, char** argv )  
{  
    CvCapture* capture = NULL;  
    IplImage *frame = NULL;  
  
    IplImage  *frame_last = NULL;//存储上一帧  
    IplImage  *m_out_image = NULL;  
  
    IplImage* frame_gray = NULL;  
    IplImage* frame_gray_last = NULL;  
    IplImage* m_out_image_copy = NULL;  
    int nFrmNum = 0;  
  
    //capture = cvCaptureFromCAM(-1);   
  
    capture = cvCaptureFromAVI(".\\test.avi");  
  
    //创建窗口  
    cvNamedWindow( "result", 1 );  
    cvNamedWindow("差分");  
  
    //逐帧读取视频  
    while(frame = cvQueryFrame( capture ))  
    {  
        nFrmNum++;  
  
        //如果是第一帧,需要申请内存,并初始化  
        if(nFrmNum == 1)  
        {  
            frame_last = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U, 

frame->nChannels);  
            cvCopy(frame,frame_last);  
        }  
        else  
        {  
            frame_gray = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U, 1);  
            frame_gray_last = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U, 
1);  
  
            m_out_image = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U, 1); 

            m_out_image_copy = cvCreateImage( cvSize(frame->width,frame-
>height),IPL_DEPTH_8U, 1 );  
  
            cvCvtColor(frame,frame_gray,CV_RGB2GRAY);    
            cvCvtColor(frame_last,frame_gray_last,CV_RGB2GRAY);    
            cvAbsDiff(frame_gray,frame_gray_last,m_out_image);    
            //cvThreshold(m_out_image,m_out_image,128, 255,CV_THRESH_BINARY);  
  
            //将处理后的图像写出到第二个图像中  
  
            if( m_out_image_copy->origin == IPL_ORIGIN_TL )  
            {  
                cvCopy( m_out_image, m_out_image_copy, 0 );  
            }  
            else  
            {  
                cvFlip( m_out_image, m_out_image_copy, 0 );  
            }  
  
            frame_last = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U, 
frame->nChannels);  
            cvCopy(frame,frame_last);  
  
            cvShowImage("差分",m_out_image_copy);  
            cvShowImage("result",frame);  
  
            cvReleaseImage( &m_out_image_copy );  
            cvReleaseImage( &frame_gray_last );  
            cvReleaseImage( &frame_gray );  
  
            if( cvWaitKey( 20 ) >= 0 )  
            {  
                break;  
            }  
        }  
    }  
    cvWaitKey();  
  
    cvReleaseImage( &m_out_image );  
    cvReleaseImage( &frame_last );  
    cvReleaseImage( &frame );  
  
    cvReleaseCapture( &capture );  
  
    cvDestroyWindow("result");  
    cvDestroyWindow("差分");  
  
    return 0;  
}  
#endif
========

Opencv中对视频流进行边缘检测

#include "stdafx.h"  
#include "cv.h"  
#include "highgui.h"  
#include  
#include  
int main( int argc, char** argv )  
{  
    IplImage* laplace = 0;  
    IplImage* colorlaplace = 0;  
    IplImage* planes[3] = { 0, 0, 0 };  // 多个图像面  
    CvCapture* capture = 0;  
    //CvCapture  
    //  
    //视频获取结构  
    //typedef struct CvCapture CvCapture;  
    //结构CvCapture 没有公共接口,它只能被用来作为视频获取函数的一个参数。  
    // 下面的语句说明在命令行执行程序时,如果指定AVI文件,那么处理从  
    // AVI文件读取的视频流,如果不指定输入变量,那么处理从摄像头获取  
    // 的视频流  
      
    //capture = cvCaptureFromAVI( "3.avi" );  
  
    if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))  
        capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );  
    else if( argc == 2 )  
        capture = cvCaptureFromAVI( argv[1] );   
  
    if( !capture )  
    {  
        fprintf(stderr,"Could not initialize capturing...\n");  
        return -1;  
    }  
    cvNamedWindow( "Laplacian", 0 );  
    // 循环捕捉,直到用户按键跳出循环体  
    for(;;)  
    {  
        IplImage* frame = 0;  
        int i;  
        //cvQueryFrame  
        //  
        //从摄像头或者文件中抓取并返回一帧  
        //IplImage* cvQueryFrame( CvCapture* capture );  
        //capture   
        //视频获取结构。  
        //函数cvQueryFrame从摄像头或者文件中抓取一帧,然后解压并返回这一帧。  
        //这个函数仅仅是函数cvGrabFrame和函数cvRetrieveFrame在一起调用的组合。  
        //返回的图像不可以被用户释放或者修改。 抓取后,capture被指向下一帧,  
        //可用cvSetCaptureProperty调整capture到合适的帧。  
        //  
        //注意: cvQueryFrame返回的指针总是指向同一块内存。建议cvQueryFrame后拷贝一份  
        //。而且返回的帧需要FLIP后才符合OPENCV的坐标系。 若返回值为NULL,说明到了视频的最后


一帧。  
        frame = cvQueryFrame( capture );  
        if( !frame )  
            break;  
        if( !laplace )  
        {  
            for( i = 0; i < 3; i++ )  
                planes[i] = cvCreateImage( cvSize(frame->width,frame->height), 8, 1 );  
            //CreateImage  
            //创建头并分配数据  
            //IplImage* cvCreateImage( CvSize size, int depth, int channels );  
            //size  
            //图像宽、高.  
            //depth   
            //图像元素的位深度,可以是下面的其中之一:  
            //IPL_DEPTH_8U - 无符号8位整型  
            //IPL_DEPTH_8S - 有符号8位整型  
            //IPL_DEPTH_16U - 无符号16位整型  
            //IPL_DEPTH_16S - 有符号16位整型  
            //IPL_DEPTH_32S - 有符号32位整型  
            //IPL_DEPTH_32F - 单精度浮点数  
            //IPL_DEPTH_64F - 双精度浮点数  
            //channels   
            //每个元素(像素)的颜色通道数量.可以是 1, 2, 3 或 4.通道是交叉存取的,例如通常
的彩色图像数据排列是:  
            //b0 g0 r0 b1 g1 r1 ...  
            //虽然通常 IPL 图象格式可以存贮非交叉存取的图像,并且一些OpenCV 也能处理他, 但是
这个函数只能创建交叉存取图像.  
            //函数 cvCreateImage 创建头并分配数据,这个函数是下列的缩写型式  
            //header = cvCreateImageHeader(size,depth,channels);  
            //cvCreateData(header); //只是创建空间,并不会初始化空间内的数据  
            laplace = cvCreateImage( cvSize(frame->width,frame->height),  
                IPL_DEPTH_16S, 1 );  
            colorlaplace = cvCreateImage( cvSize(frame->width,frame->height), 8, 3 );  
        }  
        //cvCvtPixToPlane  
        //  
        //  openCV里面的一个函数  
        //  可以看作cvSplit是他的宏:  
        //  #define cvCvtPixToPlane cvSplit  
        //  void cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1,CvArr* dst2, CvArr* 


dst3 );  
        //  作用是:分割多通道数组成几个单通道数组或者从数组中提取一个通道  
        //  一般用法是cvCvtPixToPlane(IplImage * src,IplImage * dst1,IplImage 

*dst2,IplImage * dst3,IplImage *dst4)  
        //  第一个参数是源图像,后面是分离出来每个通道的目标图像,如果圆筒到时3通道的,可


以把最后一个参数设置为空。  
        //  例如cvCvtPixToPlane(IplImage * src,IplImage * dst1,IplImage *dst2,IplImage * 


dst3,NULL)  
        cvCvtPixToPlane( frame, planes[0], planes[1], planes[2], 0 );  
        for( i = 0; i < 3; i++ )  
        {  
            //          Laplace  
            //计算图像的 Laplacian 变换  
            //void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 );  
            //src  
            //输入图像.  
            //dst  
            //输出图像.  
            //aperture_size  
            //核大小 (与 cvSobel 中定义一样).  
            cvLaplace( planes[i], laplace, 3 ); // 3: aperture_size  
            //ConvertScaleAbs  
            //使用线性变换转换输入数组元素成8位无符号整型  
            //void cvConvertScaleAbs( const CvArr* src, CvArr* dst, double scale=1, double 
shift=0 );  
            //#define cvCvtScaleAbs cvConvertScaleAbs  
            //src  
            //原数组  
            //dst  
            //输出数组 (深度为 8u).  
            //scale  
            //比例因子.  
            //shift  
            //原数组元素按比例缩放后添加的值。  
            //函数 cvConvertScaleAbs 与前一函数是相同的,但它是存贮变换结果的绝对值:  
            //dst(I)=abs(src(I)*scale + (shift,shift,...))  
            //函数只支持目标数数组的深度为 8u (8-bit 无符号) , 对于别的类型函数仿效于
cvConvertScale 和 cvAbs 函数的联合  
            cvConvertScaleAbs( laplace, planes[i], 1, 0 );  // planes[] = ABS(laplace)  
        }  
        //cvCvtPixToPlane是cvCvtPlaneToPix的逆函数  
        cvCvtPlaneToPix( planes[0], planes[1], planes[2], 0, colorlaplace );  
        //IplImage  
        //  IPL 图像头  
        //  typedef struct _IplImage  
        //{  
        //  int  nSize;           
        //  int  ID;              
        //  int  nChannels;       
        //  int  alphaChannel;    
        //  int  depth;           
        //  char colorModel[4];   
        //  char channelSeq[4];   
        //  int  dataOrder;       
        //  int  origin;          
        //  int  align;           
        //  int  width;           
        //  int  height;          
        //  struct _IplROI *roi;  
        //  struct _IplImage *maskROI;   
        //  void  *imageId;       
        //  struct _IplTileInfo *tileInfo;   
        //  int  imageSize;       
        //  char *imageData;    
        //  int  widthStep;     
        //  int  BorderMode[4];   
        //  int  BorderConst[4];   
        //  char *imageDataOrigin;   
        //}  
        //    IplImage;  
        //IplImage结构来自于 Intel Image Processing Library(是其本身所具有的)。OpenCV 只支

持其中的一个子集:  
        //alphaChannel 在OpenCV中被忽略。  
        //colorModel 和channelSeq 被OpenCV忽略。OpenCV颜色转换的唯一函数 cvCvtColor把原图像

的颜色空间的目标图像的颜色空间作为一个参数。  
        //dataOrder 必须是IPL_DATA_ORDER_PIXEL (颜色通道是交叉存取),然而平面图像的被选择通

道可以被处理,就像COI(感兴趣的通道)被设置过一样。  
        //align 是被OpenCV忽略的,而用 widthStep 去访问后继的图像行。  
        //不支持maskROI 。处理MASK的函数把他当作一个分离的参数。MASK在 OpenCV 里是 8-bit,然

而在 IPL他是 1-bit。  
        //tileInfo 不支持。  
        //BorderMode和BorderConst是不支持的。每个 OpenCV 函数处理像素的邻近的像素,通常使用

单一的固定代码边际模式。  
        //除了上述限制,OpenCV处理ROI有不同的要求。要求原图像和目标图像的尺寸或 ROI的尺寸必
须(根据不同的操作,  
        //例如cvPyrDown 目标图像的宽(高)必须等于原图像的宽(高)除以2 ±1)精确匹配,而IPL
处理交叉区域,如图像的大小或ROI大小可能是完全独立的。  
        colorlaplace->origin = frame->origin;   //让他们结构一致  
        cvShowImage("Laplacian", colorlaplace );  
        if( cvWaitKey(10) >= 0 )  
            break;  
    }  
    cvReleaseCapture( &capture );  
    cvDestroyWindow("Laplacian");  
    return 0;  

========


你可能感兴趣的:(转载,VC++)