在pcDuino上学习OpenCV系列教程(四)播放avi文件

雨后的彩虹桥 发布于 2014/03/08 23:20
阅读 410
收藏 0

使用OpenCV播放视频,几乎与使用它来显示图像一样容易。播放视频时只需要处理的新问题就是如何循环地顺序读取视频中的每一帧,以及如何从枯燥的电影视频的读取中退出该循环操作。

说明:

硬件平台:pcDuino V2

操作系统:ubuntu 12.07

编译器:gcc 4.6.3

OpenCV版本:2.4.8.2

10134644-c0813b299c634ca195466e5649315924

编辑代码

1,编写主程序,比较简单

$vim test.c

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*
 * OpenCV tutorial  on pcDuino.
 *
 * Copyright (C) 2014 LinkSprite Technologies,Inc.
 * Author: Pillar Zuo <zuobaozhu@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation version 2.
 *
 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
 * kind, whether express or implied; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
 
#include"opencv2/highgui/highgui.hpp"
#include<stdio.h>
intmain(intargc, char** argv)
{
/*新建一个窗口,窗口的名字为Example2,设置窗口大小为自动调整*/
cvNamedWindow("Example2",CV_WINDOW_AUTOSIZE);
/*打开一个视频文件,这里直接使用命令行下第一个参数*/
    CvCapture* capture = cvCreateFileCapture(argv[1] );
        if(capture == NULL)
                printf("error\n");
    /*新建一个变量保存每一帧*/
    IplImage* frame =0;
    while(1)
{
    /*从队列中读取一帧*/
        frame = cvQueryFrame(capture);
        if(!frame)
        {
            printf("no frame\n");
            break;
        }
        /*显示这一帧*/
        cvShowImage("Example2",frame);
        /*等待33ms,检查Esc键是否按下*/
        char c = cvWaitKey(33);
        /*Esc的键值为27*/
        if(c ==27)
            break;
}
/*释放视频文件*/
        cvReleaseCapture( &capture);
    /*释放Example2窗口*/
        cvDestroyWindow("Example2");
}

2,编写编译脚本

$vim build.sh

#!/bin/sh

gcc `pkg-config –cflags opencv` -o test test.c `pkg-config –libs opencv`

3,编译

$chmod +x build.sh

$./build.sh

测试

$./test video.avi

这里可能会出现视频一闪而过,这里给出解决办法。

尽管是AVI文件,但也可能使用了某种codec,例如:MJPEG Decompressor。 需要把它转换OpenCV支持的AVI文件. OpenCV支持的AVI如下:

Container

FourCC

Name

Description

AVI

‘DIB ‘

RGB(A)

Uncompressed RGB, 24 or 32 bit

AVI

‘I420′

RAW I420

Uncompressed YUV, 4:2:0 chroma subsampled

AVI

‘IYUV’

RAW I420

identical to I420

转换格式解决方法:

下载VitualDub

a. File->Open Video File;

b. Video->Filters->Add->Convert format; 选择4:2:0 Planar YCbCr (YV12)或者 32-Bit RGB。

c. Save as AVI. 保存完毕。”
最后再Import已经转换过的avi,就可以顺利运行了。


1

代码分析

这里我们还是通过前面的方法创建一个命名窗口,在“例2”中,事情变得更加有趣了。

CvCapture* capture = cvCreateFileCapture( argv[1] );

函数cvCreateFileCapture()通过参数设置确定要读入的AVI文件,返回一个指向CvCapture结构的指针。这个结构包括了所有关于要读入AVI文件的信息,其中包含状态信息。在调用这个函数后,返回指针所指向的CvCapture结构被初始化到所对应AVI文件的开头。

frame = cvQueryFrame( capture );

一旦进入while(1)循环,我们便开始读入AVI文件,cvQueryFrame的参数为CvCapture结构的指针。用来将下一帧视频文件载入内存(实际是填充或更新CvCapture结构中)。返回一个对应当前帧的指针。与cvLoadImage不同的是,cvLoadImage为图像分配内存空间,而cvQueryFrame使用已经在cvCapture结构中分配好的内存。这样的话,就没有必要通过cvReleaseImage()对这个返回的图像指针进行释放,当CvCapture结构被释放后,每一帧图像所对应的内存空间即会被释放。

c = cvWaitKey(33);

if( c == 27 ) break;

当前帧被显示后,我们会等待33 ms。[2][11]如果其间用户触发了一个按键,c会被设置成这个按键的ASCII码,否则,c会被设置成-1。如果用户触发了ESC键(ASCII 27),循环被退出,读入视频停止。否则33 ms以后继续执行循环。

需要指出的是,在这个简单的例子程序中,我们没有使用任何准确的方法来控制视频帧率。我们只是简单的通过cvWaitKey来以固定时间间隔载入帧图像,在一个精度要求更高的程序中,通过从CvCapture结构体中读取实际帧率是一个更好的方法!

cvReleaseCapture( &capture );

退出循环体(视频文件已经读入结束或者用户触发了Esc键)后,我们应该释放为CvCapture结构开辟的内存空间,这同时也会关闭所有打开的AVI文件相关的文件句柄。

linksprite学习中心

加载中
返回顶部
顶部