一、问题描述
cv::Mat 在 imwrite 时只能存储值为char类型,导致想保存int类型的数据时会越界自动转换。
那么cv::Mat是否可以存储并保存int类型的数据呢?当然是可以的,定义cv::Mat 为 CV_32S的格式,并以二进制文件进行读写即可。
二、代码实现
#include <iostream>
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <fstream>
using namespace std;
using namespace cv;
/**
* @brief 读取二进制文件转换为 cv::Mat 32S 格式
* @param filename 二进制文件名
* @param rows cv::Mat 的高
* @param cols cv::Mat 的宽
* @return cv::Mat 转换得到的图像
*/
cv::Mat loadBinaryAsMat32S(const std::string &filename, int rows, int cols)
{
cv::Mat mat(rows, cols, CV_32S);
// 以二进制读取模式打开文件
std::ifstream file(filename, std::ios::in | std::ios::binary);
if (!file.is_open())
{
std::cerr << "Failed to open file for reading!" << std::endl;
return cv::Mat(); // 返回一个空的Mat对象
}
// 读取数据到mat中
// 注意:这里我们假设二进制文件中的数据是按照行优先(row-major)顺序存储的,并且没有额外的填充或元数据
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < cols; ++x)
{
int value;
// 从文件中读取一个32位整数
file.read(reinterpret_cast<char *>(&value), sizeof(value));
// 将读取的值存储在mat的相应位置
mat.at<int>(y, x) = value;
}
}
file.close();
return mat;
}
/**
* @brief 将cv::Mat 32S 转换保存二进制文件
* @param mat cv::Mat 32S
* @param filename 二进制文件名
* @return void
*/
void saveMat32SAsBinary(const cv::Mat &mat, const std::string &filename)
{
if (mat.empty())
{
std::cerr << "Mat is empty!" << std::endl;
return;
}
if (mat.type() != CV_32S)
{
std::cerr << "Mat is not of type CV_32S!" << std::endl;
return;
}
// 打开文件以二进制写入模式
std::ofstream file(filename, std::ios::out | std::ios::binary);
if (!file.is_open())
{
std::cerr << "Failed to open file for writing!" << std::endl;
return;
}
// 写入数据
// 注意:这里我们直接写入整个mat.data指针指向的内存块
// 这假设mat是连续的(即,没有填充或行间隙)。如果mat不是连续的,你需要先将其复制到一个连续的Mat中
if (mat.isContinuous())
{
file.write(reinterpret_cast<const char *>(mat.data), mat.total() * mat.elemSize());
}
else
{
// 如果mat不是连续的,你需要逐行写入
for (int y = 0; y < mat.rows; ++y)
{
file.write(reinterpret_cast<const char *>(mat.ptr<int>(y)), mat.cols * mat.elemSize());
}
}
file.close();
std::cout << "Mat saved as binary file: " << filename << std::endl;
}
int main()
{
// 随机创建一个 5(height)*2(width)的图像
cv::Mat src = cv::Mat::zeros(5, 2, CV_32S);
for (int i = 0; i < 5; ++i) // rows
{
for (int j = 0; j < 2; ++j) // cols
{
src.at<int>(i, j) = -300 + i;
}
}
// 保存为二进制文件
saveMat32SAsBinary(src, "../data.txt");
// 读取二进制文件
cv::Mat dst = loadBinaryAsMat32S("../data.txt", 5, 2);
if (!dst.empty())
{
for (int i = 0; i < dst.cols; ++i)
{
for (int j = 0; j < dst.rows; ++j)
{
int k = dst.at<int>(j, i);
cout << "k: " << k << endl;
}
}
}
return 0;
}