2012-12-17 2 views
3

아래 코드를 사용하여 이미지에서 RGB 값을 추출합니다. 그러나 특정 파일 (비트 맵의 ​​너비로 나눌 수없는 것)에서이 코드가 작동하는 경우가 있습니다. 혼합 값 반환 :.Net 비트 맵에서 Lockbits를 사용하여 RGB 값 가져 오기

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

또는 그 일부 변화가, 그들은 단지해야 할 때 : 결과 색상을 그룹화 한 후

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() 

를, 값이 뭔가처럼

R G B 
255 255 255 
0 0 0 

올바른 방향으로 저를 지적하십시오. BTW 내 소스 bmp도 PixelFormat.Format24bppRgb에 있습니다. 그래서 문제가 있다고 생각하지 않습니다. 또한 문제가되지 않는 C#로만 대답 할 수 있다면.

답변

5

문제는 스트라이드 값을 고려하고 있지 않다는 것입니다. 보폭은 항상 패딩되어있어 이미지 행당 바이트 배열의 너비가 4로 나눌 수 있습니다. 이것은 메모리 복사 및 CPU 작동 방식과 관련된 최적화이며 수십 년 후에도 여전히 유용합니다. 그것과 같을 것이다 14 픽셀의 이미지

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

: 하나 개의 이미지는 13 개 픽셀 폭을 갖는 경우

F.ex는 스트라이드는 (하나 개의 컴포넌트로 간략화)과 같이 될 것이다 :

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

그래서 코드에서 당신은 당신이 고정 이미지의 폭을 정의 사용하지 않는 경우, 바이트 배열 대신 보폭 행을 처리해야합니다.

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() 
+0

덕분에 그 비틀기가 트릭을 할 것으로 보인다 : 그것은 보폭으로 행을 건너 뛰고 있도록

나는 코드를 수정했습니다. 하나의 작은 질문이지만, 나는 당신이 BGR의 배열에서 값을 읽고 있다는 것을 알아 차리고, 나는 이것에 대해 상충되는 의견을 보았습니다. 어떤 사람들은 그것이 분명히 RGB라고 말합니다. 확인하십시오. – Azza

+0

이 경우 BGR이 정확합니다. 리틀 엔디안/빅 엔디안/바이트 순서 및 포인터와 정수 사이의 캐스팅과 관련된 Intel/Win 플랫폼의 특질. – K3N