taji01
taji01

Reputation: 2615

Invert image faster in C#

I'm using WinForms. I have a picture-box in my form. When I open a picture in the picture-box I am able to invert the colors back and forth on a click of a button, but my code is extremely slow. How can I increase the performance.

   private void Button1_Click(object sender, System.EventArgs e) 
     {
        Bitmap pic = new Bitmap(PictureBox1.Image);
        for (int y = 0; (y 
                    <= (pic.Height - 1)); y++) {
            for (int x = 0; (x 
                        <= (pic.Width - 1)); x++) {
                Color inv = pic.GetPixel(x, y);
                inv = Color.FromArgb(255, (255 - inv.R), (255 - inv.G), (255 - inv.B));
                pic.SetPixel(x, y, inv);
                PictureBox1.Image = pic;
            }

        }

    }

Upvotes: 6

Views: 18487

Answers (4)

Joachim Otahal
Joachim Otahal

Reputation: 332

I've just searched for the same DOTNET to use in powershell. If you value speed use this colormatrix DOTNET example to invert in a single step: https://www.codeguru.com/dotnet/inverting-image-colors-in-net/ It uses https://learn.microsoft.com/en-us/dotnet/api/system.drawing.imaging.imageattributes , https://learn.microsoft.com/en-us/dotnet/api/system.drawing.imaging.colormatrix and https://learn.microsoft.com/de-de/dotnet/api/system.drawing.graphicsunit . I just applied these methods in Powershell to speed up the inversion a lot instead of doing it pixel by pixel. It should speed up the C# variant too.

Upvotes: 0

D Stanley
D Stanley

Reputation: 152624

You are setting the control's picture each time you change a pixel, which causes the control to redraw itself. Wait until you've finished the image:

Bitmap pic = new Bitmap(PictureBox1.Image);
for (int y = 0; (y <= (pic.Height - 1)); y++) {
    for (int x = 0; (x <= (pic.Width - 1)); x++) {
        Color inv = pic.GetPixel(x, y);
        inv = Color.FromArgb(inv.A, (255 - inv.R), (255 - inv.G), (255 - inv.B));
        pic.SetPixel(x, y, inv);
    }
}
PictureBox1.Image = pic;

Upvotes: 17

Gavin S.
Gavin S.

Reputation: 29

Improving on D Stanley's suggestion and avoiding the memory and processing overload of converting the image to a Bitmap and then re-assigning it, you can actually directly Get and Set pixels on the .Image of the PictureBox by simply casing it and calling the associated Bitmap manipulation functions:

private void Button1_Click(object sender, System.EventArgs e) 
 {
    for (int y = 0; (y 
                <= (PictureBox1.Image.Height - 1)); y++) {
        for (int x = 0; (x 
                    <= (PictureBox1.Image.Width - 1)); x++) {
            Color inv = ((Bitmap)PictureBox1.Image).GetPixel(x, y);
            inv = Color.FromArgb(255, (255 - inv.R), (255 - inv.G), (255 - inv.B));
            ((Bitmap)PictureBox1.Image).SetPixel(x, y, inv);

        }

    }
}

Upvotes: 0

Isidoros Moulas
Isidoros Moulas

Reputation: 697

In case someone need the similar code in VB.NET.

Also note the variable inv.A instead of the value 255. In case your picturebox has transparency you need this.

    Public Function InvertImageColors(ByVal p As Image) As Image
        Dim pic As New Bitmap(p)
        For y As Integer = 0 To pic.Height - 1
            For x As Integer = 0 To pic.Width - 1
                Dim inv As Color = pic.GetPixel(x, y)
                inv = Color.FromArgb(inv.A, 255 - inv.R, 255 - inv.G, 255 - inv.B)
                pic.SetPixel(x, y, inv)
            Next x
        Next y
        Return pic
    End Function

Usage:

    pic.image = InvertImageColors(pic.image)

Upvotes: 0

Related Questions