Azz*_*zza 3 c# vb.net rgb bitmap lockbits
我使用下面的代码从图像中提取RGB值,有时这是有效的,但是在某些文件上(看似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)
' 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()
Run Code Online (Sandbox Code Playgroud)
对结果颜色进行分组后,值类似于:
R G B
255 255 255
255 255 0
255 0 0
0 0 255
0 255 255
Run Code Online (Sandbox Code Playgroud)
或者它的一些变化,当他们应该只是:
R G B
255 255 255
0 0 0
Run Code Online (Sandbox Code Playgroud)
请指出我正确的方向,BTW我的源bmp也在PixelFormat.Format24bppRgb中,所以我不相信这是问题所在.此外,如果您只能在C#中回答不是问题.
小智 5
问题是你没有考虑步幅值.Stride总是被填充,因此每个图像行的字节数组的宽度可以分为4.这是一个与内存复制和CPU工作方式相关的优化,几十年前仍然有用.
F.ex,如果一个图像的宽度为13个像素,那么步幅将是这样的(简化为一个组件):
============= (width 13 pixels = 13 bytes when using RGB)
================ (stride would be 16)
Run Code Online (Sandbox Code Playgroud)
对于14像素的图像,它看起来像这样:
============== (width 14 pixels = 14 bytes when using RGB)
================ (stride would still be 16)
Run Code Online (Sandbox Code Playgroud)
因此,在代码中,除非使用固定和定义的图像宽度,否则需要处理跨步行而不是字节数组.
我修改了你的代码,所以它通过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()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3091 次 |
| 最近记录: |