Filtri colore SkiaSharp

Download Sample Scaricare l'esempio

I filtri colori possono convertire i colori in una bitmap (o in un'altra immagine) in altri colori per effetti come la posterizzazione:

Color Filters Example

Per utilizzare un filtro colori, impostare la ColorFilter proprietà di SKPaint su un oggetto di tipo SKColorFilter creato da uno dei metodi statici in tale classe. Questo articolo illustra:

Trasformazione del colore

La trasformazione di colore prevede l'uso di una matrice per modificare i colori. Analogamente alla maggior parte dei sistemi grafici 2D, SkiaSharp usa matrici principalmente per trasformare i punti di coordinate come iscussed nell'articolo Trasformazioni matrice in SkiaSharp. Supporta SKColorFilter anche trasformazioni di matrice, ma la matrice trasforma i colori RGB. È necessaria una certa familiarità con i concetti relativi alla matrice per comprendere queste trasformazioni di colore.

La matrice di trasformazione colore ha una dimensione di quattro righe e cinque colonne:

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

Trasforma un colore di origine RGB (R, G, B, A) nel colore di destinazione (R', G', B', A').

In preparazione della moltiplicazione della matrice, il colore di origine viene convertito in una matrice 5×1:

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

Questi valori R, G, B e A sono i byte originali compresi tra 0 e 255. Non vengono normalizzate in valori a virgola mobile nell'intervallo da 0 a 1.

La cella aggiuntiva è necessaria per un fattore di traslazione. Questo è analogo all'uso di una matrice 3×3 per trasformare i punti di coordinate bidimensionali come descritto nella sezione Motivo della matrice 3 per 3 per 3 nell'articolo sull'uso di matrici per trasformare i punti di coordinate.

La matrice 4×5 viene moltiplicata per la matrice 5×1 e il prodotto è una matrice 4×1 con il colore trasformato:

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

Ecco le formule separate per R', G', B' e 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

La maggior parte della matrice è costituita da fattori moltiplicativi generalmente compresi nell'intervallo da 0 a 2. Tuttavia, l'ultima colonna (da M15 a M45) contiene valori aggiunti nelle formule. Questi valori sono in genere compresi tra 0 e 255. I risultati sono bloccati tra i valori 0 e 255.

La matrice di identità è:

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

In questo modo non viene apportata alcuna modifica ai colori. Le formule di trasformazione sono:

R' = R

G' = G

B' = B

A' = A

La cella M44 è molto importante perché mantiene l'opacità. È in genere il caso che M41, M42 e M43 siano tutti zero, perché probabilmente non si vuole che l'opacità sia basata sui valori rosso, verde e blu. Ma se M44 è zero, A' sarà zero e nulla sarà visibile.

Uno degli usi più comuni della matrice di colori consiste nel convertire una bitmap di colore in una bitmap in scala grigia. Si tratta di una formula per una media ponderata dei valori rosso, verde e blu. Per i video visualizzati usando lo spazio dei colori sRGB ("standard rosso verde blu"), questa formula è:

grigio ombreggiatura = 0,2126· R + 0,7152 · G + 0,0722 · B

Per convertire una bitmap a colori in una bitmap in scala grigia, i risultati di R', G' e B' devono essere tutti uguali allo stesso valore. La matrice è:

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

Non esiste alcun tipo di dati SkiaSharp che corrisponde a questa matrice. È invece necessario rappresentare la matrice come matrice di 20 float valori in ordine di riga: prima riga, quindi seconda riga e così via.

Il metodo statico SKColorFilter.CreateColorMatrix ha la sintassi seguente:

public static SKColorFilter CreateColorMatrix (float[] matrix);

dove matrix è una matrice di 20 float valori. Quando si crea la matrice in C#, è facile formattare i numeri in modo che siano simili alla matrice 4×5. Questa operazione è illustrata nella pagina Matrice di scalabilità grigia nell'esempio SkiaSharpFormsDemos:

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

Il DrawBitmap metodo usato in questo codice proviene dal file BitmapExtension.cs incluso nell'esempio SkiaSharpFormsDemos .

Ecco il risultato in esecuzione in iOS, Android e piattaforma UWP (Universal Windows Platform):

Gray-Scale Matrix

Osservare il valore nella quarta riga e nella quarta colonna. Questo è il fattore cruciale moltiplicato per il valore A del colore originale per il valore A del colore trasformato. Se la cella è zero, non verrà visualizzato alcun elemento e il problema potrebbe essere difficile da individuare.

Quando si sperimentano matrici di colori, è possibile trattare la trasformazione dal punto di vista dell'origine o dalla prospettiva della destinazione. In che modo il pixel rosso dell'origine deve contribuire ai pixel rosso, verde e blu della destinazione? Determinato dai valori nella prima colonna della matrice. In alternativa, in che modo il pixel rosso di destinazione deve essere influenzato dai pixel rosso, verde e blu dell'origine? Questo è determinato dalla prima riga della matrice.

Per alcune idee su come usare le trasformazioni di colore, vedi le pagine Ricolorazione delle immagini. La discussione riguarda Windows Form e la matrice è un formato diverso, ma i concetti sono gli stessi.

La matrice pastello calcola il pixel rosso di destinazione attenuando il pixel rosso di origine e enfatizzando leggermente i pixel rossi e verdi. Questo processo si verifica in modo analogo per i pixel verdi e blu:

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

Il risultato consiste nel disattivare l'intensità dei colori come si può vedere qui:

Pastel Matrix

Tabelle a colori

Il metodo statico SKColorFilter.CreateTable è disponibile in due versioni:

public static SKColorFilter CreateTable (byte[] table);

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

Le matrici contengono sempre 256 voci. CreateTable Nel metodo con una tabella viene usata la stessa tabella per i componenti rosso, verde e blu. Si tratta di una semplice tabella di ricerca: se il colore di origine è (R, G, B) e il colore di destinazione è (R', B', G'), i componenti di destinazione vengono ottenuti tramite l'indicizzazione table con i componenti di origine:

R' = table[R]

G' = table[G]

B' = table[B]

Nel secondo metodo, ognuno dei quattro componenti di colore può avere una tabella colori separata o le stesse tabelle dei colori possono essere condivise tra due o più componenti.

Se si desidera impostare uno degli argomenti sul secondo CreateTable metodo su una tabella colori che contiene i valori da 0 a 255 in sequenza, è possibile usare null invece . Molto spesso la CreateTable chiamata ha un null primo argomento per il canale alfa.

Nella sezione relativa alla posterizzazione nell'articolo sull'accesso ai bit di pixel bitmap SkiaSharp è stato illustrato come modificare i singoli bit di pixel di una bitmap per ridurre la risoluzione dei colori. Si tratta di una tecnica denominata posterizzazione.

È anche possibile posterizzare una bitmap con una tabella colori. Il costruttore della pagina Posterize Table crea una tabella colori che esegue il mapping dell'indice a un byte con i 6 bit inferiori impostati su zero:

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

Il programma sceglie di utilizzare questa tabella colori solo per i canali verdi e blu. Il canale rosso continua ad avere una risoluzione completa:

Posterize Table

È possibile utilizzare varie tabelle di colori per i diversi canali di colore per vari effetti.