需要更快的方法来根据另一种颜色替换图像中的颜色
Need faster method to replace colors in an image based on another color
我正在寻找一种基于另一种颜色替换图像中颜色的更快方法。例如,我有一张大部分为黑色且带有灰色阴影的图像,我想根据红色为它重新着色。现在我将它传递给这个函数,黑色作为我的基色,红色作为我的新颜色。然后我逐个像素地确定它的 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 的回答更新的函数。它运行但未返回预期的重新着色图像。图像是一种纯色……基色。所以我传入基色和新颜色并得到结果。但是,结果应该是新颜色(深蓝色),因为图像是纯色,所以它应该是精确的颜色交换。
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
!)
在 ImageMagick 中,您可以
convert gray.png \( -clone 0 -fill red -colorize 100 \) \( -clone 0 -negate \) -compose colorize -composite red.png
我在这里回答了一个类似的问题(没有否定)Re-coloring image preserving luminance
ImageMagick 中另一种更简单且可能更符合您需要的方法是:
convert gray.png +level-colors red,white red.png
我正在寻找一种基于另一种颜色替换图像中颜色的更快方法。例如,我有一张大部分为黑色且带有灰色阴影的图像,我想根据红色为它重新着色。现在我将它传递给这个函数,黑色作为我的基色,红色作为我的新颜色。然后我逐个像素地确定它的 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 的回答更新的函数。它运行但未返回预期的重新着色图像。图像是一种纯色……基色。所以我传入基色和新颜色并得到结果。但是,结果应该是新颜色(深蓝色),因为图像是纯色,所以它应该是精确的颜色交换。
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
!)
在 ImageMagick 中,您可以
convert gray.png \( -clone 0 -fill red -colorize 100 \) \( -clone 0 -negate \) -compose colorize -composite red.png
我在这里回答了一个类似的问题(没有否定)Re-coloring image preserving luminance
ImageMagick 中另一种更简单且可能更符合您需要的方法是:
convert gray.png +level-colors red,white red.png