zoukankan      html  css  js  c++  java
  • Delphi图像处理 -- 颜色矩阵变换

    转载自阿发伯:http://blog.csdn.net/maozefa/article/details/8316430

    阅读提示:

        《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。

        《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。

        尽可能保持二者内容一致,可相互对照。

        本文代码必须包括文章《Delphi图像处理 -- 数据类型及公用过程》中的ImageData.pas单元。

     

        本文在《GDI+ ColorMatrix的完全揭秘》的ColorMatrix原理揭秘的基础上,用Delphi代码来完整实现GDI+的ColorMatrix功能。

        GDI+中设置ColorMatrix时有2个枚举选项,在实际运用中极少使用,所以代码中以GDI+设置ColorMatrix的缺省方式实现。

        先给一个简易的浮点版本,因为该过程没有考虑子图处理,所以称之为简易版本,主要方便阅读者理解ColorMatrix实现原理:

    [delphi] view plain copy
     
     print?
    1. procedure SetColorMatrixF(Data: TImageData; Matrix: TColorMatrix);  
    2. var  
    3.   I, J, Count: Integer;  
    4.   P: PRGBQuad;  
    5.   MainValue: Boolean;  
    6.   v: Integer;  
    7.   
    8.   procedure SetPixel;  
    9.   var  
    10.     Pixel: array[0..3] of Byte;  
    11.     I, J: Integer;  
    12.     ps: PByteArray;  
    13.   begin  
    14.     ps := Pointer(P);  
    15.     // 注意:为使矩阵与ARGB排列顺序一致,以下运算中调整了行列的顺序   
    16.     for I := to do  
    17.     begin  
    18.       if I < then  
    19.         J := 2 - I  
    20.       else  
    21.         J := I;  
    22.       // 如果只存在主对角线数据,只处理颜色缩放   
    23.       if MainValue then  
    24.         Pixel[J] := Round(Matrix[I, I] * ps[J])  
    25.       // 否则,处理所有颜色变换   
    26.       else  
    27.         Pixel[J] := Max(0, Min(255, Round(Matrix[0, I] * ps[2] +  
    28.                                           Matrix[1, I] * ps[1] +  
    29.                                           Matrix[2, I] * ps[0] +  
    30.                                           Matrix[3, I] * ps[3] +  
    31.                                           Matrix[4, I] * 255)));  
    32.     end;  
    33.     for I := to do  
    34.       ps[I] := Pixel[I];  
    35.   end;  
    36.   
    37. begin  
    38.   // 处理矩阵中大与255的值(取模),并判断主对角线外是否存在数据   
    39.   MainValue := True;  
    40.   for I := to do  
    41.     for J := to do  
    42.     begin  
    43.       v := Round(Matrix[I, J]) div 256;  
    44.       if v > then  
    45.         Matrix[I, J] := Matrix[I, J] - 256.0 * v;  
    46.       if (I <> J) and (Matrix[I, J] <> 0) then  
    47.         MainValue := False;  
    48.     end;  
    49.   Count := Data.Width * Data.Height;  
    50.   P := Data.Scan0;  
    51.   for I := to Count do  
    52.   begin  
    53.     SetPixel;  
    54.     Inc(P);  
    55.   end;  
    56. end;  

        因代码已经有了注释,而实现原理、公式已经在《GDI+ ColorMatrix的完全揭秘》中进行了详尽的介绍,所以本文不再累述。 

        该过程代码的特点是简单易读,缺点是效率较低,在我的P4 2.8G计算机上,处理一张千万像素的照片,耗时为1000ms左右(不包括GDI+图像格式转换耗时。千万像素的24位格式图像转换为32位格式,耗时就达650ms)。

        下面是一个MMX BASM代码的整数ColorMatrix实现过程: 

    [delphi] view plain copy
     
     print?
    1. 过程定义:  
    2.   
    3.   // 设置图像颜色矩阵。参数:  
    4.   //   Dest输出图,Source原图,Data自身操作图像  
    5.   //   Matrix颜色矩阵  
    6.   procedure ImageSetColorMatrix(var Data: TImageData; Matrix: TColorMatrix); overload;  
    7.     {$IF RTLVersion >= 17.00}inline;{$IFEND}  
    8.   procedure ImageSetColorMatrix(var Dest: TImageData;  
    9.     const Source: TImageData; Matrix: TColorMatrix); overload;  
    10.   
    11. 实现代码:  
    12.   
    13. type  
    14.   PARGBQuadW = ^TARGBQuadW;  
    15.   TARGBQuadW = packed record  
    16.     wBlue: Word;  
    17.     wGreen: Word;  
    18.     wRed: Word;  
    19.     wAlpha: Word;  
    20.   end;  
    21.   
    22. procedure ImageSetColorMatrix(var Dest: TImageData;  
    23.   const Source: TImageData; Matrix: TColorMatrix);  
    24. asm  
    25.     push        esi  
    26.     push        edi  
    27.     push        ebx  
    28.     mov         ebx, eax  
    29.     mov         edi, ecx        // edi = matrix  
    30.     mov         esi, 4          // for (i = 4; i >= 0; i --)  
    31.     fldz                        // {  
    32. @@iLoop:  
    33.     mov         ecx, 4          //   for (j = 4; j >= 0; j --)  
    34. @@jLoop:                        //   {  
    35.     cmp         ecx, esi  
    36.     je          @@1  
    37.     mov         eax, esi  
    38.     imul        eax, 5  
    39.     add         eax, ecx  
    40.     fcom        dword ptr [edi+eax*4]  
    41.     fstsw       ax  
    42.     sahf  
    43.     je          @@1  
    44.     fstp        st(0)           //     if (i != j && matrix[i, j] != 0)  
    45.     jmp         @@TransformAll  //       goto TransformAll  
    46. @@1:  
    47.     dec         ecx  
    48.     jns         @@jLoop         //   }  
    49.     dec         esi  
    50.     jns         @@iLoop         // }  
    51.     fstp        st(0)  
    52.     fwait  
    53.   
    54.     // 处理颜色缩放(主对角线的数据)  
    55.   
    56.     sub         esp, 8+2  
    57.     mov         dword ptr [esp], 256  
    58.     fild        dword ptr [esp]  
    59.     fld         st(0)  
    60.     fmul        dword ptr [edi+(2*5+2)*4]  
    61.     fistp       dword ptr [esp]     // matrixI[0, 0] = matrix[2, 2] * 256  
    62.     fld         st(0)  
    63.     fmul        dword ptr [edi+(1*5+1)*4]  
    64.     fistp       dword ptr [esp+2]   // matrixI[0, 1] = matrix[1, 1] * 256  
    65.     fld         st(0)                 
    66.     fmul        dword ptr [edi+(0*5+0)*4]  
    67.     fistp       dword ptr [esp+4]   // matrixI[0, 2] = matrix[0, 0] * 256  
    68.     fmul        dword ptr [edi+(3*5+3)*4]  
    69.     fistp       dword ptr [esp+6]   // matrixI[0, 3] = matrix[3, 3] * 256  
    70.     mov         eax, ebx  
    71.     call        _SetCopyRegs  
    72.     pxor        mm7, mm7  
    73.     movq        mm1, [esp]      // mm1 = m44  m11  m22  m33  
    74. @@yLoop:  
    75.     push        ecx  
    76. @@xLoop:  
    77.     movd        mm0, [esi]  
    78.     punpcklbw   mm0, mm7        // mm0 = 00  A 00  R 00  G 00  B  
    79.     pmullw      mm0, mm1        // mm0 = A*m44 R*m11 G*m22 B*m33  
    80.     psrlw       mm0, 8          // mm0 = A*m44/256 R*m11/256 G*m22/256 B*m33/256  
    81.     packuswb    mm0, mm0        // mm0 = 00 00 00 00 An Rn Gn Bn  
    82.     movd        [edi], mm0  
    83.     add         esi, 4  
    84.     add         edi, 4  
    85.     loop        @@xLoop  
    86.     add         esi, eax  
    87.     add         edi, ebx  
    88.     pop         ecx  
    89.     dec         edx  
    90.     jnz         @@yLoop  
    91.     add         esp, 8+2  
    92.     jmp         @@end  
    93.   
    94.     // 处理全部颜色变换  
    95.   
    96. @@TransformAll:  
    97.     sub         esp, 5*8+2      // 浮点颜色矩阵行列交换转换为128倍整数  
    98.     mov         dword ptr [esp], 128  
    99.     fild        dword ptr [esp]  
    100.     mov         esi, esp        // esi = matrixI  
    101.     mov         eax, edi  
    102.     mov         ecx, 4          // for (i = 0; i < 4; i ++)  
    103. @@cvtLoop:                      // {  
    104.     fld         st(0)  
    105.     fmul        dword ptr [edi]  
    106.     fistp       dword ptr [esi]     // matrixI[i, 0] = matrix[0, i] * 128  
    107.     fld         st(0)  
    108.     fmul        dword ptr [edi+1*5*4]  
    109.     fistp       dword ptr [esi+2]   // matrixI[i, 1] = matrix[1, i] * 128  
    110.     fld         st(0)  
    111.     fmul        dword ptr [edi+2*5*4]  
    112.     fistp       dword ptr [esi+4]   // matrixI[i, 2] = matrix[2, i] * 128  
    113.     fld         st(0)  
    114.     fmul        dword ptr [edi+3*5*4]  
    115.     fistp       dword ptr [esi+6]   // matrixI[i, 3] = matrix[3, i] * 128  
    116.     add         esi, 8  
    117.     add         edi, 4  
    118.     loop        @@cvtLoop       // }  
    119.     fstp        st(0)  
    120.     add         eax, 4*5*4      // 浮点数平移量转换为255倍整数  
    121.     mov         dword ptr [esi], 255  
    122.     fild        dword ptr [esi]  
    123.     mov         ecx, 4          // for (j = 0; j < 4; j ++)  
    124. @@tLoop:  
    125.     fld         st(0)  
    126.     fmul        dword ptr [eax]  
    127.     fistp       dword ptr [esi]     // matrixI[4, j] = matrix[4, j] * 255  
    128.     add         esi, 2  
    129.     add         eax, 4  
    130.     loop        @@tLoop  
    131.     fstp        st(0)  
    132.     mov         esi, esp        // 红蓝(0、2列)交换  
    133.     mov         ecx, 5          // for (i = 0; i < 5; i ++)  
    134. @@swapLoop:                     //   matrixI[i, 0] <--> matrixI[i, 2]  
    135.     mov         ax, [esi].TARGBQuadW.wBlue  
    136.     xchg        ax, [esi].TARGBQuadW.wRed  
    137.     mov         [esi].TARGBQuadW.wBlue, ax  
    138.     add         esi, 8  
    139.     loop        @@swapLoop  
    140.     mov         eax, ebx  
    141.     call        _SetCopyRegs  
    142.     pxor        mm7, mm7  
    143.     pcmpeqb     mm4, mm4        // mm4 = FF FF FF FF FF FF FF FF  
    144.     psrlw       mm4, 15         // mm4 = 00 01 00 01 00 01 00 01  
    145. @@yLoopA:  
    146.     push        ecx  
    147. @@xLoopA:  
    148.     movd        mm0, [esi]  
    149.     punpcklbw   mm0, mm7        // mm0 = 00  A 00  R 00  G 00  B  
    150.     movq        mm1, mm0  
    151.     movq        mm2, mm0  
    152.     movq        mm3, mm0  
    153.     // esp+4: ecx push stack  
    154.     pmaddwd     mm0, [esp+16+4] // mm0 = A*m43+R*m13  G*m23+B*m33  蓝色行  
    155.     pmaddwd     mm1, [esp+8+4]  // mm1 = A*m42+R*m12  G*m22+B*m32  绿色行  
    156.     pmaddwd     mm2, [esp+4]    // mm2 = A*m41+R*m11  G*m21+B*m31  红色行  
    157.     pmaddwd     mm3, [esp+24+4] // mm3 = A*m44+R*m14  G*m24+B*m34  Alpha行  
    158.     psrad       mm0, 7          // mm0 = A*m43+R*m13/128  G*m23+B*m33/128  
    159.     psrad       mm1, 7          // mm1 = A*m42+R*m12/128  G*m22+B*m32/128  
    160.     psrad       mm2, 7          // mm2 = A*m41+R*m11/128  G*m21+B*m31/128  
    161.     psrad       mm3, 7          // mm3 = A*m44+R*m14/128  G*m24+B*m34/128  
    162.     packssdw    mm0, mm1        // mm0 = Ag+Rg  Gg+Bg  Ab+Rb  Gb+Bb  
    163.     packssdw    mm2, mm3        // mm2 = Aa+Ra  Ga+Ba  Ar+Rr  Gr+Br  
    164.     pmaddwd     mm0, mm4        // mm0 = Ag+Rg+Gg+Bg=Gn  Ab+Rb+Gb+Bb=Bn  
    165.     pmaddwd     mm2, mm4        // mm2 = Aa+Ra+Ga+Ba=An  Ar+Rr+Gr+Br=Rn  
    166.     packssdw    mm0, mm2        // mm0 = 00 An 00 Rn 00 Gn 00 Bn     
    167.     paddw       mm0, [esp+32+4] // mm0 = An+At Rn+Rt Gn+Gt Bn+Bt   平移行  
    168.     packuswb    mm0, mm0        // mm0 = 00 00 00 00 An Rn Gn Bn  
    169.     movd        [edi], mm0  
    170.     add         esi, 4  
    171.     add         edi, 4  
    172.     loop        @@xLoopA  
    173.     add         esi, eax  
    174.     add         edi, ebx  
    175.     pop         ecx  
    176.     dec         edx  
    177.     jnz         @@yLoopA  
    178.     add         esp, 5*8+2  
    179. @@end:  
    180.     emms  
    181. @@Exit:  
    182.     pop         ebx  
    183.     pop         edi  
    184.     pop         esi  
    185. end;  
    186.   
    187. procedure ImageSetColorMatrix(var Data: TImageData; Matrix: TColorMatrix);  
    188. begin  
    189.   ImageSetColorMatrix(Data, Data, Matrix);  
    190. end;  

        该过程中作了更详细的注释,其特点是处理速度较快。在我的机器上,不包括图像格式转换耗时,处理千万像素图片主对角线数据耗时不到50ms,而处理全部变换耗时350-400ms。  

        下面是一个测试程序代码。该测试代码界面与《GDI+ for VCL基础 -- 颜色调整矩阵ColorMatrix详解》是一样的。有兴趣的朋友可以同里面的测试代码作一下比较。  

    [delphi] view plain copy
     
     print?
    1. unit main2;  
    2.   
    3. interface  
    4.   
    5. uses  
    6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
    7.   Dialogs, StdCtrls, Buttons, Grids, ExtCtrls, Gdiplus, ImageData;  
    8.   
    9. type  
    10.   TForm1 = class(TForm)  
    11.     Label1: TLabel;  
    12.     PaintBox1: TPaintBox;  
    13.     SpeedButton1: TSpeedButton;  
    14.     SpeedButton2: TSpeedButton;  
    15.     SpeedButton3: TSpeedButton;  
    16.     SpeedButton4: TSpeedButton;  
    17.     StringGrid1: TStringGrid;  
    18.     BitBtn1: TBitBtn;  
    19.     BitBtn3: TBitBtn;  
    20.     BitBtn2: TBitBtn;  
    21.     procedure FormCreate(Sender: TObject);  
    22.     procedure FormDestroy(Sender: TObject);  
    23.     procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;  
    24.       Rect: TRect; State: TGridDrawState);  
    25.     procedure StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;  
    26.       var Value: string);  
    27.     procedure PaintBox1Paint(Sender: TObject);  
    28.     procedure BitBtn1Click(Sender: TObject);  
    29.     procedure BitBtn2Click(Sender: TObject);  
    30.     procedure BitBtn3Click(Sender: TObject);  
    31.     procedure SpeedButton2Click(Sender: TObject);  
    32.     procedure SpeedButton3Click(Sender: TObject);  
    33.     procedure SpeedButton1Click(Sender: TObject);  
    34.     procedure SpeedButton4Click(Sender: TObject);  
    35.     procedure StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;  
    36.       const Value: string);  
    37.   private  
    38.     { Private declarations }  
    39.     Source: TGpBitmap;  
    40.     Dest: TGpBitmap;  
    41.     SrcData: TImageData;  
    42.     DstData: TImageData;  
    43.     Matrix: TColorMatrix;  
    44.   
    45.     function CheckFloatStr(Str: string): Double;  
    46.     procedure InitColorMatrix;  
    47.   public  
    48.     { Public declarations }  
    49.   end;  
    50.   
    51. var  
    52.   Form1: TForm1;  
    53.   
    54. implementation  
    55.   
    56. {$R *.dfm}  
    57.   
    58. procedure TForm1.BitBtn1Click(Sender: TObject);  
    59. begin  
    60.   ImageSetColorMatrix(DstData, SrcData, Matrix);  
    61.   PaintBox1.Invalidate;  
    62.   with StringGrid1 do  
    63.   begin  
    64.     Cells[Col, Row] := FloatToStr(Matrix[Row, Col]);  
    65.     Invalidate;  
    66.     SetFocus;  
    67.   end;  
    68. end;  
    69.   
    70. procedure TForm1.BitBtn2Click(Sender: TObject);  
    71. begin  
    72.   InitColorMatrix;  
    73.   BitBtn1.Click;  
    74. end;  
    75.   
    76. procedure TForm1.BitBtn3Click(Sender: TObject);  
    77. begin  
    78.   Close;  
    79. end;  
    80.   
    81. function TForm1.CheckFloatStr(Str: string): Double;  
    82. var  
    83.   i, len: Integer;  
    84.   dec, neg: Boolean;  
    85.   s: string;  
    86. begin  
    87.   Result := 0;  
    88.   len := Length(Str);  
    89.   if len = then Exit;  
    90.   dec := False;  
    91.   neg := False;  
    92.   i := 1;  
    93.   s := '';  
    94.   if (Str[i] = '-') or (Str[i] = '+') then  
    95.   begin  
    96.     if Str[i] = '-' then neg := True;  
    97.     Inc(i);  
    98.   end;  
    99.   while (i <= len) do  
    100.   begin  
    101.     if Str[i] = '.' then  
    102.     begin  
    103.       if dec then Break;  
    104.       dec := True;  
    105.     end  
    106.     else if (Str[i] < '0') or (Str[i] > '9') then Break;  
    107.     s := s + Str[i];  
    108.     Inc(i);  
    109.   end;  
    110.   if Length(s) > then  
    111.   begin  
    112.     if neg then s := '-' + s;  
    113.     Result := StrToFloat(s);  
    114.   end;  
    115. end;  
    116.   
    117. procedure TForm1.FormCreate(Sender: TObject);  
    118. var  
    119.   Bmp: TGpBitmap;  
    120.   Data: TBitmapData;  
    121.   R: TGpRect;  
    122. begin  
    123.   // 从文件装入图像到Bmp  
    124.   Bmp := TGpBitmap.Create('....media100_0349.jpg');  
    125.   R := GpRect(0, 0, Bmp.Width, Bmp.Height);  
    126.   // 分别建立新的源和目标图像数据到SrcData和DstData  
    127.   SrcData := NewImageData(R.Width, R.Height);  
    128.   DstData := NewImageData(R.Width, R.Height);  
    129.   // 将Bmp图像数据分别锁定拷贝到SrcData和DstData  
    130.   Data := TBitmapData(SrcData);  
    131.   Data := Bmp.LockBits(R, [imRead, imWrite, imUserInputBuf], pf32bppARGB);  
    132.   Bmp.UnlockBits(Data);  
    133.   Data.Scan0 := DstData.Scan0;  
    134.   Data := Bmp.LockBits(R, [imRead, imWrite, imUserInputBuf], pf32bppARGB);  
    135.   Bmp.UnlockBits(Data);  
    136.   Bmp.Free;  
    137.     // 分别用图像数据SrcData和DstData建立位图Source和Dest  
    138.     // 注:图像数据结构用于数据处理,位图用于显示,这样即可绑定数据结构和位图,  
    139.     //     又能避免每次处理图像数据时的锁定和解锁操作  
    140.   Source := TGpBitmap.Create(SrcData.Width, SrcData.Height, SrcData.Stride,  
    141.         pf32bppARGB, SrcData.Scan0);  
    142.   Dest := TGpBitmap.Create(DstData.Width, DstData.Height, DstData.Stride,  
    143.         pf32bppARGB, DstData.Scan0);  
    144.   
    145.   InitColorMatrix;  
    146. end;  
    147.   
    148. procedure TForm1.FormDestroy(Sender: TObject);  
    149. begin  
    150.   Dest.Free;  
    151.   Source.Free;  
    152.   FreeImageData(DstData);  
    153.   FreeImageData(SrcData);  
    154. end;  
    155.   
    156. procedure TForm1.InitColorMatrix;  
    157. var  
    158.   i, j: Integer;  
    159. begin  
    160.   for i := to do  
    161.   begin  
    162.     for j := to do  
    163.       if i = j then Matrix[i, j] := else Matrix[i, j] := 0;  
    164.   end;  
    165. end;  
    166.   
    167. procedure TForm1.PaintBox1Paint(Sender: TObject);  
    168. var  
    169.   g: TGpGraphics;  
    170. begin  
    171.   g := TGpGraphics.Create(PaintBox1.Canvas.Handle);  
    172.   try  
    173.     g.DrawImage(Source, 10, 10);  
    174.     g.DrawImage(Dest, SrcData.Width + 20, 10);  
    175.   finally  
    176.     g.Free;  
    177.   end;  
    178. end;  
    179.   
    180. procedure TForm1.SpeedButton1Click(Sender: TObject);  
    181. var  
    182.   i: Integer;  
    183. begin  
    184.     InitColorMatrix;  
    185.     for i := to do  
    186.   begin  
    187.     Matrix[0, i] := 0.30;  
    188.     Matrix[1, i] := 0.59;  
    189.     Matrix[2, i] := 0.11;  
    190.   end;  
    191.     BitBtn1.Click;  
    192. end;  
    193.   
    194. procedure TForm1.SpeedButton2Click(Sender: TObject);  
    195. var  
    196.   i: Integer;  
    197. begin  
    198.     InitColorMatrix;  
    199.     for i := to do  
    200.         Matrix[4, i] := 0.10;  
    201.     BitBtn1.Click;  
    202. end;  
    203.   
    204. procedure TForm1.SpeedButton3Click(Sender: TObject);  
    205. begin  
    206.   InitColorMatrix;  
    207.   Matrix[0, 0] := -1;  
    208.   Matrix[1, 1] := -1;  
    209.   Matrix[2, 2] := -1;  
    210.   BitBtn1.Click;  
    211. end;  
    212.   
    213. procedure TForm1.SpeedButton4Click(Sender: TObject);  
    214. begin  
    215.   InitColorMatrix;  
    216.   Matrix[3, 3] := 0.5;  
    217.   BitBtn1.Click;  
    218. end;  
    219.   
    220. procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;  
    221.   Rect: TRect; State: TGridDrawState);  
    222. var  
    223.   Text: string;  
    224. begin  
    225.   Text := Format('%.2f', [Matrix[ARow, ACol]]);  
    226.   StringGrid1.Canvas.FillRect(Rect);  
    227.   StringGrid1.Canvas.Pen.Color := clBtnShadow;  
    228.   StringGrid1.Canvas.Rectangle(Rect);  
    229.   InflateRect(Rect, -2, -2);  
    230.   DrawText(StringGrid1.Canvas.Handle, PChar(text), Length(text), &Rect, DT_RIGHT);  
    231. end;  
    232.   
    233. procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;  
    234.   var Value: string);  
    235. begin  
    236.   Value := Format('%.2f', [Matrix[ARow, ACol]]);  
    237. end;  
    238.   
    239. procedure TForm1.StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;  
    240.   const Value: string);  
    241. begin  
    242.   Matrix[ARow, ACol] := CheckFloatStr(Value);  
    243. end;  
    244.   
    245. end.  

         下面是运行效果图:

    效果图
        该效果图是个处理-1矩阵实现图像取反的画面,仔细观察右边的取反图,不难发现其中有不少黑色的点,尤其是画面右上角“圣亚”2个字下面,更是出现一些难看的色斑,这些问题在《GDI+ ColorMatrix的完全揭秘》中已经作了详细的解说。其实这个问题完全可以进行改进,但本文的目的是揭秘和完整实现,改进后,一些非主要效果肯定会与“正版”不一样。^_^
     
    后记(2012/12/20):
        昨天整理BLOG,更新《C++图像处理 -- 颜色矩阵变换》文章时,却发现Win7环境下的GDI+ 颜色矩阵变换效果同XP环境下的效果有很大不同(比如前面例子运行的反色效果图在Win7中为黑色图),而本文前面的颜色矩阵变换代码是仿XP效果写的,因此,重新写了一段仿Win7 GDI+颜色矩阵变换效果的代码贴在下面:
    [delphi] view plain copy
     
     print?
    1. procedure ImageSetColorMatrix(var Dest: TImageData;  
    2.   const Source: TImageData; Matrix: TColorMatrix); overload;  
    3. asm  
    4.     push      ebp  
    5.     push      esi  
    6.     push      edi  
    7.     push      ebx  
    8.     // ebp为16字节对齐的128位栈内存地址  
    9.     sub       esp, 32  
    10.     mov       ebp, esp  
    11.     add       ebp, 16  
    12.     and       ebp, -16  
    13.   
    14.     // 检查颜色矩阵除主对角线和虚拟列外的数据项,如不等于零,执行全部颜色变换  
    15.     mov       edi, ecx  
    16.     mov       esi, 4          // for (i = 4; i >= 0; i --)  
    17. @@iLoop:                      // {  
    18.     mov       ecx, 3          //   for (j = 3; j >= 0; j --)  
    19. @@jLoop:                      //   {  
    20.     cmp       ecx, esi        //     if (i == j) continue  
    21.     je        @@1  
    22.     lea       ebx, [esi+esi*4]  
    23.     add       ebx, ecx        //     index = i * 5 + j  
    24.     cmp       dword ptr[edi+ebx*4], 0  
    25.     jne       @@Transform     //     if (Matrix[Index]) goto @@Transform  
    26. @@1:  
    27.     dec       ecx  
    28.     jns       @@jLoop         //   }  
    29.     dec       esi  
    30.     jns       @@iLoop         // }  
    31.   
    32.     // 处理颜色缩放  
    33.     mov       ebx, [edi+(2*5+2)*4]  
    34.     mov       ecx, [edi+(1*5+1)*4]  
    35.     mov       [ebp], ebx  
    36.     mov       [ebp+4], ecx  
    37.     mov       ebx, [edi+(0*5+0)*4]  
    38.     mov       ecx, [edi+(3*5+3)*4]  
    39.     mov       [ebp+8], ebx  
    40.     mov       [ebp+12], ecx  
    41.     movaps    xmm1, [ebp]     // xmm1 = m44 m11 m22 m33  
    42.     pxor      xmm7, xmm7  
    43.     call      _SetCopyRegs  
    44. @@yLoop_Scale:  
    45.     push      ecx  
    46. @@xLoop_Scale:  
    47.     movd      xmm0, [esi]  
    48.     punpcklbw xmm0, xmm7  
    49.     punpcklwd xmm0, xmm7  
    50.     cvtdq2ps  xmm0, xmm0  
    51.     mulps     xmm0, xmm1      // xmm0 = [A R G B] * [m44 m11 m22 m33]  
    52.     cvtps2dq  xmm0, xmm0  
    53.     packssdw  xmm0, xmm7  
    54.     packuswb  xmm0, xmm7  
    55.     movd      [edi], xmm0  
    56.     add       esi, 4  
    57.     add       edi, 4  
    58.     loop      @@xLoop_Scale  
    59.     pop       ecx  
    60.     add       esi, eax  
    61.     add       edi, ebx  
    62.     dec       edx  
    63.     jnz       @@yLoop_Scale  
    64.     jmp       @@Exit  
    65.   
    66.     // 处理全部的颜色变换  
    67. @@Transform:  
    68.     // 颜色矩阵按行分别装入sse寄存器,不包括虚拟位列  
    69.     movups    xmm1, [edi+0*5*4]  
    70.     movups    xmm2, [edi+1*5*4]  
    71.     movups    xmm3, [edi+2*5*4]  
    72.     movups    xmm4, [edi+3*5*4]  
    73.     movups    xmm5, [edi+4*5*4]  
    74.     // 平移行乘上255  
    75.     mov       ebx, 255  
    76.     cvtsi2ss  xmm6, ebx  
    77.     pshufd    xmm6, xmm6, 0  
    78.     mulps     xmm5, xmm6  
    79.     // 交换每行的红与蓝位置  
    80.     pshufd    xmm1, xmm1, 11000110b  
    81.     pshufd    xmm2, xmm2, 11000110b  
    82.     pshufd    xmm3, xmm3, 11000110b  
    83.     pshufd    xmm4, xmm4, 11000110b  
    84.     pshufd    xmm5, xmm5, 11000110b  
    85.     // 平移行保存在栈中  
    86.     movaps    [ebp], xmm5  
    87.     pxor      xmm7, xmm7  
    88.     call      _SetCopyRegs  
    89. @@yLoop:  
    90.     push      ecx  
    91. @@xLoop:  
    92.     movd      xmm0, [esi]  
    93.     punpcklbw xmm0, xmm7  
    94.     punpcklwd xmm0, xmm7  
    95.     cvtdq2ps  xmm0, xmm0  
    96.     pshufd    xmm5, xmm0, 0  
    97.     pshufd    xmm6, xmm0, 01010101b  
    98.     mulps     xmm5, xmm3      // vb = blue * m3  
    99.     mulps     xmm6, xmm2      // vg = green * m2  
    100.     addps     xmm5, [ebp]     // vb += m5  
    101.     addps     xmm5, xmm6      // vb += vg  
    102.     pshufd    xmm6, xmm0, 10101010b  
    103.     pshufd    xmm0, xmm0, 11111111b  
    104.     mulps     xmm6, xmm1      // vr = red * m1  
    105.     mulps     xmm0, xmm4      // va = alpha * m4  
    106.     addps     xmm0, xmm6      // v = va + vr  
    107.     addps     xmm0, xmm5      // v += vb  
    108.     cvtps2dq  xmm0, xmm0  
    109.     packssdw  xmm0, xmm7  
    110.     packuswb  xmm0, xmm7  
    111.     movd      [edi], xmm0  
    112.     add       esi, 4  
    113.     add       edi, 4  
    114.     loop      @@xLoop  
    115.     pop       ecx  
    116.     add       esi, eax  
    117.     add       edi, ebx  
    118.     dec       edx  
    119.     jnz       @@yLoop  
    120. @@Exit:  
    121.     add       esp, 32  
    122.     pop       ebx  
    123.     pop       edi  
    124.     pop       esi  
    125.     pop       ebp  
    126. end;  
    127.   
    128. procedure ImageSetColorMatrix(var Data: TImageData; Matrix: TColorMatrix); overload;  
    129. begin  
    130.   ImageSetColorMatrix(Data, Data, Matrix);  
    131. end;  
    132. //---------------------------------------------------------------------------  
        《Delphi图像处理》系列使用GDI+单元下载地址和说明见文章《GDI+ for VCL基础 -- GDI+ 与 VCL》。

        因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com

        这里可访问《Delphi图像处理 -- 文章索引》。

  • 相关阅读:
    Android下获取FPS的几种方法
    Headless Android开发板的调试及远程显示和控制
    ServiceHub.DataWarehouseHost.exe内存泄漏问题的处理
    Android远程桌面助手(Build 0787)
    Android远程桌面助手(Build 0737)
    Vysor破解助手for Linux/macOS/Windows
    Android远程桌面助手
    Vysor破解助手for Linux and macOS
    Django入门第一步(安装和创建一个简单的项目)
    Python-操作Excel
  • 原文地址:https://www.cnblogs.com/h2zZhou/p/6524671.html
Copyright © 2011-2022 走看看