Delphi Image Processing-color phase/saturation adjustment

Source: Internet
Author: User

Reading Tips:

Delphi Image ProcessingThe series focuses on efficiency. The general code is Pascal, and the core code is BaSm.

The C ++ image processing series focuses on code clarity and readability, all using C ++ code.

Make sure that the two items are consistent and can be compared with each other.

The code in this article must include the imagedata. Pas unit in "Delphi Image Processing-data type and public process.

 

This document is a practical BaSm process based on the article "Application of GDI + in Delphi-Photoshop hue/saturation/brightness function, for implementation principles, see application of GDI + in Delphi-image saturation adjustment and Application of GDI + in Delphi-brightness adjustment of imitation Photoshop. for the pure PAS implementation code and test example code, see "Application of GDI + in Delphi-Photoshop hue/saturation/brightness function".

Procedure getbrighttable (bright: integer; var table: tgraytable); ASM push ebx cmp eax,-255 jge @ 1 mov eax,-255 JMP @ 2 @ 1: CMP eax, 255 jle @ 2 mov eax, 255 @ 2: Push eax mov EBX, 255 fild dword ptr [esp] fwait mov [esp], EBX fidiv dword ptr [esp] // bright/255 fwait XOR ECx, ECx test eax, eax JG @ loop xor ebx, EBX // mask = bright> 0? 255: 0 @ loop: mov [esp], ECx XOR [esp], EBX fild dword ptr [esp] fmul ST (0), ST (1) fistp dword ptr [esp] fwait mov eax, [esp] add eax, ECx mov [edX], Al // table [I] = (I ^ mask) * bright/255 Inc edX Inc ECx CMP ECx, 256 JB @ loop Ffree st pop eax pop ebxend; Procedure hsbsetbright (VAR data: timagedata; const table: tgraytable ); ASM push EBP push ESI push EDI push EBX mov ESI, EDX call _ setdataregs mov EBP, EDX @ yloop: Push ECx @ xloop: movzx eax, [EDI]. targbquad. blue movzx edX, [EDI]. targbquad. green mov Al, [ESI + eax] mov DL, [ESI + EDX] mov [EDI]. targbquad. blue, Al mov [EDI]. targbquad. green, DL movzx eax, [EDI]. targbquad. red mov Al, [ESI + eax] mov [EDI]. targbquad. red, Al add EDI, 4 loop @ xloop pop ECx add EDI, EBX dec EBP jnz @ yloop pop EBX pop EDI pop ESI pop ebpend; Procedure hsbsethueandsaturation (VAR data: timagedata; HV, SV: integer); const _ fcd5: single = 0.5; _ FC1: single = 1.0; _ FC2: single = 2.0; _ FC4: single = 4.0; _ fc6: single = 6.0; _ fc255: single = 255.0; _ fc510: single = 510.0; var Fhv, FSV: single; width, height, datoffset: integer; ASM push ESI push EDI push EBX push edX push ECx call _ setdataregs mov width, ECx mov height, EDX mov datoffset, EBX pop EBX // SV pop ESI/HV pxor xmm7, xmm7 mov eax, 60 cvtsi2ss xmm6, ESI cvtsi2ss xmm0, eax divss xmm6, xmm0 movss Fhv, xmm6 // FSV = HV/60 cvtsi2ss xmm6, EBX divss xmm6, _ fc255 movss FSV, xmm6 // xmm6 = FSV = SV/255 test EBX, EBX jle @ 1 mov eax, 255 XOR eax, EBX cvtsi2ss xmm0, eax movss xmm6, _ fc255 divss xmm6, xmm0 // If (Sv> 0) subss xmm6, _ FC1 // xmm6 = 255/(255-SV)-1 @ 1: pshufd xmm6, xmm6, 0 @ yloop: Push width @ xloop: movzx ECx, [EDI]. targbquad. blue movzx edX, [EDI]. targbquad. green movzx eax, [EDI]. targbquad. red CMP ECx, EDX // ECx = rgbmax jge @ 3 // edX = rgbmin xchg ECx, EDX @ 3: CMP ECx, eax jge @ 4 xchg ECx, eax @ 4: CMP edX, eax cmova edX, eax mov eax, ECx sub eax, edX // Delta = rgbmax-rgbmin JZ @ next // If (delta = 0) Continue @ 5: movd xmm0, EDX // rgbmin pinsrw xmm0, ECx, 2 // rgbmax add ECx, EDX // ECx = rgbmar + rgbmin cvtsi2ss xmm3, ECx divss xmm3, _ fc510 // xmm3 = L = ECx/510 Comiss xmm3, _ fcd5 JB @ 6 neg ECx add ECx, 510 // If (L> = 0.5) ECx = 510-ECx @ 6: cvtsi2ss xmm2, eax cvtsi2ss xmm4, ECX divss xmm2, xmm4 // xmm2 = s = delta/ECx test ESI, ESI jnz @ 7 // If (HV = 0) goto @ 20 movd xmm0, [EDI] punpcklbw xmm0, xmm7 JMP @ 20 @ 7: cvtsi2ss xmm4, eax // Delta movss xmm5, Fhv // Add = Fhv pextrw eax, xmm0, 2 // rgbmax CMP Al, [EDI]. targbquad. red JNE @ 8 // If (r = rgbmax) eax = G-B movzx eax, [EDI]. targbquad. green movzx edX, [EDI]. targbquad. blue JMP @ 10 @ 8: CMP Al, [EDI]. targbquad. green JNE @ 9 movzx eax, [EDI]. targbquad. blue movzx edX, [EDI]. targbquad. red addss xmm5, _ FC2 // If (G = rgbmax) eax = B-r; add + = 2 JMP @ 10 @ 9: movzx eax, [EDI]. targbquad. red movzx edX, [EDI]. targbquad. green addss xmm5, _ FC4 // If (B = rgbmax) eax = r-g; add + = 4 @ 10: Sub eax, EDX cvtsi2ss xmm1, eax divss xmm1, xmm4 addss xmm1, xmm5 // H = eax/Delta + Add Comiss xmm1, xmm7 Jae @ 11 addss xmm1, _ fc6 // If (H <0) H + = 6 JMP @ 12 @ 11: Comiss xmm1, _ fc6 JB @ 12 subss xmm1, _ fc6 // else if (h> = 6) h-= 6 @ 12: cvtss2si edX, xmm1 // Index = round (h) cvtsi2ss xmm4, EDX subss xmm1, xmm4 // extra = H-index Comiss xmm1, xmm7 // If (extra <0) // if the index has five entries, Jae @ 13 // {dec edX // index -- addss xmm1, _ FC1 // extra ++ @ 13: //} test edX, 1 JZ @ 14 movaps xmm4, xmm1 movss xmm1, _ FC1 subss xmm1, xmm4 // If (index & 1) Extra = 1-extra @ 14: movaps xmm4, xmm1 movss xmm5, _ FC1 subss xmm4, _ fcd5 subss xmm5, xmm2 mulss xmm4, xmm5 subss xmm1, xmm4 // extra = extra-(extra-0.5) * (1.0-S); movaps xmm4, xmm1 // extra0 = extra movaps xmm5, xmm3 subss xmm5, _ fcd5 // L0 = L-0.5 Comiss xmm5, xmm7 JB @ 15 movss xmm4, _ FC1 subss xmm4, xmm1 // If (l0> = 0) extra0 = 1-extra @ 15: mulss xmm4, xmm5 mulss xmm4, _ FC2 addss xmm1, xmm4 mulss xmm1, _ fc255 cvtss2si eax, xmm1 // rgbmid = (extra + extra0 * l0 * 2) * 255 pinsrw xmm0, eax, 1 // xmm0 = 0000 Max median min JMP @ jmptable [edX * 4]. pointer @ jmptable: dd offset @ h60 dd offset @ H120 dd offset @ h180 dd offset @ h240 dd offset @ H300 dd offset @ h360 dd offset @ 18 // when H = 6.0 hours, index = 6 due to SSE judgment error. Actually, it should be 0 @ H120: // 60-119 pshuflw xmm0, xmm0, 216 JMP @ 18 @ h180: // 120-179 pshuflw xmm0, xmm0, 201 JMP @ 18 @ h240: // 180-239 pshuflw xmm0, xmm0, 198 JMP @ 18 @ H300: // 240-299 pshuflw xmm0, xmm0, 210 JMP @ 18 @ h360: // 300-359 pshuflw xmm0, xmm0, 225 @ h60: // 0-59 @ 18: Test EBX, EBX // If (SV = 0) Continue JZ @ 25 @ 20: punpcklwd xmm0, xmm7 cvtdq2ps xmm0, xmm0 movaps xmm1, xmm0 mulss xmm3, _ fc255 pshufd xmm3, xmm3, 0 subps xmm0, xmm3 // rgb0 = RGB-l test EBX, EBX jle @ 21 movaps xmm3, xmm2 // If (Sv> 0) addss xmm3, FSV // {Comiss xmm3, _ FC1 JB @ 21 rcpss xmm2, xmm2 // If (FSV + S)> = 1) subss xmm2, _ FC1 // rgb0 = rgb0 * (1/s-1) pshufd xmm2, xmm2, 0 // else mulps xmm0, xmm2 // rgb0 = rgb0 * (1/(1-FSV)-1) JMP @ 22 //} @ 21: // else mulps xmm0, xmm6 // rgb0 = rgb0 * FSV @ 22: addps xmm0, xmm1 // RGB + = rgb0 cvtps2dq xmm0, xmm0 packssdw xmm0, xmm7 @ 25: packuswb xmm0, xmm7 mov Al, [EDI]. targbquad. alpha movd [EDI], xmm0 mov [EDI]. targbquad. alpha, Al @ next: Add EDI, 4 Dec width jnz @ xloop add EDI, datoffset pop width dec height jnz @ yloop pop EBX pop EDI pop esiend; procedure imagehsbadjustment (VAR data: timagedata; hvalue, svalue, bvalue: integer); var brighttab: tgraytable; begin if hvalue> 180 then hvalue: = 180 else if hvalue <-180 then hvalue: =-180; If svalue> 255 then svalue: = 255 else if svalue <-255 then svalue: =-255; if bvalue <> 0 then getbrighttable (bvalue, brighttab); If (svalue> 0) and (bvalue <> 0) Then hsbsetbright (data, brighttab ); if (hvalue <> 0) or (svalue <> 0) then begin hsbsethueandsaturation (data, hvalue, svalue); end; If (svalue <= 0) and (bvalue <> 0) Then hsbsetbright (data, brighttab); end;

In this revision, the brightness part is separated and replaced directly with a brightness table of 256 elements, which greatly speeds up the process. The color and saturation adjustment part is also modified, SSE code is used to improve the computing accuracy.

The following is a simple HSB demo program:

unit main;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, Gdiplus, ImageData, StdCtrls, ComCtrls, ExtCtrls;type  TForm1 = class(TForm)    Label1: TLabel;    Label2: TLabel;    Label3: TLabel;    PaintBox1: TPaintBox;    Button1: TButton;    HBar: TTrackBar;    SBar: TTrackBar;    BBar: TTrackBar;    HEdit: TEdit;    SEdit: TEdit;    BEdit: TEdit;    Button2: TButton;    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);    procedure PaintBox1Paint(Sender: TObject);    procedure HBarChange(Sender: TObject);    procedure SBarChange(Sender: TObject);    procedure BBarChange(Sender: TObject);    procedure HEditChange(Sender: TObject);    procedure HEditKeyPress(Sender: TObject; var Key: Char);    procedure Button1Click(Sender: TObject);    procedure Button2Click(Sender: TObject);  private    { Private declarations }    Bmp: TGpBitmap;    tmpBmp: TGpBitmap;    r: TGpRect;    Lock: Boolean;  public    { Public declarations }  end;var  Form1: TForm1;implementation{$R *.dfm}procedure TForm1.BBarChange(Sender: TObject);begin  if not Lock then    BEdit.Text := IntToStr(BBar.Position);end;procedure TForm1.Button1Click(Sender: TObject);begin  HBar.Position := 0;  SBar.Position := 0;  BBar.Position := 0;end;procedure TForm1.FormCreate(Sender: TObject);begin  Bmp := TGpBitmap.Create('..\..\media\100_0349.jpg');  r := GpRect(0, 0, Bmp.Width, Bmp.Height);  tmpBmp := Bmp.Clone(r, pf32bppARGB);end;procedure TForm1.FormDestroy(Sender: TObject);begin  tmpBmp.Free;  Bmp.Free;end;procedure TForm1.HBarChange(Sender: TObject);begin  if not Lock then    HEdit.Text := IntToStr(HBar.Position);end;procedure TForm1.HEditChange(Sender: TObject);var  Data: TImageData;begin  Lock := True;  with TEdit(Sender) do  begin    if Length(Text) = 0 then Text := '0';    case Tag of      0: HBar.Position := StrToInt(Text);      1: SBar.Position := StrToInt(Text);      2: BBar.Position := StrToInt(Text);    end;    Lock := False;    tmpBmp.Free;    tmpBmp := Bmp.Clone(r, pf32bppARGB);    if (HBar.Position <> 0) or (SBar.Position <> 0) or (BBar.Position <> 0) then    begin      Data := LockGpBitmap(tmpBmp);      ImageHSBAdjustment(Data, HBar.Position, Round(SBar.Position * 255.0 / 100),        Round(BBar.Position * 255.0 / 100));      UnlockGpBitmap(tmpBmp, Data);    end;    PaintBox1Paint(nil);  end;end;procedure TForm1.HEditKeyPress(Sender: TObject; var Key: Char);begin  if (Key >= #32) and not (Key in ['0'..'9']) then    Key := #0;end;procedure TForm1.PaintBox1Paint(Sender: TObject);var  g: TGpGraphics;begin  g := TGpGraphics.Create(PaintBox1.Canvas.Handle);  try    g.DrawImage(tmpBmp, r);    g.TranslateTransform(0, r.Height);    g.DrawImage(Bmp, r);  finally    g.Free;  end;end;procedure TForm1.SBarChange(Sender: TObject);begin  if not Lock then    SEdit.Text := IntToStr(SBar.Position);end;end.

The running interface is as follows:

 

For details about the use of GDI + units and descriptions in the "Delphi image processing" series, see the article 《GDI + for VCL basics-GDI + and VCL.

Due to limited levels, errors are inevitable. Correction and guidance are welcome. Email Address:Maozefa@hotmail.com

Here, you can access "Delphi Image Processing-Article Index".

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.