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に表示します。
