在C++中保存float*图像

Save float * images in C++

本文关键字:图像 float 保存 C++      更新时间:2023-10-16

我想了解如何保存float:类型的图像

float * image;

以这种方式分配:

int size = width * height;
image = (float *)malloc(size * sizeof(float));

我尝试使用CImg库,但不直接接受float。事实上,我只使用它来捕捉浮动图像,因为我只需要浮动图像。

CImg<float> image("image.jpg");
int width = image.width(); 
int height = image.height();
int size = width*height
float * image = image.data();

如何将此图片从可读的.jpg.bmp保存到float。我想打开一个写缓冲区,但没有保存任何东西,我无法从文件中读取!

好吧,你需要的首先是意识到你要做什么。您正在创建一个指向浮动数组的指针

image=(float *)malloc(size* sizeof(float));

然后你在做

float * image =image.data();

这是对image的双重使用,这将导致编译器错误,如果可以的话,这也是一件坏事。

现在,您应该在这里阅读CImg,并看到Data()返回一个指向图像第一个像素的指针。

既然我们已经建立了所有这些,让我们来看看解决方案:如果您想将浮点数组保存到文件中,请使用以下示例

#include <fstream.h>
void saveArray(float* array, int length);
int main()
{
    float image[] = { 15.25, 15.2516, 84.168, 84356};
    saveArray(floatArray, sizeof(image)/ sizeof(image[0]));
    return 0;
}
void saveArray(float* array, int length)
{
    ofstream output("output.txt");
    for(int i=0;i<length;i++)
    {
        output<<array[i]<<endl;
    }
}

由于JPEG图像格式只支持8位颜色分量(实际上标准允许12位,但我还没有看到它的实现),因此无法使用JPEG实现这一点。

您可以使用.bmp文件执行此操作。请参阅我对一个问题的回答,以及使用OpenCV库进行此操作的可能方法。对于其他一些库,使用.bmp文件可能很容易,因为OpenCV假设8位颜色通道,尽管正如我所知,.bmp格式并没有规定这一点。

你需要压缩吗?如果不只是写一个二进制文件,或者以yml格式存储文件,等等

如果您需要压缩,OpenEXR将是您的选择。Image Magick可能是最适合您的实现方式,因为它与CImg集成良好。由于CImg本机不支持.jpg,我怀疑您可能已经拥有Image Magick。

我可以从您的代码中看到,您只使用了32位浮点灰度(没有R、G、B,只有I)以下是我的建议:

  1. 辐射RGBE(.hdr)对R、G、B和1x8位指数使用3x8位尾数,这只会给你16位的精度。但是,如果您也使用R、G、B而不是用于模拟目的,则这种格式对您来说是不可行的。(因为所有通道的指数都是一样的,所以你的精度很低)

  2. 任何HDR格式都不是本机格式,因此您需要安装查看器,并且必须为源代码或使用libs 编写读/写函数

  3. 非HDR格式(bmp、jpg、tga、png、pcx…)如果你只使用灰度,这是最好的解决方案。这些格式通常为每个通道8位,因此您可以将24-32位用于单个强度。此外,您还可以在大多数操作系统上以本机方式查看/编辑这些图像。有两种方法可以做到这一点。

    • 对于32位图像,您可以简单地将float复制到color=((DWORD*)(&col))[0];其中col是您的浮点像素。这是最简单的,没有精度损失,但如果您查看图像,它将不美观:),因为浮点值的存储方式与整数类型不同。

    • 调色板的使用。创建从像素颜色的最小值到最大值的调色板(保存的颜色越多,精度越高)。然后将整个图像绑定到此值。在此之后,将float值转换为调色板中的索引并将其存储(保存),并从调色板中的颜色反向获取float(加载),以这种方式可以查看图片,类似于热图像。。。从浮点值到索引/RGB颜色的转换可以线性地(精度很低)或非线性地(通过exp、log函数或任何你想要的非线性)完成。在最好的情况下,如果你使用24位像素,并且有所有2^24颜色的比例调色板,并且你使用非线性转换,那么你只会失去25%的精度(如果你真的使用浮动的整个动态范围,如果不比损失更小,甚至降到零)

缩放技巧:

  • 看看光谱颜色,它是一个很好的色阶(有很多简单的源代码可以用谷歌创建),你也可以使用任何颜色梯度模式。

  • 非线性函数应该在需要保持精度的浮动范围(大多数像素所在的范围)上变化较小,在精度不重要的地方变化较大(+/-NaN)。我通常使用exp、ln或tan,但你们必须将它们缩放到你们的调色板范围内。

BMP文件格式非常简单:https://en.m.wikipedia.org/wiki/BMP_file_format

读取标题以确定高度、宽度、bpp和数据起始索引。然后,通过将像素通道值强制转换为float(从标头中指定的索引开始),跨越宽度,开始填充float数组。当到达指定宽度的模块时,转到数组中的下一行。

JPG解码更为复杂。我建议你不要试图自己做这件事。

如果您想保存浮点值,您需要使用支持它们的格式,而不是JPEG和BMP。最有可能的选择是:

  • TIFF-需要一个库来编写

  • FITS-主要用于天文学数据,写并不太难

  • PFM(Portable Float Format,可移植浮点格式),它是一种最小公分母格式,与NetPBM格式相同,在此进行描述。

好消息是CImg支持开箱即用的PFM,不需要额外的库。所以你的问题的答案很简单:

#include "CImg.h"
using namespace cimg_library;
int main() {
   CImg<float> image("image.png");
   image.normalize(0.0,1.0);
   image.save_pfm("result.pfm");
}

如果您想稍后查看您的图像,ImageMagick了解以上所有格式,并可以将其中任何格式转换为其他格式:

convert result.pfm image.jpg       # convert PFM to JPG
convert result.pfm image.png       # convert PFM to PNG
convert result.tif image.bmp       # convert TIF to BMP

关键词:CImg、C++、C、浮点、浮点、图像、图像处理、另存为浮点、实数、另存为实数、32位、PFM、可移植浮点映射