使用 LibTIFF.NET C# 将带有浮点像素值的 32 位灰度 Tiff 阵列化 [英] 32-bit Grayscale Tiff with floating point pixel values to array using LibTIFF.NET C#

查看:19
本文介绍了使用 LibTIFF.NET C# 将带有浮点像素值的 32 位灰度 Tiff 阵列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始在我的 c# 应用程序中使用 LibTIFF.NET 来读取 Tiff 图像作为从 ArcGIS 服务器获得的高度图.我所需要的只是用图像的像素值填充一个数组,以便基于平滑的梯度生成地形.该图像是 LZW 压缩的 32 位灰度 Tiff,浮点像素值以米为单位表示海拔.

I just started using LibTIFF.NET in my c# application to read Tiff images as heightmaps obtained from ArcGIS servers. All I need is to populate an array with image's pixel values for terrain generation based on smooth gradients. The image is a LZW compressed 32-bit Grayscale Tiff with floating point pixel values representing elevaion in meters.

有些日子以来我一直在努力返回正确的值,但假设它是全黑或全白的图像,我得到的只是0"值!

It's been some days now that I struggle to return right values but all I get is just "0" values assuming it's a total black or white image!

这是到目前为止的代码:(更新 - 阅读更新 1)

Here's the code so far: (Updated - Read Update 1)

using (Tiff inputImage = Tiff.Open(fileName, "r"))
        {
            int width = inputImage.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
            int height = inputImage.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
            int bytesPerPixel = 4;
            int count = (int)inputImage.RawTileSize(0); //Has to be: "width * height * bytesPerPixel" ?
            int resolution = (int)Math.Sqrt(count);
            byte[] inputImageData = new byte[count]; //Has to be: byte[] inputImageData = new byte[width * height * bytesPerPixel];
            int offset = 0;

            for (int i = 0; i < inputImage.NumberOfTiles(); i++)
            {
                offset += inputImage.ReadEncodedTile(i, inputImageData, offset, (int)inputImage.RawTileSize(i));
            }

            float[,] outputImageData = new float[resolution, resolution]; //Has to be: float[,] outputImageData = new float[width * height];
            int length = inputImageData.Length;
            Buffer.BlockCopy(inputImageData, 0, outputImageData, 0, length);

            using (StreamWriter sr = new StreamWriter(fileName.Replace(".tif", ".txt"))) {
                string row = "";

                for(int i = 0; i < resolution; i++) { //Change "resolution" to "width" in order to have correct array size
                    for(int j = 0; j < resolution; j++) { //Change "resolution" to "height" in order to have correct array size
                        row += outputImageData[i, j] + " ";
                    }
                    sr.Write(row.Remove(row.Length - 1) + Environment.NewLine);
                    row = "";
                }
            }
        }

示例文件和结果:http://terraunity.com/SampleElevationTiff_Results.zip

已经在互联网上到处搜索,但找不到针对此特定问题的解决方案.所以我真的很感谢它的帮助,它对其他人也有用.

Already searched everywhere on internet and couldn't find the solution for this specific issue. So I really appreciate the help which makes it useful for others too.

更新 1:

根据 Antti Leppänen 的回答更改了代码,但得到的结果似乎很奇怪是一个错误还是我错过了什么?请在此处查看上传的 zip 文件以使用新的 32x32 tiff 图像查看结果:

Changed the code based on Antti Leppänen's answer but got weird results which seems to be a bug or am I missing something? Please see uploaded zip file to see the results with new 32x32 tiff images here:

http://terraunity.com/SampleElevationTiff_Results.zip

结果:

  • LZW 压缩:RawStripSize = ArraySize = 3081 = 55x55 网格
  • 未压缩:RawStripSize = ArraySize = 65536 = 256x256 网格

必须是:RawStripSize = ArraySize = 4096 = 32x32 网格

Has to be: RawStripSize = ArraySize = 4096 = 32x32 grid

如您所见,LibTIFF 会跳过一些行并给出不相关的排序,如果图像大小不是 2 的幂,情况会变得更糟!

As you see the results, LibTIFF skips some rows and gives irrelevant orderings and it even gets worse if the image size is not power of 2!

推荐答案

一种快速读取浮点 tiff 的方法.

A fast method to read a floating point tiff.

public static unsafe float[,] ReadTiff(Tiff image)
{
    const int pixelStride = 4; // bytes per pixel

    int imageWidth = image.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
    int imageHeight = image.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
    float[,] result = new float[imageWidth, imageHeight];

    int tileCount = image.NumberOfTiles();
    int tileWidth = image.GetField(TiffTag.TILEWIDTH)[0].ToInt();
    int tileHeight = image.GetField(TiffTag.TILELENGTH)[0].ToInt();
    int tileStride = (imageWidth + tileWidth - 1) / tileWidth;

    int bufferSize = tileWidth * tileHeight * pixelStride;
    byte[] buffer = new byte[bufferSize];
    fixed (byte* bufferPtr = buffer)
    {
        float* array = (float*)bufferPtr;

        for (int t = 0; t < tileCount; t++)
        {
            image.ReadEncodedTile(t, buffer, 0, buffer.Length);

            int x = tileWidth * (t % tileStride);
            int y = tileHeight * (t / tileStride);
            var copyWidth = Math.Min(tileWidth, imageWidth - x);
            var copyHeight = Math.Min(tileHeight, imageHeight - y);

            for (int j = 0; j < copyHeight; j++)
            {
                for (int i = 0; i < copyWidth; i++)
                {
                    result[x + i, y + j] = array[j * tileWidth + i];
                }
            }
        }
    }

    return result;
}

这篇关于使用 LibTIFF.NET C# 将带有浮点像素值的 32 位灰度 Tiff 阵列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆