OpenCV的视频输入和相似度测量

现在找一个能拍摄视频的设备真是太容易了。结果大家都用视频来代替以前的序列图像。视频可能由两种形式得到,一个是像网络摄像头那样实时视频流,或者由其他设备产生的压缩编码后的视频文件。幸运的是,OpenCV可以使用相同的C++类、用同一种方式处理这些视频信息。在接下来的教程里你将学习如何使用摄像头或者视频文件。

  • 如何打开和读取视频流
  • 两种检查相似度的方法:PSNR和SSIM

如何读取一个视频流(摄像头或者视频文件)?

        总的来说,视频捕获需要的所有函数都集成在 VideoCapture C++ 类里面。虽然它底层依赖另一个FFmpeg开源库,但是它已经被集成在OpenCV里所以你不需要额外地关注它的具体实现方法。你只需要知道一个视频由一系列图像构成,我们用一个专业点儿的词汇来称呼这些构成视频的图像:“帧”(frame)。此外在视频文件里还有个参数叫做“帧率”(frame rate)的,用来表示两帧之间的间隔时间,帧率的单位是(帧/秒)。这个参数只和视频的播放速度有关,对于单独的一帧图像来说没有任何用途。

       你需要先定义一个 VideoCapture 类的对象来打开和读取视频流。具体可以通过 constructor 或者通过 open 函数来完成。如果使用整型数当参数的话,就可以将这个对象绑定到一个摄像机,将系统指派的ID号当作参数传入即可。例如你可以传入0来打开第一个摄像机,传入1打开第二个摄像机,以此类推。如果使用字符串当参数,就会打开一个由这个字符串(文件名)指定的视频文件。

结构体  CvCapture

  CvCapture 是一个结构体,用来保存图像捕获所需要的信息。 opencv提供两种方式从外部捕获图像:

一种是从摄像头中,
一种是通过解码视频得到图像。
     两种方式都必须从第一帧开始一帧一帧的按顺序获取,因此每获取一帧后都要保存相应的状态和参数。
     比如从视频文件中获取,需要保存视频文件的文件名,相应的解码器类型,下一次如果要获取将需要解码哪一帧等。
 这些信息都保存在CvCapture结构中,每获取一帧后,这些信息都将被更新,获取下一帧需要将新信息传给获取的 api接口
cvCreateFileCapture(char*name)
通过输入要读取的avi文件的路径,然后,该函数返回一个指向 CvCapture结构体的指针。
cvQueryFrame(capture)
输入一个CvCapture 类型的指针,该函数主要功能是将视频文件的下一帧加载到内存。与 cvLoadImage的不同之处是,该函数不重新分配内存空间。
C=cvWaitKey(33)
当前帧被显示后,等待 33毫秒。如果用户触发了一个按键, c会被设置成这个按键的 ASCII码,否则会被设置成 -1。
cvWaitKey(33) 在此处的另外一个作用是,控制帧率。
cvReleaseCapture(&capture)
释放为 CvCapture结构体开辟的内存空间
关闭打开的 AVI文件相关的文件句柄
简单的读写视频程序
#include<opencv2/opencv.hpp>
using namespace cv;


void main() {
    VideoCapture cap;
    cap.open("E:\\VS2015Opencv\\vs2015\\project\\video\\01.avi"); //打开视频,以上两句等价于VideoCapture cap("E://01.avi");

                           //cap.open("http://www.laganiere.name/bike.avi");//也可以直接从网页中获取图片,前提是网页有视频,以及网速够快
    if (!cap.isOpened())//如果视频不能正常打开则返回
        return ;
    Mat frame;
    while (1)
    {
        cap >> frame;//等价于cap.read(frame);
        if (frame.empty())//如果某帧为空则退出循环
            break;
        imshow("video", frame);
        waitKey(20);//每帧延时20毫秒
    }
    cap.release();//释放资源
}

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

void main() {
    VideoCapture cap;
    cap.open("E:\\VS2015Opencv\\vs2015\\project\\video\\01.avi"); 

    if (!cap.isOpened())
        return;

    int width = cap.get(CV_CAP_PROP_FRAME_WIDTH);  //帧宽度
    int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT); //帧高度
    int frameRate = cap.get(CV_CAP_PROP_FPS);  //帧率 x frames/s
    int totalFrames = cap.get(CV_CAP_PROP_FRAME_COUNT); //总帧数

    cout << "视频宽度=" << width << endl;
    cout << "视频高度=" << height << endl;
    cout << "视频总帧数=" << totalFrames << endl;
    cout << "帧率=" << frameRate << endl;
    

    Mat frame;
    while (1)
    {
        cap >> frame;//等价于cap.read(frame);
        if (frame.empty())
            break;
        imshow("video", frame);
        if (waitKey(33) != 255)
            break;
    }
    cap.release();
}

waitkey(33) 如果不按键的时候是返回 oxff,这个无符号就是255,有符号就是-1

windows vs 的环境默认了这个为非符号数 即255,而opencv的新手书中,往往作者环境会认为是-1

解决方案:把原始代码中循环读取帧的

if (waitKey(33)>=0)break;

改为

if (waitKey(33) != 255)break;

或者把waitkey的返回值用有符号数去读取。

猜你喜欢

转载自www.cnblogs.com/fcfc940503/p/11323464.html