具有LibTIFF.NET C#的具有浮点像素值的32位灰度Tiff数组 [英] 32-bit Grayscale Tiff with floating point pixel values to array using LibTIFF.NET C#
问题描述
我刚开始在我的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:
根据 AnttiLeppä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屋!