为什么当我想用 C# 合并两个大的 tiff 图像时出错?

Why is it wrong when I want merging two large tiff images with C#?

我想合并两个 Large Tiff。我尝试了很多 ways.But 每次都出错。 例如: 我使用了 ImageMagic 和 System.Drowing.Graphics 以及 ImageProcessor 等。

OneDrive 文件:https://1drv.ms/u/s!AlD9jC3hP9FTcEB2J2rKgp8Lw_E?e=JFVewK

已共享四个文件。

原始文件名:_1.tif 和 _11.tif

使用 Magick.NET-Q16-x64 V7.14.3 创建:dotnet.tif

使用 ImageMagick Q16 v 7.0.8 创建:magickcmd.tif

系统信息: OP:赢得 10 x64 Ram:64Gig Cpu:I7 显卡:8G FreeSpace:400Gig

Tif 格式:

像素格式:Format1bppIndexed

尺寸:2Gig

模式:位图

压缩:lzw

像素顺序:交错

字节顺序:lsb

宽度:95752px

高度:295464px

水平分辨率:800dpi

垂直分辨率:2400dpi

位深度:1

分辨率单位:2

感谢您的帮助...

/// Use ImageMagick
                using (MagickImageCollection images = new MagickImageCollection())
                {

                    MagickNET.SetTempDirectory(@"d:\");

                    images.Add(new MagickImage(txtAddress2.Text, new MagickReadSettings { Endian = Endian.LSB }));
                    images.Add(new MagickImage(txtAddress1.Text, new MagickReadSettings { Endian = Endian.LSB }));

                    using (IMagickImage image = images.AppendHorizontally())
                    {
                        image.Endian = Endian.LSB;
                        image.Settings.SetDefine("tiff:endian", "lsb");
                        image.Write(@"d:\output" + new Random().Next() + ".tif");
                    }

                }

//////使用System.Drowing

 public static Bitmap MergeTwoImages(Image firstImage, Image secondImage)
    {


        int outputImageWidth = firstImage.Width > secondImage.Width ? firstImage.Width : secondImage.Width;

        int outputImageHeight = firstImage.Height + secondImage.Height + 1;

        Bitmap outputImage = new Bitmap(outputImageWidth, outputImageHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

        using (Graphics graphics = Graphics.FromImage(outputImage))
        {
            graphics.DrawImage(firstImage, new Rectangle(new Point(), firstImage.Size),
                new Rectangle(new Point(), firstImage.Size), GraphicsUnit.Pixel);
            graphics.DrawImage(secondImage, new Rectangle(new Point(0, firstImage.Height + 1), secondImage.Size),
                new Rectangle(new Point(), secondImage.Size), GraphicsUnit.Pixel);
        }

        return outputImage;
    }

对于这个问题我建议...

我查看了您的输出图像,它们看起来都不错。如果您看不到它们,可能是因为它们对于您正在使用的任何程序来说都太大了。它们在 nip2, the libvips GUI 中为我显示,尽管它们需要几分钟才能打开。

您的图片很大:15,000 像素宽,180,000 像素。它们以每像素 1 位的形式存储在 TIFF 文件中,但 ImageMagick6 会将它们解压缩为五个通道,每个通道 16 位以进行处理,因此每个通道为 25GB。 ImageMagick7 将使用每个通道 32 位,因此每个图像 50GB。这已接近您计算机的极限 -- 它可能相当慢。

libvips 可以执行这样的操作,而无需将整个图像加载到内存中:它在一系列小区域中将图像从输入流传输到输出。它将 运行 为您计算机上的每个内核提供一个流,所以速度也很快。

它具有良好的 C# 绑定:net-vips。我实际上并没有在这台笔记本电脑上安装它,所以我在 Python 中尝试了。

import sys
import pyvips

left = pyvips.Image.new_from_file(sys.argv[2], access='sequential')
right = pyvips.Image.new_from_file(sys.argv[1], access='sequential')
join = left.join(right, 'horizontal', expand=True)
join.tiffsave(sys.argv[3], predictor='none', compression='lzw', squash=True)

绑定非常相似——您应该能够轻松地将其转换为 C#。

我在这台双核 2015 笔记本电脑上看到:

$ /usr/bin/time -f %M:%e python3 join.py _1.tif _11.tif vips.tif
65832:26.55

因此它 运行 需要 65MB 内存。运行 需要 65MB 内存。

您尝试过 deflate 压缩吗?它比 LZW 慢,但提供更好的结果。将保存行更改为:

join.tiffsave(sys.argv[3], compression='deflate', squash=True)

运行时间上升到57s,但输出文件小了25%。

libvips 也有一个 CLI,你也可以直接输入:

vips join _1.tif _11.tif vips.tif[compression=deflate,squash] horizontal --expand