vb.net - 需要更快的方法来根据另一种颜色替换图像中的颜色

标签 vb.net image-processing colors image-manipulation

我正在寻找一种更快的方法来根据另一种颜色替换图像中的颜色。例如,我有一个大部分为黑色并带有灰色阴影的图像,我想根据红色对其重新着色。现在我将它传递到这个函数中,黑色作为我的基色,红色作为我的新颜色。然后我逐个像素地确定其 RGB 并重新计算新的红色阴影。因此纯黑色会变成纯红色,灰色会变成浅红色,依此类推。

有没有更快的方法来做到这一点?可能使用单独的图像处理库?我研究了 ImageMagick,但找不到我正在寻找的确切功能。

这是我当前的功能。它可以工作,但速度很慢。

Public Function doRecolorImage(ByRef inBMP As Bitmap, ByVal baseColor As Color, ByVal newColor As Color) As Bitmap
        Dim newimg As New Bitmap(inBMP.Width, inBMP.Height)

            Using gIcons As Graphics = Graphics.FromImage(newimg)
                For x = 0 To inBMP.Width - 1
                    For y = 0 To inBMP.Height - 1
                        Dim ltrans As Byte = inBMP.GetPixel(x, y).A
                        Dim lR As Byte = inBMP.GetPixel(x, y).R
                        Dim lG As Byte = inBMP.GetPixel(x, y).G
                        Dim lB As Byte = inBMP.GetPixel(x, y).B

                        Dim newpixR As Integer = CInt(newColor.R) + (CInt(lR) - CInt(baseColor.R))

                        Dim newpixG As Integer = CInt(newColor.G) + (CInt(lG) - CInt(baseColor.G))

                        Dim newpixB As Integer = CInt(newColor.B) + (CInt(lB) - CInt(baseColor.B))

                        newimg.SetPixel(x, y, System.Drawing.Color.FromArgb(ltrans, newpixR, newpixG, newpixB))
                    Next
                Next
            End Using

        Return newimg

    End Function

这里我尝试使用 ColorMatrix 但它不起作用,不知道为什么......也许我对 ColorMatrix 工作原理的理解是错误的。

Public Function doNewRecolorImage(ByRef inBMP As Bitmap, ByVal baseColor As Color, ByVal newColor As Color) As Bitmap
        Dim newimg As New Bitmap(inBMP.Width, inBMP.Height)


            Dim iaImageProps As New ImageAttributes 

            Dim cmNewColors As ColorMatrix 

            cmNewColors = New ColorMatrix(New Single()() _
                {New Single() {newColor.R / baseColor.R, 0, 0, 0, 0}, _
                 New Single() {0, newColor.G / baseColor.G, 0, 0, 0}, _
                 New Single() {0, 0, newColor.B / baseColor.B, 0, 0}, _
                 New Single() {0, 0, 0, 1, 0}, _
                 New Single() {0, 0, 0, 0, 1}})

            iaImageProps.SetColorMatrix(cmNewColors) 

            Using g As Graphics = Graphics.FromImage(newimg)
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality
                g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
                g.DrawImage(inBMP, New Rectangle(0, 0, inBMP.Width, inBMP.Height), 0, 0, inBMP.Width, inBMP.Height, GraphicsUnit.Pixel, iaImageProps)
            End Using


        Return newimg

    End Function

更新 1:

这是我根据下面 Ryan 的回答更新的函数。它运行但没有返回预期的重新着色图像。图像是一种纯色...基色。所以我传入基色和新颜色并得到结果。但是,结果应该是新颜色(深蓝色),因为图像是纯色,所以它应该是精确的颜色交换。

enter image description here

Private Function calcColorSwap(_base As Byte, _new As Byte) As Single
    If _new > _base Then
        Return (CInt(_new) - CInt(_base)) / 255.0!
    Else
        Return (CInt(_base) - CInt(_new)) / 255.0!
    End If
End Function

Public Function doNewRecolorImage(inBMP As Bitmap, baseColor As Color, newColor As Color) As Bitmap
    Dim newimg As New Bitmap(inBMP.Width, inBMP.Height)
    Dim transformation As New ColorMatrix(New Single()() {
          New Single() {1, 0, 0, 0, 0},
          New Single() {0, 1, 0, 0, 0},
          New Single() {0, 0, 1, 0, 0},
          New Single() {0, 0, 0, 1, 0},
          New Single() {calcColorSwap(baseColor.R, newColor.R), calcColorSwap(baseColor.G, newColor.G), calcColorSwap(baseColor.B, newColor.B), 0, 1}
      })

    Dim imageAttributes As New ImageAttributes()
    imageAttributes.SetColorMatrix(transformation)


    Using g As Graphics = Graphics.FromImage(newimg)
        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality
        g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        g.DrawImage(inBMP, New Rectangle(0, 0, inBMP.Width, inBMP.Height), 0, 0, inBMP.Width, inBMP.Height, GraphicsUnit.Pixel, imageAttributes)
    End Using

Return newimg

End Function

更新 2(解决方案):

这是解决方案:基于下面 Ryan 的回答。

Private Function calcColorSwap(_base As Byte, _new As Byte) As Single
        Return (CInt(_new) - CInt(_base)) / 255.0!
End Function

Public Function doNewRecolorImage(inBMP As Bitmap, baseColor As Color, newColor As Color) As Bitmap
    Dim newimg As New Bitmap(inBMP.Width, inBMP.Height)
    Dim transformation As New ColorMatrix(New Single()() {
          New Single() {1, 0, 0, 0, 0},
          New Single() {0, 1, 0, 0, 0},
          New Single() {0, 0, 1, 0, 0},
          New Single() {0, 0, 0, 1, 0},
          New Single() {calcColorSwap(baseColor.R, newColor.R), calcColorSwap(baseColor.G, newColor.G), calcColorSwap(baseColor.B, newColor.B), 0, 1}
      })

    Dim imageAttributes As New ImageAttributes()
    imageAttributes.SetColorMatrix(transformation)


    Using g As Graphics = Graphics.FromImage(newimg)
        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality
        g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        g.DrawImage(inBMP, New Rectangle(0, 0, inBMP.Width, inBMP.Height), 0, 0, inBMP.Width, inBMP.Height, GraphicsUnit.Pixel, imageAttributes)
    End Using

Return newimg

End Function

最佳答案

与原始矩阵等效的矩阵 - 将固定值添加到 R、G 和 B - 如下所示:

New Single()() {
    New Single() {1, 0, 0, 0, 0},
    New Single() {0, 1, 0, 0, 0},
    New Single() {0, 0, 1, 0, 0},
    New Single() {0, 0, 0, 1, 0},
    New Single() {(CInt(newColor.R) - CInt(baseColor.R)) / 255!, (CInt(newColor.G) - CInt(baseColor.G)) / 255!, (CInt(newColor.B) - CInt(baseColor.B)) / 255!, 0, 1}
}

总体:

Public Function doRecolorImage(image As Image, baseColor As Color, newColor As Color) As Bitmap
    Dim transformation As New ColorMatrix(New Single()() {
        New Single() {1, 0, 0, 0, 0},
        New Single() {0, 1, 0, 0, 0},
        New Single() {0, 0, 1, 0, 0},
        New Single() {0, 0, 0, 1, 0},
        New Single() {(CInt(newColor.R) - CInt(baseColor.R)) / 255!, (CInt(newColor.G) - CInt(baseColor.G)) / 255!, (CInt(newColor.B) - CInt(baseColor.B)) / 255!, 0, 1}
    })

    Dim imageAttributes As New ImageAttributes()
    imageAttributes.SetColorMatrix(transformation)

    Dim result As New Bitmap(image.Width, image.Height)

    Using g As Graphics = Graphics.FromImage(result)
        g.DrawImage(image, New Rectangle(0, 0, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imageAttributes)
    End Using

    Return result
End Function

(不要无缘无故地使用ByRef!)

关于vb.net - 需要更快的方法来根据另一种颜色替换图像中的颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44982454/

相关文章:

c# - 生产者消费者使用公共(public) BlockingCollection 分离类

vb.net - 如果小于零,则在 VB.net 中强制计算结果等于零

vb.net - 选择行时保持 ListView 项目背景色

c# - 如何申请cvsobel + emgucv

Android EditText + 设置一些文字颜色

c++ - 在 cpp 中创建颜色变化

vb.net - Shell命令使用字符串确定文件名

image-processing - OpenCV图像处理-过滤图像

opencv - Numpy 翻转图像 + cv2.filter2D = 断言失败?

colors - 将绿色的 nullsrc 变为黑色