2017-07-08 2 views
1

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.

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 

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 

Répondre

1

La matrice équivalente à l'original - l'ajout d'une valeur fixée à R, G et B - ressemble à ceci:

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

générale:

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 

(Ne pas utiliser ByRef sans raison!)

+0

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. –

+0

@ChaseRocker: Il ne devrait pas y avoir 'If'; toujours soustraire dans le même ordre 'CInt (newColor.R - baseColor.R)/255!'. – Ryan

+0

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 –