.NET使用Lockbits位图获得RGB值 [英] .Net getting RGB values from a bitmap using Lockbits

查看:588
本文介绍了.NET使用Lockbits位图获得RGB值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是低于code,以从图像中提取RGB值,有时这个工程,但对某些文件(貌似那里的步幅是不是整除的位图的宽度),它返回混合起来的值:

I am using the below code to extract RGB values from images, sometimes this works, however on certain files (seemingly where the Stride is not divisible by the width of the bitmap) it is returning mixed up values:

Dim rect As New Rectangle(0, 0, bmp.Width, bmp.Height)
Dim bmpData As System.Drawing.Imaging.BitmapData = bmp.LockBits(rect, Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
Dim ptr As IntPtr = bmpData.Scan0
Dim cols As New List(Of Color)
Dim bytes As Integer = Math.Abs(bmpData.Stride) * bmp.Height
Dim rgbValues(bytes - 1) As Byte
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes)

' Retrieve RGB values
For i = modByte To rgbValues.Length Step 3
     cols.Add(Color.FromArgb(rgbValues(i + 2), rgbValues(i + 1), rgbValues(i)))
Next

bmp.UnlockBits(bmpData)
bmp.Dispose()
Dim colsCnt As List(Of RgbPixels) = cols.GroupBy(Function(g) New With {Key .R = g.R, Key .G = g.G, Key .B = g.B}).Select(Function(s) New RgbPixels With {.Colour = Color.FromArgb(s.Key.R, s.Key.G, s.Key.B), .Amount = s.Count()}).ToList()

分组所得的颜色后,将值是这样的:

After grouping the resulting colours, the values are something like:

R    G    B
255  255  255
255  255  0
255  0    0
0    0    255
0    255  255

或者是其它的变化,当他们应该仅仅是:

Or some variation of that, when they should just be:

R    G    B
255  255  255
0    0    0

请点我在正确的方向,我BTW源BMP是PixelFormat.Format24bppRgb了,所以我不相信这就是问题所在。此外,如果你可以在C#中唯一的回答是没有问题的。

Please point me in the right direction, BTW my source bmp is in PixelFormat.Format24bppRgb too, so I don't believe that is the problem. Also if you can only answer in C# that is not a problem.

推荐答案

的问题是,你不考虑步幅值。步幅始终填充,使得每幅图像的行的字节阵列的宽度是由4整除这是关系到存储器拷贝和CPU如何工作的优化,即去几十年来,回到仍然是有用的。

The problem is that you're not considering the stride value. Stride is always padded so that the width of the byte-array per image row is dividable by 4. This is an optimization related to memory copy and how the CPU works, that goes decades back and still is useful.

F.ex,如果一个图像有13个像素宽,步幅会是这样(简化为一个组件):

F.ex, if one image has a width of 13 pixels, the stride would be like this (simplified to one component):

=============    (width 13 pixels = 13 bytes when using RGB)
================ (stride would be 16)

为14像素的图像,将是这样的:

for an image of 14 pixels it would look like this:

==============   (width 14 pixels = 14 bytes when using RGB)
================ (stride would still be 16)

因此​​,在您code,你需要处理,而不是一个字节数组一个箭步行,除非你使用的是固定的,确定图像的宽度。

So in your code you need to handle a stride row instead of a byte array, unless you are using fixed and defined widths of the images.

我修改您的code,因此通过大步跳过行:

I modified your code so it skips rows by stride:

Dim rect As New Rectangle(0, 0, bmp.Width, bmp.Height)
Dim bmpData As System.Drawing.Imaging.BitmapData = bmp.LockBits(rect, Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
Dim ptr As IntPtr = bmpData.Scan0
Dim cols As New List(Of Color)
Dim bytes As Integer = Math.Abs(bmpData.Stride) * bmp.Height
Dim rgbValues(bytes - 1) As Byte
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes)

Dim x, y, dx, l as Integer

For y = 0 To rect.Height - 1

    l = y * bmpData.Stride 'calulate line based on stride

    For x = 0 To rect.Width - 1

        dx = l + x * 3  '3 for RGB, 4 for ARGB, notice l is used as offset

        cols.Add(Color.FromArgb(rgbValues(dx + 2), _
                                rgbValues(dx + 1), _
                                rgbValues(dx)))
    Next
Next

' Retrieve RGB values
'For i = modByte To rgbValues.Length Step 3
'     cols.Add(Color.FromArgb(rgbValues(i + 2), rgbValues(i + 1), rgbValues(i)))
'Next

bmp.UnlockBits(bmpData)
bmp.Dispose()

这篇关于.NET使用Lockbits位图获得RGB值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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