我有一个函数可以将普通图像转换为 RGB 字节数组。然后我编写了一个函数来将这个字节数组转回正常图像。不幸的是,颜色分量发生了偏移,即 {R=0, G=94, B=255}(蓝色)变成了 {R=255, G=94, B=0}(橙色),依此类推。 我尝试了几个答案,包括this一个和this一个。我什至尝试更换组件,但这也不起作用。我做错了什么?
编辑:
我还尝试交换颜色组件作为试验,希望它能纠正颜色问题。
这些代码行是一个测试项目。我想稍后在其他地方实现
RGB_Byte_Array_To_Image
函数。
Public Class FormMain
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim filePath As String = "C:\Users\...\Pictures\Testbild mit Gimp erstellen\Test, nicht optimiert, nicht progressiv 2.jpg"
Dim rgbByteArray As Byte() = RGB_Byte_Array_From_Image(filePath)
Dim width As Integer
Dim height As Integer
Dim pixelformat As Imaging.PixelFormat
Using image As New Bitmap(filePath)
width = image.Width
height = image.Height
pixelformat = image.PixelFormat
End Using
Using normal_Image As System.Drawing.Bitmap = RGB_Byte_Array_To_Image(rgbByteArray, width, height, pixelformat)
normal_Image.Save("C:\Users\...\Desktop\Test.png", Imaging.ImageFormat.Png)
End Using
End Sub
Private Shared Function RGB_Byte_Array_To_Image(rgbByteArray() As Byte, width As Integer, height As Integer, pixelformat As Imaging.PixelFormat) As Bitmap
Dim b As New Bitmap(width, height, pixelformat)
Dim BoundsRect As New Rectangle(0, 0, width, height)
Dim bmpData As Imaging.BitmapData = b.LockBits(BoundsRect, Imaging.ImageLockMode.WriteOnly, pixelformat)
Dim bytesPerPixel As Integer = Image.GetPixelFormatSize(pixelformat) \ 8
Dim stride As Integer = bmpData.Stride
Dim scan0 As IntPtr = bmpData.Scan0
For y As Integer = 0 To height - 1
Dim rowOffset As Integer = y * stride
Dim sourceOffset As Integer = y * width * bytesPerPixel
For x As Integer = 0 To width - 1
Dim pixelOffset As Integer = x * bytesPerPixel
' Reverse the order of color components (BGR instead of RGB)
Dim blue As Byte = rgbByteArray(sourceOffset + pixelOffset)
Dim green As Byte = rgbByteArray(sourceOffset + pixelOffset + 1)
Dim red As Byte = rgbByteArray(sourceOffset + pixelOffset + 2)
Runtime.InteropServices.Marshal.WriteByte(scan0, rowOffset + pixelOffset, blue)
Runtime.InteropServices.Marshal.WriteByte(scan0, rowOffset + pixelOffset + 1, green)
Runtime.InteropServices.Marshal.WriteByte(scan0, rowOffset + pixelOffset + 2, red)
Next
Next
b.UnlockBits(bmpData)
Return b
End Function
Private Function RGB_Byte_Array_From_Image(filePath As String) As Byte()
Dim imageBytes As Byte()
Using image As New Bitmap(filePath)
imageBytes = (New Byte(image.Width * image.Height * 3 - 1) {})
For y As Integer = 0 To image.Height - 1
For x As Integer = 0 To image.Width - 1
Dim pixelColor As Color = image.GetPixel(x, y)
Dim pixelIndex As Integer = (y * image.Width + x) * 3
imageBytes(pixelIndex) = pixelColor.R
imageBytes(pixelIndex + 1) = pixelColor.G
imageBytes(pixelIndex + 2) = pixelColor.B
Next
Next
End Using
Return imageBytes
End Function
End Class
如果您尝试将图像保存为字节数组...
'image to bytes
Dim img As Image = Image.FromFile(pathOfImg)
Dim ms As New IO.MemoryStream
img.Save(ms, Drawing.Imaging.ImageFormat.Jpeg)
Dim imageData() As Byte = ms.GetBuffer()
'image from bytes
Using RDms As New IO.MemoryStream(imageData, 0, imageData.Length)
RDms.Write(imageData, 0, imageData.Length)
PictureBox1.Image = Image.FromStream(ms, True)
End Using
在我的解决方案中,我现在有一个字节数组,它表示 BGR(蓝-绿-红)顺序的颜色分量。这很重要,因为
LockBits
方法期望在使用某些像素格式时按 BGR 顺序排列像素数据。
Private Shared Function BGR_Byte_Array_To_Image(rgbByteArray As Byte(),
width As Integer,
height As Integer,
pixelformat As Imaging.PixelFormat) As Bitmap
' ‘LockBits’ expects the color components to be in the order BGR
Dim b As New Bitmap(width, height, pixelformat)
Dim bitmapData As Imaging.BitmapData = b.LockBits(New Rectangle(0, 0, width, height),
Imaging.ImageLockMode.ReadOnly,
pixelformat)
Dim bytes_per_Pixel As Integer = Image.GetPixelFormatSize(b.PixelFormat) \ 8
Dim stride As Integer = CInt(Math.Floor(
(bytes_per_Pixel * 8.0 * width + 31.0) / 32.0
) * 4.0
)
Runtime.InteropServices.Marshal.Copy(rgbByteArray, 0, bitmapData.Scan0, stride * height)
b.UnlockBits(bitmapData)
Return b
End Function
这样称呼吧
Using normal_Image As System.Drawing.Bitmap = BGR_Byte_Array_To_Image(rgbByteArray, width, height, pixelformat)
normal_Image.Save("C:\Users\...\Desktop\Test.png", Imaging.ImageFormat.Png)
End Using
@Daniel 提供的解决方案似乎有一个错误。
根据输入图像的宽度,位图的每个扫描线需要填充最多 3 个额外字节。 提供的代码仅在 (bytes_per_Pixel * width) Mod 4 = 0
时才起作用解决办法是逐行复制bitmapData:
Private Shared Function BGR_Byte_Array_To_Image(bgrByteArray As Byte(),
width As Integer,
height As Integer,
pixelformat As Imaging.PixelFormat) As Bitmap
' ‘LockBits’ expects the color components to be in the order BGR
Dim b As New Bitmap(width, height, pixelformat)
Dim bitmapData As Imaging.BitmapData = b.LockBits(New Rectangle(0, 0, width, height),
Imaging.ImageLockMode.ReadOnly,
pixelformat)
Dim array_bytes_per_row As Integer = width * Image.GetPixelFormatSize(b.PixelFormat) \ 8
Dim ptr As IntPtr = bitmapData.Scan0
For i As Integer = 0 To height - 1
Runtime.InteropServices.Marshal.Copy(bgrByteArray, i * array_bytes_per_row, ptr, array_bytes_per_row)
ptr += bitmapData.Stride
Next
b.UnlockBits(bitmapData)
Return b
End Function