TIFF Как правильно разместить изображения - PullRequest
0 голосов
/ 03 июля 2019

Друзья!У меня есть набор небольших изображений, которые мне нужно выложить в виде таблицы в файле Tiff.

Как должны выглядеть файлы в конечном файле: enter image description here Я используюБиблиотека 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();
        }

Заранее спасибо!

1 Ответ

0 голосов
/ 04 июля 2019

Сначала давайте отложим часть вашего вопроса в формате TIFF. Основная проблема заключается в том, что вам нужно выяснить, как организовать пиксельные данные в памяти, прежде чем вы сможете сохранить окончательное изображение в любой тип изображения.

Я приведу свой собственный простой пример, чтобы проиллюстрировать, как должны быть организованы эти данные пикселей.


Допустим, мы хотим объединить 9 изображений в таблицу 3х3.
Каждое изображение будет 3х3 пикселя и 8-битным моно (1 канал).
Это делает этот пример красивым и простым с 9 байтами на изображение, и каждое изображение имеет шаг 3 байта на строку. Объединенное изображение будет 9x9 пикселей, всего 81 байт.

Эти изображения называются A, B, C ... I
A0 - это байт 0 данных пикселей для A, A1 - это байт 1 и т. Д. *

Эти изображения будут организованы в таблицу 3х3, например:

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. Класс Graphics в System.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];
        }
    }
}
...