Delphi影像處理 — 映像顏色混合

來源:互聯網
上載者:User

閱讀提示:

    《Delphi影像處理》系列以效率為側重點,一般代碼為PASCAL,核心代碼採用BASM。

    《C++影像處理》系列以代碼清晰,可讀性為主,全部使用C++代碼。

    儘可能保持二者內容一致,可相互對照。

    本文代碼必須包括文章《Delphi影像處理 -- 資料類型及公用過程》中的ImageData.pas單元。

 

    Photoshop提供了豐富的圖象圖層混合模式,其中的顏色混合模式是用層圖象的亮度與層填充顏色或者圖象色彩進行混合,形成的結果既有著層的色彩,又保留了下層圖象的灰階,基於這種混合特性,顏色混合模式常用來對灰階圖象進行著色。

    在《C++影像處理 -- 映像顏色混合(上)》、《C++影像處理 -- 映像顏色混合(中)》和《C++影像處理 -- 映像顏色混合(下)》等多篇文章中,介紹了映像顏色混合的原理、演算法最佳化和代碼完善方法,因此這裡不再介紹,直接貼出Delpha實現代碼(BASM)和例子。由於BASM彙編碼較長,在C++版的顏色混合文章的映像黑白調整和灰階圖象染色功能,準備另文發表。

    映像顏色混合實現代碼:

procedure _SetMixerMM;asm    pxor        mm7, mm7    mov         eax, 1011h    movd        mm6, eax    pshufw      mm6, mm6, 0    mov         eax, 8    movd        mm5, eax    pshufw      mm5, mm5, 0end;// --> mm7 4 * word = 0// --> mm6 4 * word = 0x1101// --> mm5 4 * word = 4// --> eax source alpha// --> esi source pixel (ARGB)// --> edi dest pixel (ARGB)// <-- eax dest alpha !!!// <-- mm0 dest pixelprocedure _PARGBMixer(srcAlpha: Integer);asm    push      edx    movd      mm0, [esi]    movd      mm1, [edi]    punpcklbw mm0, mm7    punpcklbw mm1, mm7    // dest.rgb = dest.rgb * dest.alpha / 255    movzx     edx, [edi].TARGBQuad.Alpha    pmullw    mm1, qword ptr ArgbTab[edx*8]    pmulhuw   mm1, mm6    paddusw   mm1, mm5    psrlw     mm1, 4    // dest.rgb = (dest.rgb * 255 + (source.rgb - dest.rgb) * sourec.alpha) / 255    psubw     mm0, mm1    pmullw    mm0, qword ptr ArgbTab[eax*8]    pmullw    mm1, qword ptr ArgbTab[255*8]    paddw     mm0, mm1    pmulhuw   mm0, mm6    paddusw   mm0, mm5    psrlw     mm0, 4    // dest.alpha += (source.alpha - (dest.alpha * source.alpha + 127) / 255)    push      eax    add       [esp], edx    imul      eax, edx    add       eax, 127    mul       dword ptr DivTab[255*4]    pop       eax    sub       eax, edx    // dest.rgb = dest.rgb * 255 / dest.alpha    movq      mm1, mm0    psllw     mm0, 8    psubw     mm0, mm1    pmulhuw   mm0, qword ptr MMDivTab[eax*8]    packuswb  mm0, mm7    pop       edxend;// --> mm7 4 * word = 0// --> eax source alpha// --> esi source pixel (ARGB)// --> edi dest pixel (ARGB)// <-- mm0 dest pixel (RGB)procedure _ARGBMixer(srcAlpha: Integer);asm    movd      mm0, [esi]    movd      mm1, [edi]    punpcklbw mm0, mm7    punpcklbw mm1, mm7    psubw     mm0, mm1    pmullw    mm0, qword ptr ArgbTab[eax*8]    psllw     mm1, 8    paddw     mm0, mm1    psrlw     mm0, 8    packuswb  mm0, mm0end;const    BWDefault: array[0..5] of Integer = (410, 614, 410, 819, 205, 614);    GrayConst: array[0..2] of Integer = (113, 604, 307);// eax,edx,ecx=r,g,b esi,sdi,ebx=rIndex,gIndex,bIndexprocedure CompareRgb;asm    cmp     eax, ecx    jae     @@1    xchg    eax, ecx    xchg    esi, ebx@@1:    cmp     eax, edx    jae     @@2    xchg    eax, edx    xchg    esi, edi@@2:    cmp     ecx, edx    jbe     @@3    xchg    ecx, edx    xchg    ebx, edi@@3:end;// in: edi=pixel// out: eax=bwGrayprocedure GetBWGray;asm    push    esi    push    edi    movzx   ecx, [edi].TARGBQuad.Blue    movzx   edx, [edi].TARGBQuad.Green    movzx   eax, [edi].TARGBQuad.Red    mov     ebx, 4          // blue  index    mov     edi, 2          // green index    xor     esi, esi        // red   index    call    CompareRgb      // CompareRgb(red, green, blue)    sub     eax, edx        // max - mid    sub     edx, ecx        // mid - min    add     edi, esi    dec     edi    imul    eax, BWDefault[esi*4].Integer    imul    edx, BWDefault[edi*4].Integer    add     eax, edx        // gray = (((max - mid) * params[maxIndex] +    add     eax, 512        //          (mid - min) * params[maxIndex + midIndex - 1] +    sar     eax, 10         //           512) >> 10) + min    add     eax, ecx    pop     edi    pop     esiend;// in: esi=srcPixel,edi=dstPixel,eax=gray// out: [edi]=mixerColorprocedure ColorMix;var  gray, max_min: LongWord;asm    push    esi    push    edi    mov     gray, eax    movzx   ecx, [esi].TARGBQuad.Blue    movzx   edx, [esi].TARGBQuad.Green    movzx   eax, [esi].TARGBQuad.Red    xor     ebx, ebx            // blue  index    mov     edi, 1              // green index    mov     esi, 2              // red   index    call    CompareRgb          // CompareRgb(red, green, blue)    sub     eax, ecx            // max - min    jnz     @@4    pop     edi    mov     eax, gray    mov     [edi].TARGBQuad.Blue, al    mov     [edi].TARGBQuad.Green, al    mov     [edi].TARGBQuad.Red, al    jmp     @@Exit@@4:    sub     edx, ecx            // mid - min    mov     max_min, eax    mov     ecx, eax    sub     eax, edx    imul    eax, GrayConst[edi*4].Integer    imul    ecx, GrayConst[ebx*4].Integer    add     eax, ecx    add     eax, 512            // nMax = gray +    shr     eax, 10             //   (max_min - mid_min) * grayConst[midIndex] +    add     eax, gray           //   max_min * grayConst[minIndex]    cmp     eax, 255    ja      @@5    mov     ecx, eax    sub     ecx, max_min        // nMin = nMax - max_min    js      @@6    add     edx, ecx            // nMid = nMin + mid_min    jmp     @@8@@5:// nMax > 255    shl     edx, 10             // hueCoef = (mid_min << 10) / max_min    mov     eax, max_min    xchg    eax, edx    mul     DivTab[edx*4].Integer    push    edx    mov     ecx, GrayConst[edi*4].Integer    imul    edx, ecx    shr     edx, 10             // v0 = (ys[mid.index] * hueCoef) >> 10    add     ecx, GrayConst[ebx*4].Integer    sub     ecx, edx            // v1 = ys[mid.index] + ys[min.index] - v0    add     edx, GrayConst[esi*4].Integer    mov     eax, edx    shl     edx, 8    sub     edx, eax    mov     eax, gray    shl     eax, 10    sub     eax, edx    mov     edx, ecx    shr     edx, 1    add     eax, edx    mul     DivTab[ecx*4].Integer    mov     ecx, edx            // nMin = ((gray << 10) - (ys[max.index] + v0) *    pop     eax                 //   255 + (v1 >> 1)) / v1    xor     edx, 255    imul    edx, eax    add     edx, 512    shr     edx, 10    add     edx, ecx            // nMid = nMin + (((255 ^ newMin) * hueCoef + 512) >> 10)    mov     eax, 255            // nMax = 255    jmp     @@8@@6:// nMin < 0    shl     edx, 10             // hueCoef = (mid_min << 10) / max_min    mov     eax, max_min    xchg    eax, edx    mul     DivTab[edx*4].Integer    push    edx    imul    edx, GrayConst[edi*4].Integer    add     edx, 512    shr     edx, 10             // tmp = ys[max.index] + ((ys[mid.index] * hueCoef + 512) >> 10)    add     edx, GrayConst[esi*4].Integer    mov     eax, gray    shl     eax, 10    mov     ecx, edx    shr     edx, 1    add     eax, edx    mul     DivTab[ecx*4].Integer    mov     eax, edx            // nMax = ((gray << 10) + (tmp >> 1)) / tmp    pop     edx    imul    edx, eax    add     edx, 512    shr     edx, 10             // nMid = (nMax * hueCoef + 512) >> 10    mov     ecx, 1              // nMin = 1@@8:    mov     ah, dl    pop     edx    mov     [edx+esi], al    mov     [edx+edi], ah    mov     [edx+ebx], cl    mov     edi, edx@@Exit:    pop     esiend;procedure _DoColorMixer(var Dest: TImageData; const Source: TImageData; Alpha: Integer);var  width, height, dstOffset, srcOffset: Integer;  dst, src: LongWord;  alphaI: Integer;asm    push    esi    push    edi    push    ebx    mov     alphaI, ecx    mov     cl, [eax].TImageData.AlphaFlag    mov     ch, [edx].TImageData.AlphaFlag    and     [edx].TImageData.AlphaFlag, cl    push    ecx    call    _SetCopyRegs    mov     width, ecx    mov     height, edx    mov     srcOffset, eax    mov     dstOffset, ebx    pop     ecx    cmp     alphaI, 256    jne     @@MixerA    cmp     ch, TRUE    je      @@MixerA    cmp     cl, TRUE    je      @@MixerB@@yLoop:    push    width@@xLoop:    call    GetBWGray    call    ColorMix    add     esi, 4    add     edi, 4    dec     width    jnz     @@xLoop    pop     width    add     esi, srcOffset    add     edi, dstOffset    dec     height    jnz     @@yLoop    jmp     @@End@@MixerA:    cmp     cl, True    je      @@MixerB    pxor    mm7, mm7@@yLoopA:    push    width@@xLoopA:    movzx   eax, [esi].TARGBQuad.Alpha    mul     alphaI    shr     eax, 8    jz      @@NextA    push    esi    push    edi    push    eax    mov     eax, [edi]    mov     dst, eax    lea     edi, dst    call    GetBWGray           // get dest BlackWhite gray    call    ColorMix            // dst = source.HS mixer dest.gray    mov     esi, edi    pop     eax                 // mixAlpha = source.Alpha * alpha / 256    pop     edi    call    _ARGBMixer          // dest.rgb = dst.rgb mixer dest.rgb    movd    [edi], mm0    mov     [edi].TARGBQuad.Alpha, 255    pop     esi@@NextA:    add     esi, 4    add     edi, 4    dec     width    jnz     @@xLoopA    pop     width    add     esi, srcOffset    add     edi, dstOffset    dec     height    jnz     @@yLoopA    emms    jmp     @@End@@MixerB:    call    _SetMixerMM@@yLoopB:    push    width@@xLoopB:    movzx   eax, [esi].TARGBQuad.Alpha    mul     alphaI    shr     eax, 8    jz      @@NextB    test    [edi].TARGBQuad.Alpha, 0ffh    jnz     @@B_1    mov     eax, [esi]    mov     [edi], eax    jmp     @@NextB@@B_1:    push    esi    push    edi    push    edi    push    eax    mov     eax, [esi]    mov     src, eax    mov     eax, [edi]    mov     dst, eax    lea     edi, dst    call    GetBWGray           // get dest BlackWhite gray    call    ColorMix            // dst = source.HS mixer dest.gray    mov     esi, edi    pop     eax                 // mixAlpha = source.Alpha * alpha / 256    pop     edi    call    _PARGBMixer         // dst.rgb = dst.rgb mixer dest.rgb    movd    [esi], mm0    movzx   eax, [edi].TARGBQuad.Alpha// mixAlpha = dest.Alpha    lea     edi, src    call    _PARGBMixer         // dest.rgb = dst.rgb mixer source.rgb    pop     edi    movd    [edi], mm0    mov     [edi].TARGBQuad.Alpha, al    pop     esi@@NextB:    add     esi, 4    add     edi, 4    dec     width    jnz     @@xLoopB    pop     width    add     esi, srcOffset    add     edi, dstOffset    dec     height    jnz     @@yLoopB    emms@@End:    pop     ebx    pop     edi    pop     esiend;// 映像顏色模式混合procedure ImageColorMixer(var Dest: TImageData; const Source: TImageData; Alpha: Single = 1);var  alphaI: Integer;begin  alphaI := Round(Alpha * 256);  if alphaI < 0 then Exit;  if alphaI > 256 then alphaI := 256;  _DoColorMixer(Dest, Source, alphaI);end;

    例子一:

var  source, dest: TGpBitmap;  g: TGpGraphics;  src, dst: TImageData;begin  source := TGpBitmap.Create('..\..\media\Apple.png');  dest := TGpBitmap.Create('..\..\media\xmas_011.png');  g := TGpGraphics.Create(Canvas.Handle);  g.DrawImage(dest, 0, 0);  g.DrawImage(source, dest.Width, 0);  src := LockGpBitmap(source);  dst := LockGpBitmap(dest);  ImageColorMixer(dst, src);//  ImageMixer(dst, src, 0.75);  UnlockGpBitmap(dest, dst);  UnlockGpBitmap(source, src);  g.DrawImage(dest, dst.Width + src.Width, 0);  g.Free;  dest.Free;  source.Free;end;

    例子一運行:

   例子二:

var  source: TGpBitmap;  dest: TBitmap;  tmp: TJpegImage;  g: TGpGraphics;  src, dst: TImageData;begin  dest := TBitmap.Create;  tmp := TJpegImage.Create;  tmp.LoadFromFile('..\..\media\IMG_9440_mf.jpg');  dest.Assign(tmp);  tmp.Free;  source := TGpBitmap.Create('..\..\media\xmas_011.png');  g := TGpGraphics.Create(Canvas.Handle);  Canvas.Draw(0, 0, dest);  g.DrawImage(source, dest.Width, 0);  dst := GetBitmapData(dest);  src := LockGpBitmap(source);  ImageColorMixer(dst, src);//  ImageMixer(dst, src, 1);  UnlockGpBitmap(source, src);  Canvas.Draw(dst.Width + src.Width, 0, dest);  g.Free;  dest.Free;  source.Free;end;

    例子二:

 

    本文只提供了基本的顏色混合代碼,要實現顏色混合的幾何變換,可參見本系列有關幾何變換的文章。

 

    《Delphi影像處理》系列使用GDI+單元和說明見文章《GDI+ for VCL基礎 -- GDI+ 與 VCL》。

    因水平有限,錯誤在所難免,歡迎指正和指導。郵箱地址:maozefa@hotmail.com

    這裡可訪問《Delphi影像處理 -- 文章索引》。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.