使用 FreeImage 加载 RAW 灰度图像

Loading RAW grayscale image with FreeImage

本文关键字:灰度图像 RAW 加载 FreeImage 使用      更新时间:2023-10-16

如何使用FreeImage加载RAW 16位灰度图像?

我有unsigned char*原始数据的缓冲区。我知道它的尺寸以像素为单位,我知道它是 16 位灰度。

我正在尝试加载它

FIBITMAP* bmp = FreeImage_ConvertFromRawBits(buffer, 1000, 1506, 2000, 16, 0, 0, 0);

并获得损坏的RGB888图像。目前还不清楚我应该为灰度使用什么颜色的蒙版,因为它只有一个通道。

经过多次实验,我找到了部分有效的解决方案FreeImage_ConvertFromRawBitsEx

FIBITMAP* bmp = FreeImage_ConvertFromRawBitsEx(true, buffer, FIT_UINT16, 1000, 1506, 2000, 16, 0xFFFF, 0xFFFF, 0xFFFF);

(感谢@1201ProgramAlarm对面具的提示)。

通过这种方式,FreeImage 加载数据,但采用某种半自定义格式。大多数转换和保存功能(尝试:JPG,PNG,BMP,TIF)都失败了。

由于我无法以本机 16 位格式加载数据,因此我更喜欢将其转换为 8 位灰度

unsigned short* buffer = new unsigned short[1000 * 1506];
// load data
unsigned char* buffer2 = new unsigned char[1000 * 1506];
for (int i = 0; i < 1000 * 1506; i++)
buffer2[i] = (unsigned char)(buffer[i] / 256.f);
FIBITMAP* bmp = FreeImage_ConvertFromRawBits(buffer2, 1000, 1506, 1000, 8, 0xFF, 0xFF, 0xFF, true);

这真的不是最好的解决方案,我什至不想将其标记为正确答案(将等待更好的答案)。但是在此之后,该格式对于FreeImage来说将很方便,并且可以将数据保存/转换为任何内容。

关于您的问题:我从他们的PDF文档中读到了这个 FreeImage1370.pdf:


FreeImage_ConvertFromRawBits

1 4 8 16 24 32


DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBits(BYTE *bits, int width, int 高度, 国际音高, 无符号 BPP, 无符号red_mask, 无符号green_mask, 无符号 blue_mask,布尔自上而下FI_DEFAULT(假));
将内存中某处的原始位图转换为 FIBITMAP。其中的参数 函数用于描述原始位图。第一个参数是指向 原始位。宽度和高度参数描述位图的大小。球场 定义源位图中扫描线的总宽度,包括填充字节,这些字节可能是 应用的。bpp 参数告诉 FreeImage 位图的位深度是多少。这 red_mask,green_mask和blue_mask参数告诉FreeImage颜色的位布局 位图中的组件。最后一个参数 topdown 将存储位图左上角像素 当它为 TRUE 时首先出现,当它为 FALSE 时,首先是左下角像素。
  • 当源位图使用 32 位填充时,可以使用 以下公式: 整数间距 = (((bpp * 宽度) + 31)/32) * 4);

在你显示的代码中:

FIBITMAP* bmp = FreeImage_ConvertFromRawBits(buffer, 1000, 1506, 2000, 16, 0, 0, 0);

您具有适当的FIBTMAP*返回类型,则传入raw bitsbuffer。从那里开始,第 2 和第 3 个参数是widthheightwidth = 1000height = 1506和第4 个参数,即pitchpitch = 2000(如果位图使用 32 位填充,请参阅上面的最后一条注释),5参数将是bpp测量的位深度,如bpp = 16接下来的 3 个参数适用于您的RGB color masks。在这里,您将它们全部标记为0。最后一个参数是imageorientation的布尔标志:

略值

if (topdown == true ) { 
stores top-left pixel first ) 
else { 
bottom left pixel is stored first 
}

如果没有更多代码来说明您如何读取文件、解析标头信息等以准备您的buffer,很难判断其他地方可能存在错误或问题,但从您提供的内容来看;我认为您需要检查color channel masks是否有grayscale images.


编辑- 我从这里找到了另一个 FreeImage 的 PDF standford.edu 它引用了旧版本3.13.1但是函数声明 - 定义看起来没有任何变化,它们提供了 bFreeImage_ConvertToRawBits&Free_Image_ConvertFromRawBits的示例:

// this code assumes there is a bitmap loaded and
// present in a variable called ‘dib’
// convert a bitmap to a 32-bit raw buffer (top-left pixel first)
// --------------------------------------------------------------
FIBITMAP *src = FreeImage_ConvertTo32Bits(dib);
FreeImage_Unload(dib);
// Allocate a raw buffer
int width = FreeImage_GetWidth(src);
int height = FreeImage_GetHeight(src);
int scan_width = FreeImage_GetPitch(src);
BYTE *bits = (BYTE*)malloc(height * scan_width);
// convert the bitmap to raw bits (top-left pixel first)
FreeImage_ConvertToRawBits(bits, src, scan_width, 32,
FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK,
TRUE);
FreeImage_Unload(src);
// convert a 32-bit raw buffer (top-left pixel first) to a FIBITMAP
// ----------------------------------------------------------------
FIBITMAP *dst = FreeImage_ConvertFromRawBits(bits, width, height, scan_width,
32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, FALSE);

我认为这应该可以帮助您解决有关灰度图像中颜色通道bit masks的问题。

您已经提到了FreeImage_ConvertFromRawBitsEx()函数,它是在 FreeImage v3.8 和 v3.17 之间的某个时候添加的,但你是否正确调用它?我能够将此功能用于 16 位灰度数据:

int nBytesPerRow = nWidth * 2;
int nBitsPerPixel = 16;
FIBITMAP* pFIB = FreeImage_ConvertFromRawBitsEx(TRUE, pImageData, FIT_UINT16, nWidth, nHeight, nBytesPerRow, nBitsPerPixel, 0, 0, 0, TRUE);

请注意,必须为 16 位数据正确指定nBytesPerRownBitsPerPixel。另外,我相信颜色遮罩参数与此数据无关,因为它是单色的。

编辑:我注意到您说保存16位数据无法正常工作。 这可能是由于文件格式本身。我发现唯一与 16 位灰度数据兼容的文件格式是 TIFF。因此,如果您有 16 位灰度数据,则可以使用FreeImage_Save()保存 TIFF,但无法保存 BMP。