[BlueLeaf1336]> PROBLEMS> パターン認識への長い道のり>

パターン認識への長い道のり > グレイスケール変換

historyTOP

2006/04/17:作成

2006/04/17TOP

いきなりですが、パターン認識をやりたいと考えています。どんなパターンかというと顔です。画像の中の顔を見つけ出したいと、そう考えています。なぜか。それは、今オフラインなんでリンクを示せないのでまた別の時に書きます。

そこで、グレースケール変換です。カラー画像を直接扱うパターン認識処理って、勝手に思ってるだけですが、ないんじゃないかと。多分処理が重たいだけじゃないかと。ひょっとしたら2値画像で認識してしまうのかもしれませんが、とりあえず256色のグレースケールでやってみます。

とっかかりにふさわしく、完全無欠にパクってきました。

ソースコードTOP

//-----------------------------------------------------------------------------
//  グレースケール変換を行うクラス
type
    TTest = class
    protected
        FWork: TBitmap;
        FImage: TBitmap;
    public
        constructor Create();
        destructor Destroy(); override;
        procedure SetImage(Source: TBitmap);
    public
        property Image: TBitmap read FImage;
    end;

//-----------------------------------------------------------------------------
//  コンストラクタ
constructor TTest.Create();
begin
    FWork  := TBitmap.Create();
    FImage := TBitmap.Create();
end;

//-----------------------------------------------------------------------------
//  デストラクタ
destructor TTest.Destroy();
begin
    FWork.Free();
    FImage.Free();
end;

//-----------------------------------------------------------------------------
type
    TTriple = packed record B, G, R: Byte; end;
    PTriple = ^TTriple;

//-----------------------------------------------------------------------------
//  原画像セット
//  Subject: [Delphi:48275] Re: はじめまして
//  NTSC 加重平均法 最も品質が良さそう
procedure TTest.SetImage(Source: TBitmap);
var
    x, y, i: Integer;
    LogPalette: TMaxLogPalette;
    pSource: PTriple;
    pDest: PByte;
begin
    //  加工のためにイメージを転記
    FWork.Assign(Source);
    FWork.PixelFormat := pf24bit;

    //  最終イメージを設定
    FImage.PixelFormat := pf8Bit;
    FImage.Width := FWork.Width;
    FImage.Height := FWork.Height;

    with LogPalette do
    begin
        palNumEntries := 256;
        palVersion := $0300;
        for i := 0 to 255 do
        begin
            palPalEntry[i].peRed   := 255 - i;
            palPalEntry[i].peGreen := 255 - i;
            palPalEntry[i].peBlue  := 255 - i;
        end;
    end;
    FImage.Palette := CreatePalette(PLogPalette(@LogPalette)^);

    for y := 0 to FWork.Height - 1 do
    begin
        pSource := FWork.ScanLine[y];
        pDest := FImage.ScanLine[y];

        for x := 0 to FWork.Width - 1 do
        begin
            pDest^ := Round(255 - pSource.R * 0.298912 -
                                  pSource.G * 0.586611 -
                                  pSource.B * 0.114478);
            Inc(pSource);
            Inc(pDest);
        end;
    end;

    //  イメージを解放(2006.04.24  したらだめ?)
    //  FWork.FreeImage();
    //  FWork.ReleaseHandle();
end;

//-----------------------------------------------------------------------------
//  1000回変換してその平均時間を表示するテスト関数
procedure TForm1.Button1Click(Sender: TObject);
var
    Test: TTest;
    Tick: Cardinal;
    i: Integer;
begin
    Test := TTest.Create();
    Tick := GetTickCount();
    for i := 0 to 999 do
    begin
        Test.SetImage(Image1.Picture.Bitmap);
    end;
    Label1.Caption := FormatFloat('0.00[msec]', (GetTickCount() - Tick) / 1000);
    Image2.Picture.Bitmap.Assign(Test.Image);
    Test.Free();
end;

実行結果TOP

その前に、上のコードでは、グレースケール変換を行うだけのクラスを何の脈絡もなく作ってますが、将来的にはパターン認識を行うクラスに画像を渡して、その時点で必要ならグレースケール変換を行うような感じで考えているので、こんな妙な事になってます。

ですが、今のところメインの処理は SetImage メソッドであり、そのメソッドになんらオリジナルなところはありません。

300pixel x 400pixel のフルカラー画像ですが、多分 13msec というのは、画像処理にかかる時間としては破格に長いような気がします。多分ですけど。でも、この時間が問題になるのは、まだまだ先のことだろうと思いますので、とりあえずこれで良しとします。それに、どこをチューニングできるかもわかりませんし。

EOFTOP