8ビットカラーbmpイメージを8ビットグレースケールbmpに変換する

これは私のビットマップオブジェクトです

Bitmap b = new Bitmap(columns, rows, PixelFormat.Format8bppIndexed);
BitmapData bmd = b.LockBits(new Rectangle(0, 0, columns, rows), ImageLockMode.ReadWrite, b.PixelFormat);

どのように私はこれを8ビットのグレースケールのビットマップに変換するのですか?

4
何があなたのために働いているかを確認した後、答えの一つを受け入れたものとしてマークすることを忘れないでください。すべての答えは基本的に同じですが
追加された 著者 radu florescu,
なぜ LockBits を使用していますか?
追加された 著者 Oded,
追加された 著者 Oded,

5 答え

はい、ピクセルを変更する必要はありません。ただパレットは問題ありません。 ColorPaletteは薄れたタイプですが、このサンプルコードはうまくいきました:

        var bmp = Image.FromFile("c:/temp/8bpp.bmp");
        if (bmp.PixelFormat != System.Drawing.Imaging.PixelFormat.Format8bppIndexed) throw new InvalidOperationException();
        var newPalette = bmp.Palette;
        for (int index = 0; index < bmp.Palette.Entries.Length; ++index) {
            var entry = bmp.Palette.Entries[index];
            var gray = (int)(0.30 * entry.R + 0.59 * entry.G + 0.11 * entry.B);
            newPalette.Entries[index] = Color.FromArgb(gray, gray, gray);
        }
        bmp.Palette = newPalette;   //Yes, assignment to self is intended
        if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
        pictureBox1.Image = bmp;

私は実際にこのコードを使用することをお勧めしません、インデックス付きピクセル形式は、対処するピタです。 この回答では、より速くより一般的なカラーからグレースケールへの変換を見つけることができます。

5
追加された
コードコメントには、実際には「自己への割り当て」ではありません。パレットを取得すると新しいオブジェクトが作成されます。そのため、最後にこの割り当てが必要で、なぜパレットを bmp.Palette.Entries [index] = value;
追加された 著者 Nyerguds,
パレットを最適化するのは、24bppイメージを8bppイメージに変換する必要がある場合のみです。これは、1600万の可能な色をわずか256の利用可能な色にマッピングすることを必要とする。これはあなたが求めているものではありません。
追加された 著者 Hans Passant,
はい、新しい8bppビットマップを最初から作成すると、GDI +は既定のパレットを作成します。実際にこれを行うことはまれです。インデックス付きピクセル形式のビットマップを使用することはあまりありません。それに引き込むことはできません。ペイントプログラムは、8bppビットマップの一般的なソースです。
追加された 著者 Hans Passant,
8ビットカラーパレットのエントリは常に同じですか?最適化された画像を使って画像を最適化できると思いました。同じものだけがvar gray =(int)(0.30 * entry.R + 0.59 * entry.G + 0.11 * entry.B)を使用できます。右 ?
追加された 著者 crowso,
つまり、C#は、常に8ビットイメージを作成するときにデフォルトのカラーパレットに置かれますか?
追加された 著者 crowso,

何かのようなもの:

Bitmap b = new Bitmap(columns, rows, PixelFormat.Format8bppIndexed);
for (int i = 0; i < columns; i++)
{
   for (int x = 0; x < rows; x++)
    {
       Color oc = b.GetPixel(i, x);
        int grayScale = (int)((oc.R * 0.3) + (oc.G * 0.59) + (oc.B * 0.11));
       Color nc = Color.FromArgb(oc.A, grayScale, grayScale, grayScale);
       b.SetPixel(i, x, nc);
  }
}
BitmapData bmd = b.LockBits(new Rectangle(0, 0, columns, rows), ImageLockMode.ReadWrite, b.PixelFormat);
3
追加された
これだけで十分ですか?カラーテーブルを変更する必要はありませんか?それでもまだ変更されたビットマップデータは同じカラーテーブルを使用しているでしょうか?
追加された 著者 klijo,
SetPixel はインデックス付きイメージでも機能しますか?彼らは、色ではなくピクセル値としてインデックスを持っています。
追加された 著者 Nyerguds,

こんにちは、あなたはグレースケールに色パレットを変更することができます

次のコードはVb.netにあります。それを簡単にC#に変換することができます

Private Function GetGrayScalePalette() As ColorPalette  
    Dim bmp As Bitmap = New Bitmap(1, 1, Imaging.PixelFormat.Format8bppIndexed)  

    Dim monoPalette As ColorPalette = bmp.Palette  

    Dim entries() As Color = monoPalette.Entries  

    Dim i As Integer 
    For i = 0 To 256 - 1 Step i + 1  
        entries(i) = Color.FromArgb(i, i, i)  
    Next 

    Return monoPalette  
End Function 

Original Source -> http://social.msdn.microsoft.com/Forums/en-us/vblanguage/thread/500f7827-06cf-4646-a4a1-e075c16bbb38

2
追加された
元の画像のパレットが、既に完全な奇跡によって、明るさによって順序付けされていない限り、画像にこのパレットを割り当てるだけで、それは完全に邪魔になります。
追加された 著者 Nyerguds,

現代のHDTVと同じ変換をしたい場合は、Rec。変換のための709の係数。上記で提供されたもの(.3、.59、.11)はRec(ほぼ)です。 601(標準偏差)係数。レコーディング709係数は、グレー= 0.2126R '+ 0.7152G' + 0.0722B 'であり、ここで、R'、G 'およびB'は、ガンマ補正された赤色、緑色および青色成分である。

2
追加された

このリンクを確認してください。私たちは大学でこれを行い、それは機能します。

それはあなたが入力と出力で必要とするすべてです。

0
追加された