近期遇到了需要将浮点型数据(float或double)存储在一张图中的问题,例如将图像中的某一像素对应于点云中的大地坐标XYZ,即仿照原图像RGB存储伪图像XYZ。忙活了几天研究了一些图像格式以及相关函数库,找到了三种方法,就此记录下来。
普通的图像格式如.bmp .jpg .png等只能以整型的形式被存储在图片中,无法满足浮点数据的存储要求,但.tiff类型支持浮点数据的存储。使用opencv版本为3.4.15,下面则以三通道浮点型数据无压缩存储tiff为例,直接上代码:
void main()
{
Mat image = cv::imread(img_path); //读取某张图片
Mat image_xyz(image.rows, image.cols, CV_32FC3, Scalar(0.0, 0.0, 0.0)); //浮点型数据初始化
{...//可进行某些赋值处理操作}
cout << "存储前为:" << image_xyz.ptr<Vec3f>(66)[66] << endl;//存储前该像素对应的坐标
vector<int> compression_params; //无损压缩参数
compression_params.push_back(IMWRITE_TIFF_COMPRESSION);
compression_params.push_back(1);
imwrite(("images\\" + img_name + ".tiff").c_str(), image_xyz, compression_params);
Mat image001 = cv::imread(("images\\" + img_name + ".tiff").c_str(), IMREAD_ANYCOLOR | IMREAD_ANYDEPTH);
cout << "存储后再读取:" << image001.ptr<Vec3f>(66)[66] << endl;//存储后再读取对应的坐标(验证无损压缩)
}
测试用时2.172s文件大小384M
普通的图像格式如.bmp .jpg .png等只能以整型的形式被存储在图片中,无法满足浮点数据的存储要求,但.tiff类型支持浮点数据的存储。使用GDAL版本为2.3.1,下面则以三通道浮点型数据无压缩存储tiff为例,直接上代码:
bool MatToFile(Mat& dst, const char* outputpath)
{
///
/// 参考https://blog.csdn.net/wangxiaotan620/article/details/108883897
///
/// Mat文件
/// 输出路径
///
if (dst.empty())
{
return 0;
}
int band = dst.channels();//获取图像通道数
int sizex = dst.cols;
int sizey = dst.rows;
//创建新图像,存储处理完成的图像
GDALAllRegister();
GDALDriver* poDriver = (GDALDriver*)GDALGetDriverByName("Gtiff");
GDALDataset* pdst = poDriver->Create(outputpath, sizex, sizey, band, GDT_Float32, NULL);
//将每一个通道的Mat类型存成GDAL类型,并写出
for (int nband = 0; nband < band; nband++)
{
GDALRasterBand* poBand = pdst->GetRasterBand(nband + 1);
float* inputbuff = new float[sizex * sizey];
float* outputbuff = new float[sizex * sizey];
memset(inputbuff, 0, sizeof(float) * sizex * sizey); //内存初始化
memset(outputbuff, 0, sizeof(float) * sizex * sizey);
for (int i = 0; i < sizey; i++)
{
for (int j = 0; j < sizex; j++)
{
inputbuff[i * sizex + j] = dst.at<Vec3f>(i, j)[nband];//Mat到GDAL
outputbuff[i * sizex + j] = inputbuff[i * sizex + j];
}
}
pdst->GetRasterBand(nband + 1)->RasterIO(GF_Write, 0, 0, sizex, sizey, outputbuff, sizex, sizey, GDT_Float32, 0, 0);
delete[]inputbuff;
delete[]outputbuff;
}
GDALClose(pdst);
return 1;
}
void main()
{
Mat image = cv::imread(img_path); //读取某张图片
Mat image_xyz(image.rows, image.cols, CV_32FC3, Scalar(0.0, 0.0, 0.0)); //浮点型数据初始化
{...//可进行某些赋值处理操作}
cout << "存储前为:" << image_xyz.ptr<Vec3f>(66)[66] << endl;//存储前该像素对应的坐标
cv::cvtColor(image_xyz, image_xyz, COLOR_BGR2RGB); //转换下通道
MatToFile(image_xyz, ("images\\" + img_name + ".tiff").c_str()); //将Mat存储为tiff文件
Mat image001 = cv::imread(("images\\" + img_name + ".tiff").c_str(), IMREAD_ANYCOLOR | IMREAD_ANYDEPTH);
cout << "存储后再读取:" << image001.ptr<Vec3f>(66)[66] << endl;//存储后再读取对应的坐标(验证无损压缩)
}
测试用时6.61秒文件大小384M
普通的图像格式如.bmp .jpg .png等只能以整型的形式被存储在图片中,无法满足浮点数据的存储要求,因此此次可存储为.xml格式。使用opencv版本为3.4.15,下面则以三通道浮点型数据无压缩存储tiff为例,直接上代码:
void main()
{
Mat image = cv::imread(img_path); //读取某张图片
Mat image_xyz(image.rows, image.cols, CV_32FC3, Scalar(0.0, 0.0, 0.0)); //浮点型数据初始化
{...//可进行某些赋值处理操作}
cout << "存储前为:" << image_xyz.ptr<Vec3f>(66)[66] << endl;//存储前该像素对应的坐标
cv::FileStorage fs(".\\img.xml", FileStorage::WRITE);
fs << "img" << image_xyz;
fs.release();
cv::FileStorage fs1(".\\img.xml", FileStorage::READ);
Mat image001;
fs1["img"] >> image001;
cout << "存储后再读取:" << image001.ptr<Vec3f>(66)[66] << endl;//存储后再读取对应的坐标(验证无损压缩)
}
测试用时83.313秒文件大小310M