OpenCV C++简单的视频读取和保存入门

举报
jackwangcumt 发表于 2021/12/09 22:16:36 2021/12/09
【摘要】 视频的本质可以看作是连续的图像序列,图像序列中的每一个图像被称为帧,换句话说:一帧就是一幅图像。本文用C++演示了如何用OpenCV来从摄像头读取视频数据,并通过不同的编码,如H264、X264和XVID等来保存不同编码的视频文件。

1 视频编码概述


        根据百度百科的定义,视频编码本质上就是一种视频的压缩技术,不同的视频编码方式代表不同的压缩方式,其压缩率和视频质量都存在一定的差异。不同编码的视频往往需要通过工具进行视频格式转换。目前来说,视频流传输中最为重要的编解码标准有:国际电联的H.263、H.264H.265;运动静止图像专家组的M-JPEG;运动图像专家组的MPEG系列标准。
        视频的本质可以看作是连续的图像序列,图像序列中的每一个图像被称为帧,换句话说:一帧就是一幅图像。由于人眼的视觉暂留效应,当帧序列以一定的速率播放时,比如1秒24帧,那么往我们看到的就是连续的动作比较流畅的视频。由于连续的帧之间相似性极高,为便于储存传输,需要对原始的视频进行编码压缩,以去除空间、时间维度的冗余。

2 重要的视频编码概述


        视频编码方式非常的多,但是基于标准的视频编码系列可以总结如下几类 :(1)MPEG系列,由ISO(国际标准组织机构)下属的运动图象专家组开发的视频编码方案,其中主要是Mpeg1(VCD)、Mpeg2(DVD)、Mpeg4(如divx,xvid等)、Mpeg4 AVC。主要应用于视频存储、广播电视、互联网或无线网络的流媒体等。(2)H.26X系列,侧重网络传输,主要应用于实时视频通信领域,如可视电话、实时视频会议、视频监控、流媒体、多媒体视频和Internet视频及多媒体等;H.262标准等同于 MPEG-2的视频编码标准,而H.264/AVC标准则被纳入 MPEG-4的第10部分。 如今广泛使用的 H.264 视频压缩标准(如.mp4文件)可以基于H5进行视频播放,目前还有一种更高的压缩率以及更高质量的编码标准H.265/HEVC标准。H.265的压缩有了显著提高,一样质量的编码视频能节省40%至50%的码流,还提高了并行机制。

3 OpenCV 视频入门


      首先用Visual Studio 工具新建一个C++项目,并进行相关配置,具体可以参考上一篇博文《OpenCV 4 C++环境快速搭建》,这里不再赘述。下面给出一个视频操作的核心代码,具体如下所示:

#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <stdio.h>

using namespace cv;
using namespace std;

int main(int, char**)
{
    //Matrix 对象,存储图像的数值,处理图像而引入的一个封装类
    Mat src;
    //默认摄像头
    VideoCapture cap(0);
    // 检查摄像头是否打开
    if (!cap.isOpened()) {
        cerr << "Unable to open camera\n";
        return -1;
    }
    //获取帧的宽和高,以及每秒帧数
    cout << "Frame width: " << cap.get(CAP_PROP_FRAME_WIDTH) << endl;
    cout << "Frame height: " << cap.get(CAP_PROP_FRAME_HEIGHT) << endl;
    cout << "FPS: " << cap.get(CAP_PROP_FPS) << endl;  // 0
    //读取
    cap >> src;
    // 检测读取视频情况
    if (src.empty()) {
        cerr << "blank frame grabbed\n";
        return -1;
    }
    //是否是彩色的
    bool isColor = (src.type() == CV_8UC3);

    //VideoWriter可以将图像生成视频
    VideoWriter writer;
    double fps = 24.0;

    if (cap.get(CAP_PROP_FPS) > 0) {
        fps = cap.get(CAP_PROP_FPS);
    } 
    // !!! fourcc 编码和 视频扩展名,需要匹配,而且不同平台是不同的
    /////////////////////////////////////////////////////////////// 
    int codec = VideoWriter::fourcc('X', 'V', 'I', 'D');
    string filename = "./live_xvid.mp4";
    ///////////////////////////////////////////////////////////////
    writer.open(filename, codec, fps, src.size(), isColor);
    //检查是否可以正常打开文件
    if (!writer.isOpened()) {
        cerr << "Could not open the output video file for write\n";
        return -1;
    }
    cout << "###################### " << endl;
    for (;;)
    {
        //检查是否读取正常
        if (!cap.read(src)) {
            cerr << " blank frame grabbed\n";
            break;
        }
        //将帧图像写入视频文件
        writer.write(src);
        //显示标题为Live的窗口来显示视频
        imshow("Live", src);
        //监听键盘任意键,退出
        if (waitKey(5) >= 0)
            break;
    }
    return 0;
}

       首先,需要用 include 引入相关的头文件,然后用 using namespace cv 引入 opencv命令空间,int main(int, char**) 是函数入口,Mat src中的Mat是一个Matrix 对象,存储图像的数值,处理图像而引入的一个封装类。VideoCapture cap(0) 从默认摄像头进行捕获,cap.isOpened()可以判断是否可以正常捕获视频,cap.get(CAP_PROP_FRAME_WIDTH)和cap.get(CAP_PROP_FRAME_HEIGHT)可以获取获取帧的宽和高。
     cap >> src 则读取视频数据到Mat src中,VideoWriter可以将图像生成视频,这是opencv图像操作的核心类,int codec = VideoWriter::fourcc('X', 'V', 'I', 'D');则给出了视频的编码方案Xvid,它是一个开放源代码的MPEG-4视频编解码器,它是基于OpenDivX而编写的,同时它是世界上最常用的视频编码解码器(codec),它的总体表现非常的好。还有一种DivX视频编码,支持MPEG-4, H.264和H.265标准的视频,分辨率可高达4K超高清。
     注意:XviD编码的的视频文件扩展名可以是AVI、MKV、MP4等。需要说明的是,仅从扩展名并不能看出这个视频的编码格式。
     那么,opencv能否支持H.264呢,比较将设置如下所示:

int codec = VideoWriter::fourcc('H', '2', '6', '4'); 
string filename = "./live_h264.mp4";

    在Windows平台上运行此代码,则抛出如下信息:

Failed to load OpenH264 library : openh264 - 1.8.0 - win64.dll
Please check environment and /or download library : https://github.com/cisco/openh264/releases

    其中让我们使用OpenH264,从 https://github.com/cisco/openh264/releases 上下载 openh264-1.8.0-win64.dll ,放于 文件源码目录中即可加载。再次运行,则抛出如下信息:

PluginBackend::initWriterAPI Video I / O: plugin is ready to use 'FFmpeg OpenCV Video I/O Writer plugin'
OpenCV : FFMPEG : tag 0x34363248 / 'H264' is not supported with codec id 27 and format 'mp4 / MP4 (MPEG-4 Part 14)'
OpenCV : FFMPEG : fallback to use tag 0x31637661 / 'avc1'

OpenH264 Video Codec provided by Cisco Systems, Inc.

Writing videofile : . / live.mp4
Press any key to terminate

     其中正确加载了 openh264-1.8.0-win64.dll ,显示OpenH264 Video Codec 相关字样。但是提示了 'H264' is not supported with codec id 27 and format 'mp4 / MP4 (MPEG-4 Part 14)' 。说明H264和mp4文件不兼容,系统回退到OpenH264提供的 AVC1编码,因此修改编码如下即可:

int codec = VideoWriter::fourcc('a', 'v', 'c', '1'); //avc1   //openh264
string filename = "./live.mp4";

     我尝试了另外一种编码,也成功了,代码如下:

int codec = VideoWriter::fourcc('X', '2', '6', '4');
string filename = "./live_x264.mkv";

     如何查看视频的编码信息呢,可以按照 ffmpeg 工具,其中一个组件为 ffprobe ,下面给出命令:

C:\ffmpeg\bin>ffprobe.exe   live_x264.mkv

     输出如下信息:

  Metadata:
    ENCODER         : Lavf58.76.100
  Duration: 00:00:46.04, start: 0.000000, bitrate: 3681 kb/s
  Stream #0:0: Video: h264 (Constrained Baseline), yuv420p(progressive), 640x480, 24 fps, 24 tbr, 1k tbn, 2k tbc (default)
    Metadata:
      DURATION        : 00:00:46.042000000

     其中的 h264 (Constrained Baseline), yuv420p(progressive), 640x480, 24 fps 则表示h264编码,视频宽高为640x480,帧数为24 。下面给出AVC1编码生成的视频信息:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'live.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.76.100
  Duration: 00:01:13.75, start: 0.000000, bitrate: 1847 kb/s
  Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 640x480, 1847 kb/s, 12 fps, 12 tbr, 12288 tbn, 24576 tbc (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]

   其中显示的是 h264 (Constrained Baseline) (avc1 / 0x31637661)  。下面给出另外的编码及输出信息:

int codec = VideoWriter::fourcc('M', 'J', 'P', 'G'); 
string filename = "./live_mjpg.avi"; 
#######################################
Input #0, avi, from 'live_mjpg.avi':
  Metadata:
    software        : Lavf58.76.100
  Duration: 00:00:11.08, start: 0.000000, bitrate: 7185 kb/s
  Stream #0:0: Video: mjpeg (Baseline) (MJPG / 0x47504A4D), yuvj420p(pc, bt470bg/unknown/unknown), 640x480, 7203 kb/s, 24 fps, 24 tbr, 24 tbn, 24 tbc

    说明此时是mjpeg (Baseline) (MJPG / 0x47504A4D) 编码。下面给出本文示例中的编码及输出信息:

int codec = VideoWriter::fourcc('X', 'V', 'I', 'D');
string filename = "./live_xvid.mp4";
#############################
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'live_xvid.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2mp41
    encoder         : Lavf58.76.100
  Duration: 00:00:05.38, start: 0.000000, bitrate: 5824 kb/s
  Stream #0:0(und): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D), yuv420p, 640x480 [SAR 1:1 DAR 4:3], 5822 kb/s, 24 fps, 24 tbr, 12288 tbn, 24 tbc (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]

     由此可见,XVID编码使用的是 mpeg4 (Simple Profile) (mp4v / 0x7634706D) 。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。