Color Matrix zum Ersetzen von Farben ?

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von Peter329.

    Color Matrix zum Ersetzen von Farben ?

    Hi,

    ich versuche in einer Bitmap Farben zu ersetzen.

    Im Netz habe ich gefunden, wie man mit einer Color Matrix eine farbige Grafik in eine "gray Scale" Grafik umwandeln kann. Hier ein Code Beispiel:

    VB.NET-Quellcode

    1. Dim grayscale As New Imaging.ColorMatrix(New Single()() _
    2. {
    3. New Single() {0.299, 0.299, 0.299, 0, 0},
    4. New Single() {0.587, 0.587, 0.587, 0, 0},
    5. New Single() {0.114, 0.114, 0.114, 0, 0},
    6. New Single() {0, 0, 0, 1, 0},
    7. New Single() {0, 0, 0, 0, 1}
    8. })
    9. Dim bmp As Bitmap = copyBitmap
    10. Dim imgattr As New Imaging.ImageAttributes()
    11. imgattr.SetColorMatrix(grayscale)
    12. Using g As Graphics = Graphics.FromImage(bmp)
    13. g.DrawImage(bmp, New Rectangle(0, 0, bmp.Width, bmp.Height),
    14. 0, 0, bmp.Width, bmp.Height,
    15. GraphicsUnit.Pixel, imgattr)
    16. End Using


    Das klappt prima ... ist aber leider nicht ganz das was ich haben möchte.

    Ich möchte, folgende Umsetzung:

    schwarz = schwarz
    weiß = weiß
    alle anderen Farben = schwarz

    Leider habe ich nicht gefunden, wie die Felder der 5x5 Matrix zu interpretieren sind ... und auch durch "Probieren" erschließt sich mir nicht die Funktion ...

    Kann mir jemand sagen, ob und ggfs. wie ich die von mir beabsichtigte Umsetzung hinbekommen kann ?

    LG
    Peter
    Mit colormatrix habich mich mal vor langem beschäftigt, das ist dabei herausgekommen:
    activevb.de/cgi-bin/tippupload…_Farbwerte_transformieren
    (kann sein, du musst dich auf der Site anmelden.)
    Ist eine wunnehübsche TestAnwendung für Farbverfremdungen. Wenn ich recht erinnere habich in einem Label auch angegeben, wie eine Colormatrix zu "lesen" ist.

    Inhaltlich habich vergessen, wies genau geht, nur der erste Satz aus dem Tippvorschlag:
    Mit der Colormatrix kann für jeden Farbwert einer Bitmap ein Transformations-Wert festgelegt werden, der sich aus allen Farbkomponenten zusammensetzen kann, incl. Farbsättigung.


    Ob du damit deine Ziele erreichen kannst, weiss ich nicht - glaub fast nicht.
    Schwarz und weiss sind ja gar keine Farben, sondern Zustände, bei denen alle FarbKomponenten auf 0 stehen, bzw. auf 255.
    "alle anderen Farben" auf Schwarz setzen geht mit Colormatrix wohl nicht.
    Wie das Zitat sagt: Jede Farbe wird quasi mit einer 3-dimensionalen Gewichtung umgefärbt - also jede Farbe bekommt genau eine neue Farbe.
    Mehreren Farben dieselbe neue Farbe zuordnen ist damit wohl nicht möglich.
    Hallo @Peter329

    Ich bin gerade auf diese Seite gestossen, habe es aber nicht ausprobiert.
    stackoverflow.com/a/29577805

    VB.NET-Quellcode

    1. imgattr.SetThreshold(0.5)


    Müsste man mal ausprobieren.

    EDIT:
    Ich denke so darf man eine Colormatrix interpretieren
    Die Colormatrix hat 5 Single-Arrays.
    Die erste Array manipuliert die Resultierende für Rot, die zweite Array die Resultierenden für Grün, und die Dritte die Resultierende für Blau. Die vierte Array bestimmt den Alphakanal, und die fünfte Array bestimmt die Intensität der Farben. Das begründet warum die vierte und die fünfte Array keine manipulierte Wirkung zeigen.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    @Peter329 Das ist nicht ganz trivial.
    Es fängt an damit, dass diese ColorMatrix kein reines Grau macht, sondern eine Grau-ähnliche Farbe, deren RGB-Komponenten verschieden sind.
    Bei einem richtigen Grau sind die RGB-Werte jeweils gleich, das bedeutet, dass in der 3x3-Sub-Matrix dieselben Werte drin stehen müssen.
    Ich hab mal ein kleines Testprogramm gemacht mit einem Slider zur Vorgabe des Threshold-Wertes und mit einem relativ schlechten Testbild.
    Kompilieren, starten und am Slider schieben.
    Das Ergebnis ist etwas anders als erwartet.
    ColorMatrix.zip
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Auch wenn es an der ColorMatrix vorbeigeht, komm ich nochmal auf die Startwünsche zurück: weiß -> weiß, alles andere -> schwarz. Das könnte man doch auch so machen, dass man sich mit LockBits die ganzen Pixeldaten in ein Array lädt, dann durchschaut, wo RGB jeweils 255 sind und überall dort, wo sie das nicht sind, die RGB-Werte auf Null setzt. Ist natürlich da auch die Frage, ob nur 255,255,255,(255)-Pixel als Weiß gewertet werden sollen oder ob da leichte Abweichungen ins Graue erlaubt sind, aber das muss Peter entscheiden.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Bitmap As Bitmap = Nothing
    2. Private Rectangle As Rectangle = Nothing
    3. Private BitmapData As Imaging.BitmapData = Nothing
    4. Private StartPointer As IntPtr = IntPtr.Zero
    5. Private ByteCount As Integer = 0
    6. Private BGRAValues As Byte() = Nothing
    7. Public Function LockBitmapAndGetBGRAValuesByScanning(Image As Image) As Byte()
    8. Bitmap = New Bitmap(Image)
    9. Rectangle = New Rectangle(0, 0, Bitmap.Width, Bitmap.Height)
    10. BitmapData = Bitmap.LockBits(Rectangle, Imaging.ImageLockMode.ReadWrite, Bitmap.PixelFormat)
    11. StartPointer = BitmapData.Scan0
    12. ByteCount = Math.Abs(BitmapData.Stride) * Bitmap.Height
    13. ReDim BGRAValues(ByteCount - 1)
    14. Runtime.InteropServices.Marshal.Copy(StartPointer, BGRAValues, 0, ByteCount)
    15. Return BGRAValues
    16. End Function
    17. Public Sub MakeNonWhitePixelsBlackIn(BGRAValues As Byte())
    18. For i = 0 To BGRAValues.Length - 3 Step 4
    19. Dim BlueValue = BGRAValues(i)
    20. Dim GreenValue = BGRAValues(i + 1)
    21. Dim RedValue = BGRAValues(i + 2)
    22. Dim AlphaValue = BGRAValues(i + 3)
    23. If RedValue < 255 OrElse GreenValue < 255 OrElse BlueValue < 255 OrElse AlphaValue < 255 Then
    24. BGRAValues(i) = 0
    25. BGRAValues(i + 1) = 0
    26. BGRAValues(i + 2) = 0
    27. BGRAValues(i + 3) = 255
    28. End If
    29. Next
    30. End Sub
    31. Public Function UnlockBitmapAndGetFinalPicture() As Bitmap
    32. Runtime.InteropServices.Marshal.Copy(BGRAValues, 0, StartPointer, ByteCount)
    33. Bitmap.UnlockBits(BitmapData)
    34. Return Bitmap
    35. End Function


    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Also erst mal DANKE an alle, die sich mit diesem Problem befasst haben ! Das war wirklich sehr freundlich von euch !

    @EDR und @RFG

    Jau ... jetzt verstehe ich das besser. Offensichtlich ist die Sache mit der Matrix so zu verstehen, dass darauf der Pixel RGBAx Vektor angewendet wird. Die Beispielmatrix wirkt dann so, dass alle Farben auf einen "gewichteten grauen Einheitsbrei" abgebildet werden. Und natürlich bleibt schwarz dann auch schwarz. Aber Farben werden halt mehr oder weniger grau.

    Für mein Vorhaben ist die ColorMatrix also ungeeignet.

    @exc-jdbi

    Ich hab das mit dem ia.SetThreshold(0.5) ausprobiert. Aber das funzt leider nicht ... es wird sehr viel "gray garbage" mit ausgegeben.

    @VapiZed

    Deine Routine ist Klasse ... die habe ich jetzt recht erfolgreich für mein Vorhaben abgewandelt ...

    Ich musste die Auswahl der Felder, die auf schwarz gesetzt werden soll ein bissl verfeinern:

    VB.NET-Quellcode

    1. Public Sub MakeNonWhitePixelsBlackIn(ByRef BGRAValues As Byte())
    2. For i = 0 To BGRAValues.Length - 3 Step 4
    3. Dim b As Integer = BGRAValues(i)
    4. Dim g As Integer = BGRAValues(i + 1)
    5. Dim r As Integer = BGRAValues(i + 2)
    6. Dim a As Integer = BGRAValues(i + 3)
    7. 'Remove non black or white pixels
    8. Dim blnRemove As Boolean = False
    9. If r < 50 AndAlso g < 50 AndAlso b < 50 Then blnRemove = True
    10. If g + b - r < 64 Then blnRemove = True
    11. If r > 200 AndAlso g < 120 AndAlso b < 120 Then blnRemove = True
    12. If blnRemove Then
    13. BGRAValues(i) = 0
    14. BGRAValues(i + 1) = 0
    15. BGRAValues(i + 2) = 0
    16. BGRAValues(i + 3) = 255
    17. End If
    18. Next
    19. End Sub


    Das sind nicht alle Auswahlkriterien ... ich trace halt die Maps ... und sehe dann zu, wie ich das auf schwarz setze, was nicht angezeigt werden soll. Mühsam nährt sich das Eichhörnchen. :)

    Deine Routine läuft übrigens super schnell (im Gegensatz zu anderen Routinen, die ich Netz zur Attribut Manipulation gefunden haben.

    Also ... wieder einmal ein herzliches Dankeschön an die Ratgeber ... ihr habt mir SEHR geholfen !

    LG
    Peter