RGBをHSVに変換して指定した色相範囲を変換する(VCL) ~Delphiでお手軽プログラミング
(参考)バイキュービック法(bicubic)で拡大縮小する(VCL)
(参考)バイキュービック法(bicubic)で拡大縮小する(FMX)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(VCL)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(FMX)
(参考)ガンマ(gamma)補正を画像に適用する(VCL)
(参考)ガンマ(gamma)補正を画像に適用する(FMX)
(参考)ソーベルフィルタ(Sobel filter)で境界(エッジ)検出(VCL)
プロジェクトの作成とソースコードの記述
プロジェクトを新規作成(VCLアプリケーション)し、以下のようにコンポーネントを配置する。Image4のPictureプロパティから、色相を変換したい画像をロードしておく。
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Imaging.jpeg,Vcl.Imaging.pngimage; type TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; Label3: TLabel; ScrollBar1: TScrollBar; ScrollBar2: TScrollBar; ScrollBar3: TScrollBar; Image1: TImage; Image2: TImage; Image3: TImage; Button1: TButton; ScrollBar4: TScrollBar; Label4: TLabel; ScrollBox1: TScrollBox; Image4: TImage; ScrollBox2: TScrollBox; Image5: TImage; procedure FormCreate(Sender: TObject); procedure Image4MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure ScrollBar1Change(Sender: TObject); procedure ScrollBar2Change(Sender: TObject); procedure ScrollBar4Change(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } procedure DrawHue(); end; TRGB=record B,G,R:Byte; end; TRGBArr=array[0..32767] of TRGB; PRGBArr=^TRGBArr; //H(0~360),S(0~1),V(0~1) THSV=record H,S,V:Single; end; //HSVとは // 色相(Hue 0~360°) // 彩度(Saturation・Chroma 0~100%) // 明度(Value・Brightness 0~100%) //RGB から HSV(HSB) に変換 function RGBtoHSV(frgb:TRGB):THSV; //HSV(HSB) から RGB に変換 function HSVtoRGB(fhsv:THSV):TRGB; var Form1: TForm1; implementation {$R *.dfm} uses System.Math; //RGB から HSV(HSB) に変換 function RGBtoHSV(frgb:TRGB):THSV; var RGBMax,RGBMin:Byte; begin RGBMax:=System.Math.Max(frgb.R,frgb.G); RGBMax:=System.Math.Max(RGBMax,frgb.B); RGBMin:=System.Math.Min(frgb.R,frgb.G); RGBMin:=System.Math.Min(RGBMin,frgb.B); //色相(Hue 0~360°) if RGBMax=RGBMin then result.H:=0 else if frgb.R=RGBMax then result.H:=60*(frgb.G-frgb.B)/(RGBMax-RGBMin) else if frgb.G=RGBMax then result.H:=60*(frgb.B-frgb.R)/(RGBMax-RGBMin)+120 else result.H:=60*(frgb.R-frgb.G)/(RGBMax-RGBMin)+240; result.H:=FMod(result.H, 360); if result.H<0 then result.H:=result.H+360; //彩度(Saturation or Chroma 0~100%) if RGBMax=0 then result.S:=0 else result.S:=(RGBMax-RGBMin) / RGBMax; //明度(Value or Brightness 0~100%) result.V:=RGBMax/255; end; //HSV(HSB) から RGB に変換 function HSVtoRGB(fhsv:THSV):TRGB; var RGBMax,RGBMin:Byte; begin fhsv.H:=FMod(fhsv.H,360); if fhsv.H<0 then fhsv.H:=fhsv.H+360; RGBMax:=Round(fhsv.V*255); RGBMin:=Round(RGBMax-(fhsv.S*RGBMax)); if fhsv.S=0 then begin result.R:=RGBMax; result.G:=RGBMax; result.B:=RGBMax; end else if fhsv.H<60 then begin result.R:=RGBMax; result.G:=Round((fhsv.H- 0)/60*(RGBMax-RGBMin)+RGBMin); result.B:=RGBMin; end else if fhsv.H<120 then begin result.R:=Round((120-fhsv.H)/60*(RGBMax-RGBMin)+RGBMin); result.G:=RGBMax; result.B:=RGBMin; end else if fhsv.H<180 then begin result.R:=RGBMin; result.G:=RGBMax; result.B:=Round((fhsv.H-120)/60*(RGBMax-RGBMin)+RGBMin); end else if fhsv.H<240 then begin result.R:=RGBMin; result.G:=Round((240-fhsv.H)/60*(RGBMax-RGBMin)+RGBMin); result.B:=RGBMax; end else if fhsv.H<300 then begin result.R:=Round((fhsv.H-240)/60*(RGBMax-RGBMin)+RGBMin); result.G:=RGBMin; result.B:=RGBMax; end else begin result.R:=RGBMax; result.G:=RGBMin; result.B:=Round((360-fhsv.H)/60*(RGBMax-RGBMin)+RGBMin); end; end; { TForm1 } { Image4.Picture.Bitmap 画像で 色相が ScrollBar1.Position ± ScrollBar2.Position のピクセルの 色相を ScrollBar3.Position ± ScrollBar2.Position に変換 [つまり色相を+(ScrollBar3.Position-ScrollBar1.Position)] し、 Image5.Picture.Bitmap に描画する } procedure TForm1.Button1Click(Sender: TObject); var sbmp,dbmp:TBitmap; fsrgb,fdrgb:PRGBArr; frgb:TRGB; fhsv:THSV; x,y:Integer; h1,h2:Integer; h11,h12,h21,h22:Integer; begin sbmp:=TBitmap.Create; dbmp:=TBitmap.Create; try sbmp.Assign(Image4.Picture.Graphic); sbmp.PixelFormat:=pf24bit; dbmp.Width:=sbmp.Width; dbmp.Height:=sbmp.Height; dbmp.PixelFormat:=pf24bit; for y := 0 to sbmp.Height-1 do begin fsrgb:=sbmp.ScanLine[y]; fdrgb:=dbmp.ScanLine[y]; for x := 0 to sbmp.Width-1 do begin frgb.R:=fsrgb[x].R; frgb.G:=fsrgb[x].G; frgb.B:=fsrgb[x].B; fhsv:=RGBtoHSV(frgb); //色相(Hue 0~360°)の変換範囲を求める //ScrollBar1.Position ± ScrollBar2.Positionの範囲 h1:=ScrollBar1.Position-ScrollBar2.Position; h2:=ScrollBar1.Position+ScrollBar2.Position; h11:=h1; h12:=h2; h21:=-1; h22:=-1; if h1<0 then begin h11:=h1+360; h12:=360; h21:=0; h22:=h2; end else if h2>=360 then begin h11:=h1; h12:=360; h21:=0; h22:=h2-360; end; //色相(Hue 0~360°)の変換範囲内のピクセルのみ色相を変換する if ((fhsv.H>=h11) and (fhsv.H<h12)) OR ((fhsv.H>=h21) and (fhsv.H<h22)) then begin //色相(Hue 0~360°)を変換する fhsv.H:=fhsv.H+(ScrollBar3.Position-ScrollBar1.Position); fhsv.H:=FMod(fhsv.H,360); frgb:=HSVtoRGB(fhsv); fdrgb[x].R:=frgb.R; fdrgb[x].G:=frgb.G; fdrgb[x].B:=frgb.B; end else begin //色相を変換しないピクセルの場合 fdrgb[x].R:=fsrgb[x].R; fdrgb[x].G:=fsrgb[x].G; fdrgb[x].B:=fsrgb[x].B; end; end; end; Image5.Picture.Bitmap.Assign(dbmp); finally sbmp.Free; dbmp.Free; end; Image2.Invalidate; ScrollBar4Change(nil); end; procedure TForm1.DrawHue(); var i:Integer; frgb:TRGB; fhsv:THSV; hmax,hmin:Integer; begin fhsv.S:=1; fhsv.V:=1; hmin:=ScrollBar1.Position-ScrollBar2.Position; hmax:=ScrollBar1.Position+ScrollBar2.Position; image2.Width:=hmax-hmin; image2.Picture.Bitmap.Width:=Image2.Width; for i := hmin to hmax do begin fhsv.H:=i; frgb:=HSVtoRGB(fhsv); //変換対象の色相の範囲を表示 image2.Picture.Bitmap.Canvas.Pen.Color:=RGB(frgb.R,frgb.G,frgb.B); image2.Picture.Bitmap.Canvas.MoveTo(i-hmin,0); image2.Picture.Bitmap.Canvas.LineTo(i-hmin,Image2.Height); end; end; procedure TForm1.FormCreate(Sender: TObject); var fhsv:THSV; frgb:TRGB; i:integer; bmp:TBitmap; begin if Assigned(Image4.Picture.Graphic) then begin bmp:=TBitmap.Create; try bmp.Assign(Image4.Picture.Graphic); Image4.Picture.Bitmap.Assign(bmp); finally bmp.Free; end; end; //変換対象の色相中心(度) ScrollBar1.Width:=359+20*2; ScrollBar1.Max:=359; ScrollBar1.Min:=0; ScrollBar1.Position:=0; //変換対象の色相中心の幅(度)(変換対象色相中心 ± 幅 が対象) ScrollBar2.Width:=180+20*2; ScrollBar2.Max:=180; ScrollBar2.Min:=1; ScrollBar2.Position:=10; //変換後の色相中心(度)(変換後色相中心 ± 幅 に色相を変換する) ScrollBar3.Width:=359+20*2; ScrollBar3.Max:=359; ScrollBar3.Min:=1; ScrollBar3.Position:=30; //画像の表示倍率 ScrollBar4.Width:=100; ScrollBar4.Min:=10; ScrollBar4.Max:=200; ScrollBar4.Position:=50; //変換元画像表示 Image4.Left:=0; Image4.Top:=0; Image4.Proportional:=True; Image4.Stretch:=True; Image4.Cursor:=crCross; //変換した画像表示用 Image5.Left:=0; Image5.Top:=0; Image5.Proportional:=True; Image5.Stretch:=True; Image5.Picture.Bitmap.PixelFormat:=pf24bit; //色相(0~359°)中心の表示用 Image1.Width:=360; Image1.Height:=8; Image1.Picture.Bitmap.Width:=360; Image1.Picture.Bitmap.Height:=8; Image1.Picture.Bitmap.PixelFormat:=pf24bit; //変換後の色相(色相中心±幅) 表示用 Image3.Width:=360; Image3.Height:=8; Image3.Picture.Bitmap.Width:=360; Image3.Picture.Bitmap.Height:=8; Image3.Picture.Bitmap.PixelFormat:=pf24bit; ////色相(Hue 0~360°)の描画 fhsv.S:=1; fhsv.V:=1; for i := 0 to 359 do begin fhsv.H:=i; frgb:=HSVtoRGB(fhsv); image1.Picture.Bitmap.Canvas.Pen.Color:=RGB(frgb.R,frgb.G,frgb.B); image1.Picture.Bitmap.Canvas.Pen.Style:=psSolid; image1.Picture.Bitmap.Canvas.MoveTo(i,0); image1.Picture.Bitmap.Canvas.LineTo(i,image3.Height); image3.Picture.Bitmap.Canvas.Pen.Color:=RGB(frgb.R,frgb.G,frgb.B); image3.Picture.Bitmap.Canvas.Pen.Style:=psSolid; image3.Picture.Bitmap.Canvas.MoveTo(i,0); image3.Picture.Bitmap.Canvas.LineTo(i,image3.Height); end; //変換対象の色相幅(色相中心±幅)表示用 Image2.Height:=8; Image2.Picture.Bitmap.Height:=Image1.Height; DrawHue(); ScrollBar4Change(nil); end; procedure TForm1.Image4MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var col:TColor; frgb:TRGB; fhsv:THSV; pt:TPoint; begin //元画像でマウスボタンが押されたとき、 //マウスダウンした対象ピクセルの色相(0~359度)を取得して //ScrollBar1.Positionに設定する try pt.X:=X*100 div ScrollBar4.Position; pt.Y:=Y*100 div ScrollBar4.Position; col:=Image4.Picture.Bitmap.Canvas.Pixels[pt.X,pt.Y]; frgb.R:=((col shr 0) and $FF); frgb.G:=((col shr 8) and $FF); frgb.B:=((col shr 16) and $FF); fhsv:=RGBtoHSV(frgb); ScrollBar1.Position:=Round(fhsv.H); finally end; end; procedure TForm1.ScrollBar1Change(Sender: TObject); begin DrawHue(); end; procedure TForm1.ScrollBar2Change(Sender: TObject); begin DrawHue(); end; procedure TForm1.ScrollBar4Change(Sender: TObject); begin //画像の拡大縮小スクロールバーの値が変更されたとき if Assigned(Image4.Picture.Bitmap) then begin Image4.Width :=Image4.Picture.Bitmap.Width *ScrollBar4.Position div 100; Image4.Height:=Image4.Picture.Bitmap.Height*ScrollBar4.Position div 100; end; if Assigned(Image5.Picture.Bitmap) then begin Image5.Width :=Image5.Picture.Bitmap.Width *ScrollBar4.Position div 100; Image5.Height:=Image5.Picture.Bitmap.Height*ScrollBar4.Position div 100; end; end; end.
実行する
実行ボタンを押して実行します。(デバッグ実行でもOK)Image4の色相を変換したいピクセルをクリックします。
ScrollBar3をドラッグして変換したい色相に設定します。
Button1をクリックすると、Image4画像の指定色相範囲を変換してImage5に表示します。