エンボス処理
エンボス処理は、画像を浮き出したように見せる処理です。
画像のエッジの濃淡の差分を利用して、光が当たったように明るくする場所と、影になったように暗くする場所をエッジ部分につくり、浮きだしたように見せる処理です。
濃淡の方向と、差分用フイルターによって、凸になるか、凹になるか変わります。
フィルターを変えることによって、好みのエンボス処理を行います。
フィルター例
方向を変える例
上図は、差分データーを取り出すフィルターですが、エンボスの高さを変えるため、次の計算を行います。
グレーの場合
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.