bitmap get pixel too slow

12padams

Well-known member
Joined
Feb 19, 2010
Messages
48
Programming Experience
Beginner
I am testing out applying interesting effects to photos...

One effect I have invented is make the image only have 4 colors in it... red (at 255), green at (255), blue at (255) and black at (0)

Basically calculations are done for each pixel and then sets each pixel depending on the color which is the strongest.

For example a pixel with r = 140 g = 120 b = 100
The highest color intensity is red so it would become r = 255 g = 0 b = 0

The only problem is speed...

The only object on the form is a picturebox.

Here is my code:

VB.NET:
Public Class Form1
    Dim mybitmap As New Bitmap(56, 456)

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        OpenFileDialog1.ShowDialog()
        mybitmap = New Bitmap(OpenFileDialog1.FileName)
        PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage
        PictureBox1.Dock = DockStyle.Fill
        sync()
    End Sub

    Private Sub sync()
        PictureBox1.Image = mybitmap
    End Sub

    Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
        For y As Integer = 0 To mybitmap.Height - 1
            For x As Integer = 0 To mybitmap.Width - 1
                Dim red, green, blue As Integer
                red = mybitmap.GetPixel(x, y).R.ToString
                green = mybitmap.GetPixel(x, y).G.ToString
                blue = mybitmap.GetPixel(x, y).B.ToString
                If red > green And red > blue Then
                    red = 255
                    blue = 0
                    green = 0
                ElseIf green > blue And green > red Then
                    green = 255
                    red = 0
                    blue = 0
                ElseIf blue > red And blue > green Then
                    blue = 255
                    red = 0
                    green = 0
                Else
                    blue = 0
                    red = 0
                    green = 0
                End If

                mybitmap.SetPixel(x, y, Color.FromArgb(red, green, blue))
                sync()
                Dim per As Integer
                per = (y / mybitmap.Height) * 100
                Me.Text = per & "% Complete"
            Next
        Next
    End Sub
End Class

***How can I speed it up to be finished basically instantly...

***Also the form freezes and is unusable while the operation is in process... is there a way to allow the form to still be used such as moved around while its working?

***Lastly... how come I only see the result at the end and not see it slowly converting the picture... since I am using the sync method (my own) to constantly update the bitmap throughout the whole process... but it only shows the result at the end
 
Last edited:
Just a general note about this part:
red = mybitmap.GetPixel(x, y).R.ToString
green = mybitmap.GetPixel(x, y).G.ToString
blue = mybitmap.GetPixel(x, y).B.ToString
Knowing that Bitmap.GetPixel method is rather slow, why call it three times more than you have to? GetPixel returns a Color value, once you have that value use it to get each RGB component, and not call GetPixel again only to get exactly the same Color value. This is a general principle in programming you should keep in mind. There is also similar redunancy in your code to set color, thought it doesn't have that much impact on performance.
 
Thank You... It worked!!!


Here is my new code to show others how I did it...

VB.NET:
 Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
        Dim rect As New Rectangle(0, 0, mybitmap.Width, mybitmap.Height)
        Dim bmpData As System.Drawing.Imaging.BitmapData = mybitmap.LockBits(rect, Drawing.Imaging.ImageLockMode.ReadWrite, mybitmap.PixelFormat)
        Dim ptr As IntPtr = bmpData.Scan0
        Dim bytes As Integer = Math.Abs(bmpData.Stride) * mybitmap.Height
        Dim rgbValues(bytes - 1) As Byte
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes)
        For counter As Integer = 0 To rgbValues.Length - 1 Step 3
            Dim red, green, blue As Integer
            red = rgbValues(counter)
            green = rgbValues(counter + 1)
            blue = rgbValues(counter + 2)
            If red > green And red > blue Then
                rgbValues(counter) = 255
                rgbValues(counter + 1) = 0
                rgbValues(counter + 2) = 0
            ElseIf green > blue And green > red Then
                rgbValues(counter) = 0
                rgbValues(counter + 1) = 255
                rgbValues(counter + 2) = 0
            ElseIf blue > red And blue > green Then
                rgbValues(counter) = 0
                rgbValues(counter + 1) = 0
                rgbValues(counter + 2) = 255
            Else
                rgbValues(counter) = 0
                rgbValues(counter + 1) = 0
                rgbValues(counter + 2) = 0
            End If
        Next
        System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes)
        mybitmap.UnlockBits(bmpData)
        PictureBox1.Image = mybitmap
    End Sub
 
That code will only be correct if pixel format is Format24BppRgb and the image Width*3 is a multiple of 4, ie when there is no Stride padding. Check back on the article on second link to learn what Stride means and 'Finding the right byte'.
 
Use a Color matrix its a lot quicker here i post a class i wrote for editing photos. it still has issues, mainly i cant stack mulitple effects but if you feel up to it you can try to get around maybe create a new bitmap from a screen shot of the modifed one then add another effect to it.

VB.NET:
[SIZE=2]Imports System.Drawing.Imaging
Public Class BMF
    Public Shared IA As New ImageAttributes
    'Done
    Public Shared Sub AdjustBrightness(ByVal Brightness As Single)
        ' Brightness should be -1 (black) to 0 (neutral) to 1 (white) 
        Dim colorMatrixVal As Single()()
           New Single() {1, 0, 0, 0, 0}, _
           New Single() {0, 1, 0, 0, 0}, _
           New Single() {0, 0, 1, 0, 0}, _
           New Single() {0, 0, 0, 1, 0}, _
           New Single() {Brightness, Brightness, Brightness, 0, 1}}
        Dim colorMatrix As New ColorMatrix(colorMatrixVal)
        IA.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
    End Sub
    Public Shared Sub Negative(ByVal D As Single)
        Dim colorMatrixVal As Single()() = { _
                          New Single() {D, 0, 0, 0, 0}, _
                          New Single() {0, D, 0, 0, 0}, _
                          New Single() {0, 0, D, 0, 0}, _
                          New Single() {0, 0, 0, 1, 0}, _
                          New Single() {0, 0, 0, 0, 1}}
        Dim colorMatrix As New ColorMatrix(colorMatrixVal)
        IA.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
    End Sub
    Public Shared Sub adjustGamma(ByVal Gamma As Single)
        IA.SetGamma(Gamma)
    End Sub
    Public Shared Sub AdjustTempature(ByVal Red As Single, ByVal Green As Single, ByVal Blue As Single)
        Dim colorMatrixVal As Single()() = { _
                  New Single() {1, 0, 0, 0, 0}, _
                  New Single() {0, 1, 0, 0, 0}, _
                  New Single() {0, 0, 1, 0, 0}, _
                  New Single() {0, 0, 0, 1, 0}, _
                  New Single() {Red, Green, blue, 0, 1}}
        Dim colorMatrix As New ColorMatrix(colorMatrixVal)
        IA.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
 
    End Sub
 
    'Incomplete
  
    Public Shared Sub AdjustSaturation()
 
    End Sub
   
    Public Shared Sub Rotate_Play1(ByVal Degree As Single)
        Degree = Degree * (Math.PI / 180)
        Dim colorMatrixVal As Single()() = { _
                     New Single() {-Math.Cos(Degree), Math.Sin(Degree), -Math.Sin(Degree), 0, 0}, _
                     New Single() {-Math.Sin(Degree), Math.Cos(Degree), Math.Sin(Degree), 0, 0}, _
                     New Single() {Math.Sin(Degree), -Math.Sin(Degree), Math.Cos(Degree), 0, 0}, _
                     New Single() {0, 0, 0, 1, 0}, _
                     New Single() {0, 0, 0, 0, 1}}
        Dim colorMatrix As New ColorMatrix(colorMatrixVal)
        IA.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
 
    End Sub
    Public Shared Sub rotate_Colors(ByVal Degree As Single)
        Degree = Degree * (Math.PI / 180)
        Dim colorMatrixVal As Single()() = { _
                     New Single() {Math.Cos(Degree), Math.Sin(Degree), -Math.Sin(Degree), 0, 0}, _
                     New Single() {-Math.Sin(Degree), Math.Cos(Degree), Math.Sin(Degree), 0, 0}, _
                     New Single() {Math.Sin(Degree), -Math.Sin(Degree), Math.Cos(Degree), 0, 0}, _
                     New Single() {0, 0, 0, 1, 0}, _
                     New Single() {0, 0, 0, 0, 1}}
        Dim colorMatrix As New ColorMatrix(colorMatrixVal)
        IA.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
 
    End Sub
    Public Shared Sub Rotate_blue(ByVal Degree As Single)
        Degree = Degree * (Math.PI / 180)
        Dim colorMatrixVal As Single()() = { _
                     New Single() {Math.Cos(Degree), 0, -Math.Sin(Degree), 0, 0}, _
                     New Single() {0, 1, 0, 0, 0}, _
                     New Single() {Math.Sin(Degree), 0, Math.Cos(Degree), 0, 0}, _
                     New Single() {0, 0, 0, 1, 0}, _
                     New Single() {0, 0, 0, 0, 1}}
        Dim colorMatrix As New ColorMatrix(colorMatrixVal)
        IA.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
 
    End Sub
    Public Shared Sub Rotate_Green(ByVal Degree As Single)
        Degree = Degree * (Math.PI / 180)
        Dim colorMatrixVal As Single()() = { _
                     New Single() {1, 0, 0, 0, 0}, _
                     New Single() {0, Math.Cos(Degree), Math.Sin(Degree), 0, 0}, _
                     New Single() {0, -Math.Sin(Degree), Math.Cos(Degree), 0, 0}, _
                     New Single() {0, 0, 0, 1, 0}, _
                     New Single() {0, 0, 0, 0, 1}}
        Dim colorMatrix As New ColorMatrix(colorMatrixVal)
        IA.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
 
    End Sub
    Public Shared Sub Rotate_red(ByVal degree As Single)
        degree = degree * (Math.PI / 180)
        Dim colorMatrixVal As Single()() = { _
                     New Single() {Math.Cos(degree), Math.Sin(degree), 0, 0, 0}, _
                     New Single() {-Math.Sin(degree), Math.Cos(degree), 0, 0, 0}, _
                     New Single() {0, 0, 1, 0, 0}, _
                     New Single() {0, 0, 0, 1, 0}, _
                     New Single() {0, 0, 0, 0, 1}}
        Dim colorMatrix As New ColorMatrix(colorMatrixVal)
        IA.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
    End Sub
    Public Shared Sub Scale_Colors(ByVal Red As Single, ByVal Green As Single, ByVal Blue As Single)
        Dim colorMatrixVal As Single()() = { _
                New Single() {Red, 0, 0, 0, 0}, _
                New Single() {0, Green, 0, 0, 0}, _
                New Single() {0, 0, Blue, 0, 0}, _
                New Single() {0, 0, 0, 1, 0}, _
                New Single() {0, 0, 0, 0, 1}}
        Dim colorMatrix As New ColorMatrix(colorMatrixVal)
        IA.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
    End Sub
End Class


some code showing how to draw the bitmap 
[SIZE=2]PictureBox1.CreateGraphics.DrawImage(your picture, PictureBox1.DisplayRectangle, 0, 0, G.Width, G.Height, GraphicsUnit.Pixel, BMF.IA)
[/SIZE]
[/SIZE]
 
Back
Top