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

パターン認識への長い道のり > 画像を平滑化して少々のズレを吸収する

historyTOP

2006/04/24:作成

2006/04/24TOP

前回は完全に同じサイズの画像を比較して「似ている度」を評価するために、同じ位置にあるピクセルの階調値の差分の合計を計算し、合計値が小さいほうがより似ている、としていました。が、この方法では1ピクセルずれているだけでぜんぜん違うものとして判定されてしまう可能性があります。でも、多分、現実の写真とかならその程度のズレでどうこうなるようなものでもないとは思いますが。

そこで、画像を平滑化(ぼかし?)して、近くのピクセル(厳密にはあるピクセルの周囲8ピクセル)の階調値を反映させて、少々のズレなら吸収できるように(と勝手にいってますが実際にそういう意図かどうかは知りません)しました。

結論からいうと、単純に平均点があがっただけのような気が...。また、周囲1ピクセルは範囲外処理をサボってそのまま(平滑化処理をしていない)です。

線形平滑化フィルタを行うクラスTOP

//-----------------------------------------------------------------------------
//  線形平滑化フィルタを行うクラス
type
    TTest = class
    protected
        FWork: TBitmap;
        FImage: TBitmap;
    public
        constructor Create();
        destructor Destroy(); override;
        procedure LinearSmoothingGrayScaleImage(Source: TBitmap);
    public
        property Image: TBitmap read FImage;
    end;

//-----------------------------------------------------------------------------
//  コンストラクタ
constructor TTest.Create();
var
    i: Integer;
    LogPalette: TMaxLogPalette;
begin
    FWork  := TBitmap.Create();
    FImage := TBitmap.Create();

    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)^);
    FImage.PixelFormat := pf8bit;
end;

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

//-----------------------------------------------------------------------------
//  256色グレースケール画像限定線形平滑化フィルタ
procedure TTest.LinearSmoothingGrayScaleImage(Source: TBitmap);
const
    WEIGHT: array[0..2] of array[0..2] of Byte
            = ((1, 1, 1), (1, 2, 1), (1, 1, 1));
    DIVVAL = 10;
var
    x, y: Integer;
    pSource: array[0..2] of PByteArray;
    pDest: PByteArray;
begin
    //  加工のためにイメージを転記
    FWork.Assign(Source);
    FWork.PixelFormat := pf8bit;

    //  最終イメージを設定
    FImage.Assign(FWork);

    //  画像の端っこ1ピクセルは放置する(問題がおきたら対処する)

    //  フィルター処理
    for y := 1 to FWork.Height - 2 do
    begin
        pSource[0] := FWork.ScanLine[y - 1];
        pSource[1] := FWork.ScanLine[y];
        pSource[2] := FWork.ScanLine[y + 1];
        pDest := FImage.ScanLine[y];

        for x := 1 to FWork.Width - 2 do
        begin
            pDest[x] := Trunc((  WEIGHT[0][0] * pSource[0][x - 1]
                               + WEIGHT[0][1] * pSource[0][x]
                               + WEIGHT[0][2] * pSource[0][x + 1]
                               + WEIGHT[1][0] * pSource[1][x - 1]
                               + WEIGHT[1][1] * pSource[1][x]
                               + WEIGHT[1][2] * pSource[1][x + 1]
                               + WEIGHT[2][0] * pSource[2][x - 1]
                               + WEIGHT[2][1] * pSource[2][x]
                               + WEIGHT[2][2] * pSource[2][x + 1]) / DIVVAL);
        end;
    end;
end;

実行結果TOP

TestMatch2.zip(223,255Bytes) ソースコードと実行ファイルです。いつものとおり画像ファイルをフォームに抱え込んでいるので、えらくサイズがでかくなってますが、中身のほうはサイズに比例してません。

ベースは、前回のプログラムですが、原画像とテンプレート画像に平滑化処理を行ってから「似ている度」の評価を行うようにしました。前述したとおり、単に平均点があがっただけのような気がします。

左側がその平滑化処理を施したもので、右側が前回の結果です。実際には、図の左に前回使用したものと同じマインスイーパのキャプチャ画像をグレースケール変換したものがあります。

EOFTOP