【C++】保存浮点型数值图像Mat文件的三种方法

近期遇到了需要将浮点型数据(float或double)存储在一张图中的问题,例如将图像中的某一像素对应于点云中的大地坐标XYZ,即仿照原图像RGB存储伪图像XYZ。忙活了几天研究了一些图像格式以及相关函数库,找到了三种方法,就此记录下来。

1.使用opencv库存储.tiff

普通的图像格式如.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

2.使用GDAL库存储.tiff

普通的图像格式如.bmp .jpg .png等只能以整型的形式被存储在图片中,无法满足浮点数据的存储要求,但.tiff类型支持浮点数据的存储。使用GDAL版本为2.3.1,下面则以三通道浮点型数据无压缩存储tiff为例,直接上代码:

bool MatToFile(Mat& dst, const char* outputpath)
{ 
	/// <summary>
	/// 参考https://blog.csdn.net/wangxiaotan620/article/details/108883897
	/// </summary>
	/// <param name="dst">Mat文件</param>
	/// <param name="outputpath">输出路径</param>
	/// <returns></returns>
	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

3.使用opencv库存储.xml

普通的图像格式如.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

《【C++】保存浮点型数值图像Mat文件的三种方法》

    原文作者:PRSer_ljx
    原文地址: https://blog.csdn.net/qq_42672745/article/details/124010158
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞