システム開発・Webサイト構築 プラスラス

2008/2/16 土曜日

【.NET】カラー行列(ColorMatrix)で画像をグレースケール化する

このエントリーを含むはてなブックマーク Yahoo!ブックマークに登録 Google ブックマーク del.icio.us

C#、VB.NETでカラーの画像をグレースケール化するのに、ColorMatrixが使えます。

グレースケールとは、全てのピクセルにおいてR(赤)とG(緑)とB(青)の値が等しくなるような色、つまり、白、灰色(濃淡あわせて)、黒だけで描画した状態です。

NTSC加重平均法によるグレースケール化
(写真はうちの犬です。)

今回、カラー画像をグレースケール化するのに使用するのは、NTSC加重平均法と呼ばれる方法です。

(ColorMatrixの説明は、前回のカラー行列(ColorMatrix)で画像のRGBの値を調整するをご覧ください。)

カラーをグレーにするには?

カラーをグレーにするには、各ピクセルの明るさの違いだけを残して、RとGとBの差がないような色にします。

単純なのは、

(R + G + B) ÷ 3

という風に平均をとってしまう方法です。

しかし、人間の目には、色の違いによって明るさが違うように見えます。

色による明るさの感じ方

下の画像は、R(赤)とG(緑)とB(青)のうちいずれか一つを最大にし、他はゼロにした色で塗った四角形です。

RGBの各値をそれぞれ最大にした色

しかし、おそらく、緑が一番明るく、次に赤、一番暗いのは青と感じるのではないでしょうか?

より自然な感じにするには、この色による心理的な感じ方の差を反映する方法を用いた方が良いです。

NTSC加重平均法

NTSCは、National Television Standards Committeeによって定められたアメリカや日本で使われるアナログのテレビに使われる規格です。

NTSCでは、白黒放送と両立させるために輝度信号と色信号にわけられています(YIQカラーモデル)

色による明るさの感じ方の違いを考慮しており、輝度信号(Y)とRGBの関係は以下の式で表されます。

Y = R × 0.298912 + G × 0.586611 + B × 0.114478

プログラムのサンプル

上記のRGBと輝度との関係をプログラムに使ってみます。

最終的にRGBのそれぞれに上の式のYを入れます。

'VB.NETのサンプル

'(Imports System.Drawing.Imagingが必要)

'ファイルを読み込む
Dim sourceImage As Bitmap = _
    DirectCast(Bitmap.FromFile("ファイル名.bmp", True), Bitmap)

 'RGBの比率(YIQカラーモデル)
Const r As Single = 0.298912F
Const g As Single = 0.586611F
Const b As Single = 0.114478F

'ColorMatrixにセットする行列を 5 * 5 の配列で用意
'入力のRGBの各チャンネルを重み付けをした上で、
'出力するRGBがR = G = B となるような行列をセット
Dim matrixElement As Single()() = _
                   {New Single() {r, r, r, 0, 0}, _
                    New Single() {g, g, g, 0, 0}, _
                    New Single() {b, b, b, 0, 0}, _
                    New Single() {0, 0, 0, 1, 0}, _
                    New Single() {0, 0, 0, 0, 1}}

'ColorMatrixオブジェクトの作成
Dim matrix As ColorMatrix = New ColorMatrix(matrixElement)

'ImageAttributesにセット
Dim attr As ImageAttributes = New ImageAttributes()

attr.SetColorMatrix(matrix)

Dim imageWidth As Integer = sourceImage.Width
Dim imageHeight As Integer = sourceImage.Height

'新しいビットマップを用意
Dim changedImage As Bitmap = New Bitmap(imageWidth, imageHeight)

'新しいビットマップにImageAttributesを指定して
'元のビットマップを描画
Dim graph As Graphics = Graphics.FromImage(changedImage)

graph.DrawImage(sourceImage, _
                New Rectangle(0, 0, imageWidth, imageHeight), _
                0, 0, imageWidth, imageHeight, _
                GraphicsUnit.Pixel, _
                attr)

graph.Dispose()

'--表示や保存などの処理をここに記述--

'使い終わったら後始末
'sourceImage.Dispose()
'changedImage.Dispose()
//C#のサンプル

//(using System.Drawing.Imaging;が必要)

//元のイメージを読み込む
Bitmap sourceImage =
    (Bitmap)Bitmap.FromFile(@"ファイル名.bmp", true)

//RGBの比率(YIQカラーモデル)
const float r = 0.298912F;
const float g = 0.586611F;
const float b = 0.114478F;

//ColorMatrixにセットする行列を 5 * 5 の配列で用意
//入力のRGBの各チャンネルを重み付けをした上で、
//出力するRGBがR = G = B となるような行列をセット
float[][] matrixElement =
                      {new float[]{r, r, r, 0, 0},
                       new float[]{g, g, g, 0, 0},
                       new float[]{b, b, b, 0, 0},
                       new float[]{0, 0, 0, 1, 0},
                       new float[]{0, 0, 0, 0, 1}};

//ColorMatrixオブジェクトの作成
ColorMatrix matrix = new ColorMatrix(matrixElement);

//ImageAttributesにセット
ImageAttributes attr = new ImageAttributes();
attr.SetColorMatrix(matrix);

int imageWidth = sourceImage.Width;
int imageHeight = sourceImage.Height;

//新しいビットマップを用意
Bitmap changedImage = new Bitmap(imageWidth, imageHeight);

//新しいビットマップにImageAttributesを指定して
//元のビットマップを描画
Graphics graph = Graphics.FromImage(changedImage);

graph.DrawImage(sourceImage,
                new Rectangle(0, 0, imageWidth, imageHeight),
                0, 0, imageWidth, imageHeight,
                GraphicsUnit.Pixel,
                attr);

graph.Dispose();

//--表示や保存などの処理をここに記述--

//使い終わったら後始末
//sourceImage.Dispose();
//changedImage.Dispose();

サンプルプログラムのダウンロード

グレースケールの実行形式ファイル

グレースケールのVB.NETソースコード

グレースケールのC#ソースコード

関連図書

ディジタル画像処理の基礎と応用 改訂版―Visual C#.NET&Visual Basic.NETによる 基本概念から

関連記事

タグ: ,
Filed under: C#,Programming,VB.NET — Nakai @ 6:02:05

2件のコメント »

  1. PictureBoxのImageをグレーアウト C#

    ツールバーなどで表示する画像を そのボタンが使えないときに(Enabled=false)
    画像をグレーアウト処理したいと思い調べていると
    CommentOut? » 【.NET】カラー行列(ColorMatrix)で画像をグレー…

    トラックバック by SOHOプログラマのぼやき @Links[アットリンクス] — 2008/6/5 木曜日 @ 18:29:10

  2. 大変参考になりました。

    今後も利用させていただきます!

    コメント by しおじ — 2008/11/25 火曜日 @ 16:50:18

この投稿へのコメントの RSS フィード。 TrackBack URL

コメントする

HTML convert time: 0.873 sec. Powered by WordPress