使用getpixel和lockbit获得不同的颜色值 [英] Getting different color values with getpixel and lockbits

查看:78
本文介绍了使用getpixel和lockbit获得不同的颜色值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我出于某种目的使用getpixel方法读取颜色值.
为了克服getpixel的缓慢性,我尝试使用lockbits方法.
现在,代码运行速度更快,但是我通过两种方法获得的值都不同.
这是带有getpixel
的代码

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)



在这两种情况下,我在jc2中获得的值都是不同的.
位图是32bitPargb格式.



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

What could be the reason?

推荐答案

我几年前做了类似的事情.这是我在代码中留下的注释,以及一些代码.希望这对您有帮助...

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





在鲍勃·鲍威尔(Bob Powell)关于锁定位的常见问题解答中也发现了这一点.





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

报价:

Format32BppArgb给定X和Y坐标,像素中第一个元素的地址为Scan0 +(y * stride)+(x * 4 ).这指向蓝色字节.以下三个字节包含绿色,红色和Alpha字节

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 [



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


Good luck!

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


好吧,这是完全正常的功能,并且可以通过将存储的像素倒出并验证图像正确来进行测试.


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


这篇关于使用getpixel和lockbit获得不同的颜色值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆