OpenCV 4.x API 详解与C++实例-图像与视频读取与保存

第二节 图像与视频读取与保存

在前面,详细描述了OpenCV库的imgcodecs模块的图像读取、保存、编码、解码及highgui模块的基本操作。接下来将详细描述highgui模块对图像、视频的显示操作。

1、图像显示


cv::imshow:在指定的窗口中显示图像。

void cv::imshow (const String & winname,InputArray mat)

imshow函数在指定的窗口中显示图像。 如果窗口是使用cv :: WINDOW_AUTOSIZE标志创建的,则图像以其原始大小显示,但是它仍然受屏幕分辨率的限制。 否则,将缩放图像以适合窗口。 该功能可能会缩放图像,具体取决于其深度:

  • 如果图像是8位无符号的,则按原样显示。
  • 如果图像是16位无符号或32位整数,则将像素除以256。即,值范围[0,255 * 256]映射到[0,255]。
  • 如果图像是32位或64位浮点,则将像素值乘以255。即,值范围[0,1]映射为[0,255]。

如果使用OpenGL支持创建了window,则cv :: imshow还支持ogl :: Buffer,ogl :: Texture2D和cuda :: GpuMat作为输入。

如果在创建窗口之前调用此函数,则假定使用cv :: WINDOW_AUTOSIZE创建一个新窗口。

如果需要显示大于屏幕分辨率的图像,则需要在imshow之前调用namedWindow(“”,WINDOW_NORMAL)。

注意

此函数后应跟cv :: waitKey函数,该函数显示指定毫秒的图像。 否则,它将不会显示图像。 例如,waitKey(0)将无限期显示窗口,直到任何按键为止(适用于图像显示)。 waitKey(25)将显示25毫秒的帧,此后将自动关闭显示。 (如果将其放在循环中以阅读视频,它将逐帧显示视频)

在windows系统中,OpenCV还支持如下操作:

  • 按Ctrl + C会将图像复制到剪贴板。
  • 按Ctrl + S将显示一个对话框来保存图像。
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;

int main()
{
    // 创建窗口
    cv::namedWindow("image",cv::WINDOW_NORMAL);
    cv::Mat src = cv::imread("d:/develop/machine-vision-workbench/resources/images/f1.jpg");
    // 调整窗口大小
    cv::resizeWindow("image",640,480);
    cv::imshow("image",src);
    cv::waitKey();
    cv::destroyAllWindows();
    return 0;
}

2、视频读取、显示与保存


1)、cv::VideoCapture:从视频文件(本地或网络流)、图像序列、摄像机捕获视频的类。

  • cv::VideoCapture()

  • cv::VideoCapture::VideoCapture(const String & filename,int apiPreference = CAP_ANY)

  • cv::VideoCapture::VideoCapture(int index,int apiPreference = CAP_ANY)

经常使用的为VideoCapture第二、第三个构造函数。当filename为本地视频文件路径或网络视频流(如rtsp、rtmp、hls等协议);参数index为本地摄像头设备的序号,一般是从0开始。

VideoCapture提个了几个简单而高效的函数:

  • cv::VideoCapture::get:查询视频的属性。具体可以参考cv::VideoCaptureProperties

    virtual double cv::VideoCapture::get(int propId)const

  • cv::VideoCapture::getBackendName:返回使用的后端API名称(一般情况下默认为FFMPG)

    String cv::VideoCapture::getBackendName ()const

  • cv::VideoCapture::grab:抓取视频文件或摄像头设备下一帧图像。如果成功,则返回true。

    virtual bool cv::VideoCapture::grab()

    该功能的主要用途是在多相机环境中,尤其是在相机没有硬件同步的情况下。 也就是说,您为每个摄像机调用VideoCapture :: grab(),然后调用较慢的方法VideoCapture :: retrieve()解码并从每个摄像机获取帧。 这样,消除了去马赛克或运动jpeg解压缩等方面的开销,并且从不同摄像机检索到的帧将在时间上更近。

    另外,当连接的摄像机是多头摄像机(例如,立体摄像机或Kinect设备)时,从中检索数据的正确方法是先调用VideoCapture :: grab(),然后再调用VideoCapture :: retrieve() 使用不同的channel参数值一次或多次。

  • cv::VideoCapture::isOpened:判断文件是否准备好或摄像设备是否初始化成功。如果成功,则返回true。

  • cv::VideoCapture::open:打开视频文件或摄像设备,效果等同VideoCapture构造函数传递相关参数初始化

  • **操作符>>:**抓取并返回下一帧图像。

  • cv::VideoCapture::read:抓取、解码并返回下一帧图像。

    virtual bool cv::VideoCapture::read (OutputArray image)

  • cv::VideoCapture::release:关闭打开文件或摄像设备。

  • cv::VideoCapture::retrive:解码并返回抓取的视频帧。

    virtual bool cv::VideoCapture::retrieve (OutputArray image,int flag = 0)

  • cv::VideoCapture::set:VideoCapture中属性设置。

    virtual bool cv::VideoCapture::set(int propId,double value)

    propId请参考:cv::VideoCaptureProperties

  • cv::VideoCapture::waitAny:静态函数,等待来自VideoCapture的就绪帧。

    static bool cv::VideoCapture::waitAny(const std::vector< VideoCapture > & streams,std::vector< int > & readyIndex,int64 timeoutNs = 0)

    参数streams为输入流列表;readyIndex,为就绪的设备列表序号;timeoutNs超时时间。

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;

int main()
{
    // 打开一个网络视频流
    const std::string webstream = "http://ivi.bupt.edu.cn/hls/cctv3hd.m3u8";
    cv::VideoCapture cap(webstream);

    if(!cap.isOpened()){
        cerr << "cannot open rtsp stream.\n";
        exit(0);
    }
    // 查询后端支持的API
    cout << "backend name:" << cap.getBackendName();
    // 获取视频流的帧宽度和高度
    int width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
    int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
    cout << "width = " << width << ",height = " << height << endl;

    cv::Mat frame;
    int key = -1;
    while(true){
        cap >> frame;

        if(frame.empty()){
            cerr << "cannot grab frame from video stream\n";
            break;
        }
        cv::imshow("video",frame);
        key = cv::waitKey(10);
        if(key == 27){
            break;
        }
    }
    cv::destroyAllWindows();
    cap.release();

    return 0;
}

2)cv::VideoWriter:将视频或图像序列写到文件。

  • VideoWriter()
  • VideoWriter (const String &filename, int fourcc, double fps, Size frameSize, bool isColor=true)
  • VideoWriter (const String &filename, int apiPreference, int fourcc, double fps, Size frameSize, bool isColor=true)
  • VideoWriter (const String &filename, int fourcc, double fps, const Size &frameSize, const std::vector< int > &params)
  • VideoWriter (const String &filename, int apiPreference, int fourcc, double fps, const Size &frameSize, const std::vector< int > &params)

其中,参数fourcc为视频或图像序列的编码格式,比如VideoWriter :: fourcc(‘P’,‘I’,‘M’,‘1’)是MPEG-1编解码器,VideoWriter :: fourcc(‘M’,‘J’,‘P’,‘G’)是 运动jpeg编解码器等;参数fps为帧率;参数frameSize为帧大小;参数isColor为是否按彩色图像编码;经常使用的为第二个构造函数。

cv::VideoCapture::write函数实现了将视频帧或图像序列写到文件。

virtual void cv::VideoWriter::write(InputArray image)

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;

int main()
{
    // 从本地摄像头创建VideoCapture
    cv::VideoCapture cap(0);
    if(!cap.isOpened()){
        cerr << "cannot open camera.\n";
        exit(0);
    }
    // 获取视频流的帧宽度、高度和帧率
    int width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
    int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
    int rate = cap.get(cv::CAP_PROP_FPS);
    cout << "video info:width = " << width << ",height = " << height << ",frame rate = " << rate << endl;
    // 创建一个MPEG-4编码 视频Writer
    cv::VideoWriter writer("e:/temp/output.mp4",
                           cv::VideoWriter::fourcc('D','I','V','X'),rate,
                           cv::Size(width,height));
    cv::Mat frame;
    int key = -1;
    while(cap.isOpened()){
        cap >> frame;
        if(frame.empty()){
            cout << "cannot grab frame from camera.\n";
            break;
        }
        // TODO:对图像进行各种处理
        // 对图像进行取反,实现底片效果
        cv::imshow("video",frame);
        frame -= 255;
        // 保存视频
        writer.write(frame);
        cv::imshow("video:invert",frame);
        key = cv::waitKey(10);
        if(key == 27){
            break;
        }
    }
    cv::destroyAllWindows();
    cap.release();
    writer.release();
    return 0;
}

常见的视频格式编码如下:

  • CV_FOURCC(‘P’, ‘I’, ‘M’, ‘1’) = MPEG-1 code

  • CV_FOURCC(‘M’, ‘J’, ‘P’, ‘G’) = motion-jpeg codec

  • CV_FOURCC(‘M’, ‘P’, ‘4’, ‘2’) = MPEG-4.2 codec

  • CV_FOURCC(‘D’, ‘I’, ‘V’, ‘3’) = MPEG-4.3 codec

  • CV_FOURCC(‘D’, ‘I’, ‘V’, ‘X’) = MPEG-4 codec

  • CV_FOURCC(‘U’, ‘2’, ‘6’, ‘3’) = H263 codec

  • CV_FOURCC(‘I’, ‘2’, ‘6’, ‘3’) = H263I codec

CV_FOURCC(‘F’, ‘L’, ‘V’, ‘1’) = FLV1 codec MPEG-1是为CD光盘介质定制的视频和音频压缩格式; Motion JPEG是一种视频压缩格式,其中每一帧图像都分别使用JPEG编码; MPEG-4利用很窄的带宽,通过帧重建技术,压缩和传输数据,以求以最少的数据获得最佳的图像质量;

具体可以参考fourcc

猜你喜欢

转载自blog.csdn.net/wujuxKkoolerter/article/details/112134706