Click here to Skip to main content
11,640,910 members (60,644 online)
Rate this: bad
good
Please Sign up or sign in to vote.
See more: GDI+ VB.NET
Hi all,

I am using getpixel method to read the color values for some purpose.
To overcome the slowness with getpixel, I tried using lockbits method.
Now the code runs faster but the values I'm getting with both the methods are different.
This is the code with getpixel

'jImg is bitmap
Dim jc2(jImg.Height, jImg.Width) As Color
For i As Integer = 0 To jImg.Height - 1
    For j As Integer = 0 To jImg.Width - 1
      cl = jImg.GetPixel(j, i)
      jc2(i, j) = New Color(cl.A, cl.R, cl.G, cl.B)
    Next
Next

This is the code with lockbits

Dim bd As Drawing.Imaging.BitmapData
Dim bg As Byte, bb As Byte, br As Byte, ba As Byte
Dim st As Integer
bd = jImg.LockBits(New Drawing.Rectangle(0, 0, jImg.Width, jImg.Height), Drawing.Imaging.ImageLockMode.ReadOnly, jImg.PixelFormat)
 
For i As Integer = 0 To jImg.Height
   st = bd.Stride * i
   For j As Integer = 0 To jImg.Width
      ba = System.Runtime.InteropServices.Marshal.ReadByte(bd.Scan0, (st) + (j))
      bb = System.Runtime.InteropServices.Marshal.ReadByte(bd.Scan0, (st) + (j + 1))
      bg = System.Runtime.InteropServices.Marshal.ReadByte(bd.Scan0, (st) + (j + 2))
      br = System.Runtime.InteropServices.Marshal.ReadByte(bd.Scan0, (st) + (j + 3))
      jc2(i, j) = New Color(br, bg, bb, ba)
   Next
Next
jImg.UnlockBits(bd)

In both the cases the values I'm getting in jc2 is differnet.
The bitmap is 32bitPargb format.

What could be the reason?
Posted 13-Jul-12 20:19pm
thams1.3K
Edited 13-Jul-12 20:20pm
v2
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

I did something similar years ago. Here was a comment I left in my code, plus a bit of the code. Hope this is helpful...

'ok now its 1:20AM and I figured out that the reason they have to be applied in reverse is because that is the order (BGRA)

  Dim r, g, b As Integer
 
  b = sourceBuffer(sourceIndex) ' Blue (8 bits)
  g = sourceBuffer(sourceIndex + 1) ' Green (8 bits)
  r = sourceBuffer(sourceIndex + 2) ' Red (8 bits)

...
 
destinationBuffer(destinationIndex) = destinationB ' Blue (8 bits)
destinationBuffer(destinationIndex + 1) = destinationG ' Green
destinationBuffer(destinationIndex + 2) = destinationR ' Red
destinationBuffer(destinationIndex + 3) = destinationA ' Alpha


Edit:

Found this also in Bob Powell's FAQ's on lockbits..

Quote:
Format32BppArgb Given X and Y coordinates, the address of the first element in the pixel is Scan0+(y * stride)+(x*4). This Points to the blue byte. The following three bytes contain the green, red and alpha bytes


http://www.bobpowell.net/lockingbits.htm[^]


Good luck!

Edit: I have modified your code for how it should be. Hope this solves your issue.

Dim bd As Drawing.Imaging.BitmapData
Dim bg As Byte, bb As Byte, br As Byte, ba As Byte
Dim st As Integer
'create a buffer to hold the source data
Dim sourceBuffer(imageSize) As Byte
 
bd = jImg.LockBits(New Drawing.Rectangle(0, 0, jImg.Width, jImg.Height), Drawing.Imaging.ImageLockMode.ReadOnly, jImg.PixelFormat)
 
Dim imageSize As Integer = sourceData.Stride * sourceData.Height 'forgot to add this variable first edit

'copy the source image pixel data to the buffer
Marshal.Copy(bd.Scan0, sourceBuffer, 0, imageSize)
 
jImg.UnlockBits(bd)
 
For i As Integer = 0 To jImg.Height - 1 'added -1 so don't end up with index out of range

   st = bd.Stride * i 'get index for current row

   For j As Integer = 0 To jImg.Width - 1 'added -1 so don't end up with index out of range
      'Changed order to BGRA order
      bb = sourceBuffer(st)
      bg = sourceBuffer(st + 1)
      br = sourceBuffer(st + 2)
      ba = sourceBuffer(st + 3)
 
      jc2(i, j) = New Color(br, bg, bb, ba) 'not sure if you can do this... thinking it should be Color.FromARGB(a, r, g, b)

      st += 4 'increment for the 4 bytes we read

   Next
 
Next
 
  Permalink  
v5
Comments
thams at 16-Jul-12 5:03am
   
Thanks for your reply.
I've also gone through the same link.
In my case everything is fine except some 35% of piexls are not matching.

Through immediate window I've got the jc2 array
Values from both the methods are given below.
(3,10): {R:255 G:147 B:75 A:93} (3,10): {R:255 G:147 B:75 A:93}
(3,11): {R:111 G:47 B:26 A:32} (3,11): {R:111 G:107 B:59 A:73}
(3,12): {R:0 G:0 B:0 A:0} (3,12): {R:0 G:0 B:0 A:0}
(3,13): {R:37 G:8 B:3 A:4} (3,13): {R:37 G:8 B:3 A:4}
(4,0): {R:37 G:8 B:3 A:4} (4,0): {R:37 G:55 B:20 A:27}
(4,1): {R:248 G:82 B:14 A:31} (4,1): {R:248 G:84 B:14 A:31}
(4,2): {R:255 G:88 B:15 A:34} (4,2): {R:255 G:88 B:15 A:34}
(4,3): {R:255 G:98 B:30 A:50} (4,3): {R:255 G:98 B:30 A:50}
(4,4): {R:255 G:101 B:32 A:52} (4,4): {R:255 G:101 B:32 A:52}
See some values are matching some are not.
Its just pulling my hair.
Pls help.
Trak4Net at 17-Jul-12 14:42pm
   
thams, just curious if your issue is now resolved? I didn't get a chance to test this, I put that code together in notepad since I dind't have Visual Studio handy when I made the edit.
thams at 18-Jul-12 3:31am
   
No boss.
Still struggling with the same issue.
Thanks for your pity
Trak4Net at 18-Jul-12 4:26am
   
Ok, I will post a full working example shortly. I have already done similar in C# so will create a test app in VB and post soon, with proven results.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

Ok this is fully functioning and tested by outputting stored pixels back out and verified image is correct.


Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        ComparePixelReads()
    End Sub
 
    ''' <summary>
    ''' Compares the pixel reads.
    ''' </summary>
    Public Sub ComparePixelReads()
        Try
 

            Using sw As New System.IO.StreamWriter("D:\pixeltest\pixeloutput.txt", False)
 
                Dim tmp As System.Drawing.Bitmap = System.Drawing.Bitmap.FromFile("D:\pixeltest\ManagerPanel.bmp")
                Dim jImg As System.Drawing.Bitmap = ConvertToRGB(tmp)
 

                Dim jc2(jImg.Height, jImg.Width) As System.Drawing.Color
                Dim jc3(jImg.Height, jImg.Width) As System.Drawing.Color
 

                '//get pixel usage (very slow)
                For i As Integer = 0 To jImg.Height - 1
                    For j As Integer = 0 To jImg.Width - 1
                        Dim cl As System.Drawing.Color = jImg.GetPixel(j, i)
                        jc2(i, j) = cl
                    Next
                Next
 
                '//lock bits method (much faster)
                Dim bd As System.Drawing.Imaging.BitmapData = jImg.LockBits(New System.Drawing.Rectangle(0, 0, jImg.Width, jImg.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
 
                Dim sourceBuffer((bd.Stride * bd.Height)) As Byte
                '//copy intPtr to buffer
                System.Runtime.InteropServices.Marshal.Copy(bd.Scan0, sourceBuffer, 0, sourceBuffer.Length)
 
                '//unlock bits
                jImg.UnlockBits(bd)
 

                Dim st As Integer = 0
                Dim bb, bg, br, ba As Integer
 
                For i As Integer = 0 To jImg.Height - 1 '// 'added -1 so don't end up with index out of range

                    st = bd.Stride * i '//'get index for current row

                    For j As Integer = 0 To jImg.Width - 1 '// 'added -1 so don't end up with index out of range

                        '//'Changed order to BGRA order
                        bb = sourceBuffer(st)
                        bg = sourceBuffer(st + 1)
                        br = sourceBuffer(st + 2)
                        ba = sourceBuffer(st + 3)
 
                        jc3(i, j) = System.Drawing.Color.FromArgb(ba, br, bg, bb) '//'not sure if you can do this... thinking it should be Color.FromARGB(a, r, g, b)

                        st += 4 '//'increment for the 4 bytes we read

                    Next
 
                Next
 
                Dim outputCompare1 As New System.Drawing.Bitmap(jImg.Width, jImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
                Dim outputCompare2 As New System.Drawing.Bitmap(jImg.Width, jImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
 
                If (jc2.Length = jc3.Length) Then
 
                  For y As Integer = 0 To jImg.Height - 1
 
                        For x As Integer = 0 To jImg.Width - 1
                            'write new pixels from jc2
                            outputCompare1.SetPixel(x, y, jc2(y, x))
                            'write new pixels from jc3
                            outputCompare2.SetPixel(x, y, jc3(y, x))
 
                            sw.WriteLine(String.Format("PixelGet: {0}      LockBitsGet: {1}", "(" & y.ToString() & ", " & x.ToString() + ")" & jc2(y, x).ToArgb().ToString(), "(" & y.ToString() & ", " & x.ToString() & ")" & jc3(y, x).ToArgb().ToString()))
 
                        Next
 
                    Next
 
                End If
 
                outputCompare1.Save("D:\pixeltest\jc2.bmp")
                outputCompare2.Save("D:\pixeltest\jc3.bmp")
 
            End Using
 
        Catch ex As Exception
            MessageBox.Show(ex.Message & vbCrLf & ex.StackTrace)
        End Try
    End Sub
 

 
    ''' <summary>
    ''' Converts to Format32bppArgb.
    ''' </summary>
    ''' <param name="original">The original.</param>
    ''' <returns></returns>
    Public Function ConvertToRGB(ByVal original As Bitmap) As Bitmap
 
        If original.PixelFormat = Imaging.PixelFormat.Format32bppArgb Then Return original
 
        Dim newImage As Bitmap = New Bitmap(original.Width, original.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        newImage.SetResolution(original.HorizontalResolution, original.VerticalResolution)
 
        Dim g As Graphics = Graphics.FromImage(newImage)
        g.DrawImageUnscaled(original, 0, 0)
        g.Dispose()
 
        Return newImage
    End Function
  Permalink  
v2
Comments
Trak4Net at 18-Jul-12 5:09am
   
Just tested again with bitmap that has different height/width values and now is correct with my v2 correction of y, x variables.
thams at 11-Aug-12 9:07am
   
Thank u all.
Sorry 4 the delay. I went to some other project.
For this problem, I didnt find any solution. Yes, I accept your code works fine. But before that i've not specified that I'm doing this code in XNA.
Basically I'm using xna framework. Thats y this kind of color constructors. I've tested the code in XNA and found the same problem, ofcource it works fine in winforms. Anyway I gave it up and went with first method itself, even it is slow.
Thanks.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 Mika Wendelius 400
1 OriginalGriff 205
2 DamithSL 203
3 Afzaal Ahmad Zeeshan 169
4 CPallini 145
0 Mika Wendelius 380
1 OriginalGriff 205
2 DamithSL 203
3 CPallini 125
4 Afzaal Ahmad Zeeshan 89


Advertise | Privacy | Mobile
Web04 | 2.8.150731.1 | Last Updated 18 Jul 2012
Copyright © CodeProject, 1999-2015
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100