Click here to Skip to main content
15,887,746 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
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

VB
'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

VB
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
Updated 13-Jul-12 20:20pm
v2

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...

VB
'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.

VB
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
 
Share this answer
 
v5
Comments
thams 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 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 18-Jul-12 3:31am    
No boss.
Still struggling with the same issue.
Thanks for your pity
Trak4Net 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.
Ok this is fully functioning and tested by outputting stored pixels back out and verified image is correct.


VB
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
 
Share this answer
 
v2
Comments
Trak4Net 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 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)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900