图像识别与处理之Opencv——图像数据获取与存储(imread()和imwrite()函数)

来源:互联网 发布:淘宝外卖怎么看在骑手 编辑:程序博客网 时间:2024/06/05 04:12

一、 读写图像文件

将图像文件读入内存,可以使用 imread()函数;
将 Mat 对象以图像文件格式写入内存,可以使用imwrite()函数。

1.1 读图像文件——imread()
imread()函数返回的是 Mat 对象,如果读取文件失败,则会返回一个空矩阵,即 Mat::data 的值是 NULL。执行 imread()之后,需要检查文件是否成功读入,你可以使用 Mat::empty()函数进行检查。
imread()函数的声明如下:

Mat imread(const string& filename, int flags=1)

很明显参数 filename 是被读取或者保存的图像文件名;在 imread()函数中,flag 参数值有三种情况:

  • flag>0,该函数返回 3 通道图像,如果磁盘上的图像文件是单通道的灰度图像,则会被强制转为 3 通道;
  • flag=0,该函数返回单通道图像,如果磁盘的图像文件是多通道图像,则会被强制转为单通道;
  • flag<0,则函数不对图像进行通道转换。

imread()函数支持多种文件格式,且该函数是根据图像文件的内容来确定文件格式,而不是根据文件的扩展名来确定。所指示的文件格式如下:

  • Windows 位图文件 - BMP, DIB;
  • JPEG 文件 - JPEG, JPG, JPE;
  • 便携式网络图片 - PNG;
  • 便携式图像格式 - PBM, PGM, PPM;
  • Sun rasters - SR, RAS;
  • TIFF 文件 - TIFF, TIF;
  • OpenEXR HDR 图片 - EXR;
  • JPEG 2000 图片- jp2。

你所安装的 OpenCV 并不一定能支持上述所有格式,文件格式的支持需要特定的库,只有在编译 OpenCV 添加了相应的文件格式库,才可支持其格式。

1.2 写图像文件
将图像写入文件,可使用 imwrite()函数,该函数的声明如下:

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

文件的格式由 filename 参数指定的文件扩展名确定。推荐使用 PNG 文件格式。 BMP 格式是无损格式,但是一般不进行压缩,文件尺寸非常大; JPEG 格式的文件娇小,但是 JPEG 是有损压缩,会丢失一些信息。 PNG 是无损压缩格式,推荐使用

imwrite()函数的第三个参数 params 可以指定文件格式的一些细节信息。这个参数里面的数值是跟文件格式相关的:

  • JPEG:表示图像的质量,取值范围从 0 到 100。数值越大表示图像质量越高,当然文件也越大。默认值是 95。
  • PNG:表示压缩级别,取值范围是从 0 到 9。数值越大表示文件越小,但是压缩花费的时间也越长。默认值是 3。
  • PPM, PGM 或 PBM:表示文件是以二进制还是纯文本方式存储,取值为0 或 1。如果取值为 1,则表示以二进制方式存储。默认值是 1。

并不是所有的 Mat 对象都可以存为图像文件,目前支持的格式只有 8U 类型的单通道和 3 通道(颜色顺序为 BGR)矩阵;如果需要要保存 16U 格式图像, 只能使用 PNG、 JPEG 2000 和 TIFF 格式。
如果希望将其他格式的矩阵保存为图像文件,可以先用 Mat::convertTo()函数或者 cvtColor()函数将矩阵转为可以保存的格式。
另外需要注意的是,在保存文件时,如果文件已经存在, imwrite()函数不会进行提醒,将直接覆盖掉以前的文件。

下面例程展示了如何读入一副图像,然后对图像进行 Canny 边缘操作,最后将结果保存到图像文件中。

#include "stdafx.h"#include<iostream>  #include <opencv2/core/core.hpp>  #include <opencv2/highgui/highgui.hpp>  #include "opencv2/opencv.hpp"using namespace std;using namespace cv;int main(int argc, char* argv[]){  //读入图像,并将之转为单通道图像    Mat im = imread("lena.jpg", 0); //相对路径,即在工程文件夹里    //请一定检查是否成功读图        if (im.empty())        {            cout << "Can not load image." << endl;            return -1;        }        //进行 Canny 操作,并将结果存于 result        Mat result;        Canny(im, result, 50, 150);        //保存结果        imwrite("lena-canny.png", result);        return 0;    }


lena.jpg 文件放在当前目录,运行该例程后, lena-canny.png 将会出现在当前目录。 lena-canny.png 图像如下图所示,是 lena.jpg 的边缘提取结果

这里写图片描述

二、读写视频

介绍 OpenCV 读写视频之前,先介绍一下编解码器(codec)。如果是图像文件,我们可以根据文件扩展名得知图像的格式。但是此经验并不能推广到视频文件中。有些 OpenCV 用户会碰到奇怪的问题,都是 avi 视频文件,有的能用 OpenCV打开,有的不能。
视频的格式主要由压缩算法决定。压缩算法称之为编码器(coder),解压算法称之为解码器(decoder),编解码算法可以统称为编解码器(codec)。视频文件能读或者写,关键看是否有相应的编解码器。编解码器的种类非常多,常用的有 MJPG、 XVID、 DIVX 等,完整的列表请参考 FOURCC 网站 http://www.fourcc.org/codecs.php。因此视频文件的扩展名(如 avi 等)往往只能表示这是一个视频文件。OpenCV 2 中提供了两个类来实现视频的读写。读视频的类是 VideoCapture写视频的类是 VideoWriter

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

如果要读一帧,可以使用 VideoCapture::read()函数。VideoCapture 类重载了>>操作符,实现了读视频帧的功能。 下面的例程演示了使用 VideoCapture 类读视频。

#include <iostream>#include "opencv2/opencv.hpp"    using namespace std;    using namespace cv;    int main(int argc, char** argv)    {        //打开第一个摄像头        //VideoCapture cap(0);        //打开视频文件        VideoCapture cap("video.short.raw.avi");        //检查是否成功打开        if (!cap.isOpened())        {            cerr << "Can not open a camera or file." << endl;            return -1;        }        Mat edges;        //创建窗口        namedWindow("edges", 1);        for (;;)        {            Mat frame;            //从 cap 中读一帧,存到 frame            cap >> frame;            if (frame.empty())//如果未读到图像                break;            cvtColor(frame, edges, CV_BGR2GRAY);//将读到的图像转为灰度图            Canny(edges, edges, 0, 30, 3); //进行边缘提取操作            //显示结果            imshow("edges", edges);            //等待 30 秒,如果按键则退出循环            if (waitKey(30) >= 0)                break;        }        //退出时会自动释放 cap 中占用资源        return 0;    }

2.2 写视频

使用 OpenCV 创建视频也非常简单,与读视频不同的是,你需要在创建视频时设置一系列参数,包括:文件名,编解码器,帧率,宽度和高度等。编解码器使用四个字符表示,可以是
CV_FOURCC(‘M’,’J’,’P’,’G’)、
CV_FOURCC(‘X’,’V’,’I’,’D’)、
CV_FOURCC(‘D’,’I’,’V’,’X’)等。

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

将图像写入视频可以使用 VideoWriter::write()函数, VideoWriter 类中也重载了<<操作符,使用起来非常方便。另外需要注意:待写入的图像尺寸必须与创建
视频时指定的尺寸一致。下面例程演示了如何写视频文件。本例程将生成一个视频文件,视频的第 0帧上是一个红色的“0”,第 1 帧上是个红色的“1”,以此类推,共 100 帧。

#include "stdafx.h"#include<iostream>  #include <opencv2/core/core.hpp>  #include <opencv2/highgui/highgui.hpp>  #include "opencv2/opencv.hpp"using namespace std;using namespace cv;int main(int argc, char* argv[]){    //定义视频的宽度和高度    Size s(320, 240);    //创建 writer,并指定 FOURCC 及 FPS 等参数    VideoWriter writer = VideoWriter("myvideo.avi", CV_FOURCC('M', 'J', 'P', 'G'), 25, s);    //检查是否成功创建    if (writer.isOpened())    {        cerr << "Can create video file.\n" << endl;    }    if (!writer.isOpened())    {        cerr << "Can not create video file.\n" << endl;        return -1;    }    //视频帧    Mat frame(s, CV_8UC3);    for (int i = 0; i < 100; i++)    {        frame = Scalar::all(255);        //将整数 i 转为 i 字符串类型        char text[128];        snprintf(text, sizeof(text), "%d", i);        //将数字绘到画面上        putText(frame, text, Point(s.width / 3, s.height / 3),            FONT_HERSHEY_SCRIPT_SIMPLEX, 3,            Scalar(0, 0, 255), 3, 8); //将在图像中呈现指定的文本字符串        writer << frame;  //将图像写入视频    }    //退出程序时会自动关闭视频文件    return 0;}

该程序生成的视频截图:
这里写图片描述

阅读全文
0 0
原创粉丝点击