【问题标题】:Load 32-bit greyscale TIFF image in C#在 C# 中加载 32 位灰度 TIFF 图像
【发布时间】:2015-03-20 18:30:26
【问题描述】:

我正在开发一个小型 C# 工具,它必须能够加载 TIFF 图像,将图像裁剪为特定大小,并将其保存为 PNG 文件。

我有大约 28000x256 像素、32 位位深度的大型灰度 TIFF 图像。当我尝试使用我的工具处理图像时,它只会输出一张空白的白色图像。

此外,当我尝试使用 Windows 照片查看器打开原始 TIFF 图像(不是使用我的工具处理的图像)时,它还会显示一个空白图像。其他一些应用程序,例如ImageJ,正确显示图像。这里有什么问题?

我加载图片的代码如下:

Image image = Bitmap.FromFile(path.LocalPath);
int width = image.Width;
int height = image.Height;

Bitmap bmp = new Bitmap(width, height);
Graphics g = Graphics.FromImage(bmp);

【问题讨论】:

  • 您希望您的代码完成什么?除了获取它的尺寸之外,它没有对图像做任何事情。
  • 我的问题不是图像的处理,而是如何正确加载图像。目前,我只是将加载的图像保存为 PNG 文件。

标签: c# image


【解决方案1】:

问题在于 C#(或者更好地说是底层 API)无法处理 Colordepth 大于 8 位的灰度图像。

我建议使用LibTiff.NET 处理 TIFF 图像。 当我遇到这样的问题时,我将 TIFF 图像原始数据加载到一个数组中

using (var inputImage = Tiff.Open(image, "r"))
{
    width = inputImage.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
    height = inputImage.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
    inputImageData = new byte[width * height * bytePerPixel];
    var offset = 0;
    for (int i = 0; i < inputImage.NumberOfStrips(); i++)
    {
        offset += inputImage.ReadRawStrip(i, inputImageData, offset, (int)inputImage.RawStripSize(i));
    }
}

然后必须将字节转换为uint 的数组(在我的情况下,imagedata 只有 16 位,所以我使用了ushort)记住要注意数据的字节顺序!

// has to be done by hand to ensure endiannes is kept correctly.
var outputImageData = new ushort[inputImageData.Length / 2];

for (var i = 0; i < outputImageData.Length; i++)
{
    outputImageData[i] = (ushort)((inputImageData[i * 2 + 1]) + (ushort)(inputImageData[i * 2] << 8));
}

然后您可以使用正常的数组操作来操作图像。我建议您使用普通的数组操作而不是 Lambda 表达式,因为它们要快得多。 (在 My Scenario 100s vs 2s Runtime 中)

终于可以再次使用 LibTiff 保存图片了

using (var output = Tiff.Open(imageout, "w"))
{
    output.SetField(TiffTag.IMAGEWIDTH, width);
    output.SetField(TiffTag.IMAGELENGTH, height);
    output.SetField(TiffTag.SAMPLESPERPIXEL, 1);
    output.SetField(TiffTag.BITSPERSAMPLE, 16);
    output.SetField(TiffTag.ROWSPERSTRIP, height);
    output.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);
    output.SetField(TiffTag.FILLORDER, FillOrder.MSB2LSB);

    // Transform to Byte-Array
    var buffer = new byte[outputImageData.Length * sizeof(ushort)];
    Buffer.BlockCopy(outputImageData, 0, buffer, 0, buffer.Length);

    // Write it to Image
    output.WriteRawStrip(0, buffer, buffer.Length);
}

【讨论】:

  • 我不能以某种方式加载 32 位 TIFF 图像并将其转换为 16 位 TIFF 吗?我不允许使用任何第三方库。我必须以某种方式使用标准库来解决这个问题。
  • 这需要将 TIFF 作为原始数据加载,因此您必须编写自己的 TIFF 库。标准库允许您加载 32 位 TIFF 数据,但您无能为力。由于 LibTiff.Net 在 BSD 许可下,我仍然会考虑使用它。
  • 我不能将32位图像转换为16位,然后使用标准库进行处理吗?
  • 连16bit都不行,只有8bit,导致精度损失很大
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
  • 2011-09-19
  • 2014-03-18
  • 2015-08-21
  • 1970-01-01
相关资源
最近更新 更多