1

I;m learning about images processing and to start off with something simple, I wrote a program to convert full-color image to a black-and-white version of it.

I used C# and Windows Forms. I used PictureBox to load an image. Then I click a button to do the conversion and here's the event handler of it:

private void button1_Click(object sender, EventArgs e)
{
    Color kolor, kolor_wynik;
    byte r, g, b, avg, prog;

    prog = 85;

    int h = MainPictureBox.Height;
    int w = MainPictureBox.Width;

    Bitmap bitmap = new Bitmap(MainPictureBox.Image); //needed for GetPixel()
    Graphics graphics = MainPictureBox.CreateGraphics();

    for (int j = 0; j < h; j++)
    {
        for (int i = 0; i < w; i++)
        {
            kolor = bitmap.GetPixel(i, j);
            r = kolor.R;
            g = kolor.G;
            b = kolor.B;

            avg = (byte)((r + g + b) / 3);

            if (avg > prog)
                kolor_wynik = Color.White;
            else
                kolor_wynik = Color.Black;

            Pen pen = new Pen(kolor_wynik);


            graphics.DrawEllipse(pen, i, j, 1, 1);

        }
    }
}

The program does its job, but the problem is - it is really slow. It takes about 21 seconds to convert 400x400 image to black-and-white.

Now, I wouldn't be that surprized, if I didn't also have this program written in VB 6.0:

Private Sub Command2_Click()

    Dim kolor   As Long ' kolor

    Dim kolor_wynik  As Long ' kolor    
    Dim r, g, b, avg As Byte

    Dim prog As Byte

prog = 85



h = Picture1.ScaleHeight
w = Picture1.ScaleWidth

For j = 0 To h Step 1
For i = 0 To w Step 1

kolor = Picture1.Point(i, j)

r = kolor And &HFF
g = (kolor And &HFF00&) / &H100&
b = (kolor And &HFF0000) / &H10000

avg = (r + g + b) / 3

If (avg > prog) Then
kolor_wynik = vbWhite
Else
kolor_wynik = vbBlack
End If

Picture1.PSet (i, j), kolor_wynik

Next i
Next j

End Sub

These two algorithms are very similiar, but the VB 6.0 version finished the job almost instantly (I only could test it on Windows XP though, while the C# version on Windows 10).

What's the reason for this behaviour? I wanted to do stuff in C#, but it turns out 'll have to switch to VB 6.0 (whic is not what I'd like to do).

Loreno
  • 668
  • 8
  • 26
  • 1
    Rather than iterating pixels, use `Imaging.ColorMatrix`. BLack and white usually isnt what someone means - they look really odd, like a negative. If you mean grayscale see: [Faster method to Convert Image to grayscale](http://stackoverflow.com/a/23595488/1070452) – Ňɏssa Pøngjǣrdenlarp Nov 16 '16 at 16:56
  • Have you tried using [FillRectangle](https://msdn.microsoft.com/en-us/library/system.drawing.graphics.fillrectangle(v=vs.110).aspx) instead of `DrawEllipse`? – Pikoh Nov 16 '16 at 16:56
  • 1
    Yes, Get/SetPixel are not performant due to locking, see http://stackoverflow.com/questions/24701703/c-sharp-faster-alternatives-to-setpixel-and-getpixel-for-bitmaps-for-windows-f / http://stackoverflow.com/questions/1563038/fast-work-with-bitmaps-in-c-sharp – Alex K. Nov 16 '16 at 16:57
  • 1
    [C# - Faster Alternatives to SetPixel and GetPixel for Bitmaps for Windows Forms App](http://stackoverflow.com/questions/24701703/c-sharp-faster-alternatives-to-setpixel-and-getpixel-for-bitmaps-for-windows-f) – Reza Aghaei Nov 16 '16 at 16:59
  • 1
    To change the image at the pixel level fast look into [LockBits](http://stackoverflow.com/search?q=user%3A3152130+lockbits+Marshal.Copy). To do a simply color change look into [ColorMatrix](http://stackoverflow.com/search?q=user%3A3152130+ColorMatrix). – TaW Nov 16 '16 at 17:11

1 Answers1

-1

The C# code is deal with a per pixel change. While your VB6 is simply a bit shift which is super fast.

You can do the same in C#.

Ross Miller
  • 656
  • 3
  • 9