Эффективный способ создания негатива изображения без внешних DLL

Это решение сделать негатив с изображения в С# Windows Forms без каких-либо DLL и эффективным, быстрым способом?

Ответ 1

Лучший способ сделать это - прямой доступ к пикселям с растровыми данными.

Просто добавьте некоторые детали времени:

Выполнение Negate на 8-мегапиксельном изображении (на 2.4 Ghz Core 2 Duo):

  • SetPixel (~ 22 секунды) - менее 220 раз
  • Цветовая матрица, метод Матаджона ниже (~ 750 миллисекунд) - в 7 раз медленнее
  • Непосредственно доступ к данным растрового изображения (~ 100 миллисекунд) - Самый быстрый

Итак, если у вас не может быть небезопасный код, тогда Color Matrix намного лучше, чем SetPixel.

    public static void Negate(Bitmap image)
    {
        const int RED_PIXEL = 2;
        const int GREEN_PIXEL = 1;
        const int BLUE_PIXEL = 0;


        BitmapData bmData = currentImage.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat);

        try
        {
            int stride = bmData.Stride;
            int bytesPerPixel = (currentImage.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4);

            unsafe
            {
                byte* pixel = (byte*)(void*)bmData.Scan0;
                int yMax = image.Height;
                int xMax = image.Width;

                for (int y = 0; y < yMax; y++)
                {
                    int yPos = y * stride;
                    for (int x = areaSize.X; x < xMax; x++)
                    {
                        int pos = yPos + (x * bytesPerPixel);

                        pixel[pos + RED_PIXEL] = (byte)(255 - pixel[pos + RED_PIXEL]);
                        pixel[pos + GREEN_PIXEL] = (byte)(255 - pixel[pos + GREEN_PIXEL]);
                        pixel[pos + BLUE_PIXEL] = (byte)(255 - pixel[pos + BLUE_PIXEL]);                                                    
                    }

                }
            }
        }
        finally
        {
            image.UnlockBits(bmData);
        }

    }

Если вам интересно, вот код для цветовой матрицы:

    public static void Negate(Bitmap image)
    {

            Bitmap clone = (Bitmap) image.Clone();

            using (Graphics g = Graphics.FromImage(image))
            {

                // negation ColorMatrix
                ColorMatrix colorMatrix = new ColorMatrix(
                    new float[][]
                        {
                            new float[] {-1, 0, 0, 0, 0},
                            new float[] {0, -1, 0, 0, 0},
                            new float[] {0, 0, -1, 0, 0},
                            new float[] {0, 0, 0, 1, 0},
                            new float[] {0, 0, 0, 0, 1}
                        });

                ImageAttributes attributes = new ImageAttributes();

                attributes.SetColorMatrix(colorMatrix);

                g.DrawImage(clone, new Rectangle(0, 0, clone.Width, clone.Height),
                            0, 0, clone.Width, clone.Height, GraphicsUnit.Pixel, attributes);
           }
    }

Ответ 2

Никогда не используйте SetPixel!! это самый медленный api!

Ответ 3

Пройдите все пиксели по одному (Bitmap.GetPixel() или что-то еще) и вычтите значения RGB от 0xff, чтобы создать пиксель отрицательного цвета. Сохраните этот пиксель на новом изображении или на том же изображении, используя (Bitmap.SetPixel()) в том же положении.

    // Retrieve the image.
    var image1 = new Bitmap(@"C:\Documents and Settings\All Users\" 
        + @"Documents\My Music\music.bmp", true);

    int x, y;

    // Loop through the images pixels to reset color.
    for(x=0; x<image1.Width; x++)
    {
        for(y=0; y<image1.Height; y++)
        {
            Color pixelColor = image1.GetPixel(x, y);
            Color newColor = Color.FromArgb(0xff - pixelColor.R
            , 0xff - pixelColor.G, 0xff - pixelColor.B);
            image1.SetPixel(x, y, newColor);
        }
    }