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に変化する、こんな画像↓
を作るのにカラーパレットの設定を失敗すると、こんな感じ↓になっていました。
画像処理では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);
}
カラーパレット設定前
カラーパレット設定後
他の画像で輝度値127~255を赤く表示している例↓
この方法だと実際に二値化の処理は行っていないので、結果が表示されるまでの時間が殆どかかりません。
二値化のしきい値をどの程度にするか?プレビューする場合などは便利です。
疑似カラー画像
黒~白の画像を青~緑~赤と色を付けて表示している、いわゆる疑似カラーのカラーパレットを設定するメソッドを作成しました。
/// <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);
}
カラーパレット設定前
カラーパレット設定後
他の画像では
サーモグラフィ―っぽい画像
サーモグラフィ―でよく目にする画像では温度の高い部分が赤く、低い部分が青く表示されている場合が多いかと思いますが、実際にサーモグラフィーのカメラで撮影した画像データは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#テクニックへ戻る
コメント