SkiaSharp-Farbfilter

Beispiel herunterladen Das Beispiel herunterladen

Farbfilter können Farben in einer Bitmap (oder einem anderen Bild) für Effekte wie die Posterisierung in andere Farben übersetzen:

Beispiel für Farbfilter

Um einen Farbfilter zu verwenden, legen Sie die ColorFilter -Eigenschaft von SKPaint auf ein Objekt vom Typ SKColorFilter fest, das von einer der statischen Methoden in dieser Klasse erstellt wurde. In diesem Artikel wird Folgendes veranschaulicht:

Die Farbtransformation

Die Farbtransformation umfasst die Verwendung einer Matrix zum Ändern von Farben. Wie die meisten 2D-Grafiksysteme verwendet SkiaSharp Matrizen hauptsächlich zum Transformieren von Koordinatenpunkten, wie im Artikel Matrixtransformationen in SkiaSharp beschrieben. Unterstützt SKColorFilter auch Matrixtransformationen, aber die Matrix transformiert RGB-Farben. Um diese Farbtransformationen zu verstehen, sind einige Kenntnisse mit Matrixkonzepten erforderlich.

Die Farbtransformationsmatrix hat eine Dimension von vier Zeilen und fünf Spalten:

| M11 M12 M13 M14 M15 |
| M21 M22 M23 M24 M25 |
| M31 M32 M33 M34 M35 |
| M41 M42 M43 M44 M45 |

Sie transformiert eine RGB-Quellfarbe (R, G, B, A) in die Zielfarbe (R', G', B', A').

Zur Vorbereitung der Matrixmultiplikation wird die Quellfarbe in eine 5×1-Matrix konvertiert:

| R |
| G |
| B |
| A |
| 1 |

Diese R-, G-, B- und A-Werte sind die ursprünglichen Bytes im Bereich von 0 bis 255. Sie werden nicht auf Gleitkommawerte im Bereich von 0 bis 1 normalisiert.

Die zusätzliche Zelle ist für einen Übersetzungsfaktor erforderlich. Dies entspricht der Verwendung einer 3×3-Matrix zum Transformieren von zweidimensionalen Koordinatenpunkten, wie im Abschnitt Der Grund für die 3-by-3-Matrix im Artikel zur Verwendung von Matrizen zum Transformieren von Koordinatenpunkten beschrieben.

Die 4×5-Matrix wird mit der 5×1-Matrix multipliziert, und das Produkt ist eine 4×1-Matrix mit der transformierten Farbe:

| M11 M12 M13 M14 M15 |    | R |   | R' |
| M21 M22 M23 M24 M25 |    | G |   | G' |
| M31 M32 M33 M34 M35 |  × | B | = | B' |
| M41 M42 M43 M44 M45 |    | A |   | A' |
                           | 1 |

Hier sind die separaten Formeln für R', G', B' und A':

R' = M11·R + M12·G + M13·B + M14·A + M15

G' = M21·R + M22·G + M23·B + M24·A + M25

B' = M31·R + M32·G + M33·B + M34·A + M35

A' = M41·R + M42·G + M43·B + M44·A + M45

Der größte Teil der Matrix besteht aus multiplikativen Faktoren, die im Allgemeinen im Bereich von 0 bis 2 liegen. Die letzte Spalte (M15 bis M45) enthält jedoch Werte, die den Formeln hinzugefügt werden. Diese Werte liegen im Allgemeinen zwischen 0 und 255. Die Ergebnisse werden zwischen den Werten 0 und 255 eingespannt.

Die Identitätsmatrix lautet:

| 1 0 0 0 0 |
| 0 1 0 0 0 |
| 0 0 1 0 0 |
| 0 0 0 1 0 |

Dies führt zu keiner Änderung der Farben. Die Transformationsformeln sind:

R' = R

G' = G

B' = B

A' = A

Die M44-Zelle ist sehr wichtig, da sie die Deckkraft bewahrt. Es ist im Allgemeinen der Fall, dass M41, M42 und M43 alle null sind, da Sie wahrscheinlich nicht möchten, dass die Deckkraft auf den roten, grünen und blauen Werten basiert. Wenn M44 jedoch null ist, ist A' null, und nichts ist sichtbar.

Eine der häufigsten Verwendungen der Farbmatrix ist das Konvertieren einer Farbbittebit in eine Grauskala-Bitmap. Dies umfasst eine Formel für einen gewichteten Durchschnitt der roten, grünen und blauen Werte. Bei Videoanzeigen, die den Farbraum sRGB ("Standard rotgrün blau") verwenden, lautet diese Formel:

grau-shade = 0,2126· R + 0,7152· G + 0,0722· B

Um eine Farbbittebit in eine Graustufen-Bitmap zu konvertieren, müssen die Ergebnisse von R', G' und B' denselben Wert aufweisen. Die Matrix lautet:

| 0.21 0.72 0.07 0 0 |
| 0.21 0.72 0.07 0 0 |
| 0.21 0.72 0.07 0 0 |
| 0    0    0    1 0 |

Es gibt keinen SkiaSharp-Datentyp, der dieser Matrix entspricht. Stattdessen müssen Sie die Matrix als Array von 20 float Werten in der Zeilenreihenfolge darstellen: erste Zeile, dann zweite Zeile usw.

Die statische SKColorFilter.CreateColorMatrix Methode weist die folgende Syntax auf:

public static SKColorFilter CreateColorMatrix (float[] matrix);

Dabei matrix ist ein Array der 20 float Werte. Beim Erstellen des Arrays in C# ist es einfach, die Zahlen so zu formatieren, dass sie der 4×5-Matrix ähneln. Dies wird auf der Seite Graustufenmatrix im SkiaSharpFormsDemos-Beispiel veranschaulicht:

public class GrayScaleMatrixPage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
                        typeof(CenteredTilesPage),
                        "SkiaSharpFormsDemos.Media.Banana.jpg");

    public GrayScaleMatrixPage()
    {
        Title = "Gray-Scale Matrix";

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPaint paint = new SKPaint())
        {
            paint.ColorFilter =
                SKColorFilter.CreateColorMatrix(new float[]
                {
                    0.21f, 0.72f, 0.07f, 0, 0,
                    0.21f, 0.72f, 0.07f, 0, 0,
                    0.21f, 0.72f, 0.07f, 0, 0,
                    0,     0,     0,     1, 0
                });

            canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
        }
    }
}

Die DrawBitmap in diesem Code verwendete Methode stammt aus der Datei BitmapExtension.cs , die im SkiaSharpFormsDemos-Beispiel enthalten ist.

Dies ist das Ergebnis, das unter iOS, Android und Universelle Windows-Plattform ausgeführt wird:

Graustufenmatrix

Achten Sie auf den Wert in der vierten Zeile und der vierten Spalte. Dies ist der entscheidende Faktor, der mit dem A-Wert der ursprünglichen Farbe für den A-Wert der transformierten Farbe multipliziert wird. Wenn diese Zelle null ist, wird nichts angezeigt, und das Problem ist möglicherweise schwierig zu finden.

Wenn Sie mit Farbmatrizen experimentieren, können Sie die Transformation entweder aus der Perspektive der Quelle oder der Perspektive des Ziels behandeln. Wie sollte das rote Pixel der Quelle zu den roten, grünen und blauen Pixeln des Ziels beitragen? Dies wird durch die Werte in der ersten Spalte der Matrix bestimmt. Alternativ dazu, wie sollte das rote Zielpixel von den roten, grünen und blauen Pixeln der Quelle beeinflusst werden? Dies wird durch die erste Zeile der Matrix bestimmt.

Einige Ideen zur Verwendung von Farbtransformationen finden Sie auf den Seiten "Bilder neu einfärben ". Die Diskussion betrifft Windows Forms, und die Matrix hat ein anderes Format, aber die Konzepte sind identisch.

Die Pastellmatrix berechnet das rote Zielpixel, indem das rote Quellpixel abgeschwächt und die roten und grünen Pixel leicht hervorgehoben werden. Dieser Vorgang erfolgt ähnlich für die grünen und blauen Pixel:

public class PastelMatrixPage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
                        typeof(PastelMatrixPage),
                        "SkiaSharpFormsDemos.Media.MountainClimbers.jpg");

    public PastelMatrixPage()
    {
        Title = "Pastel Matrix";

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPaint paint = new SKPaint())
        {
            paint.ColorFilter =
                SKColorFilter.CreateColorMatrix(new float[]
                {
                    0.75f, 0.25f, 0.25f, 0, 0,
                    0.25f, 0.75f, 0.25f, 0, 0,
                    0.25f, 0.25f, 0.75f, 0, 0,
                    0, 0, 0, 1, 0
                });

            canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
        }
    }
}

Das Ergebnis ist, die Intensität der Farben stummzuschalten, wie Sie hier sehen können:

Pastellmatrix

Farbtabellen

Die statische SKColorFilter.CreateTable Methode ist in zwei Versionen verfügbar:

public static SKColorFilter CreateTable (byte[] table);

public static SKColorFilter CreateTable (byte[] tableA, byte[] tableR, byte[] tableG, byte[] tableB);

Die Arrays enthalten immer 256 Einträge. In der CreateTable -Methode mit einer Tabelle wird dieselbe Tabelle für die roten, grünen und blauen Komponenten verwendet. Es handelt sich um eine einfache Nachschlagetabelle: Wenn die Quellfarbe (R, G, B) und die Zielfarbe (R', B', G') lautet, werden die Zielkomponenten durch Indizierung table mit den Quellkomponenten abgerufen:

R' = table[R]

G' = table[G]

B' = table[B]

In der zweiten Methode kann jede der vier Farbkomponenten eine separate Farbtabelle haben, oder die gleichen Farbtabellen können von zwei oder mehr Komponenten gemeinsam verwendet werden.

Wenn Sie eines der Argumente für die zweite CreateTable Methode auf eine Farbtabelle festlegen möchten, die nacheinander die Werte 0 bis 255 enthält, können Sie stattdessen verwenden null . Sehr oft hat der CreateTable Aufruf ein null erstes Argument für den Alphakanal.

Im Abschnitt zur Posterisierung im Artikel Zugriff auf SkiaSharp-Bitmappixelbits haben Sie erfahren, wie Sie die einzelnen Pixelbits einer Bitmap ändern, um die Farbauflösung zu verringern. Dies ist eine Technik, die als Posterisierung bezeichnet wird.

Sie können auch eine Bitmap mit einer Farbtabelle nachbilden. Der Konstruktor der Seite Posterize Table erstellt eine Farbtabelle, die den Index einem Byte zuordnet, wobei die unteren 6 Bits auf null festgelegt sind:

public class PosterizeTablePage : ContentPage
{
    SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
                        typeof(PosterizeTablePage),
                        "SkiaSharpFormsDemos.Media.MonkeyFace.png");

    byte[] colorTable = new byte[256];

    public PosterizeTablePage()
    {
        Title = "Posterize Table";

        // Create color table
        for (int i = 0; i < 256; i++)
        {
            colorTable[i] = (byte)(0xC0 & i);
        }

        SKCanvasView canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPaint paint = new SKPaint())
        {
            paint.ColorFilter =
                SKColorFilter.CreateTable(null, null, colorTable, colorTable);

            canvas.DrawBitmap(bitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
        }
    }
}

Das Programm verwendet diese Farbtabelle nur für die grünen und blauen Kanäle. Der rote Kanal verfügt weiterhin über eine vollständige Auflösung:

Posterize Table

Sie können verschiedene Farbtabellen für die verschiedenen Farbkanäle für verschiedene Effekte verwenden.