OpenCV开发笔记(四):OpenCV图片和视频数据的读取与存储

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100735114

目录

前言

OpenCV读取图片文件

OpenCV存储图片文件

图片测试Demo

代码

运行效果

OpenCV读取视频

OpenCV存储视频

视频测试Demo

代码

运行效果

Demo源码

入坑

入坑一:读取图片成功,窗口显示成功,但是图片显示失败

参考引用

工程模板:对应版本号v1.2.0


 

OpenCV开发专栏

OpenCV开发笔记(〇):使用mingw530_32编译openCV3.4.1源码,搭建Qt5.9.3的openCV开发环境

OpenCV开发笔记(一):OpenCV介绍、编译

OpenCV开发笔记(二):cvui交互界面

OpenCV开发笔记(三):OpenCV图像的概念和基本操作

OpenCV开发笔记(四):OpenCV图片和视频数据的读取与存储

OpenCV开发笔记(五):OpenCV读取与操作摄像头

OpenCV开发笔记(六):OpenCV基础数据结构、颜色转换函数和颜色空间

OpenCV开发笔记(七):OpenCV基础图形绘制

OpenCV开发笔记(八):OpenCV常用操作之计时、缩放、旋转、镜像

OpenCV开发笔记(九):OpenCV区域图像(ROI)和整体、局部图像混合

OpenCV开发笔记(十):OpenCV图像颜色通道分离和图像颜色多通道混合

持续补充中…

 

    OpenCV开发笔记(四):图片和视频数据的读取与存储

前言

       OpenCV对图像进行操作,图像包含图片和视频。

 

OpenCV读取图片文件

       读取图像文件,使用的imread()。

       imread()函数返回的是Mat对象,如果读取函数文件失败,会返回一个空矩阵(常量cv::Mat::data变量的值是NULL)。

Mat imread(const string& filename, int flags=1 )
  • filename:是被读取或者保存的图像文件名;
  • flag:参数值有三种情况:

        flag>0,该函数返回3通道图像,如果磁盘上的图像文件是单通道的灰度图像,则会被强制转为3通道;

        flag=0,该函数返回单通道图像,如果磁盘的图像文件是多通道图像,则会被强制转为单通道;

        flag<0,则函数不对图像进行通道转换。

       imread()函数支持多种文件格式,且该函数是根据图像文件的内容来确定文

件格式,而不是根据文件的扩展名来确定。

       支持的图像格式:bmp、dib、jpg、jpeg、jpe、png、pbm、pgm、ppm、sr、ras、tiff、tif、exr、jp2。(需要对应的库支持,开发使用的库要编译时添加进去,然后编译生成opencv库)

 

OpenCV存储图片文件

       保存图像文件,使用的imwrite()。

       imwrite()函数返回的是bool。

bool imwrite(const string& filename, 
           InputArray image,
           const vector<int>& params=vector<int>())

       filename是存成指定的文件名,注意格式是由指定的文件扩展名确定。

       PNG-是无损压缩格式,推荐使用。

       BMP-格式是无损格式,但是一般不进行压缩,文件尺寸非常大;

       JPEG-格式的文件娇小,但是JPEG是有损压缩,会丢失一些信息。

       并不是所有的 Mat 对象都可以存为图像文件,目前支持的格式只有8U类型的单通道和3通道(颜色顺序为 BGR)矩阵;如果需要要保存16U格式图像, 只能使用PNG、JPEG 2000和TIFF格式。

       如果希望将其他格式的矩阵保存为图像文件,可以先用Mat::convertTo()函数或者cvtColor()函数将矩阵转为可以保存的格式。

       注意:在保存文件时,如果文件已经存在,imwrite()函数不会进行提醒,将直接覆盖掉以前的文件。

 

图片测试Demo

代码

#if TEST_IMAGE
    // 读取
    cv::Mat image = cv::imread("1.jpg");
    // 判断是否读取成功
    if(image.data == NULL)
    {
        QMessageBox::warning(0, "读取图片失败", "1.jpg");
        return;
    }
    // 显示
    cv::imshow("readImage", image);
    // 作一个图像行列转换操作,再保存
    image = image.t();
    // 保存
    if(!cv::imwrite("1 to 2.jpg", image))
    {
        QMessageBox::warning(0, "保存失败", "1.jpg");
        return;
    }
#endif

运行效果

          

 

OpenCV读取视频

       图像文件,可以根据文件扩展名得知图像的格式。但是此经验并不能推广到视频文件中。有时候会碰到奇怪的问题,都是avi视频文件,有的能用OpenCV打开,有的不能。

       视频的格式主要由压缩算法决定,就是视频编解码器。视频文件能读或者写,关键看是否有相应的编解码器。

       OpenCV 2中提供了两个类来实现视频的读写。读视频的类是VideoCapture,写视频的类是VideoWriter。

       VideoCapture 既可以从视频文件读取图像,也可以从摄像头读取图像。可以使用该类的构造函数打开视频文件或者摄像头。如果 VideoCapture 对象已经创建,也可以使用VideoCapture::open()打开,VideoCapture::open()函数会自动调用VideoCapture::release()函数,先释放已经打开的视频,然后再打开新视频。

OpenCV存储视频

       使用OpenCV创建视频与读视频不同的是,需要在创建视频时设置一系列参数,包括:文件名,编解码器,帧率,宽度和高度等。

       编解码器使用四个字符表示,可以是:

  • CV_FOURCC('M','J','P','G')
  • CV_FOURCC('X','V','I','D')
  • CV_FOURCC('D','I','V','X')
  • 还有其他的

如果使用某种编解码器无法创建视频文件,请尝试其他的编解码器。

       将图像写入视频可以使用VideoWriter::write()函数,VideoWriter类中也重载了<<操作符,使用起来非常方便。另外需要注意:待写入的图像尺寸必须与创建视频时指定的尺寸一致。

 

视频测试Demo

代码

#if TEST_VIDEO
    cv::VideoCapture videoCapture;
    // 打开视频
    if(!videoCapture.open("1.mp4"))
    {
        QMessageBox::warning(0, "读取视频失败", "1.mp4");
        return;
    }
    int width = 0;
    int height = 0;
    for(;;)
    {
        cv::Mat frame;
        videoCapture >> frame;
        // 第一次进入,记录视频尺寸
        if(width == 0)
        {
            width = frame.cols;
            height = frame.rows;
        }
        // 最后一帧之后为空,退出
        if(frame.empty())
        {
            break;
        }
        // 显示
        cv::imshow("readVideo", frame);
        // 等待1s,有按键输入立即结束本次
        if(cv::waitKey(1) >= 0)
            break;

    }
    // 将视频输入流返回到第0帧
    videoCapture.set(cv::CAP_PROP_POS_FRAMES, 0);
    cv::VideoWriter videoWrite;
    // 翻转操作了
    width = width + height;
    height = width - height;
    width = width - height;
    if(!videoWrite.open("1 to 1.avi", CV_FOURCC('M','J','P','G'), 25, cv::Size(width, height)))
    {
        QMessageBox::warning(0, "保存视频失败", "1 to 1.avi");
        return;
    }
    QString version = "v1.3.0";
    QString text = QString("OpenCVDemo %1 QQ21497936 blog.csdn.net/qq21497936").arg(version);
    for(;;)
    {
        cv::Mat frame;
        videoCapture >> frame;
        if(frame.empty())
        {
            break;
        }
        // 沿对角线行列翻转
        frame = frame.t();
        cv::putText(frame,
                    cv::String(text.toUtf8().data()),
                    cv::Point(0, height / 2),
                    cv::FONT_HERSHEY_SCRIPT_SIMPLEX,
                    0.8,
                    cv::Scalar(0,0,255),
                    3,
                    8,
                    false);
        cv::imshow("readVideo", frame);
        videoWrite << frame;
        if(cv::waitKey(1) >= 0)
            break;
    }
#endif

 

运行效果

然后

 

Demo源码

void OpenCVManager::testImageAndVideo()
{
#define TEST_IMAGE (0)
#define TEST_VIDEO (1)

#if TEST_IMAGE
    // 读取
    cv::Mat image = cv::imread("1.jpg");
    // 判断是否读取成功
    if(image.data == NULL)
    {
        QMessageBox::warning(0, "读取图片失败", "1.jpg");
        return;
    }
    // 显示
    cv::imshow("readImage", image);
    // 作一个图像行列转换操作,再保存
    image = image.t();
    // 保存
    if(!cv::imwrite("1 to 2.jpg", image))
    {
        QMessageBox::warning(0, "保存失败", "1.jpg");
        return;
    }
#endif

#if TEST_VIDEO
    cv::VideoCapture videoCapture;
    // 打开视频
    if(!videoCapture.open("1.mp4"))
    {
        QMessageBox::warning(0, "读取视频失败", "1.mp4");
        return;
    }
    int width = 0;
    int height = 0;
    for(;;)
    {
        cv::Mat frame;
        videoCapture >> frame;
        // 第一次进入,记录视频尺寸
        if(width == 0)
        {
            width = frame.cols;
            height = frame.rows;
        }
        // 最后一帧之后为空,退出
        if(frame.empty())
        {
            break;
        }
        // 显示
        cv::imshow("readVideo", frame);
        // 等待1s,有按键输入立即结束本次
        if(cv::waitKey(1) >= 0)
            break;

    }
    // 将视频输入流返回到第0帧
    videoCapture.set(cv::CAP_PROP_POS_FRAMES, 0);
    cv::VideoWriter videoWrite;
    // 翻转操作了
    width = width + height;
    height = width - height;
    width = width - height;
    if(!videoWrite.open("1 to 1.avi", CV_FOURCC('M','J','P','G'), 25, cv::Size(width, height)))
    {
        QMessageBox::warning(0, "保存视频失败", "1 to 1.avi");
        return;
    }
    QString version = "v1.2.0";
    QString text = QString("OpenCVDemo %1 QQ21497936 blog.csdn.net/qq21497936").arg(version);
    for(;;)
    {
        cv::Mat frame;
        videoCapture >> frame;
        if(frame.empty())
        {
            break;
        }
        // 沿对角线行列翻转
        frame = frame.t();
        cv::putText(frame,
                    cv::String(text.toUtf8().data()),
                    cv::Point(0, height / 2),
                    cv::FONT_HERSHEY_SCRIPT_SIMPLEX,
                    0.8,
                    cv::Scalar(0,0,255),
                    3,
                    8,
                    false);
        cv::imshow("readVideo", frame);
        videoWrite << frame;
        if(cv::waitKey(1) >= 0)
            break;
    }
#endif
}

 

入坑

入坑一:读取图片成功,窗口显示成功,但是图片显示失败     

     

解决方法:使用了中文作为窗口标题要改为英文标题

      

 

参考引用

       《OpenCV入门教程》

 

工程模板:对应版本号v1.2.0

       对应版本号v1.2.0

欢迎技术交流和帮助,提供IT相关服务,索要源码请联系博主QQ: 21497936,若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100735114

发布了227 篇原创文章 · 获赞 237 · 访问量 40万+

猜你喜欢

转载自blog.csdn.net/qq21497936/article/details/100735114