首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我可以从FreeImage导出的最高位深度灰度图像是什么?

我可以从FreeImage导出的最高位深度灰度图像是什么?
EN

Stack Overflow用户
提问于 2019-10-22 04:49:51
回答 1查看 240关注 0票数 0

作为背景,我正在建设一个地形程序,需要相对极端的细节。我不期望这些文件是小的,它们也不需要在显示器上被正式查看,它们只需要有很高的分辨率。

我知道大多数图像格式被限制在8 bpp,因为这两个显示器的标准限制(以合理的价格)和人类的感知。然而,2⁸值仅为256个可能值,从而导致重建位移中的稳定伪影。2⁶1可能足够接近于65,536个可能的数值,这一点我已经实现了。

我使用FreeImage和DLang来构造数据,目前在Linux机器上。

然而,当我走到2立方米时,软件支持似乎在我身上消失了。我尝试过这种形式的TIFF,似乎没有任何东西能够解释它,要么显示一个完全(或大部分)透明的图像(记住我不希望任何显示器真正支持2平方千米的通道),要么抱怨无法解码RGB数据。我想这是因为它被认为是一个RGB或RGBA图像。

FreeImage在大多数情况下都有很好的文档记录,但是我现在想知道,我可以导出的最高精度的单通道格式是什么,我将如何做呢?有人能举个例子吗?我真的被限制在任何典型的和非家庭滚动的图像格式,16位吗?我知道这对医学成像来说已经够高了,但是我相信我不是第一个试图提高目标的人,而且我们这些科学类型的人对于我们的精确水平的…可能是相当雄心勃勃的。

我的代码犯了一个明显的错误吗?对于这种精确度,我还需要尝试其他的方法吗?

这是我的密码。

16位TIFF运行

代码语言:javascript
复制
void writeGrayscaleMonochromeBitmap(const double width, const double height) {
    FIBITMAP *bitmap = FreeImage_AllocateT(FIT_UINT16, cast(int)width, cast(int)height);
    for(int y = 0; y < height; y++) {
        ubyte *scanline = FreeImage_GetScanLine(bitmap, y);
        for(int x = 0; x < width; x++) {
            ushort v = cast(ushort)((x * 0xFFFF)/width);
            ubyte[2] bytes = nativeToLittleEndian(cast(ushort)(x/width * 0xFFFF));
            scanline[x * ushort.sizeof + 0] = bytes[0];
            scanline[x * ushort.sizeof + 1] = bytes[1];
        }
    }
    FreeImage_Save(FIF_TIFF, bitmap, "test.tif", TIFF_DEFAULT);
    FreeImage_Unload(bitmap);
}

32位TIFF没有真正运行

代码语言:javascript
复制
void writeGrayscaleMonochromeBitmap32(const double width, const double height) {
    FIBITMAP *bitmap = FreeImage_AllocateT(FIT_UINT32, cast(int)width, cast(int)height);
    writeln(width, ", ", height);
    writeln("Width: ", FreeImage_GetWidth(bitmap));
    for(int y = 0; y < height; y++) {
        ubyte *scanline = FreeImage_GetScanLine(bitmap, y);
        writeln(y, ": ", scanline);
        for(int x = 0; x < width; x++) {
            //writeln(x, " < ", width);
            uint v = cast(uint)((x/width) * 0xFFFFFFFF);
            writeln("V: ", v);
            ubyte[4] bytes = nativeToLittleEndian(v);
            scanline[x * uint.sizeof + 0] = bytes[0];
            scanline[x * uint.sizeof + 1] = bytes[1];
            scanline[x * uint.sizeof + 2] = bytes[2];
            scanline[x * uint.sizeof + 3] = bytes[3];
        }
    }
    FreeImage_Save(FIF_TIFF, bitmap, "test32.tif", TIFF_NONE);
    FreeImage_Unload(bitmap);
}

谢谢你的指点。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-24 02:30:32

对于单个信道,FreeImage中可用的最高值是32位,如FIT_UINT32.但是,文件格式必须能够做到这一点,到目前为止,只有TIFF才能完成任务(请参阅斯坦福文献的第104页)。此外,大多数监视器无法代表8位以上的样本,在极端情况下为12位,因此很难读取数据并使其正确呈现。

一个单元测试涉及在封送到位图之前比较字节,然后从相同的位图中采样,显示数据实际上正在被编码。

要将数据压缩到16位灰度(目前由J2K、JP2、PGM、PGMRAW、PNG和TIF支持),您可以这样做:

代码语言:javascript
复制
void toFreeImageUINT16PNG(string fileName, const double width, const double height, double[] data) {
    FIBITMAP *bitmap = FreeImage_AllocateT(FIT_UINT16, cast(int)width, cast(int)height);
    for(int y = 0; y < height; y++) {
            ubyte *scanline = FreeImage_GetScanLine(bitmap, y);
            for(int x = 0; x < width; x++) {
                    //This magic has to happen with the y-coordinate in order to keep FreeImage from following its default behavior, and generating
                    //the image upside down.
                    ushort v = cast(ushort)(data[cast(ulong)(((height - 1) - y) * width + x)] * 0xFFFF); //((x * 0xFFFF)/width);
                    ubyte[2] bytes = nativeToLittleEndian(v);
                    scanline[x * ushort.sizeof + 0] = bytes[0];
                    scanline[x * ushort.sizeof + 1] = bytes[1];
            }
    }
    FreeImage_Save(FIF_PNG, bitmap, fileName.toStringz);
    FreeImage_Unload(bitmap);
}

当然,您希望对目标文件类型进行调整。要导出为48位RGB16,您可以这样做.

代码语言:javascript
复制
void toFreeImageColorPNG(string fileName, const double width, const double height, double[] data) {
    FIBITMAP *bitmap = FreeImage_AllocateT(FIT_RGB16, cast(int)width, cast(int)height);
    uint pitch = FreeImage_GetPitch(bitmap);
    uint bpp = FreeImage_GetBPP(bitmap);
    for(int y = 0; y < height; y++) {
            ubyte *scanline = FreeImage_GetScanLine(bitmap, y);
            for(int x = 0; x < width; x++) {
                    ulong offset = cast(ulong)((((height - 1) - y) * width + x) * 3);
                    ushort r = cast(ushort)(data[(offset + 0)] * 0xFFFF);
                    ushort g = cast(ushort)(data[(offset + 1)] * 0xFFFF);
                    ushort b = cast(ushort)(data[(offset + 2)] * 0xFFFF);
                    ubyte[6] bytes = nativeToLittleEndian(r) ~ nativeToLittleEndian(g) ~ nativeToLittleEndian(b);
                    scanline[(x * 3 * ushort.sizeof) + 0] = bytes[0];
                    scanline[(x * 3 * ushort.sizeof) + 1] = bytes[1];
                    scanline[(x * 3 * ushort.sizeof) + 2] = bytes[2];
                    scanline[(x * 3 * ushort.sizeof) + 3] = bytes[3];
                    scanline[(x * 3 * ushort.sizeof) + 4] = bytes[4];
                    scanline[(x * 3 * ushort.sizeof) + 5] = bytes[5];
            }
    }
    FreeImage_Save(FIF_PNG, bitmap, fileName.toStringz);
    FreeImage_Unload(bitmap);
}

最后,要编码UINT32灰度图像(目前仅限于TIFF ),您可以这样做。

代码语言:javascript
复制
void toFreeImageTIF32(string fileName, const double width, const double height, double[] data) {
    FIBITMAP *bitmap = FreeImage_AllocateT(FIT_UINT32, cast(int)width, cast(int)height);

    //DEBUG
    int xtest = cast(int)(width/2);
    int ytest = cast(int)(height/2);
    uint comp1a = cast(uint)(data[cast(ulong)(((height - 1) - ytest) * width + xtest)] * 0xFFFFFFFF);
    writeln("initial: ", nativeToLittleEndian(comp1a));

    for(int y = 0; y < height; y++) {
            ubyte *scanline = FreeImage_GetScanLine(bitmap, y);
            for(int x = 0; x < width; x++) {
                    //This magic has to happen with the y-coordinate in order to keep FreeImage from following its default behavior, and generating
                    //the image upside down.
                    ulong i = cast(ulong)(((height - 1) - y) * width + x);
                    uint v = cast(uint)(data[i] * 0xFFFFFFFF);
                    ubyte[4] bytes = nativeToLittleEndian(v);
                    scanline[x * uint.sizeof + 0] = bytes[0];
                    scanline[x * uint.sizeof + 1] = bytes[1];
                    scanline[x * uint.sizeof + 2] = bytes[2];
                    scanline[x * uint.sizeof + 3] = bytes[3];
            }
    }

    //DEBUG
    ulong index = cast(ulong)(xtest * uint.sizeof);
    writeln("Final: ", FreeImage_GetScanLine(bitmap, ytest)
            [index .. index + uint.sizeof]);

    FreeImage_Save(FIF_TIFF, bitmap, fileName.toStringz);
    FreeImage_Unload(bitmap);
}

我还没有找到一个由其他人构建的程序,它可以很容易地在监视器的调色板上呈现32位的灰度图像。但是,我留下了我的检查代码,在这些代码中,在顶部调试和底部调试时都会始终写出相同的数组,这对我来说已经足够一致了。

希望这能在未来帮助其他人。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58497249

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档