お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル

"カスタムフィルタ"




{
TBitmapを使用してのカスタムフィルタ(5x5)のサンプルです。飛ぶ出す部分など
は補完しているのでかなり汚いコードですが、お役に立てれば幸いです。
}

type
  TOpValue = -999..999;  //オペレーターの許容範囲
  TOffSet  = -9999..9999;//オフセットの許容範囲
  TScale   = 1..9999;    //スケールの許容範囲

  //オペレーター
  TOperator    = array[-2..2, -2..2]of TOpValue;
  //マトリクス
  TMatrix      = array[-2..2, -2..2]of TRGBQuad;
  TQuadArray   = array[0..MaxInt div SizeOf(TRGBQuad) -1]of TRGBQuad;
  PQuadArray   = ^TQuadArray;
  TMatrixArray = array[-2..2]of PQuadArray;

//{$DEFINE ROUNDBYTE}

procedure CustomFilter(Source: TBitmap; Operator: TOperator;
  OffSet: TOffSet; Scale: TScale);
var
  Dest: TBitmap;
  x, y, W, H, yh, xw, mx, my, R, G, B: Integer;
  pSrcLine: TMatrixArray;
  pDstLine: PQuadArray;
  Matrix: TMatrix;
begin
  Source.PixelFormat := pf32bit;
  Dest := TBitmap.Create;
  try
    W  := Source.Width -1;
    xw := W -1;
    H  := Source.Height -1;
    yh := H -1;
    Dest.PixelFormat := pf32bit;
    Dest.Width       := Source.Width;
    Dest.Height      := Source.Height;
    for y := 0 to H do
    begin
      pDstLine := Dest.ScanLine[y];
      pSrcLine[0] := Source.ScanLine[y];
      //飛び出すラインは補完
      if y < 2 then
      begin
        if y = 0 then
        begin
          pSrcLine[-2] := Source.ScanLine[y];
          pSrcLine[-1] := Source.ScanLine[y];
        end else begin
          pSrcLine[-2] := Source.ScanLine[y];
          pSrcLine[-1] := Source.ScanLine[y-1];
        end;
      end else begin
        pSrcLine[-2] := Source.ScanLine[y-2];
        pSrcLine[-1] := Source.ScanLine[y-1];
      end;
      if y >= yh then
      begin
        if y = H then
        begin
          pSrcLine[1] := Source.ScanLine[y];
          pSrcLine[2] := Source.ScanLine[y];
        end else begin
          pSrcLine[1] := Source.ScanLine[y+1];
          pSrcLine[2] := Source.ScanLine[y];
        end;
      end else begin
        pSrcLine[1] := Source.ScanLine[y+1];
        pSrcLine[2] := Source.ScanLine[y+2];
      end;
      for x := 0 to W do
      begin
        {マトリクスにピクセルをマップする}
        for my := -2 to 2 do
          Matrix[0, my] := pSrcLine[my]^[x];
        //飛び出すピクセルは補完
        if x < 2 then
        begin
          if x = 0 then
          begin
            for my := -2 to 2 do
            begin
              Matrix[-1, my] := pSrcLine[my]^[x];
              Matrix[-2, my] := pSrcLine[my]^[x];
            end;
          end else begin
            for my := -2 to 2 do
            begin
              Matrix[-1, my] := pSrcLine[my]^[x-1];
              Matrix[-2, my] := pSrcLine[my]^[x-1];
            end;
          end;
        end else begin
          for my := -2 to 2 do
          begin
            Matrix[-1, my] := pSrcLine[my]^[x-1];
            Matrix[-2, my] := pSrcLine[my]^[x-2];
          end;
        end;
        if x >= xw then
        begin
          if x = W then
          begin
            for my := -2 to 2 do
            begin
              Matrix[1, my] := pSrcLine[my]^[x];
              Matrix[2, my] := pSrcLine[my]^[x];
            end;
          end else begin
            for my := -2 to 2 do
            begin
              Matrix[1, my] := pSrcLine[my]^[x+1];
              Matrix[2, my] := pSrcLine[my]^[x+1];
            end;
          end;
        end else begin
          for my := -2 to 2 do
          begin
            Matrix[1, my] := pSrcLine[my]^[x+1];
            Matrix[2, my] := pSrcLine[my]^[x+2];
          end;
        end;
        //演算(オペレーターに従って乗算)
        R := 0; G := 0; B := 0;
        for mx := -2 to 2 do
          for my := -2 to 2 do
          begin
            R := R + Matrix[mx, my].rgbRed   * Operator[mx, my];
            G := G + Matrix[mx, my].rgbGreen * Operator[mx, my];
            B := B + Matrix[mx, my].rgbBlue  * Operator[mx, my];
          end;
        //スケールで割ってオフセットを加算してできあがり
        R := Round(R / Scale) + OffSet;
        G := Round(G / Scale) + OffSet;
        B := Round(B / Scale) + OffSet;
{$IFDEF ROUNDBYTE}
        if R > 255 then R := 255 else if R < 0 then R := 0;
        if G > 255 then G := 255 else if G < 0 then G := 0;
        if B > 255 then B := 255 else if B < 0 then B := 0;
{$ENDIF}
        DWORD(pDstLine^[x]) := (R shl 16) or (G shl 8) or B;
      end;
    end;
    Source.Assign(Dest);
  finally
    Dest.Free;
  end;
end;

{使用例 (フォームにTImageとTButtonを貼り付けてイメージを読み込ませておい
てください)}
procedure TForm1.Button1Click(Sender: TObject);
var
  Operator: TOperator;
begin
  //エンボス(光源左上の場合)
  FillChar(Operator, SizeOf(TOperator), 0);
  Operator[-2, -2] := 1;
  Operator[2, 2]   := -1;
  CustomFilter(Image1.Picture.Bitmap, Operator, 128, 1);
end;

//                                               紅月 燐火(BZF05041)

Original document by 紅月 燐火      氏 ID:(BZF05041)


ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。

Copyright 1996-2002 Delphi Users' Forum