Je cherche une méthode plus rapide pour remplacer les couleurs dans une image basée sur une autre couleur. Par exemple, j'ai une image qui est principalement noire avec des nuances de gris et je veux la recolorer sur la base du rouge. En ce moment je le passe dans cette fonction avec le noir comme couleur de base et rouge comme ma nouvelle couleur. Ensuite, je vais pixel par pixel pour déterminer son RVB et recalculer cela à la nouvelle nuance rouge. Le noir pur devient alors rouge pur et les gris deviennent un rouge plus clair et ainsi de suite.Besoin d'une méthode plus rapide pour remplacer les couleurs dans une image basée sur une autre couleur
Existe-t-il un moyen plus rapide de faire cela? Peut-être utiliser une bibliothèque de manipulation d'image séparée? J'ai regardé dans ImageMagick mais je ne peux pas trouver la fonctionnalité exacte que je recherche.
Voici ma fonction actuelle. Cela fonctionne mais est lent.
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
Ici, j'ai essayé d'utiliser ColorMatrix mais il ne fonctionne pas, ne sais pas pourquoi ... peut-être ma compréhension de la façon dont fonctionne ColorMatrix est erroné.
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
MISE À JOUR 1:
Voici ma fonction mis à jour en fonction de la réponse de Ryan ci-dessous. Il s'exécute mais ne renvoie pas l'image recolorée attendue. L'image est une couleur unie ... la couleur de base. Donc je passe dans la couleur de base et la nouvelle couleur et obtenons le résultat. Cependant, le résultat devrait être la nouvelle couleur (bleu foncé), car l'image est une couleur unie, il devrait donc s'agir d'un changement de couleur exact.
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
MISE À JOUR 2 (SOLUTION):
Voici la solution: basée sur la réponse de Ryan ci-dessous.
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
J'ai testé votre code, voir mon code mis à jour ci-dessus. Il lançait une erreur _ (ne pouvait pas être convertie en Byte) _ quand les valeurs 'baseColor' sont plus grandes que les valeurs' newColor', donc j'ai ajouté une fonction pour les changer ... pas sûr que ce soit la bonne logique. En outre, il ne fait pas tout à fait ce que j'attends quand l'image est une couleur unie. –
@ChaseRocker: Il ne devrait pas y avoir 'If'; toujours soustraire dans le même ordre 'CInt (newColor.R - baseColor.R)/255!'. – Ryan
Il génère une erreur. Par exemple, quand new = 87 et base = 255, il déclenche une exception de débordement: http://i.imgur.com/54V0e4H.jpg –