【C#】Bitmapのカラーパレットの設定

8bitのグレースケールのBitmap(PixelFormatがFormat8bppIndexed)を新規で作成する場合、カラーパレットを設定する必要があるのですが、安易に下記のようなコード

// これは設定できない
var bmp = new Bitmap(256, 64, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
for (int i = 0; i < 256; i++)
{
    bmp.Palette.Entries[i] = Color.FromArgb(i, i, i);
}

のようにするとちゃんと設定できていそうで、実は設定できていません。

これはBitmapのPaletteプロパティで値の取得が呼ばれたときに内部でカラーパレットのメモリが確保され、実際にGDI+で描画に用いているカラーパレットをメモリに格納するようにしているためで、上記のコードではコピーしてきたカラーパレットに設定しているだけで、実際に用いているカラーパレットには設定できていません。

そこで正しく修正したのがこちら↓

// これなら設定できる
var bmp = new Bitmap(256, 64, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
var pal = bmp.Palette;
for (int i = 0; i < 256; i++)
{
    pal.Entries[i] = Color.FromArgb(i, i, i);
}
bmp.Palette = pal;

ちなみに、画像の輝度値が0~255に変化する、こんな画像↓

C# ColorPaletteの設定

を作るのにカラーパレットの設定を失敗すると、こんな感じ↓になっていました。

C# ColorPaletteの設定

画像処理では8ビットのグレースケールの画像を用いることは多いかと思いますが、カラーパレットの設定は、だた、グレースケールを設定するだけではつまらないので、少し変わった使い方を紹介します。

二値化のプレビューとして

指定した範囲の輝度値(val1~val2)に色を付けるメソッド(SetPaletteGrayScal)を作りました。

/// <summary>
/// 8bitグレースケールのカラーパレットを設定
/// </summary>
/// <param name="bmp">カラーパレットを設定するBitmapオブジェクト</param>
/// <param name="val1">val1~val2の範囲を指定した色(col)にする</param>
/// <param name="val2">val1~val2の範囲を指定した色(col)にする</param>
/// <param name="col">指定色</param>
public void SetPaletteGrayScal(Bitmap bmp, int val1 = -1, int val2 = -1, Color? col = null)
{
    var pal = bmp.Palette;

    // グレースケールのパレットの設定
    for (int i = 0; i < 256; i++)
    {
        pal.Entries[i] = Color.FromArgb(i, i, i);
    }

    if (col == null) col = Color.Red;

    // 値が設定されているとき
    if (
        (val1 >= 0) &&
        (val1 < 256) &&
        (val2 >= 0) &&
        (val2 < 256)
    )
    {
        if (val1 <= val2)
        {
            // val1~val2の範囲を指定した色に設定する
            for (int i = val1; i <= val2; i++)
            {
                pal.Entries[i] = (Color)col;
            }
        }
        else
        {
            // 0~val2、val1~255の範囲を指定した色に設定する
            for (int i = 0; i <= val2; i++)
            {
                pal.Entries[i] = (Color)col;
            }
            for (int i = val1; i < 256; i++)
            {
                pal.Entries[i] = (Color)col;
            }
        }
    }

    // カラーパレットの設定
    bmp.Palette = pal;
}

使い方は、こんな感じ↓

using (var bmp = new Bitmap("Grayscale.bmp"))
{
    // グレースケールの設定(64~128を赤くする)
    SetPaletteGrayScal(bmp, 64, 128);
    bmp.Save("GrayscaleRed.bmp", System.Drawing.Imaging.ImageFormat.Bmp);

    // 元に戻す場合は
    // グレースケールの設定(通常)
    SetPaletteGrayScal(bmp);
}

カラーパレット設定前

C# ColorPaletteの設定

カラーパレット設定後

C# ColorPaletteの設定

他の画像で輝度値127~255を赤く表示している例↓

C# ColorPaletteの設定  C# ColorPaletteの設定

この方法だと実際に二値化の処理は行っていないので、結果が表示されるまでの時間が殆どかかりません。

二値化のしきい値をどの程度にするか?プレビューする場合などは便利です。

疑似カラー画像

黒~白の画像を青~緑~赤と色を付けて表示している、いわゆる疑似カラーのカラーパレットを設定するメソッドを作成しました。

/// <summary>
/// 疑似カラーのパレットを設定
/// </summary>
/// <param name="bmp">カラーパレットを設定するBitmapオブジェクト</param>
public void SetPalettePseudoColor(Bitmap bmp)
{
    var pal = bmp.Palette;

    int r, g, b;

    // 疑似カラー
    for (int i = 0; i < 52; i++)
    {
        r = 0;
        g = (int)((Math.Cos(Math.PI * (i * 900 / 255.0 - 180) / 180.0) + 1) * 110.0);
        b = 255;
        pal.Entries[i] = Color.FromArgb(r, g, b);
    }
    for (int i = 52; i < 102; i++)
    {
        r = 0;
        g = 220;
        b = (int)((Math.Cos(Math.PI * (i * 900 / 255.0 - 180) / 180.0) + 1) * 127.5);
        pal.Entries[i] = Color.FromArgb(r, g, b);
    }
    for (int i = 102; i < 154; i++)
    {
        r = (int)((Math.Cos(Math.PI * (i * 900 / 255.0 - 180) / 180.0) + 1) * 127.5);
        g = 220;
        b = 0;
        pal.Entries[i] = Color.FromArgb(r, g, b);
    }
    for (int i = 154; i < 204; i++)
    {
        r = 255;
        g = (int)((Math.Cos(Math.PI * (i * 900 / 255.0 - 180) / 180.0) + 1) * 110.0);
        b = 0;
        pal.Entries[i] = Color.FromArgb(r, g, b);
    }
    for (int i = 204; i < 256; i++)
    {
        r = 255;
        g = 0;
        b = (int)((Math.Cos(Math.PI * (i * 900 / 255.0 - 180) / 180.0) + 1) * 127.5);
        pal.Entries[i] = Color.FromArgb(r, g, b);
    }
    // カラーパレットの設定
    bmp.Palette = pal;
}

使い方は、こんな感じ↓

using (var bmp = new Bitmap("Grayscale.bmp"))
{
    // 疑似カラーの設定
    SetPalettePseudoColor(bmp);
    bmp.Save("SetColorPalette_PseudoColor.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}

カラーパレット設定前

C# ColorPaletteの設定

カラーパレット設定後

C# ColorPaletteの設定

他の画像では

C# ColorPaletteの設定  C# ColorPaletteの設定

サーモグラフィ―っぽい画像

サーモグラフィ―でよく目にする画像では温度の高い部分が赤く、低い部分が青く表示されている場合が多いかと思いますが、実際にサーモグラフィーのカメラで撮影した画像データは8ビット(それ以上の場合もあるかも?)の場合は、8ビットの画像をカラーの24ビットに変換して色を付けるまでもなく、カラーパレットを設定することで、それっぽい画像になってくれます。

/// <summary>
/// サーモグラフィーっぽいカラーパレットを設定
/// </summary>
/// <param name="bmp">カラーパレットを設定するBitmapオブジェクト</param>
public void SetPaletteThermo(Bitmap bmp)
{
    var pal = bmp.Palette;

    // カラーパレットの設定

    int r, g, b;

    for (int i = 0; i < 256; i++)
    {
        if (i < 32)
        {
            r = 0;
        }
        else if (i < 164)
        {
            r = (int)((Math.Cos(Math.PI * (i * 360 / 255.0 - 225) / 180.0) + 1) * 127.5);
        }
        else
        {
            r = 255;
        }

        if (i < 96)
        {
            g = 0;
        }
        else if (i < 224)
        {
            g = (int)((Math.Cos(Math.PI * (i * 360 / 255.0 + 45) / 180.0) + 1) * 127.5);
        }
        else
        {
            g = 255;
        }

        if (i < 128)
        {
            b = (int)((Math.Cos(Math.PI * (i * 720 / 255.0 - 180) / 180.0) + 1) * 127.5);
        }
        else if (i < 192)
        {
            b = 0;
        }
        else
        {
            b = (int)((Math.Cos(Math.PI * (i * 720 / 255.0) / 180.0) + 1) * 127.5);
        }

        pal.Entries[i] = Color.FromArgb(r, g, b);
    }
    // カラーパレットの設定
    bmp.Palette = pal;
}

使い方は、こんな感じ↓

using (var bmp = new Bitmap("Grayscale.bmp"))
{
    // グレースケールの設定(64~128を赤くする)
    SetPaletteThermo(bmp);
    bmp.Save("SetColorPalette_Thermo.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}

カラーパレット設定前

C# ColorPaletteの設定

カラーパレット設定後

C# ColorPaletteの設定

他の画像では

C# ColorPaletteの設定  C# ColorPaletteの設定

画像処理のためのC#テクニックへ戻る

シェアお願いします

  • このエントリーをはてなブックマークに追加
関連記事

関連記事

関連記事
スポンサーリンク