一、 读写图像文件
将图像文件读入内存,可以使用 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 参数值有三种情况:
imread()函数支持多种文件格式,且该函数是根据图像文件的内容来确定文件格式,而不是根据文件的扩展名来确定。所指示的文件格式如下:
你所安装的 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 可以指定文件格式的一些细节信息。这个参数里面的数值是跟文件格式相关的:
并不是所有的 Mat 对象都可以存为图像文件,目前支持的格式只有 8U 类型的单通道和 3 通道(颜色顺序为 BGR)矩阵;如果需要要保存 16U 格式图像, 只能使用 PNG、 JPEG 2000 和 TIFF 格式。
如果希望将其他格式的矩阵保存为图像文件,可以先用 Mat::convertTo()函数或者 cvtColor()函数将矩阵转为可以保存的格式。
另外需要注意的是,在保存文件时,如果文件已经存在, imwrite()函数不会进行提醒,将直接覆盖掉以前的文件。
下面例程展示了如何读入一副图像,然后对图像进行 Canny 边缘操作,最后将结果保存到图像文件中。
#include "stdafx.h"
#include
#include
#include
#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
#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
#include
#include
#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;
}