如何将Ciff.ReadEncodedTile从C#中的高度图转换为高程地形矩阵?

时间:2016-05-25 13:05:11

标签: c# tile libtiff geotiff heightmap

我是处理读取tiff图像的新手,我正试图通过使用LibTiff从tiff地图获取高程地形值。我需要解码的地图是有组织的。根据图书馆文档和网络研究,我目前正在使用的代码片段下面获取这些值:

copy "$(SolutionDir)Program 1.exe" "$(OutDir)Program 1.exe"

我一直在测试两个不同的地图(每个样本32位和64位)并且结果是相似的:在开始时,数据似乎是一致的,但是有一点其中所有其他值都被破坏了(在数据结果结束时甚至为零)。我推断有一些字节需要忽略,但我不知道如何识别它们来淡化我的代码。方法Tiff.ReadScanline对我不起作用,因为我需要解码的地图是有组织的图块,而且这种方法不适用于处理这些类型的图像(根据BitMiracle.LibTiff文档)。方法Tiff.ReadRGBATile也无效,因为tiff图像不是RGB。我可以用Matlab读取这些值,但我的项目需要用C#构建,所以我可以将预期结果与我的比较。作为参考(我认为它可能会有所帮助),这些是使用LibTiff标签读取方法从其中一个tiff文件中提取的一些数据:

  • ImageWidth:2001
  • ImageLength:2001
  • BitsPerSample:32
  • 压缩:PackBits(又名Macintosh RLE)
  • 光度学:MinIsBlack
  • SamplesPerPixel:1
  • PlanarConfig:Contig
  • TileWidth:208
  • TileLength:208
  • SampleFormat:3

先谢谢你们的帮助!

2 个答案:

答案 0 :(得分:0)

好的,最后我找到了解决方案:我的错误是参数" count"在函数Tiff.ReadEncodedTile(tile,buffer,offset,count)中。 Tiff.RawTileSize(int)函数返回磁贴的压缩字节大小(每个磁贴不同,具体取决于压缩算法),但Tiff.ReadEncodedTile返回解压缩的字节(所有磁贴的大小和常量)。这就是为什么不能正确保存所有信息,而只是保存数据的一部分。在具有地形高程矩阵的正确代码下方(需要优化,但它有效,我认为它可能会有所帮助)

 private void getBytes()
    {
        int numBytes = bitsPerSample / 8;
        int numTiles = tif.NumberOfTiles();
        int stride = numBytes * height;
        int bufferSize = tileWidth * tileHeight * numBytes * numTiles;
        int bytesSavedPerTile = tileWidth * tileHeight * numBytes; //this is the real size of the decompressed bytes
        byte[] bufferTiff = new byte[bufferSize];

        FieldValue[] value = tif.GetField(TiffTag.TILEWIDTH);
        int tilewidth = value[0].ToInt();

        value = tif.GetField(TiffTag.TILELENGTH);
        int tileHeigth = value[0].ToInt();

        int matrixSide = (int)Math.Sqrt(numTiles); // this works for a square image (for example a tiles organized tiff image)
        int bytesWidth = matrixSide * tilewidth;
        int bytesHeigth = matrixSide * tileHeigth;

        int offset = 0;

        for (int j = 0; j < numTiles; j++)
        {
            offset += tif.ReadEncodedTile(j, bufferTiff, offset, bytesSavedPerTile); //Here was the mistake. Now it works!
        }

        double[,] aux = new double[bytesHeigth, bytesWidth]; //Double for a 64 bps tiff image. This matrix will save the alldata, including the transparency (the "blank zone" I was talking before)

        terrainElevation = new double[height, width]; // Double for a 64 bps tiff image. This matrix will save only the elevation values, without transparency

        int ptr = 0;
        int m = 0;
        int n = -1;
        int contNumTile = 1;
        int contBytesPerTile = 0;
        int i = 0;
        int tileHeigthReference = tileHeigth;
        int tileWidthReference = tileWidth;
        int row = 1;
        int col = 1;

        byte[] bytesHeigthMeters = new byte[numBytes]; // Buffer to save each one elevation value to parse

        while (i < bufferTiff.Length && contNumTile < numTiles + 1)
        {
            for (contBytesPerTile = 0; contBytesPerTile < bytesSavedPerTile; contBytesPerTile++)
            {
                bytesHeigthMeters[ptr] = bufferTiff[i];
                ptr++;
                if (ptr % numBytes == 0 && ptr != 0)
                {
                    ptr = 0;
                    n++;

                    if (n == tileHeigthReference)
                    {
                        n = tileHeigthReference - tileHeigth;
                        m++;
                        if (m == tileWidthReference)
                        {
                            m = tileWidthReference - tileWidth;
                        }
                    }
                    double heigthMeters = BitConverter.ToDouble(bytesHeigthMeters, 0);

                    if (n < bytesWidth)
                    {
                        aux[m, n] = heigthMeters;
                    }
                    else
                    {
                        n = -1;
                    }

                }
                i++;
            }

            if (i % tilewidth == 0)
            {
                col++;
                if (col == matrixSide + 1)
                {
                    col = 1;
                }
            }

            if (contNumTile % matrixSide == 0)
            {
                row++;
                n = -1;
                if (row == matrixSide + 1)
                {
                    row = 1;

                }
            }

            contNumTile++;
            tileHeigthReference = tileHeight * (col);
            tileWidthReference = tileWidth * (row);

            m = tileWidth * (row - 1);

        }

        for (int x = 0; x < height; x++)
        {
            for (int y = 0; y < width; y++)
            {
                terrainElevation[x, y] = aux[x, y]; // Final result. Each position of matrix has saved each pixel terrain elevation of the map
            }
        }

    }

问候!

答案 1 :(得分:0)

这是一个改进的代码,适用于非方形图块:

(function() {
    // Do something to global_variable now
}())