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画像処理--色相/彩度調整」のコードを更新したいと思っていたが、以前のコードは残したほうがいいと思っていたので、この改善コードを続編として、両者の間で比較するようにした.
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画像処理--記事インデックス』にアクセスできます.