Поделиться через


Фильтры цветов SkiaSharp

Фильтры цветов могут переводить цвета в растровом изображении (или другом изображении) в другие цвета для эффектов, таких как плакатизация:

Пример цветовых фильтров

Чтобы использовать фильтр цветов, задайте ColorFilter свойство SKPaint объекта типа SKColorFilter , созданного одним из статических методов в этом классе. В этой статье показано:

  • Преобразование цвета, созданное CreateColorMatrix с помощью метода.
  • Таблица цветов, созданная с CreateTable помощью метода.

Преобразование цвета

Преобразование цвета включает использование матрицы для изменения цветов. Как и большинство трехмерных графических систем, SkiaSharp использует матрицы в основном для преобразования точек координат, как показано в статье "Матрица преобразований в SkiaSharp". Кроме SKColorFilter того, матрица поддерживает преобразования матриц, но матрица преобразует цвета RGB. Некоторые понятия матрицы необходимы для понимания этих преобразований цветов.

Матрица преобразования цвета имеет измерение четырех строк и пяти столбцов:

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

Он преобразует цвет источника RGB (R, G, B, A) в целевой цвет (R', G', B', A).

При подготовке к умножению матрицы исходный цвет преобразуется в матрицу 5×1:

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

Эти значения R, G, B и A — это исходные байты от 0 до 255. Они не нормализованы для значений с плавающей запятой в диапазоне от 0 до 1.

Для коэффициента перевода требуется дополнительная ячейка. Это аналогично использованию матрицы 3×3 для преобразования двухмерных точек координат, как описано в разделе "Причина 3-к-3 Матрицы " в статье об использовании матриц для преобразования точек координат.

Матрица 4×5 умножается на матрицу 5×1, а продукт — это матрица 4×1 с преобразованным цветом:

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

Ниже приведены отдельные формулы для R', G', B и 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

Большая часть матрицы состоит из мультипликативных факторов, которые обычно находятся в диапазоне от 0 до 2. Однако последний столбец (M15–M45) содержит значения, добавленные в формулы. Эти значения обычно варьируются от 0 до 255. Результаты зажаты между значениями от 0 до 255.

Матрица удостоверений:

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

Это не приводит к изменению цветов. Формулы преобразования:

R' = R

G' = G

B' = B

A' = A

Ячейка M44 очень важна, так как она сохраняет прозрачность. Как правило, это так, что M41, M42 и M43 являются нулевыми, потому что вы, вероятно, не хотите, чтобы прозрачность была основана на красных, зеленых и синих значениях. Но если M44 равно нулю, то "А" будет нулевым, и ничего не будет видно.

Одним из наиболее распространенных вариантов использования цветовой матрицы является преобразование растровой карты цвета в серую масштабируемую растровую карту. Это включает в себя формулу для взвешенный средний показатель красных, зеленых и синих значений. Для отображения видео с помощью цветового пространства SRGB ("стандартный красный зеленый синий") эта формула:

серый оттенок = 0,2126· R + 0.7152· G + 0.0722· B

Чтобы преобразовать цветовую растровую карту в серую масштабируемую растровую карту, результаты R', G и B должны быть равными одному и тому же значению. Матрица:

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

Тип данных SkiaSharp не соответствует этой матрице. Вместо этого необходимо представить матрицу в виде массива из 20 float значений в порядке строк: первая строка, вторая строка и т. д.

SKColorFilter.CreateColorMatrix Статический метод имеет следующий синтаксис:

public static SKColorFilter CreateColorMatrix (float[] matrix);

где matrix массив из 20 float значений. При создании массива в C#можно легко отформатировать числа, чтобы они напоминали матрицу 4×5. Это показано на странице "Матрица серого масштабирования" в примере:

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

Метод DrawBitmap , используемый в этом коде, состоит из файла BitmapExtension.cs , включенного в пример.

Ниже приведен результат работы в iOS, Android и универсальная платформа Windows:

Матрица серого масштабирования

Следите за значением в четвертой строке и четвертом столбце. Это важный фактор, умноженный на значение исходного цвета для значения преобразованного цвета A. Если эта ячейка равна нулю, отображается ничего, и проблема может оказаться сложной.

При эксперименте с цветными матрицами можно рассматривать преобразование либо с точки зрения источника, либо с точки зрения назначения. Как красный пиксель источника способствует красному, зеленому и синему пикселям назначения? Это определяется значениями в первом столбце матрицы. Кроме того, каким образом целевой красный пиксель должен влиять на красный, зеленый и синий пиксели источника? Это определяется первой строкой матрицы.

Некоторые идеи о том, как использовать преобразования цветов, см. на страницах "Перекраска изображений". Обсуждение касается Windows Forms, и матрица является другим форматом, но основные понятия одинаковы.

Матрица пастели вычисляет целевой красный пиксель, затеняя исходный красный пиксель и немного подчеркивая красные и зеленые пиксели. Этот процесс выполняется аналогичным образом для зеленых и синих пикселей:

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

Результатом является отключение интенсивности цветов, как можно увидеть здесь:

Матрица пастели

Цветовые таблицы

SKColorFilter.CreateTable Статический метод поставляется в двух версиях:

public static SKColorFilter CreateTable (byte[] table);

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

Массивы всегда содержат 256 записей. В методе CreateTable с одной таблицей та же таблица используется для красных, зеленых и синих компонентов. Это простая таблица поиска: если исходный цвет имеет значение (R, G, B), а конечный цвет — (R', B', G'), то конечные компоненты получаются путем индексирования table с помощью исходных компонентов:

R' = table[R]

G' = table[G]

B' = table[B]

Во втором методе каждый из четырех компонентов цвета может иметь отдельную таблицу цветов, или одни и те же таблицы цветов могут быть общими для двух или нескольких компонентов.

Если вы хотите задать один из аргументов второго CreateTable метода в цветовую таблицу, содержащую значения от 0 до 255 в последовательности, можно использовать null вместо этого. Очень часто CreateTable вызов имеет null первый аргумент для альфа-канала.

В разделе " Плакатизация " статьи о доступе к битам растрового изображения SkiaSharp вы узнали, как изменить отдельные биты растрового изображения, чтобы уменьшить разрешение цвета. Это метод, называемый афистеризацией.

Вы также можете плакать растровое изображение с помощью цветовой таблицы. Конструктор страницы "Плакатизация таблицы " создает цветовую таблицу, которая сопоставляет его индекс с байтами с нижними 6 битами, равными нулю:

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

Программа выбирает использовать эту таблицу цветов только для зеленых и синих каналов. Красный канал продолжает иметь полное разрешение:

Плакатизация таблицы

Для различных цветовых каналов можно использовать различные таблицы цветов для различных эффектов.