【问题标题】:For each pixel in a image, get the color, pixel position, and coordinates relatively to the image对于图像中的每个像素,获取颜色、像素位置和相对于图像的坐标
【发布时间】:2016-02-09 01:52:41
【问题描述】:

场景

我正在尝试编写一个函数,该函数将使用以下结构 PixelInfo 来返回源图像中每个像素的位置集合,将存储 Color、像素位置和 @987654323 @ 相对于图像的坐标位置:

<Serializable>
<StructLayout(LayoutKind.Sequential)>
Public Structure PixelInfo

    Public ReadOnly Property Color As Color
        Get
            Return Me.colorB
        End Get
    End Property
    Private ReadOnly colorB As Color

    Public ReadOnly Property Position As Integer
        Get
            Return Me.positionB
        End Get
    End Property
    Private ReadOnly positionB As Integer

    Public ReadOnly Property Location As Point
        Get
            Return Me.locationB
        End Get
    End Property
    Private ReadOnly locationB As Point

    <DebuggerStepThrough>
    Public Sub New(ByVal color As Color,
                   ByVal position As Integer,
                   ByVal location As Point)

        Me.colorB = color
        Me.positionB = position
        Me.locationB = location

    End Sub

End Structure

这是函数:

<DebuggerStepThrough>
<Extension>
Iterator Function GetPixelInfo(ByVal sender As Image) As IEnumerable(Of PixelInfo)

    Dim bytesPerPixel As Integer = (Image.GetPixelFormatSize(sender.PixelFormat) \ 8)

    If (bytesPerPixel <> 3) AndAlso (bytesPerPixel <> 4) Then
        Throw New NotImplementedException(
        message:="Only PixelFormats that has 3 or 4 bytes-per-pixel are supported.")

    Else
        ' Lock the bitmap's bits.
        Dim bmp As Bitmap = DirectCast(sender, Bitmap)
        Dim rect As New Rectangle(0, 0, bmp.Width, bmp.Height)
        Dim bmpData As BitmapData = bmp.LockBits(rect, ImageLockMode.ReadWrite,
                                                 bmp.PixelFormat)

        ' Get the address of the first line.
        Dim ptr As IntPtr = bmpData.Scan0

        ' Declare an array to hold the bytes of the bitmap. 
        Dim numBytes As Integer = (Math.Abs(bmpData.Stride) * rect.Height)
        Dim rgbData(numBytes - 1) As Byte

        ' Copy the RGB values into the array.
        Marshal.Copy(ptr, rgbData, 0, numBytes)

        ' Unlock the bits.
        bmp.UnlockBits(bmpData)

        ' Iterate the pixels.
        For i As Integer = 0 To (rgbData.Length - bytesPerPixel) Step bytesPerPixel

            Dim color As Color = color.FromArgb(red:=rgbData(i + 2),
                                                green:=rgbData(i + 1),
                                                blue:=rgbData(i))

            Dim position As Integer = (i \ bytesPerPixel)

            Dim location As Point =
                New Point(X:=(position Mod rect.Width),
                          Y:=(position - (position Mod rect.Width)) \ rect.Width)

            Yield New PixelInfo(color, position, location)

        Next i

    End If

End Function

问题

我已经对像素格式为PixelFormat.Format32bppRgbPixelFormat.Format32bppArgb 的图像进行了测试,它似乎可以按预期工作。

我遇到的问题是,如果我使用像素格式为PixelFormat.Format24bppRgb 的图像,一切都会出错,我得到的Color 与真实颜色不对应,而且我得到的像素也比图像多。


问题

我的计算在哪里失败?,以及如何修复函数以使用 PixelFormat.Format24bppRgb 图像?。


演示

通过下面的使用示例,我创建了一个PixelFormat.Format24bppRgb格式的2x2大小(4像素)的位图,我用指定的纯色填充位图,然后我使用我的函数来测试结果。

Dim color As Color = color.FromArgb(255, 117, 228, 26)
Dim bmp As Bitmap =
    ImageUtil.CreateSolidcolorBitmap(New Size(2, 2), color, PixelFormat.Format24bppRgb)

Dim pxInfoCol As IEnumerable(Of PixelInfo) = bmp.GetPixelInfo()

For Each pxInfo As PixelInfo In pxInfoCol

    Console.WriteLine(String.Format("Position: {0}, Location: {1}, Color: {2}",
                      pxInfo.Position, pxInfo.Location, pxInfo.Color.ToString))

Next

这是执行的意外结果:

Position: 0, Location: {X=0,Y=0}, Color: Color [A=255, R=117, G=228, B=26]
Position: 1, Location: {X=1,Y=0}, Color: Color [A=255, R=117, G=228, B=26]
Position: 2, Location: {X=0,Y=1}, Color: Color [A=255, R=26, G=0, B=0]
Position: 3, Location: {X=1,Y=1}, Color: Color [A=255, R=26, G=117, B=228]
Position: 4, Location: {X=0,Y=2}, Color: Color [A=255, R=0, G=117, B=228]

有 5 个元素(对于 5 个像素,当图像只有 4 个像素时),元素 2、3 和 4 的颜色不同。

我做错了。

【问题讨论】:

    标签: .net vb.net colors bitmap gdi+


    【解决方案1】:

    我建议你在维基百科上研究BMP file format 文章,尤其是Pixel storage 部分。

    像素格式由 DIB 标头或额外位掩码定义。 Pixel 数组中的每一行在大小上填充为 4 个字节的倍数

    所以 2x2 24bppRgb 位图的每一行中的字节如下所示。如您所见,每行末尾都有两个“填充字节”。

    B G R B G R P P B G R B G R P P
    

    在 4x2 24bppRgb 位图中不会有填充,因为每行中的字节正好是 3 个 DWORD。

    B G R B G R B G R B G R B G R B G R B G R B G R
    

    【讨论】:

      【解决方案2】:

      在位图中的行之间移动时,您需要考虑 BitmapData.Stride 属性。在 32bpp 时,Stride 将始终等于 Width*4,这就是您的代码正常工作的原因,但在 24bpp 中并非总是如此。

      【讨论】:

        猜你喜欢
        • 2018-08-15
        • 1970-01-01
        • 2019-09-18
        • 2014-04-18
        • 2019-07-27
        • 1970-01-01
        • 2023-04-05
        • 2013-07-21
        • 1970-01-01
        相关资源
        最近更新 更多