c # Создание матрицы из подматриц - PullRequest
0 голосов
/ 05 сентября 2018

Привет высококвалифицированным программистам

У меня есть тестовое изображение 1600x1600. Я импортировал это в матрицу как значения int в градациях серого. Затем я создал 4x4 подматрицы из этой матрицы. Я сделал несколько математических операций в этих блоках и создал новые блоки. Теперь мне нужно снова создать новую матрицу (1600x1600) из этих новых блоков 4x4. Но я не смог создать цикл. У меня есть (1600/4 * 1600/4 = 160 000) подматриц всего. (Конечно, моя программа не является статичной, входное изображение может быть любым. Это для тестового изображения). Теперь это моя структура.

Bitmap bmp = new Bitmap("c:\\test.jpg");
pictureBox1.Image = Image.FromFile("c:\\test.jpg");
int width = bmp.Width; int height = bmp.Height;

  while (y < height) {
      while (x < width) {
      pxl = bmp.GetPixel(x, y);
      int_grayscale_map[x, y] = GetGrayScale(pxl); //getgrayscale is function that returns int value
      x++;}
   y++;}

   int totalblocknumber = (width/4) * (height / 4); //160 000 in this case

Теперь я создал и заполнил подблоки из этого кода. Кто-то помог мне здесь (подумайте, что мы озадачили изображение 1600х1600 до 4х4)

Bitmap image = new Bitmap(FILENAME);

        List<List<List<Int32>>> grayscale_map_block = newList<List<List<Int32>>>();
         for (int row = 0; row < height; row += 4)
        {
            for (int col = 0; col < width; col += 4)
            {
                block.Add(new List<List<Color>>()  {
                     new List<Color>() { image.GetPixel(col, row), image.GetPixel(col + 1, row), image.GetPixel(col + 2, row), image.GetPixel(col + 3, row)} ,
                     new List<Color>() { image.GetPixel(col, row + 1), image.GetPixel(col + 1, row + 1), image.GetPixel(col + 2, row + 1), image.GetPixel(col + 3, row + 1)} ,
                     new List<Color>() { image.GetPixel(col, row + 2), image.GetPixel(col + 1, row + 2), image.GetPixel(col + 2, row + 2), image.GetPixel(col + 3, row + 2)} ,
                     new List<Color>() { image.GetPixel(col, row + 3), image.GetPixel(col + 1, row + 3), image.GetPixel(col + 2, row + 3), image.GetPixel(col + 3, row + 3)} ,
                });

                grayscale_map_block.Add(new List<List<Int32>>()  {
                     new List<Int32>() { GetGrayScale(image.GetPixel(col, row)), GetGrayScale(image.GetPixel(col + 1, row)), GetGrayScale(image.GetPixel(col + 2, row)), GetGrayScale(image.GetPixel(col + 3, row))} ,
                     new List<Int32>() { GetGrayScale(image.GetPixel(col, row + 1)), GetGrayScale(image.GetPixel(col + 1, row + 1)), GetGrayScale(image.GetPixel(col + 2, row + 1)), GetGrayScale(image.GetPixel(col + 3, row + 1))} ,
                     new List<Int32>() { GetGrayScale(image.GetPixel(col, row + 2)), GetGrayScale(image.GetPixel(col + 1, row + 2)), GetGrayScale(image.GetPixel(col + 2, row + 2)), GetGrayScale(image.GetPixel(col + 3, row + 2))} ,
                     new List<Int32>() { GetGrayScale(image.GetPixel(col, row + 3)), GetGrayScale(image.GetPixel(col + 1, row + 3)), GetGrayScale(image.GetPixel(col + 2, row + 3)), GetGrayScale(image.GetPixel(col + 3, row + 3))} ,
                });

            }
        }          // Getgrayscale is a function that input color return int value

Все, что есть. Теперь у меня есть 160 000 кусочков матрицы 4х4 с кодом "grayscale_map_block" я использую этот код, чтобы получить элемент блоков grayscale_map_block [n] [x] [y] / n-й блок, элемент x, y. где n = 0-общее количество блоков

Из этих блоков я должен ловко создать цикл, который собирает кусочки. Новая матрица 1600х1600. Спасибо за вашу помощь ..

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

OK. Вот тот, который использует GetPixel и SetPixel (Плохо для производительности, но легко понять. В идеальном мире вы бы вместо этого использовали LockBits. Но давайте пока просто будем делать это просто.)

И вместо использования списков списков я просто использовал 2D-массивы. Это намного проще. «Блоки» - это просто 2D-массивы 2D-массивов. Я полагаю, вы могли бы думать об этом как об изображении, где каждый пиксель является целым изображением - или, возможно, думать об этом как о сетке из крошечных квадратных изображений.

Похоже, вы управляете загрузкой и сохранением растровых изображений, поэтому я пропущу эту часть.

/// <summary>
/// Example Image Processing class
/// Demonstrates treating images as 2D arrays.
/// </summary>
public class ImageProcessor {
    /// <summary>
    /// Creates a 2D array of Colors from a bitmap.
    /// </summary>
    /// <param name="bm">The input bitmap</param>
    /// <returns>The output Color array</returns>
    public static Color[,] BitmapToColorArray(Bitmap bm) {
        int width = bm.Width;
        int height = bm.Height;
        Color[,] colorArray = new Color[width, height];
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                colorArray[x, y] = bm.GetPixel(x, y);
            }
        }
        return colorArray;
    }

    /// <summary>
    /// Creates a Bitmap from a 2D array of Colors.
    /// </summary>
    /// <param name="colorArray">The input Color 2D array</param>
    /// <returns>The output bitmap</returns>
    public static Bitmap ColorArrayToBitmap(Color[,] colorArray) {
        int width = colorArray.GetLength(0);
        int height = colorArray.GetLength(1);
        Bitmap bm = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                bm.SetPixel(x, y, colorArray[x, y]);
            }
        }
        return bm;
    }

    /// <summary>
    /// Converts a Color to a gray value 0-255.
    /// </summary>
    /// <param name="color">The input color</param>
    /// <returns>The output gray value.</returns>
    public static int ColorToGray(Color color) {
        int gray = (color.R * 30 + color.G * 59 + color.B * 11) / 100;
        return gray;
    }

    /// <summary>
    /// Converts a gray value to a Color
    /// </summary>
    /// <param name="gray">The input gray value</param>
    /// <returns>The output Color</returns>
    public static Color GrayToColor(int gray) {
        return Color.FromArgb(gray, gray, gray);
    }

    /// <summary>
    /// Creates a 2D gray array from a 2D Color array
    /// </summary>
    /// <param name="colorArray">The input 2D Color array</param>
    /// <returns>The output 2D gray array</returns>
    public static int[,] ColorArrayToGrayArray(Color[,] colorArray) {
        int width = colorArray.GetLength(0);
        int height = colorArray.GetLength(1);
        int[,] grayArray = new int[width, height];
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                grayArray[x,y] = ColorToGray(colorArray[x, y]);
            }
        }
        return grayArray;
    }

    /// <summary>
    /// Creates a 2D Color Array from a 2D gray array
    /// </summary>
    /// <param name="grayArray">The input 2D gray array</param>
    /// <returns>The output 2D Color array</returns>
    public static Color[,] GrayArrayToColorArray(int[,] grayArray) {
        int width = grayArray.GetLength(0);
        int height = grayArray.GetLength(1);
        Color[,] colorArray = new Color[width, height];
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                colorArray[x, y] = GrayToColor(grayArray[x, y]);
            }
        }
        return colorArray;
    }

    /// <summary>
    /// Generic function to extract a 2D rectangular sub-area of an array as a new 2D array.
    /// </summary>
    /// <typeparam name="T">The generic type</typeparam>
    /// <param name="src">The input 2D array</param>
    /// <param name="srcx">The column of the top-left corner of the sub-area to extract</param>
    /// <param name="srcy">The row of the top-left corner of the sub-area to extract</param>
    /// <param name="dstWidth">The width of the sub-area to extract</param>
    /// <param name="dstHeight">The height o fthe sub-area to extract</param>
    /// <returns>The output 2D array</returns>
    public static T[,] SubArray<T>(T[,] src, int srcx, int srcy, int dstWidth, int dstHeight) {
        int srcWidth = src.GetLength(0);
        int srcHeight = src.GetLength(1);
        if (srcx < 0) throw new ArgumentOutOfRangeException();
        if (srcy < 0) throw new ArgumentOutOfRangeException();
        if (srcx + dstWidth > srcWidth) throw new ArgumentOutOfRangeException();
        if (srcy + dstHeight > srcHeight) throw new ArgumentOutOfRangeException();
        T[,] dst = new T[dstWidth, dstHeight];
        for (int dsty = 0; dsty < dstHeight; ++dsty) {
            for (int dstx = 0; dstx < dstWidth; ++dstx) {
                dst[dstx, dsty] = src[srcx + dstx, srcy + dsty];
            }
        }
        return dst;
    }

    /// <summary>
    /// Generic function to convert a 2D array into blocks (2D array of 2D arrays)
    /// </summary>
    /// <typeparam name="T">The generic type</typeparam>
    /// <param name="src">The input 2D array</param>
    /// <param name="blockSize">The width and height of each square block</param>
    /// <returns>The output 2D array of 2D arrays</returns>
    public T[,][,] ArrayToBlockArray<T>(T[,] src, int blockSize) {
        int srcWidth = src.GetLength(0);
        int srcHeight = src.GetLength(1);
        if (srcWidth % blockSize != 0) throw new Exception(string.Format("Width must be divisible by {0}", blockSize));
        if (srcHeight % blockSize != 0) throw new Exception(string.Format("Height must be divisible by {0}", blockSize));
        int dstWidth = srcWidth / blockSize;
        int dstHeight = srcHeight / blockSize;
        T[,][,] dst = new T[dstWidth, dstHeight][,]; // The syntax for creating new array of arrays is weird.
        for (int dsty = 0; dsty < dstHeight; ++dsty) {
            for (int dstx = 0; dstx < dstWidth; ++dstx) {
                dst[dstx, dsty] = SubArray(src, dstx * blockSize, dsty * blockSize, blockSize, blockSize);
            }
        }
        return dst;
    }

    /// <summary>
    /// Generic function to convert a 2D array of blocks (2D array of 2D arrays) back into a single 2D array.
    /// </summary>
    /// <typeparam name="T">The generic type</typeparam>
    /// <param name="src">The input 2D array of 2D arrays</param>
    /// <returns>The output 2D array</returns>
    public T[,] BlockArrayToArray<T>(T[,][,] src) {
        // assume uniform size
        int blockWidth = src[0, 0].GetLength(0);
        int blockHeight = src[0, 0].GetLength(1);
        int srcWidth = src.GetLength(0);
        int srcHeight = src.GetLength(1);
        int dstWidth = srcWidth * blockWidth;
        int dstHeight = srcHeight * blockHeight;
        T[,] dst = new T[dstWidth, dstHeight];
        for (int srcy = 0; srcy < srcHeight; ++srcy) {
            for (int srcx = 0; srcx < srcWidth; ++srcx) {
                for (int blocky = 0; blocky < blockHeight; ++blocky ) {
                    for (int blockx = 0; blockx < blockWidth; ++blockx) {
                        T[,] block = src[srcx, srcy];
                        if (block.GetLength(0) != blockWidth) throw new Exception(string.Format("Blocks must all have width {0}", blockWidth));
                        if (block.GetLength(1) != blockHeight) throw new Exception(string.Format("Blocks must all have height {0}", blockHeight));
                        int dstx = srcx * blockWidth + blockx;
                        int dsty = srcy * blockHeight + blocky;
                        dst[dstx, dsty] = src[srcx, srcy][blockx, blocky];
                    }
                }
            }
        }
        return dst;
    }

    /// <summary>
    /// Example function that does end-to-end processing of a Bitmap.
    /// </summary>
    /// <param name="srcBitmap">The input bitmap</param>
    /// <returns>The output bitmap</returns>
    public Bitmap Process(Bitmap srcBitmap) {
        const int blockSize = 4;

        Color[,] srcColorArray = BitmapToColorArray(srcBitmap);
        int[,] srcGrayArray = ColorArrayToGrayArray(srcColorArray);
        int[,][,] srcBlockArray = ArrayToBlockArray(srcGrayArray, blockSize);

        // TODO: Presumably you're going to modify the source block array.
        int[,][,] dstBlockArray = srcBlockArray; // PLACEHOLDER: do nothing for now.

        // Reconstitute a new bitmap from the (presumably modified) destination block array.
        int[,] dstGrayArray = BlockArrayToArray(dstBlockArray);
        Color[,] dstColorArray = GrayArrayToColorArray(dstGrayArray);
        Bitmap dstBitmap = ColorArrayToBitmap(dstColorArray);
        return dstBitmap;
    }
}
0 голосов
/ 06 сентября 2018

Вот пример доступа к двумерному массиву с другим механизмом индексации. Здесь n - номер блока, а x и y - индексы 0-3 в блоке 4x4. Это просто преобразует (n, x, y) в (xx, yy), которые являются индексами данных в исходном двумерном массиве.

class BlockData
{
    public int[,] data;

    internal void reindex(int n, int x, int y, out int xx, out int yy)
    {
        const int blockSize = 4;
        int width = data.GetLength(0);
        int columns = width / blockSize;
        int row = n / columns;
        int col = n % columns;
        xx = col * blockSize + x;
        yy = row * blockSize + y;
    }

    public int this[int n, int x, int y]
    {
        get
        {
            int xx, yy;
            reindex(n, x, y, out xx, out yy);
            return data[xx, yy];
        }
        set
        {
            int xx, yy;
            reindex(n, x, y, out xx, out yy);
            data[xx, yy] = value;
        }
    }
    public int this[int xx, int yy]
    {
        get
        {
            return data[xx, yy];
        }
        set
        {
            data[xx, yy] = value;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        BlockData b = new BlockData() { data = new int[1600, 1600] };
        b[10, 5] = 999;
        // (10,5) is in the 402nd block of 4x4 at (2,1) within that block.
        Debug.Assert(b[402, 2, 1] == 999);

        b[888, 3, 2] = 777;
        // The 888th block is row 2, column 88.  Its top-left is at ((88*4),(2*4)).
        // (352 + 3, 8 + 2) = (355, 10)
        Debug.Assert(b[355, 10] == 777);
    }
}

Используя ту же стратегию, вы также можете хранить свои данные в виде одномерного массива и предоставлять различные сопоставления индексов от [n] [x] [y] до просто линейного [i].

Предоставление объекта с оператором индекса массива на самом деле просто "мило". Это необязательно. Идея состоит в том, чтобы просто посчитать индексы исходных данных, к которым вы хотите получить доступ. Но это помогает проиллюстрировать мою точку зрения.

(Примечание по производительности: вы можете оптимизировать это так, чтобы blockSize, width и columns были предварительно вычислены при инициализации data, если вы хотите ускорить время доступа и избегать постоянного вызова data.GetLength(0) .)

0 голосов
/ 05 сентября 2018

Вы можете отобразить [x, y] -> [n, x_, y_] следующим образом:

n = (y / 4) * (width/4) + (x/4);
x_ = x % 4;
y_ = y % 4;

Идея состоит в том, чтобы вычислить n, использовать индекс подблока по вертикали (у / 4), а затем умножить его на количество подблоков в строке (ширина / 4), а затем добавить индекс подблока по горизонтали (х / 4).

Затем используйте оператор модуля (%) для вычисления адреса строки, столбца в подблоке.

Для отображения из [n, x_, y_] в [x, y]

x = (n % (width / 4)) * 4 + x_;
y = (n / (width / 4)) * 4 + y_;

Идея состоит в том, чтобы восстановить горизонтальный и вертикальный индекс подблока из единственного индекса n. Вертикальный индекс равен n, деленному на количество субблоков в строке, которое равно (width / 4). Вертикальный адрес пикселя - это число по вертикали, умноженное на 4, плюс строка субблока. По горизонтали вы снова используете оператор модуля, чтобы восстановить горизонтальный индекс блока. n% (ширина / 4). Затем аналогичным образом умножьте на 4 и добавьте x_, чтобы получить горизонтальный индекс пикселей (индекс столбца).

Примечание: Приведенная мною математика работает только в том случае, если ширина и высота даже кратны 4. Если ширина и высота не делятся равномерно на 4, то вам нужно сделать немного другую математику, но вы также потребовалось бы обрабатывать субблоки размером не 4 x 4, поэтому я предполагаю, что вы пока не хотите этого делать, но я могу помочь вам и в этом, если потребуется.

...