需要更快的方法来替换基于另一种颜色的图像中的颜色(Need faster method to replace colors in an image based on another color)

编程入门 行业动态 更新时间:2024-10-27 18:29:24
需要更快的方法来替换基于另一种颜色的图像中的颜色(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

I'm looking for a faster method of replacing colors in an image based on another color. For example, I have an image that is mostly black with shades of gray and I want to recolor it based on red. Right now I pass it into this function with black as my base color and red as my new color. Then I go pixel by pixel to determine its RGB and recalculate that to the new red shade. So pure black becomes pure red and grays become a lighter red and so on.

Is there a quicker way to do this? Possibly using a separate image manipulation library? I looked into ImageMagick but I can't find the exact functionality I'm looking for.

Here's my current function. It works but is slow.

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

Here I tried using ColorMatrix but it didn't work, not sure why...maybe my understanding of how ColorMatrix works is wrong.

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

UPDATE 1:

Here's my updated function based on Ryan's answer below. It runs but it isn't returning the expected recolored image. The image is one solid color...the base color. So I'm passing in the base color and the new color and getting the result. However, the result should be the new color (dark blue) because the image is a solid color so it should be an exact color swap.

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

UPDATE 2 (SOLUTION):

Here's the solution: based on Ryan's answer below.

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

The matrix equivalent to your original – adding a fixed value to R, G, and B – looks like this:

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} }

Overall:

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

(Don’t use ByRef for no reason!)

更多推荐

本文发布于:2023-07-27 22:47:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1296671.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:更快   方法来   种颜色   图像   颜色

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!