Delphi画像処理--色相/彩度調整(続き)
9978 ワード
ヒントを読む:
「Delphi画像処理」シリーズは効率に重点を置き、一般コードはPASCAL、コアコードはBASMを採用している.
「C++画像処理」シリーズはコードがはっきりしていて、可読性が主で、すべてC++コードを使用しています.
できるだけ両者の内容を一致させ、互いに対照することができる.
本明細書のコードは、文書「Delphi画像処理--データ型および共通プロセス」のImageDataを含む必要がある.pasユニット.
最近、以前の文章を整理していて、先日「Delphi画像処理--色相/飽和度調整」という文章を修正して整理したばかりですが、昨日は「Delphi画像処理--色相/飽和度調整」のコードが優化の余地があることをふと思い出しました.私の画像の色相/飽和度調整に関するいくつかの文章の中で、ずっとSHLベースで書かれているコードですが、実際にはPhotoshopの色相/飽和度調整機能も確かにSHLベースですが、Photoshopの色相/飽和度調整はSHL調整ではなく、明度、色相、飽和度にかかわらず大きな独立性があり、それらの関係は緩やかで、SHLのように3つのつながりが緊密ではありません.「Delphi画像処理--色相/彩度調整」では、明度部分は独立して調整されているが、色相と彩度部分にはいくつかの関連があり、主に画素を共有するS、L部分であるが、実際にはSHLで色相を調整するのは面倒である.SHVを用いて色相を調整するとずっと簡単になります(もちろん、これは私が採用したSSEコードのことですが、SSEコードでなければ、『Delphi画像処理--色相/飽和度調整』です.一文の色相調整コードでは、中間値のみを計算し、最大値と最小値を元のままにすることで、それ自体が多くのコードを節約できます).改善コードが書き終わったら、「Delphi画像処理--色相/彩度調整」のコードを更新したいと思っていたが、以前のコードは残したほうがいいと思っていたので、この改善コードを続編として、両者の間で比較するようにした.
上のコード構造から見ると、色相、飽和度、明度の3つは基本的に「独立」しており、明度は言うまでもなく、早く独立しており、色相と飽和度の間で共有されている部分は画素RGB値の最大値と差(HSBSetHueAndSaturation過程におけるecxとxmm 3)にすぎない.簡単なテストを経て、改善されたコード速度はかなり向上し、色相、飽和度、明度の3つのすべての調整時間は「Delphi画像処理--色相/飽和度調整」の色相部分の調整時間に相当する.
最後にCSDNを軽蔑して、最近ずっと前の文章を整理して修正して、すべての文章はすべて再び4-5つのラベルをプラスして、しかし数日も経っていないで、文章のラベルはなくて、私は私が設置していないと思って、また再びプラスして、数日後、またありません!このような人を連れて行かないで、再びCSDNを軽蔑します.
「Delphi画像処理」シリーズはGDI+ユニットを使用してアドレスをダウンロードし、説明は文章「GDI+for VCL基礎--GDI+とVCL」を参照してください.
レベルが限られているため、間違いは避けられないので、指摘と指導を歓迎します.メールアドレス:[email protected]
ここでは『Delphi画像処理--記事インデックス』にアクセスできます.
「Delphi画像処理」シリーズは効率に重点を置き、一般コードはPASCAL、コアコードはBASMを採用している.
「C++画像処理」シリーズはコードがはっきりしていて、可読性が主で、すべてC++コードを使用しています.
できるだけ両者の内容を一致させ、互いに対照することができる.
本明細書のコードは、文書「Delphi画像処理--データ型および共通プロセス」のImageDataを含む必要がある.pasユニット.
最近、以前の文章を整理していて、先日「Delphi画像処理--色相/飽和度調整」という文章を修正して整理したばかりですが、昨日は「Delphi画像処理--色相/飽和度調整」のコードが優化の余地があることをふと思い出しました.私の画像の色相/飽和度調整に関するいくつかの文章の中で、ずっとSHLベースで書かれているコードですが、実際にはPhotoshopの色相/飽和度調整機能も確かにSHLベースですが、Photoshopの色相/飽和度調整はSHL調整ではなく、明度、色相、飽和度にかかわらず大きな独立性があり、それらの関係は緩やかで、SHLのように3つのつながりが緊密ではありません.「Delphi画像処理--色相/彩度調整」では、明度部分は独立して調整されているが、色相と彩度部分にはいくつかの関連があり、主に画素を共有するS、L部分であるが、実際にはSHLで色相を調整するのは面倒である.SHVを用いて色相を調整するとずっと簡単になります(もちろん、これは私が採用したSSEコードのことですが、SSEコードでなければ、『Delphi画像処理--色相/飽和度調整』です.一文の色相調整コードでは、中間値のみを計算し、最大値と最小値を元のままにすることで、それ自体が多くのコードを節約できます).改善コードが書き終わったら、「Delphi画像処理--色相/彩度調整」のコードを更新したいと思っていたが、以前のコードは残したほうがいいと思っていたので、この改善コードを続編として、両者の間で比較するようにした.
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 ebx
end;
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 ebp
end;
procedure HSBSetHueAndSaturation(var Data: TImageData; Hv, Sv: Integer);
const
_fc2: Single = 2.0;
_fc4: Single = 4.0;
_fc6: Single = 6.0;
_fc128: Single = 128.0;
var
Hv0: Integer;
fHv: Single;
width, height, datOffset: Integer;
asm
push esi
push edi
push ebx
push ecx
mov Hv0, edx
call _SetDataRegs
mov width, ecx
mov height, edx
mov datOffset, ebx
pop ebx // Sv
pxor xmm7, xmm7
pxor xmm3, xmm3 // xmm3 ,
mov eax, 1
cvtsi2ss xmm6, eax
mov eax, 60
cvtsi2ss xmm5, Hv0
cvtsi2ss xmm4, eax
divss xmm5, xmm4
movss fHv, xmm5 // fHv = Hv / 60
mov eax, 255
cvtsi2ss xmm5, ebx
cvtsi2ss xmm4, eax
divss xmm5, xmm4
movss xmm4, xmm5 // xmm4 = xmm5 = Sv / 255
test ebx, ebx
jle @@1
movaps xmm5, xmm6 // if (Sv > 0)
subss xmm5, xmm4 // xmm5 = 1 / (1 - xmm4) - 1
rcpss xmm5, xmm5
subss xmm5, xmm6
@@1:
pshufd xmm5, xmm5, 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
jz @@next // if (delta == 0) continue
cvtsi2ss xmm3, eax // xmm3 = delta = rgbMax - rgbmin
cmp Hv0, 0
jne @@6
movd xmm0, [edi]
punpcklbw xmm0, xmm7
punpcklwd xmm0, xmm7
cvtdq2ps xmm0, xmm0
jmp @@20
@@6:
// HSV , HSL 40%
movss xmm2, fHv // add = fHv
cmp cl, [edi].TARGBQuad.Red
jne @@8 // if (R == rgbMax) eax = G - B
movzx eax, [edi].TARGBQuad.Green
movzx esi, [edi].TARGBQuad.Blue
jmp @@10
@@8:
cmp cl, [edi].TARGBQuad.Green
jne @@9
movzx eax, [edi].TARGBQuad.Blue
movzx esi, [edi].TARGBQuad.Red
addss xmm2, _fc2 // if (G == rgbMax) eax = B - R; add += 2
jmp @@10
@@9:
movzx eax, [edi].TARGBQuad.Red
movzx esi, [edi].TARGBQuad.Green
addss xmm2, _fc4 // if (B == rgbMax) eax = R - G; add += 4
@@10:
sub eax, esi
cvtsi2ss xmm1, eax
divss xmm1, xmm3
addss xmm1, xmm2 // 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 esi, xmm1 // index = Round(H)
cvtsi2ss xmm2, esi
subss xmm1, xmm2 // extra = H - index
comiss xmm1, xmm7 // if (extra < 0) // index
jae @@13 // {
dec esi // index --
addss xmm1, xmm6 // extra ++
@@13: // }
test esi, 1
jnz @@14
movaps xmm2, xmm1
movss xmm1, xmm6
subss xmm1, xmm2 // if ((index & 1) == 0) extra = 1 - extra
@@14:
mulss xmm1, xmm3 // xmm1 = delta * extra
pslldq xmm1, 4
orps xmm1, xmm3
movlhps xmm1, xmm7 // xmm1 = 0 0 delta*extra delta
cvtsi2ss xmm0, ecx // xmm0 = V = rgbMax
pshufd xmm0, xmm0, 0 // xmm0 = V V V V
subps xmm0, xmm1 // xmm0 - xmm1 = NAN V T P
jmp @@jmpTable[esi*4].Pointer
@@jmpTable: dd offset @@H60
dd offset @@H120
dd offset @@H180
dd offset @@H240
dd offset @@H300
dd offset @@H360
dd offset @@H60// H=6.0 ,SSE index=6, 0
@@H360: // 300 - 359 (V, P, T)
pshufd xmm0, xmm0, 11100001b
jmp @@H60
@@H300: // 240 - 299 (T, P, V)
pshufd xmm0, xmm0, 11010010b
jmp @@H60
@@H240: // 180 - 239 (P, T, V)
pshufd xmm0, xmm0, 11000110b
jmp @@H60
@@H180: // 120 - 179 (P, V, T)
pshufd xmm0, xmm0, 11001001b
jmp @@H60
@@H120: // 60 - 119 (T, V, P)
pshufd xmm0, xmm0, 11011000b
@@H60: // 0 - 59 (V, T, P)
test ebx, ebx
je @@25
@@20:
// 。 HSL
add ecx, edx // ecx = rgbMar + rgbMin
cvtsi2ss xmm2, ecx
divss xmm2, _fc2 // xmm3 = L = ecx / 2
pshufd xmm2, xmm2, 0
movaps xmm1, xmm0
subps xmm0, xmm2 // rgb0 = rgb - L
test ebx, ebx
jle @@23
// , SHL
comiss xmm2, _fc128 // if (Sv > 0)
jb @@21 // {
neg ecx
add ecx, 510 // if (L >= 128) ecx = 510 - ecx
@@21:
cvtsi2ss xmm2, ecx
divss xmm3, xmm2 // S = delta / ecx
addss xmm3, xmm4
comiss xmm3, xmm6
jb @@23
subss xmm3, xmm4 // if ((xmm4 + S) >= 1)
rcpss xmm2, xmm3 // rgb0 = rgb0 * (1 / S - 1)
subss xmm2, xmm6 // else
pshufd xmm2, xmm2, 0 // // xmm5
mulps xmm0, xmm2 // rgb0 = rgb0 * (1 / (1 - xmm4) - 1)
jmp @@24 // }
@@23: // else
mulps xmm0, xmm5 // rgb0 = rgb0 * fSv
@@24:
addps xmm0, xmm1 // rgb += rgb0
@@25:
cvtps2dq xmm0, xmm0
packssdw xmm0, xmm7
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 esi
end;
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;
上のコード構造から見ると、色相、飽和度、明度の3つは基本的に「独立」しており、明度は言うまでもなく、早く独立しており、色相と飽和度の間で共有されている部分は画素RGB値の最大値と差(HSBSetHueAndSaturation過程におけるecxとxmm 3)にすぎない.簡単なテストを経て、改善されたコード速度はかなり向上し、色相、飽和度、明度の3つのすべての調整時間は「Delphi画像処理--色相/飽和度調整」の色相部分の調整時間に相当する.
最後にCSDNを軽蔑して、最近ずっと前の文章を整理して修正して、すべての文章はすべて再び4-5つのラベルをプラスして、しかし数日も経っていないで、文章のラベルはなくて、私は私が設置していないと思って、また再びプラスして、数日後、またありません!このような人を連れて行かないで、再びCSDNを軽蔑します.
「Delphi画像処理」シリーズはGDI+ユニットを使用してアドレスをダウンロードし、説明は文章「GDI+for VCL基礎--GDI+とVCL」を参照してください.
レベルが限られているため、間違いは避けられないので、指摘と指導を歓迎します.メールアドレス:[email protected]
ここでは『Delphi画像処理--記事インデックス』にアクセスできます.