2017-07-08 9 views
1

Ich bin auf der Suche nach einer schnelleren Methode zum Ersetzen von Farben in einem Bild basierend auf einer anderen Farbe. Zum Beispiel habe ich ein Bild, das hauptsächlich schwarz mit Grautönen ist und ich möchte es basierend auf rot neu einfärben. Im Moment gebe ich es in diese Funktion mit Schwarz als meine Grundfarbe und rot als meine neue Farbe. Dann gehe ich Pixel für Pixel, um sein RGB zu bestimmen und dieses auf den neuen roten Farbton neu zu berechnen. So wird reines Schwarz zu reinem Rot und Grau zu einem helleren Rot und so weiter.Benötigen Sie schnellere Methode zum Ersetzen von Farben in einem Bild basierend auf einer anderen Farbe

Gibt es einen schnelleren Weg, dies zu tun? Möglicherweise mit einer separaten Bildbearbeitungsbibliothek? Ich habe ImageMagick untersucht, aber ich kann nicht die genaue Funktionalität finden, nach der ich suche.

Hier ist meine derzeitige Funktion. Es funktioniert, ist aber langsam.

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 

Hier habe ich versucht, mit Colormatrix, aber es hat nicht funktioniert, nicht sicher, warum ... vielleicht mein Verständnis davon, wie Colormatrix funktioniert falsch ist.

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:

Hier ist meine aktualisierte Funktion basiert auf Ryans unten Antwort. Es wird ausgeführt, es wird jedoch nicht das erwartete umgefärbte Bild zurückgegeben. Das Bild ist eine einfarbige Farbe ... die Grundfarbe. Also gebe ich die Grundfarbe und die neue Farbe und bekomme das Ergebnis. Das Ergebnis sollte jedoch die neue Farbe (dunkelblau) sein, da das Bild eine Volltonfarbe ist, also sollte es sich um einen exakten Farbwechsel handeln.

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 

UPDATE 2 (Lösung):

Hier ist die Lösung: basierend auf Ryans Antwort unten.

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 

Antwort

1

Die Matrix entspricht Ihrer ursprünglichen - einen festen Wert zu R Zugabe, G und B - sieht wie folgt aus:

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

Gesamt:

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 

(Do not Verwenden Sie ByRef ohne Grund!)

+0

Ich habe Ihren Code getestet, siehe oben meinen aktualisierten Code. Es wurde ein Fehler _ geworfen (konnte nicht in Byte konvertiert werden) _ wenn 'baseColor' Werte größer als' newColor' Werte sind, fügte ich eine Funktion hinzu, um sie umzuschalten ... nicht sicher, ob das die richtige Logik ist. Außerdem macht es nicht ganz das, was ich erwarte, wenn das Bild eine feste Farbe hat. –

+0

@ChaseRocker: Es sollte kein 'If' geben; subtrahiere immer in der gleichen Reihenfolge 'CInt (newColor.R - baseColor.R)/255!'. – Ryan

+0

Es wird ein Fehler ausgegeben. Zum Beispiel, wenn new = 87 und base = 255, gibt es eine Überlauf-Ausnahme: http://i.imgur.com/54V0e4H.jpg –

Verwandte Themen