【问题标题】:32-bit Grayscale Tiff with floating point pixel values to array using LibTIFF.NET C#使用 LibTIFF.NET C# 将浮点像素值的 32 位灰度 Tiff 转换为数组
【发布时间】:2015-08-21 11:57:45
【问题描述】:

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

我已经有几天努力返回正确的值,但我得到的只是“0”值,假设它是一个全黑或全白的图像!

到目前为止的代码如下:(已更新 - 阅读更新 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

已在 Internet 上到处搜索,但找不到此特定问题的解决方案。所以我真的很感激帮助,这也使它对其他人有用。

更新 1:

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

http://terraunity.com/SampleElevationTiff_Results.zip

结果:

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

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

正如您所看到的结果,LibTIFF 会跳过一些行并给出不相关的排序,如果图像大小不是 2 的幂,它甚至会变得更糟!

【问题讨论】:

    标签: c# floating-point 32-bit grayscale libtiff.net


    【解决方案1】:

    您的示例文件似乎是平铺的 tiff 并且没有被剥离。控制台说:

    ElevationMap.tif:无法从平铺图像中读取扫描线

    我更改了您的代码以读取磁贴。这样它似乎在读取数据。

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

    【讨论】:

    • 感谢 Antti 的回答,您的代码将我引向了正确的方向,但请查看第一篇文章中的更新以查看最新问题。
    • 您好我也在尝试使用 LibTiff.Net 库从灰度 tiff 读取像素值,但不知何故无法弄清楚 - 有人有工作解决方案吗?在 Python rasterio 库中,有一个名为 sample 的函数,您可以在其中传递栅格数据 X 和 Y,并返回该像素处的值。任何帮助将不胜感激。谢谢
    【解决方案2】:

    我知道可能会迟到,但我最近犯了同样的错误,我找到了解决方案,所以它可能会有所帮助。错误在函数Tiff.ReadEncodedTile(tile, buffer, offset, count) 的参数count 中。它必须是解压缩的字节大小,而不是压缩的字节大小。这就是您没有所有信息的原因,因为您没有将整个数据保存在缓冲区中。见how-to-translate-tiff-readencodedtile-to-elevation-terrain-matrix-from-height

    【讨论】:

      【解决方案3】:

      读取浮点 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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-16
        • 2013-01-06
        相关资源
        最近更新 更多