首页 > 解决方案 > TIFF 如何有序地放置图像

问题描述

朋友们!我有一组小图像,需要在 Tiff 文件中布置为表格。

文件在最终文件中的样子: 在此处输入图像描述 我为此使用了 LibTIFF 库。告诉我如何实现?我用 C# 实现了我的解决方案,但语言并不重要,因为重写解决方案不是问题。

        var Row = 10;
        var Column = 10;

        var PIXEL_WIDTH = 8810;
        var PIXEL_HEIGHT = 11810;
        //Each small image has a resolution of 881x1181
        using (Tiff tiff = Tiff.Open("big.tif", "w"))
        {
            tiff.SetField(TiffTag.IMAGEWIDTH, PIXEL_WIDTH);
            tiff.SetField(TiffTag.IMAGELENGTH, PIXEL_HEIGHT);
            tiff.SetField(TiffTag.COMPRESSION, Compression.LZW);
            tiff.SetField(TiffTag.PHOTOMETRIC, Photometric.RGB);
            tiff.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);
            tiff.SetField(TiffTag.ROWSPERSTRIP, PIXEL_HEIGHT);

            tiff.SetField(TiffTag.XRESOLUTION, 120);
            tiff.SetField(TiffTag.YRESOLUTION, 120);

            tiff.SetField(TiffTag.BITSPERSAMPLE, 8);
            tiff.SetField(TiffTag.SAMPLESPERPIXEL, 3);

            tiff.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);

            int tileC = 0;

            for (int row = 0; row < Row; row++)
            {
                for (int col = 0; col < Column; col++)
                {
                    Bitmap bitmap = new Bitmap($"{row}x{col}.png");
                    byte[] raster = getImageRasterBytes(bitmap, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                    tiff.WriteEncodedStrip(tileC++, raster, raster.Length);
                }
            }
            tiff.WriteDirectory();
        }

提前致谢!

标签: c#imageimage-processingtifflibtiff

解决方案


首先让我们把你问题的 TIFF 部分放在一边。主要问题是您需要弄清楚如何在内存中组织像素数据,然后才能将最终图像保存为任何图像类型。

我将提供我自己的简单示例来说明应该如何组织像素数据。


假设我们想在一个 3x3 的表格中组合 9 个图像。
每个图像将是 3x3 像素和 8 位单声道(1 个通道)。
这使得这个例子变得漂亮而简单,每个图像 9 个字节,每个图像每行的步幅为 3 个字节。合并后的图像最终将是 9x9 像素,总共 81 字节。

这些图像被命名为 A、B、C ... I
A0是 A 的像素数据的字节 0,A1是字节 1,依此类推...

这些图像将被组织在一个 3x3 的表格中,如下所示:

ABC
DEF
GHI

那么最终的数据布局需要如下所示:

byte[] pixelData = [
    A0,A1,A2,B0,B1,B2,C0,C1,C2,
    A3,A4,A5,B3,B4,B5,C3,C4,C5,
    A6,A7,A8,B6,B7,B8,C6,C7,C8,
    D0,D1,D2,E0,E1,E2,F0,F1,F2,
    D3,D4,D5,E3,E4,E5,F3,F4,F5,
    D6,D7,D8,E6,E7,E8,F6,F7,F8,
    G0,G1,G2,H0,H1,H2,I0,I1,I2,
    G3,G4,G5,H3,H4,H5,I3,I4,I5,
    G6,G7,G8,H6,H7,H8,I6,I7,I8
];

然后可以将上面的像素阵列写入您想要的任何图像文件。包括 TIFF。

请注意上面的数组:
当您从索引 0 到 80 遍历该数组时,您将在同一行上的三个图像之间来回跳转,直到您完全到达下一行,接下来的 3 个图像来自该行行以相同的模式访问。


要实现这样的内存布局,您可以使用多种方法。

  1. TIFF 文件支持将大图像分解为大小相等的图块。这可用于通过使用 libTIFF 库将每个图像写入其自己的图块来实现您的要求。每个 TIFF 切片的尺寸必须是 16 的倍数,这是一个限制。
  2. 中的GraphicsSystem.Drawing可用于制作一个大的空白图像,然后您可以将每个子图像绘制到任意位置的大图像中。(这是得到你想要的最简单的方法,但它可能很慢。)
  3. 使用循环手动执行:
// For the example I have given above, in pseudo C# code

int composite_stride = image_stride * 3; // 3 is the number of images per row
int composite_size = composite_stride * image_height * 3 // 3 is the number of images per column
byte[] composite_pixels = new byte[composite_size];

// Loop over each image you want to combine
// We need some way to know which row/column the image is from, let that be assigned to table_row and table_col
// We are also assuming all images have the same width and height
foreach (image in table)
{
    int comp_x = table_col * image.width;
    int comp_y = table_row * image.height;

    for (int y=0; y<image.height; y++)
    {
        // Calculate the array index that the current row starts at
        int comp_row_start = comp_y * composite_stride;

        for (int x=0; x<image.width; x++)
        {
            // Calculate the array index in the composite image to write to, and the source image index to copy from
            int comp_index = comp_row_start + ((comp_x + x) * image.bytes_per_pixel);
            int img_index = (y * image.stride) + (x * image.bytes_per_pixel);
            composite_pixels[pixel_index] = image.pixels[img_index];
        }
    }
}

推荐阅读