PictureBox image pixels

Megalith

Well-known member
Joined
Aug 21, 2006
Messages
66
Programming Experience
10+
I am trying to copy the contents of a picture box into a bitmap for further manipulation but i have encoutered a problem, what the sample code below does is to copy the original image into a bitmap, wheres i want to copy only the contents of the controls imagespace into the bitmap i wrote a method using this code and extracts color information from each pixel, the procedure was great using a 16 color tiled bmp image but on a 640*480 24bit color bmp file it took 20 minutes before i exited the program. heres my sample :-

VB.NET:
   Public Structure ColourMap
        Public colour As Color
        Public count As Integer
    End Structure

public sub TestPixels()
        Dim colors As New Collection()
        Dim map, tMap As ColourMap
        Dim instance As Bitmap = CType(PictureBox1.Image, Bitmap)
        Dim x, y As Integer
        Dim yes As Boolean
        Dim test As Color
        map.count = 1 : map.colour = Color.White
        ProgressBar1.Maximum = instance.Size.Width - 1
        For x = 0 To instance.Size.Width - 1
            ProgressBar1.Value = x
            My.Application.DoEvents()
            For y = 0 To instance.Size.Height - 1
                test = instance.GetPixel(x, y)
                map.Colour = test
                map.Count = 1
                yes = False
                ' we now have our map so we need to search the collection for it
                ' if it exists we add 1 to the count value and return it to the collection
                ' if not we add it to the collection
                If colors.Count > 0 Then
                    For index As Integer = 1 To colors.Count
                        tMap = CType(colors(index), ColourMap)
                        If tMap.Colour = map.Colour Then
                            tMap.Count += map.Count
                            colors.Remove(index)
                            colors.Add(tMap)
                            yes = True
                        End If
                    Next
                    If yes = False Then
                        colors.Add(map)
                    End If
                Else
                    colors.Add(map)
                End If

            Next
        Next
end sub
is there a way to obtain the actual pixels for the image on screen without having to resort to API?
 
Every time a call is made to GetPixel on a bitmap the bitmap is locked in memory and then the processing is done and then the memory is released. This makes things very slow. Here's a link to a thread where JohnH wrote some very efficient code to traverse a bitmaps pixels. It makes use of the bitmapdata object, and the LockBits method of the bitmap which means that the bitmap stays locked in memory untill you are finished with it, this makes things much faster but in turn it is qiute a bit more complex. Check it out....

http://www.vbdotnetforums.com/showthread.php?t=14691
 
thanks very much thats helped A LOT :) i had read somewhere that getpixel should be avoided at all costs and your explanation of what getpixel actually does makes sense as to why, i can however see places where it would be useful now which is great for my own development too.
 
I reviewed my color count method from above and rewrote it as the routine slowed down exponentially the more colors where in the image. in essence what i did was to create an array colorgrid(255,255,255) each color as it was scanned was added to the the grid incrementing its contents and after the data was processed i filled my collection by scanning the colorgrid array and adding any cell with a positive value this made a negligable change with limited color images but a huge increase with true color images, my initial method took 20 minutes i gave up, the change to bitmapdata incresed it to 5 minutes with the result my latest change took just about 3 seconds, and that includes some lengthy processing on the collection once i have it.
 
the BitMapData routine uses the entire image, as did my initial suggestion. I am now working on an 'eyedropper' and need to read the color of the pixel actually in the box, how can this be done?
 
like you did first, with GetPixel.
 
If i have the sizemode set to stretch image so that the entire image appears on the picturebox then using get pixel is taking the pixels as though it was displaying at 1:1 and reads from top left so it isnt reading the actual pixel on the screen but from the bitmap of the image.
 
For curiosity, there is a managed way to do it also; get the image and draw it to bitmap streched to same client size as the picturebox, then use Bitmap.GetPixel:
VB.NET:
Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles PictureBox1.MouseDown
    Dim pb As PictureBox = DirectCast(sender, PictureBox)
    Dim bmp As New Bitmap(pb.ClientSize.Width, pb.ClientSize.Height)
    Dim g As Graphics = Graphics.FromImage(bmp)
    g.Clear(pb.BackColor)
    g.DrawImage(pb.Image, bmp.GetBounds(GraphicsUnit.Pixel))
    g.Dispose()
    Dim col As Color = bmp.GetPixel(e.X, e.Y)
 
End Sub
It's even 2 lines of code shorter than the Win32 version :) You also don't have to do this processing every time there is a mousedown, only when image changes or picturebox size changes.
 
Back
Top