c# Создание матрицы из подматриц

Здравствуйте высококвалифицированные программисты.

У меня есть тестовое изображение 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

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

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 фрагментов матрицы 4x4 с именем "grayscale_map_block". Я использую этот код для получения элемента блоков grayscale_map_block [n] [x] [y] / n-й блок, элемент x,y. где n = 0-общее число блоков

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


person SadViolinMan    schedule 05.09.2018    source источник
comment
Первое, что я замечаю, это то, что totalblocknumber должен быть, возможно, шириной * высота / 16. Количество блоков 4 x 4 в изображении ширина x высота равно (ширина / 4) * (высота / 4) = ширина * высота / 16.   -  person Wyck    schedule 05.09.2018
comment
да я тут не правильно написал..исправил   -  person SadViolinMan    schedule 05.09.2018
comment
Любая идея, как это делается?   -  person SadViolinMan    schedule 05.09.2018
comment
Случайный совет: pictureBox1.Image = bmp. Bitmap это Image. Нет необходимости загружать изображение дважды.   -  person Wyck    schedule 12.09.2018
comment
спасибо за совет, но как насчет всего решения. Тем не менее я не мог использовать ваши коды:/   -  person SadViolinMan    schedule 12.09.2018


Ответы (3)


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

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).)

person Wyck    schedule 06.09.2018
comment
Хм. Я думаю, что я получаю где-то. Теперь предположим, что я выполнил математические операции в блоках и назначу их для зашифрованного_массива [ширина, высота]. Как я буду заполнять его элементами в блоках, используя эти коды. Также эта строка Debug.Assert(b[402, 2, 1] == 999); Visual Studio не распознает Debug. Он говорит, что имя Debug не существует в текущем контексте. Для чего это. Что мне делать после того, как BlockData enrypted_Array = new BlockData() {data = new int[width, height]}; (Также не думайте, что я просто спрашиваю и спрашиваю, не пытаясь. Я делаю все возможное, чтобы понять и заставить это работать, тогда я пришел сюда) - person SadViolinMan; 06.09.2018
comment
Два варианта устранения ошибки «Отладка имени не существует...»: 1) Добавьте using System.Diagnostics; в начало файла, чтобы Debug работало. или 2) вы можете просто явно заменить слово Debug на System.Diagnostics.Debug. Извините, что упустил это, но решение с помощью вопросов — довольно типичная вещь, которую мы делаем в стране C#. Настолько, что Visual Studio предоставляет быстрые действия и рефакторинг... чтобы справиться с этим. Вы можете поставить курсор на Debug и нажать Ctrl+. (это Control и точка), и IDE предложит два решения, о которых я упоминал выше. - person Wyck; 07.09.2018
comment
Что касается того, как вы будете его использовать... это должна быть подходящая оболочка для вашего int_grayscale_map. - person Wyck; 08.09.2018
comment
я пробовал много решений, все еще не смог добиться успеха. я не знаю почему. Да Debug.Assert работает. Но я не знаю, что он делает. Из этих кодов, где моя последняя 2d матрица. ИС ИТ б? Как бы я заполнил его? добавление BlockData b = new BlockData() { data = new int[1600, 1600] }; кода достаточно? - person SadViolinMan; 11.09.2018
comment
я должен иметь возможность передать grayscale_map_block [n] [x] [y] в класс, но я не могу этого сделать, он говорит, что не может преобразовать тип List... в int [,]. я пробовал convert.toint32 , не работает. Классу для передачи требуется 2d-матрица - person SadViolinMan; 11.09.2018
comment
В написанном мной примере изначально используется двумерный массив и предоставляется трехмерный доступ к нему. Вы можете скопировать его поэлементно, если хотите. for(int n=0; n<N; ++n) for( int y=0; y<4; ++y) for( int x=0; x<4; ++x) b[n,x,y] = int_grayscale_map[n][x][y]. Извините, у вас все еще проблемы. - person Wyck; 12.09.2018
comment
мне просто нужно очистить 2d массив от блоков. Я не думаю, что эта структура работает для меня. все равно выдает ошибки. я должен начать с Strach. спасибо четыре ваша помощь. я должен удалить вопрос, чтобы снова задать разные идеи. спасибо за все - person SadViolinMan; 13.09.2018
comment
Просто чтобы подтвердить .... ваш ввод - это массив int_grayscale_map[n][x][y], а ваш вывод будет обратно в 2d int_grayscale_map[1600,1600] (или, возможно, совершенно новый int_brandnew_grayscale_map[1600,1600] - который в основном является тем же кодом), верно? - person Wyck; 14.09.2018
comment
мой первый ввод пришел из изображения grayscale_map [1600,1600] , затем со структурой List‹List‹List я разделил его на блоки 4x4 grayscale_map_block [n] [x] [y] , и после некоторых операций с этими блоками моя окончательная 2d-матрица будет int_brandnew_grayscale_map[1600,1600]. Где я застрял, так это от grayscale_map_block [n] [x] [y] до массива 2d brandnew_grayscale_map[1600,1600]. В основном вот и все - person SadViolinMan; 17.09.2018

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

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

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

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

Чтобы сопоставить от [n,x_,y_] до [x,y]

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

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

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

person Wyck    schedule 05.09.2018
comment
я разберусь с делимой на 4 проблемой позже. Теперь тестовые объекты всегда делятся на 4. Но я не мог получить эту структуру полностью :( извините. Как я могу запустить цикл из блоков, используя этот пример, который заполняет мою окончательную матрицу 1600x1600 - person SadViolinMan; 05.09.2018
comment
Будет ли полезно, если я напишу это полностью? Это займет у меня больше времени, я думал, что этого будет достаточно, чтобы дать вам суть. Я не хочу на самом деле писать этот код, потому что список списков — неэффективный способ хранения пикселей, гораздо лучше использовать массив. И шаблон доступа getpixel/setpixel также плох, если вы собираетесь посетить каждый пиксель. Вместо этого вы должны использовать LockBits, и это будет во много раз быстрее. Это не очень хороший совет делать то, что вы делаете. Но я сделаю это, если хочешь. - person Wyck; 05.09.2018
comment
когда я начал эту программу, появилось слишком много предложений, включая локбиты, но, поскольку я новичок в С# (на самом деле это моя первая программа), все они выглядели очень сложными. я не мог их понять. Но с этим я справился. Потому что в математических операциях мне нужна была эта форма. Блок [номер блока] [строка] [столбец]. Вот почему я выбрал его. Это будет программа для шифрования изображений. Если это будет медленно, я могу снова изменить свои коды. СЕЙЧАС я все еще пытаюсь понять эту концепцию. Но все же я не мог. Может быть, вы должны написать все . Спасибо. И я буду искать Lockbits, а также - person SadViolinMan; 05.09.2018
comment
Спасибо за код. Это хорошая структура. Я думаю, что немного понимаю. Но я должен сказать, что моя программа на самом деле не является программой обработки изображений. Я использую функции изображения только в начале и в конце программы. Между ними я просто выполняю математические операции. Вот почему я использовал эту форму Блок [i] [x] [y]. математические операции, которые я делаю с блоками 4x4, сложны. Поэтому мне подходит эта форма. Вы можете увидеть, что я делаю, по этой ссылке, если вы скажете, что я могу получить эту форму блок [i] [x][y] из этой структуры, я могу изменить все свои коды. - person SadViolinMan; 06.09.2018
comment
В противном случае мне нужны только коды для получения окончательной матрицы из блоков. Структура List‹List не имеет большого значения, потому что 99 процентов моей программы просто добавляют операции сдвига. - person SadViolinMan; 06.09.2018
comment
В своем предыдущем комментарии вы сказали, что это будет программа шифрования изображений, а затем вы сказали, что на самом деле это не программа обработки изображений. Эти два утверждения противоречат друг другу, потому что шифрование изображения является обработкой изображения IMO. - person Wyck; 06.09.2018
comment
если вы посмотрите на эту ссылку, вы поймете, что на самом деле это не ссылка. просто математические операции. Много математических операций с блоками 4x4 - person SadViolinMan; 06.09.2018
comment
Похоже, вам просто нужен шаблон доступа [i][x'][y'] к вашему массиву 2d [x][y], где i – это номер блока при преобразовании вашего массива 2d в блоки 4х4. Это просто упражнение по переназначению индекса. На самом деле вам не нужно хранить данные в другом формате, чтобы получить к ним доступ по другому шаблону. Я могу показать, если хотите. - person Wyck; 06.09.2018

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

И вместо того, чтобы использовать списки списков, я просто использовал двумерные массивы. Это намного проще. «Блоки» — это просто 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;
    }
}
person Wyck    schedule 06.09.2018