エンボス処理

エンボスサンプル

 エンボス処理は、画像を浮き出したように見せる処理です。
画像のエッジの濃淡の差分を利用して、光が当たったように明るくする場所と、影になったように暗くする場所をエッジ部分につくり、浮きだしたように見せる処理です。
濃淡の方向と、差分用フイルターによって、凸になるか、凹になるか変わります。
フィルターを変えることによって、好みのエンボス処理を行います。

フィルター例
3x3
方向を変える例
方向サンプル
上図は、差分データーを取り出すフィルターですが、エンボスの高さを変えるため、次の計算を行います。

グレーの場合
グレー計算
128は、グレーの中間の値ですが、小さくすれば、暗くなり、大きくすれば明るいグレーの画像となります。
この計算結果は、255よりも大きくなることもあるし、ゼロより小さくなることもあるので、その値を超えないようにする必要があります。

カラーの場合

カラーエンボス

RGBは、赤、緑、青のうちのどれかの色を表します。
三色 色毎に:計算します。
この場合も、255より大きくなる場合もあるし、ゼロより小さくなることがあるので、その値を超えないようにします。

サンプルプログラム

unit EmbossMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.ExtDlgs, System.Types, System.UITypes,
  System.UIConsts, Math;

type
  TForm1 = class(TForm)
    FileOpen: TButton;
    OpenPictureDialog1: TOpenPictureDialog;
    EmbossBtn: TButton;
    SavePictureDialog1: TSavePictureDialog;
    FileSaveBtn: TButton;
    ScrollBox1: TScrollBox;
    Image1: TImage;
    ColorEmbossBtn: TButton;
    RadioGroup1: TRadioGroup;
    LabeledEdit1: TLabeledEdit;
    SourceBtn: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FileOpenClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FileSaveBtnClick(Sender: TObject);
    procedure EmbossBtnClick(Sender: TObject);
    procedure ColorEmbossBtnClick(Sender: TObject);
    procedure SourceBtnClick(Sender: TObject);
  private
    { Private 宣言 }
    procedure GrayEmboss;
    procedure ColorEmboss;
    procedure Light;          // エンボスフィルターの設定
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

type
  TPrgbarry = array[0..0] of Trgbtriple;      // 24ビットカラーレコード 32ビット用はTRGBQuadArray
  Prgbarray  = ^TPrgbarry;                    // ポインター
                                              // 配列のポインターが必要なだけなので、長さは1 [0..0]で問題ありません。
implementation

{$R *.dfm}

const
  OpenFileFilter =
    '画像ファイル|*.png;*.jpg;*.gif;*.bmp;*.tif;*.ico;*.wdp'+
    '|*.png|*.png' +
    '|*.jpg|*.jpg' +
    '|*.gif|*.gif' +
    '|*.bmp|*.bmp' +
    '|*.tif|*.tif' +
    '|*.ico|*.ico' +
    '|*.wdp|*.wdp';

  SaveFileFilter =
    '画像ファイル|*.png;*.jpg;*.gif;*.bmp;*.tif;*.wdp' +
    '|*.png|*.png' +
    '|*.jpg|*.jpg' +
    '|*.gif|*.gif' +
    '|*.bmp|*.bmp' +
    '|*.tif|*.tif' +
    '|*.wdp|*.wdp';

  RK    = 0.298912;                           // グレースケール輝度係数 赤
  GK    = 0.586611;                           // グレースケール輝度係数 緑
  BK    = 0.114478;                           // グレースケール輝度係数 青

var
  InBitmap        : TBitmap;                  // ビットマップ
  OutBitmap       : TBitmap;
  GHeight, GWidth : integer;                  // ソース画像サイズ
  BlueMat         : array of array of Byte;
  GreenMat        : array of array of Byte;
  RedMat          : array of array of Byte;
  YPPOS, YMPOS    : Integer;
  XPPOS, XMPOS    : Integer;
  EmbossK         : Double;

//================================================================
// 光りの効果方向設定 エンボスフィルターの設定
// バックの色濃度によって効果が逆になる場合もあります
// -1 0 0   0-1 0   0 0-1   0 0 0   1 0 0   0 1 0   0 0 1   0 0 0
//  0 0 0   0 0 0   0 0 0   1 0-1   0 0 0   0 0 0   0 0 0  -1 0 1
//  0 0 1   0 1 0   1 0 0   0 0 0   0 0-1   0-1 0  -1 0 0   0 0 0
//================================================================
procedure TForm1.Light;
var
  Check : Integer;
begin
  Val(LabeledEdit1.Text, EmbossK, Check);
  if (Check <> 0) or (EmbossK < 0) then EmbossK := 1;
  case RadioGroup1.ItemIndex of
    0 : begin         // 左上
      YPPOS :=  1;
      XPPOS :=  1;
      YMPOS := -1;
      XMPOS := -1;
    end;
    1 : begin         // 上
      YPPOS :=  1;
      XPPOS :=  0;
      YMPOS := -1;
      XMPOS :=  0;
    end;
    2 : begin         // 右上
      YPPOS :=  1;
      XPPOS := -1;
      YMPOS := -1;
      XMPOS :=  1;
    end;
    3 : begin         // 右
      YPPOS :=  0;
      XPPOS := -1;
      YMPOS :=  0;
      XMPOS :=  1;
    end;
    4 : begin         // 右下
      YPPOS := -1;
      XPPOS := -1;
      YMPOS :=  1;
      XMPOS :=  1;
    end;
    5 : begin         // 下
      YPPOS := -1;
      XPPOS :=  0;
      YMPOS :=  1;
      XMPOS :=  0;
    end;
    6 : begin         // 左下
      YPPOS := -1;
      XPPOS :=  1;
      YMPOS :=  1;
      XMPOS := -1;
    end;
    7 : begin         // 左
      YPPOS :=  0;
      XPPOS :=  1;
      YMPOS :=  0;
      XMPOS := -1;
    end;
  end;
end;

//=======================================
// グレーのエンボス
// 輝度変換後エンボス
// -1 0 0
//  0 0 0 X 係数 + 128
//  0 0 1
//=======================================
procedure TForm1.GrayEmboss;
var
  XX, YY  : Integer;
  PRGB    : Prgbarray;
  EmbD    : Smallint;
begin
// グレー輝度変換
  for YY := 0 to GHeight - 1 do begin
    PRGB := InBitmap.ScanLine[YY];
    for XX := 0 to GWidth - 1 do begin
      BlueMat[YY, XX] := Round(PRGB[XX].rgbtBlue  * BK +
                               PRGB[XX].rgbtGreen * GK +
                               PRGB[XX].rgbtRed   * RK);
    end;
  end;
// エンボス処理
  for YY := 0 to GHeight - 1 do begin
    PRGB := OutBitmap.ScanLine[YY];
    for XX := 0 to GWidth - 1 do begin
      // 最外周は処理しない
      if (YY = 0) or (XX = 0) or (YY = GHeight - 1) or (XX = GWidth - 1) then
        EmbD := BlueMat[YY, XX]
      // エンボス処理
      else begin
        EmbD := BlueMat[YY + YPPOS, XX + XPPOS] - BlueMat[YY + YMPOS, XX + XMPOS];
        EmbD := round(EmbD * EmbossK + 128);
        if EmbD > 255 then EmbD := 255;
        if EmbD < 0   then EmbD := 0;
      end;
      // 三色同じ値セット
      PRGB[XX].rgbtBlue := EmbD;
      PRGB[XX].rgbtGreen := EmbD;
      PRGB[XX].rgbtRed := EmbD;
    end;
  end;
  Image1.Picture.Bitmap := OutBitmap;                // 出力枠に出力
end;

//===================================
// カラーのエンボス
// -1 0 0
//  0 0 0 × 係数 + カラー
//  0 0 1
//===================================
procedure TForm1.ColorEmboss;
var
  XX, YY  : Integer;
  PRGB    : Prgbarray;
  EmbB    : Smallint;
  EmbG    : Smallint;
  EmbR    : Smallint;
begin
  // 三色の配列に分解
  for YY := 0 to GHeight - 1 do begin
    PRGB := InBitmap.ScanLine[YY];
    for XX := 0 to GWidth - 1 do begin
      BlueMat[YY, XX]   := PRGB[XX].rgbtBlue;
      GreenMat[YY, XX]  := PRGB[XX].rgbtGreen;
      RedMat[YY, XX]    := PRGB[XX].rgbtRed;
    end;
  end;
  // エンボス処理
  for YY := 0 to GHeight - 1 do begin
    PRGB := OutBitmap.ScanLine[YY];
    for XX := 0 to GWidth - 1 do begin
      // 最外周は処理しない
      if (YY = 0) or (XX = 0) or (YY = GHeight - 1) or (XX = GWidth - 1) then begin
        EmbB := BlueMat[YY, XX];
        EmbG := GreenMat[YY, XX];
        EmbR := RedMat[YY, XX];
      end
      // 三色エンボス処理
      else begin
        // 青
        EmbB := BlueMat[YY + YPPOS, XX + XPPOS] - BlueMat[YY + YMPOS, XX + XMPOS];
        EmbB := round(EmbB * EmbossK + BlueMat[YY, XX]);
        if EmbB > 255 then EmbB := 255;
        if EmbB < 0   then EmbB := 0;
        // 緑
        EmbG := GreenMat[YY + YPPOS, XX + XPPOS] - GreenMat[YY + YMPOS, XX + XMPOS];
        EmbG := round(EmbG * EmbossK + GreenMat[YY, XX]);
        if EmbG > 255 then EmbG := 255;
        if EmbG < 0   then EmbG := 0;
        // 赤
        EmbR := RedMat[YY + YPPOS, XX + XPPOS] - RedMat[YY + YMPOS, XX + XMPOS];
        EmbR := round(EmbR * EmbossK + RedMat[YY, XX]);
        if EmbR > 255 then EmbR := 255;
        if EmbR < 0   then EmbR := 0;
      end;
      // 三色それぞれの値をセット
      PRGB[XX].rgbtBlue  := EmbB;
      PRGB[XX].rgbtGreen := EmbG;
      PRGB[XX].rgbtRed   := EmbR;
    end;
  end;
  Image1.Picture.Bitmap := OutBitmap;                // 出力枠に出力
end;

procedure TForm1.SourceBtnClick(Sender: TObject);
begin
  Image1.Picture.Bitmap := inBitmap;                // 出力枠に出力
end;

procedure TForm1.ColorEmbossBtnClick(Sender: TObject);
begin
  Light;                                            // エンボスフィルターの設定
  ColorEmboss;                                      // カラーエンボス
  FileSaveBtn.Enabled   := True;
  SourceBtn.Enabled := True;
end;

procedure TForm1.EmbossBtnClick(Sender: TObject);
begin
  Light;                                            // エンボスフィルターの設定
  GrayEmboss;                                       // グレーエンボス
  FileSaveBtn.Enabled   := True;
  SourceBtn.Enabled := True;
end;

// ファイルのオープン WIC がファイルの種類が多いので使用
procedure TForm1.FileOpenClick(Sender: TObject);
var
  WIC         : TWICImage;
  InFilename  : String;
begin
  EmbossBtn.Enabled  := False;
  ColorEmbossBtn.Enabled := False;
  FileSaveBtn.Enabled   := False;
  SourceBtn.Enabled := False;
  OpenPictureDialog1.Filter := OpenFileFilter;                // ファイルオープンフィルターの設定
  if OpenPictureDialog1.Execute then                          // ファイルが指定されたら
    begin
      WIC := TWICImage.Create;                                // TWICImageの生成
      try
        InFilename := OpenPictureDialog1.FileName;            // ファイル名の取得
        WIC.LoadFromFile(InFilename);                         // 画像の読み込み
        GHeight := WIC.Height;                                // 画像高さ取得
        GWidth  := WIC.Width;                                 // 画像幅
        InBitmap.Width    := GWidth;
        InBitmap.Height   := GHeight;
        InBitmap.Canvas.Draw(0, 0, WIC);                      // DrawでInBitmapに入力画像設定フォーマット24ビットに変換されます
        Image1.Picture.Bitmap := InBitmap;
        OutBitmap.Width := GWidth;
        OutBitmap.Height:= GHeight;
      finally
        WIC.Free;                                             // TWICImage 解放
      end;
    end
    else Exit;
  Setlength(BlueMat,        GHeight, GWidth);
  Setlength(GreenMat,       GHeight, GWidth);
  Setlength(RedMat,         GHeight, GWidth);
  EmbossBtn.Enabled   := True;
  ColorEmbossBtn.Enabled := True;
end;

// ファイルのオープン
procedure TForm1.FileSaveBtnClick(Sender: TObject);
var
  WIC     : TWicImage;
  WICF    : TWicImageFormat;

  Fname   : String;
  ExeStr  : String;
  FnameTop: String;
  Findex  : integer;

  function WFormatSet: Boolean;                                            // 拡張子によるファイルフォーマット設定
  begin
    Result := false;
    ExeStr := LowerCase(ExeStr);
    if ExeStr = '.jpg'  then  begin WICF := Wifjpeg; Result := True; end;
    if ExeStr = '.jpeg' then  begin WICF := Wifjpeg; Result := True; end;
    if ExeStr = '.tif'  then  begin WICF := Wiftiff; Result := True; end;
    if ExeStr = '.tiff' then  begin WICF := Wiftiff; Result := True; end;
    if ExeStr = '.png'  then  begin WICF := Wifpng;  Result := True; end;
    if ExeStr = '.gif'  then  begin WICF := Wifgif;  Result := True; end;
    if ExeStr = '.bmp'  then  begin WICF := Wifbmp;  Result := True; end;
    if ExeStr = '.wdp'  then  begin WICF := WifWMPhoto; Result := True; end;
    if ExeStr = '.hdp'  then  begin WICF := WifWMPhoto; Result := True; end;
  end;

begin
  SavePictureDialog1.Filter := SaveFileFilter;
//  SavePictureDialog1.DefaultExt := GraphicExtension(TWicImage);
  if not SavePictureDialog1.Execute then exit;
  ExeStr := ExtractFileExt(SavePictureDialog1.FileName);
  if ExeStr = '' then begin                                                // 拡張子がなかったら
    Findex := SavePictureDialog1.FilterIndex;                              // FilterIndexによる拡張子の設定
    case Findex of
      1, 3 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.jpg');   // 拡張子の設定
         2 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.png');   // 拡張子の設定
         4 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.gif');   // 拡張子の設定
         5 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.bmp');   // 拡張子の設定
         6 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.tif');   // 拡張子の設定
         7 : Fname := ChangeFileExt(SavePictureDialog1.FileName,'.wdp');   // 拡張子の設定
    end;
  end
  else
    Fname := SavePictureDialog1.FileName;
  ExeStr := ExtractFileExt(Fname);                                         // 拡張子だけ取り出し
  if not WFormatSet then begin                                             // 拡張子によるファイルフォーマット設定と確認
    application.MessageBox('ファイルの拡張子が間違っています。','注意', 0);
    exit;
  end;
  FnameTop := ExtractFileName(Fname);                                      // ファイル名だけ取り出し
  if Length(FnameTop) = Length(ExeStr) then begin                          // ファイル名の長さ確認
    application.MessageBox('ファイル名がありません。','注意', 0);
    exit;
  end;

  if FileExists(Fname) then                                                // ファイル名によるファイル検索
    if MessageDlg('既に同じ名前のファイルがあります上書きしますか ' + ExtractFileName(Fname) + '?',
                                                      mtConfirmation, [mbYes, mbNo], 0, mbNo) = IDNo then exit;

  WIC := TWicImage.Create;                                                 // TWicImage生成
  try
    WIC.Assign(OutBitmap);                                                  // TWicImageにビットマップデーター割り付け
    WIC.ImageFormat := WICF;                                               // 保存フォーマットセット
    WIC.SaveTofile(Fname);                                                 // ファイルの書き出し
  finally
    WIC.Free;                                                              // TWicImage解放
  end;
end;

// 初期設定
procedure TForm1.FormCreate(Sender: TObject);
begin
  EmbossBtn.Enabled := False;
  ColorEmbossBtn.Enabled := False;
  FileSaveBtn.Enabled   := False;
  SourceBtn.Enabled := False;
  InBitmap      := TBitmap.Create;        // 入力画像用
  OutBitmap     := TBitmap.Create;        // 24ビット出力用
  InBitmap.PixelFormat    := pf24bit;     // 24ビットカラーに設定
  OutBitmap.PixelFormat   := pf24bit;     // 24ビットカラーに設定
end;

// ビットマップの解放
procedure TForm1.FormDestroy(Sender: TObject);
begin
  InBitmap.Free;
  OutBitmap.Free;
end;

end.

    download EmbossProcessing.zip

画像処理一覧へ戻る

      最初に戻る