OpenCVSharpで画像をグレースケールに変換

OpenCVSharp コンピュータ

OpenCVには画像を扱う機能が沢山あります。その中からカラー画像をグレースケールに変換してみたいと思います。

OpenCVSharpの導入方法

ソース

// 
// グレイスケール
// 

using System;
using System.Windows.Forms;
using System.Drawing;

using OpenCvSharp;
using OpenCvSharp.Extensions;

// コンパイル
// csc gray.cs /r:OpenCvSharp.dll /r:OpenCvSharp.Extensions.dll

class Form1 : Form
{
    PictureBox picbox1;

    // コンストラクタ
    Form1()
    {
        picbox1 = new PictureBox {
            Dock = DockStyle.Fill,
            SizeMode = PictureBoxSizeMode.Zoom,
        };
        this.Controls.Add(picbox1);

        string path = @"H:\csharp\opencv\sample.png";

        using (var dst = new Mat())
        using (var src = new Mat(path))
        {
            // グレイスケール
            Cv2.CvtColor(src, dst, ColorConversionCodes.RGB2GRAY);
            
            var bmp = BitmapConverter.ToBitmap(dst);
            Console.WriteLine("Flags:{0} ", bmp.Flags); // 2...ImageFlagsHasAlpha
            Console.WriteLine("PixelFormat:{0}", bmp.PixelFormat); // Format8bppIndexed

            var pallet = bmp.Palette;
            Console.WriteLine("Pallet.Flags:{0}", pallet.Flags); // 4...配列内の色はハーフトーン値です。
            for(int i = 0; i < pallet.Entries.Length; i++)
            {
                Console.WriteLine("{0} {1}", i, pallet.Entries[i]);
            }


            picbox1.Image = bmp;
        }
    }
    // エントリーポイント
    [STAThread]
    static void Main()
    {
        Application.Run(new Form1());
    }
}

カラーをグレイスケールに変換しているのはCv2.CvtColor(src, dst, ColorConversionCodes.RGB2GRAY);の部分です。
1行で済んでしまうあたりが大変すばらしい。正直画像加工は専門知識が無いとプログラミングは難しいので目的の機能を関数で呼び出せるOpenCVを使えば大変楽が出来そうです。

結果

元画像

グレースケール

カラーデータ

見た目グレイスケールになりましたが、Bitmapオブジェクトとしてピクセルを表現するカラーデータの形式を確認してみたいと思います。

ビットマップオブジェクトのPixelFormatを確認したところFormat8bppIndexedとなっておりました。
意味をMicrosoftのサイトで確認したところ以下のような説明がありました。

この形式が 1 ピクセルあたり 8 ビットであり、インデックス付きであることを指定します。 したがって、カラー テーブルには 256 色含まれています。

グレースケールだと256諧調の明暗を表現するので1ピクセルあたり8ビットで0~255で表現することが出来そうですが、カラーテーブルやインデックスなどの用語を見ると、単純にそういことでは無いようです。

想像すると256パターンの色をもつパレット(カラーテーブル)があり、ピクセル配列の値(8ビット:0-255)はパレットの色番号(インデックス)に割り当てられるということだと思われます。

とは言え、グレースケールですので結局、ピクセルの数値=パレットの色番号(インデックス)=グレースケールの256諧調の明暗になっていると思われます。

Bitmap.Palletプロパティからカラーテーブルの配列の中身を見てみると以下の値になっていました。

0 Color [A=255, R=0, G=0, B=0]
1 Color [A=255, R=1, G=1, B=1]
2 Color [A=255, R=2, G=2, B=2]
3 Color [A=255, R=3, G=3, B=3]

~中略~

253 Color [A=255, R=253, G=253, B=253]
254 Color [A=255, R=254, G=254, B=254]
255 Color [A=255, R=255, G=255, B=255]

最左の数値のインデック番号とRGBの値が同じです。Aのアルファチャンネルは255ですので不透明度(?)が100%になります。
グレースケールで256色のパレットだと、一見回りくどい構造にも見えますが、8ビットでアルファチャンネルを表現できる分お得な構造なんだと思います。

コメント