SkiaSharp カラー フィルター
カラー フィルターは、ビットマップ (または他の画像) の色を他の色に変換して、ポスター化などの効果を得ることができます。
カラー フィルターを使用するには、そのクラスのいずれかの静的メソッドによって作成された型 SKColorFilter
のオブジェクトに SKPaint
の ColorFilter
プロパティを設定します。 この記事では、次の内容について説明します。
CreateColorMatrix
メソッドを使用して作成された色変換。CreateTable
メソッドで作成されたカラー テーブル。
色変換
色変換では、マトリックスを使用して色を変更します。 SkiaSharp のマトリックス変換に関する記事で説明されているように、ほとんどの 2D グラフィックス システムと同様に、SkiaSharp ではほとんどの場合、座標点を変換するためにマトリックスが使用されます。 SKColorFilter
ではマトリックス変換もサポートされていますが、マトリックスは RGB カラーを変換します。 これらの色変換を理解するには、マトリックスの概念に関する知識が必要です。
色変換マトリックスの次元は、4 行 5 列です。
| 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 行列を使用して 2 次元座標点を変換する方法に似ています。座標点を変換するための行列の使用に関するこの記事の「 3-by-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 が 0 の場合、A' は 0 になり、何も見えなくなります。
カラー マトリックスの最も一般的な用途の 1 つは、カラー ビットマップをグレースケール ビットマップに変換することです。 これには、赤、緑、青の値の加重平均の数式が含まれます。 sRGB ("標準の赤、緑、青") 色空間を使用したビデオ ディスプレイの場合、この公式は次のようになります。
gray-shade = 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 プラットフォーム (UWP) で実行されているプログラムを次に示します。
4 行目と 4 列目の値に注意してください。 これは、変換された色の A' 値に対する元の色の A 値を乗算する重要な要素です。 そのセルが 0 の場合は何も表示されないので、問題の特定が困難になる場合があります。
カラー マトリックスを使用して実験する場合は、変換元の観点からも変換先の観点からも変換を処理できます。 変換元の赤いピクセルは、変換先の赤、緑、青のピクセルにどのように影響しますか? それは、マトリックスの最初の列の値によって決まります。 または、変換元の赤、緑、青のピクセルによって変換先の赤いピクセルがどのように影響を受けるようにする必要がありますか? それは、マトリックスの最初の行によって決まります。
色変換の使用方法に関するアイデアについては、画像イメージの色の変更に関するページを参照してください。 この議論は Windows フォームに関するもので、マトリックスの形式は異なりますが、概念は同じです。
パステル マトリックスは、変換元の赤いピクセルを減衰させ、赤と緑のピクセルをわずかに強調することによって、変換先の赤いピクセルを計算します。 このプロセスは、緑と青のピクセルでも同様に行われます。
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
には、次の 2 つのバージョンがあります。
public static SKColorFilter CreateTable (byte[] table);
public static SKColorFilter CreateTable (byte[] tableA, byte[] tableR, byte[] tableG, byte[] tableB);
配列には常に 256 個のエントリが含まれます。 1 つのテーブルを持つ CreateTable
メソッドでは、赤、緑、青の各コンポーネントに同じテーブルが使用されます。 これは単純な検索テーブルです。変換元の色が (R、G、B)、変換先の色が (R'、B'、G') の場合、変換先コンポーネントは変換元コンポーネントで table
にインデックスを作成することによって取得できます。
R' = table[R]
G' = table[G]
B' = table[B]
2 番目のメソッドでは、4 つの色コンポーネントのそれぞれで個別のカラー テーブルを使用することも、同じカラー テーブルを 2 つ以上のコンポーネント間で共有することもできます。
2番目の CreateTable
メソッドの引数の 1 つを、0 から 255 までの値を順番に含むカラー テーブルに設定する場合は、代わりに null
を使用できます。 多くの場合、CreateTable
呼び出しはアルファ チャネルのための最初の null
引数を持っています。
SkiaSharp ビットマップ ピクセル ビットへのアクセスのポスター化のセクションで、ビットマップの個々のピクセル ビットを変更して色の解像度を下げる方法について説明しました。 これは、ポスター化と呼ばれる手法です。
カラー テーブルを使用してビットマップをポスター化することもできます。 [テーブルのポスター化] ページのコンストラクターは、そのインデックスを下位 6 ビットが 0 に設定されたバイトにマップするカラー テーブルを作成します。
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);
}
}
}
プログラムは、緑と青のチャネルにのみこのカラー テーブルを使用することを選択します。 赤チャネルは引き続き完全な解像度を保持します。
さまざまな効果を得るために、さまざまなカラー チャネルにさまざまなカラー テーブルを使用できます。