1. 将 cv::Mat 写入 bin 文件
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
void saveMatToBinary(const cv::Mat& mat, const std::string& filename) {
std::ofstream file(filename.c_str(), std::ios::binary);
if (!file.is_open()) {
std::cerr << "Error opening file for writing" << std::endl;
return;
}
int rows = mat.rows;
int cols = mat.cols;
int type = mat.type();
file.write((char*)&rows, sizeof(int)); // 在bin中写入第一个头信息 描述矩阵行数 占4个字节(即sizeof(int))
file.write((char*)&cols, sizeof(int)); // 在bin中写入第二个头信息 描述矩阵列数 占4个字节(即sizeof(int))
file.write((char*)&type, sizeof(int)); // 在bin中写入第三个头信息 描述矩阵类型(数据类型+通道数) 占4个字节(即sizeof(int))
file.write((char*)mat.data, rows * cols * mat.elemSize()); // 在bin中写入矩阵数据
file.close();
}
2. 从 bin 读出 cv::Mat
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
cv::Mat readMatFromBinary(const std::string& filename) {
std::ifstream file(filename.c_str(), std::ios::binary);
if (!file.is_open()) {
std::cerr << "Error opening file for reading" << std::endl;
return cv::Mat();
}
int rows, cols, type;
file.read((char*)&rows, sizeof(int)); // 从bin中读出前4个字节(即一个int的字节数)的信息 以获悉矩阵行数
file.read((char*)&cols, sizeof(int)); // 再从bin中读出4个字节(即一个int的字节数)的信息 以获悉矩阵列数
file.read((char*)&type, sizeof(int)); // 再从bin中读出4个字节(即一个int的字节数)的信息 以获悉矩阵数据类型和通道数
cv::Mat mat(rows, cols, type); // 根据头信息读出的内容 初始化一个尺寸、数据类型、通道数一定的矩阵
file.read((char*)mat.data, rows * cols * mat.elemSize()); // 读出bin的剩余信息 装填矩阵
file.close();
return mat;
}
3. 关于字节数大小的意义(即bin的大小)
3.1 前置知识:mat.type()
已知一个cv::Mat mat, 通过 :
int type = mat.type();
可以获悉该矩阵的通道数以及数据类型,如下表所示:
数据类型 | C1 (单通道) | C3(三通道) |
CV_8U (uchar) | type = 0 | type = 16 |
CV_32S (int) | type = 4 | type = 20 |
CV_32F (float) | type = 5 | type = 21 |
CV_64F (double) | type = 6 | type = 22 |
附:对于大于4通道的多通道矩阵,基于其通道数和数据类型,也会有对应的type值
3.2 前置知识:mat.elemSize()
已知一个cv::Mat mat, 通过 :
int elemSize = mat.elemSize()
可以得到一个值, 它是“矩阵数据类型所占的字节数”和“矩阵通道数”的乘积。
比如:
某cv::Mat矩阵是由float组成的,那么其数据类型为float,而一个float占的字节数是4;
再假设该矩阵是三通道的,那么该矩阵的 elemSize 等于 4 * 3 等于 12
3.3 前置知识:如何获悉矩阵的通道数
int channels = mat.channels();
3.4 前置知识:某数据类型所占的字节数
通过代码 sizeof(某数据类型) 来获取,以下为示例:
std::cout << "uchar 字节数 = " << sizeof(uchar) << std::endl; //uchar 字节数 = 1
std::cout << "int 字节数 = " << sizeof(int) << std::endl; //int 字节数 = 4
std::cout << "float 字节数 = " << sizeof(float) << std::endl; //float 字节数 = 4
std::cout << "double 字节数 = " << sizeof(double) << std::endl; //double 字节数 = 8
3.5 输出bin的大小是如何得出的
对于一个由cv::Mat转成的bin文件,其大小满足:
bin文件大小 (字节数) = 头信息字节数 + 矩阵数据字节数
- 其中,头信息字节数根据bin写入方式的不同会有多种可能,如果使用我给的代码,则满足:
头信息字节数 = 12 (这是由于该头信息是用三个int值描述的,而一个int占4个字节)
- 其中,矩阵数据字节数 = 矩阵行数 * 矩阵列数 * 矩阵数据类型字节数 * 矩阵通道数,即:
矩阵数据字节数 = mat.rows * mat.cols * mat.elemSize()
举例说明,如下图所示,是某输出的bin文件的大小,可以看到,其“大小”一栏中显示:1392字节
下面展示,生成该bin文件的代码:
int main() {
cv::Mat mat = cv::Mat::zeros(5, 4, CV_64FC(12));
saveMatToBinary(mat, "./Input/matrix.bin"); // 保存bin文件
std::cout << "mat.elemSize()=" << mat.elemSize() << std::endl; // mat.elemSize()=96
std::cout << "mat.type()=" << mat.type() << std::endl; // mat.type()=94
std::cout << "mat.rows=" << mat.rows << std::endl; // mat.rows=5
std::cout << "mat.cols=" << mat.cols << std::endl; // mat.cols=4
std::cout << "mat.channels()=" << mat.channels() << std::endl; // mat.channels()=12
return 0;
}
由上述代码可知,该矩阵 mat 有 5行4列12个通道,且数据类型是double(一个double占8个字节);再加上头信息由12个字节,因此:
12 + 5 *4 * 8 * 12 = 1932 个字节