七. 图像、视频和数据文件
图像
从磁盘读取图像或者将图像保存到磁盘是我们完成的最基本的任务, 最简单的实现方法是利用OpenCV的cv::imread() 和 cv::imwrite() 函数, 这些函数会帮助你完成包括与文件系统进行交互, 图像编码和解码在内的所有工作.
cv::imread()
用来读取图像, 其函数定义:
cv::Mat cv::imread(
const string& filename, //inut name
int flags = cv::IMREAD_COLOR //flags set how to interpret file
);
flags可选参数:
标志 | 含义 | 默认值 |
---|---|---|
cv::IMREAD_COLOR | 总是读取三通道图形图像 | 是 |
cv::IMREAD_GRAYSCALE | 总是读取单通道图像(灰度图像) | 否 |
cv::IMREAD_ANYCOLOR | 通道数由文件实际通道数(不超过3) | 否 |
cv::IMREAD_ANYDEPTH | 允许加载超过8bit深度 | 否 |
cv::IMREA_UNCHANGED | cv::IMREAD_ANYCOLOR和cv::IMREAD_ANYDEPTH组合 | 否 |
若cv::imread()载入图像失败, 并不会抛出一场, 而是返回一空的cv::Mat(可以用cv::Mat::empty()==ture来进行判断)
cv::imwrite()
用来保存图像, 其函数定义:
bool cv::imwrite(
const string& filename, //Input filename
cv::InputArry image, //Image to write to file
const vector<int>& params = vector<int>() //(Optional) for paramterized fmts
);
第一个参数定义了文件名, 文件拓展名部分可用来决定如何保存图像, OpenCV支持的常用拓展名:
- .jpg或者.jpeg 8位数据;单通道或三通道输入
- .jp2
- .tif或.tiff 8位或者16位数据; 单通道, 三通道或四通道输入
- .png 8/16位数据; 单, 三, 四通道输入
- .bmp 8位数据; 单, 三, 四通道输入
- .ppm 8位数据; 单, 三通道
第三个参数被用作特殊类型文件的写入操作时所需的数据. 输入参数为内部为整型数据的一个STL vector.
其具体内容为: 一系列的参数ID, 以及与该参数对应的参数值, 每个参数ID之后跟着其对应的值
参数ID起的别名以及取值范围:
标志 | 含义 | 取值范围 | 默认值 |
---|---|---|---|
cv::IMWRITE_JPG_QUALITY | JPEG的质量 | 0~100 | 95 |
cv::IMWRITE_PNG_COMPRESSION | PNG的压缩值(值高压缩率高) | 0~9 | 3 |
cv::IMWEITE_PXM_BINARY | 对PPM, PNG或PBM文件是否使用二进制 | 0或1 | 1 |
若成功保存图像则返回true, 反之, 返回false
cv::imencode()
用于对图像进行编码
cv::imdecode()
用于对图像进行解码
视频
cv::VideoCapture
构造方式
cv::VideoCapture::VideoCapture(
const string& filename //input filename
);
cv::VideoCapture::VideoCapture(
int device //Viedo capture device id
);
cv::VideoCapture::VideoCapture();
第一个构造函数中, 需要给出视频的文件名, 若打开成功会返回true, 可以通过使用cv::VideoCapture::isOpen()来对返回值进行检查.
第二个构造函数中, 若当前系统中只有一个摄像机时参数为0, 当有多个相机时, 参数随之递增.
第三个构造函数可以通过先声明对象而不提供关于即将打开的硬件设备的任何信息.
cv::VideoCapture cap;
cap.open("my_video.avi")
在这种情况下, cv::VideoCapture::open()函数最终产生的效果与调用相同参数的cv::VideoCapture构造函数相同.
read()
用于从视频流中读取图像
bool cv::VideoCapture::read(
cv::OutputArray image //image into which to read data
);
该函数的作用是从cv::VideoCapture表示的文件中读取下一帧数据, 并将数据插入你提供的变量中, 同时, 这个行为将使VideoCapture对象更新, 以方便读取下一帧. 若读取没有成功(比如已经读取到文件的最后一帧), 那么该函数将返回false.
opertor>>()
从视频流中读取图像数据.
cv::VideoCapture& cv::VideoCapture::operator>>(
cv::Mat& image //image into which to read data
);
作为对cv::VideoCapture::read()函数的补充, 你还可以使用重载函数cv::VideoCapture::operator>>() (输入流操作符号)从VideoCapture对象中读取下一帧数据.
grab()和etrieve()
*一个捕获操作(类似于内存的拷贝) 和 恢复操作(对已抓取的数据进行解码). *
bool cv::VideoCapture::grab(void);
bool cv::VideoCapture::retrieve(
cv::OutputArray image,
int channel = 0 //used for mulihead devices
);
grab()函数将当前的图像数据拷贝到用户看不见的内存缓冲区. grab()函数只是设计用于将原始图像数据尽快获取到电脑.
tips
之所以将捕获(grab) 和 恢复(retrieve)分开进行而不是像read()那样将捕获和解码同时进行是因为, 多相机的捕获是最常见的一种情况(例如立体成像). 在这种情况下需要缩短多个相机获取的图像帧之间的时间差. 因为对于数据的抓取, 将数据安全放入缓存区之后在进行解码恢复, 这样做非常有意义.
get()和set()
用于获取相机属性
double cv::VideoCapture::get(
int propid //Property identifier
);
bool cv::VideoCapture::set(
int propid, //Property identifier
double value //Value to which to set the property
);
cv::VideoCapture::get()常用属性:
视频捕获属性 | 是否只有在摄像头 模式下使用 | 含义 |
---|---|---|
cv::CAP_PROP_POS_MSEC | 视频文件中的当前位置(毫秒)或视频捕获 时间戳 | |
cv::CAP_PROP_POS_FRAMES | 从零开始下一帧的索引 | |
cv::CAP_PROP_POS_AVI_RATIO | 视频中的相对位置(范围从0.0到1.0) | |
cv::CAP_PROP_FRAME_WIDTH | 视频帧的像素宽度 | |
cv::CAP_PROP_FRAME_HEIGHT | 视频帧的像素高度 | |
cv::CAP_PROP_FPS | 录制视频的帧速率 | |
cv::CAP_PROP_FOURCC | 四个字符代码指示编解码 | |
cv::CAP_PROP_FRAME_COUNT | 视频文件的帧总数 | |
cv::CAP_PROP_FORMAT | 返回的Mat对象的格式(例如CV_8UC3) | |
cv::CAP_RPOP_MODE | 表示捕捉模式, 值是特定与正在使用的后端 | |
cv::CAP_PROP_BRIGHTNESS | ✔️ | 相机的亮度设置(支持时) |
cv::CAP_PROP_CONTRAST | ✔️ | 相机的对比度设置(支持时) |
cv::CAP_PROP_SATURATION | ✔️ | 相机饱和度设置(支持时) |
cv::CAP_PROP_HUE | ✔️ | 相机色调设置(支持时) |
cv::CAP_PROP_GAIN | ✔️ | 相机的增益设置(支持时) |
cv::CAP_PROP_EXPOSURE | ✔️ | 相机曝光设置(支持时) |
cv::CAP_PROP_CONVERT_RGB | ✔️ | 如果非零, 捕获的图像被转化为具有三个通道 |
cv::CAP_PROP_WHITE_BALANCe | ✔️ | 相机的白平衡设置(支持时) |
cv::CAP_PROP_RECTIFICATION | ✔️ | 立体相机整流标志 |
这里的所有参数都以double类型返回
例子: 获取视频宽高:
cv::VideoCapture cap("../../resource/video/test_for_car.mp4");
double videoWidth = cap.get(cv::CAP_PROP_FRAME_WIDTH);
double videoHeight = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
cv::VideoWriter
用于将视频写入磁盘
构造方法
//默认构造函数
cv::VideoWriter::VideoWriter
//参数构造函数
cv::VideoWriter::VideoWriter(
const string& filename, //input filename
int fourcc, //编码
double fps, //帧率
cv::SIze frame_size,
bool is_color = ture
);
也可以使用open方法对其初始化的对象进行设置:
cv::ViedoWriter out;
out.open(
"my_video.mpg",
CV_FOURCC('D', 'I', 'V', 'X'),
30.0,
cv::Size(640, 480)
);
可是使用isOpened函数对VideoWriter对象进行查询其是否已经完全就绪, 若就绪, 返回true, 否则返回false
wirte()
确定号VideoWriter对象后可以同多wirte对其进行写入:
cv::VideoWrite::write(
const Mat& image //要写入的数据帧
);
operator<<()
也可以像cout一样使用<<()向视频写入图像数据:
myVideoWriter << myFrame;
数据存储
cv::FileStorage
用于将不同数据类型的和数据以YAML或XML格式写入磁盘或者从磁盘读取, 这些方法可以用来加载或保存任何OpenCV的数值变量(包括基本数据变量)到一个文件中.
构造方法
FileSorage::FileStorage();
FileStorage;:FileStorage(
string fileName,
int flag
);
写入
默认构造函数创建对象后, 可以通过open函数进行打开XML或YAML格式的文件.
flag参数可以为cv::FileStorage::WRITE或cv::FileStorage::APPEND
FileStorage::open( string fileName, int flag );
打开文件后可以通过**cv::FileStorage::operator<<()**进行写入操作
在cv::FileStorage内部数据的存储主要有两种形式, “mapping” (健/值对)和 “sequence” (一系列为命名的条目)
在最顶层, 所写入的数据都在一个mapping中, 在该mapping中, 你可以放置其他的mapping或者sequences, 甚至在mapping中继续放入mapping等.
myFileStorage << "someInteger" << 27; //存储一个整数
myFileStorage << "anArray" << cv::Mat::eye( 3, 3, CV_32F ); //存储一个矩阵
可以使用 { 创建mapping, 使用 [ 创建sequences.
创建maping:
myFileStorage << "theCat" << "{";
myFileStorage << "fur" << "gray" << "eyes" << "green" << "weightLbs" << 16;
myFileStorage << "}";
创建一个mapping后, 需要按照顺序输入条目名以及对应的值. 如果创建的是sequence, 只需要一个接一个输入元素即可, 知道sequence结束.
myFileStorage << "theTeam" << "[";
myFileStorage << "eddie" << "tom" << "scott";
myFileStorage << "]";
一旦完成工作, 可以使用**cv::FileStorage::release()**关闭该文件.
读取
cv::FileStorage对象在打开之后既可以用于写入, 也可以用作读取. 唯一的区别是参数flag的值为cv::FileStorage::READ. 和写入时一样, 也可以用默认构造函数和创建一个FileStorage对象, 之后再通过**cv::FileStorage::open*()**函数打开.