Как манипулировать изображениями на уровне пикселей в C # - PullRequest
45 голосов
/ 10 октября 2008

Как мне манипулировать изображениями на уровне пикселей в C #?

Мне нужно иметь возможность читать / изменять значения RGB каждого растрового пикселя отдельно.

Пример кода будет приветствоваться.

Ответы [ 4 ]

49 голосов
/ 10 октября 2008

Если вам нужна скорость, то LockBits . Смотрите здесь для хорошего прохождения Боба Пауэлла . Если вы просто хотите отредактировать несколько, то GetPixel / SetPixel должно делать то, что вы хотите.

15 голосов
/ 10 октября 2008

Пример процедуры кода (я использую ее для простого слияния и сравнения функций. Она берет два изображения и создает третье изображение в оттенках серого, показывающее различия между двумя изображениями в виде уровня оттенков серого. Чем оно темнее, тем больше разность .):

    public static Bitmap Diff(Bitmap src1, Bitmap src2, int x1, int y1, int x2, int y2, int width, int height)
{
    Bitmap diffBM = new Bitmap(width, height, PixelFormat.Format24bppRgb);

    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            //Get Both Colours at the pixel point
            Color col1 = src1.GetPixel(x1 + x, y1 + y);
            Color col2 = src2.GetPixel(x2 + x, y2 + y);

            // Get the difference RGB
            int r = 0, g = 0, b = 0;
            r = Math.Abs(col1.R - col2.R);
            g = Math.Abs(col1.G - col2.G);
            b = Math.Abs(col1.B - col2.B);

            // Invert the difference average
            int dif = 255 - ((r+g+b) / 3);

            // Create new grayscale RGB colour
            Color newcol = Color.FromArgb(dif, dif, dif);

            diffBM.SetPixel(x, y, newcol);

        }
    }

    return diffBM;
}

Пост Марка отмечает LockBits и использует его для изменения изображения непосредственно в памяти. Я бы посоветовал взглянуть на это, а не на то, что я написал, если производительность вызывает беспокойство. Спасибо Марк!

5 голосов
/ 10 октября 2008

System.Drawing.Bitmap имеет открытый метод GetPixel (int x, int y), который возвращает структуру System.Drawing.Color. Эта структура имеет байтовые члены R, G, B и A, которые вы можете изменить напрямую, а затем снова вызвать SetPixel (Color) для вашего растрового изображения.
К сожалению, это будет относительно медленно, но это самый простой способ сделать это в C #. Если вы много работаете с отдельными пикселями и обнаруживаете, что производительности не хватает, и вам нужно что-то более быстрое, вы можете использовать LockBits ... Хотя это намного сложнее, поскольку вам необходимо понять структуру битов для этой глубины цвета и типа. и работать с шагом растрового изображения, а что нет ... так что, если вы обнаружите, что это необходимо, убедитесь, что вы найдете хороший учебник! В интернете есть несколько, гуглинг "C # LockBits" даст вам полдюжины, которые стоит прочитать.

3 голосов
/ 10 октября 2008

Если производительность критична, другой альтернативой LockBits является управляемый DirectX.

См. Предыдущий вопрос переполнения стека Визуализация графики в C # для получения дополнительной информации.

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

Вы также получаете более высокую производительность рендеринга экрана с помощью буферизации DirectX по сравнению с использованием обычного класса Bitmap и элемента управления PictureBox.

...