转载自阿发伯: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实现原理:

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

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

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

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

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

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

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

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

下面是运行效果图:

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

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

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

Delphi图像处理 -- 颜色矩阵变换的更多相关文章

  1. Delphi图像处理 -- 文章索引

    转载:http://blog.csdn.net/maozefa/article/details/7188354 本文对已发布<Delphi图像处理>系列文章进行索引链接,以方便阅读和查找. ...

  2. Delphi图像处理 -- RGB与HSV转换

    阅读提示:     <Delphi图像处理>系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM.     <C++图像处理>系列以代码清晰,可读性为主,全部使用C ...

  3. Delphi图像处理 -- RGB与HSL转换

    阅读提示:     <Delphi图像处理>系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM.     <C++图像处理>系列以代码清晰,可读性为主,全部使用C ...

  4. Delphi图像处理 -- 最大值

    阅读提示:     <Delphi图像处理>系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM.     <C++图像处理>系列以代码清晰,可读性为主,全部使用C ...

  5. Delphi图像处理 -- 最小值

    阅读提示:     <Delphi图像处理>系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM.     <C++图像处理>系列以代码清晰,可读性为主,全部使用C ...

  6. Delphi图像处理控件

    Envision Image Library (Full Sources for D7 to D10-Seattle) v3.08http://www.intervalsoftware.com/env ...

  7. C 图像处理 颜色相关宏定义

    很多年前整理的,像素处理的宏定义,包括r8g8b8到r5g6b5之间的相互转化,浮点数像素与整数值之间的相互转化,像素值的插值.取反等处理.具体没什么好说的,宏定义的代码还是很容易看的.这套东西对搞图 ...

  8. Delphi word 颜色

    unit Unit1;   interface   uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, ...

  9. 图像处理------颜色梯度变化 (Color Gradient)

    有过UI设计经验的一定对2D图形渲染中的Color Gradient 或多或少有些接触,很多编程 语言也提供了Gradient的接口,但是想知道它是怎么实现的嘛? 本文介绍三种简单的颜色梯度变化算法, ...

随机推荐

  1. 模拟 - BZOJ 1510 [POI2006] Kra-The Disks

    BZOJ 1510 [POI2006] Kra-The Disks 描述 Johnny 在生日时收到了一件特殊的礼物,这件礼物由一个奇形怪状的管子和一些盘子组成. 这个管子是由许多不同直径的圆筒(直径 ...

  2. Python_Virtualenv及Pycharm配置

    Virtualenv存在的意义 在Python使用过程中,你是否有遇到过同时需要开发多个应用的情况? 假设A应用需要使用DJango1.X版本,而B应用需要使用DJango2.X的版本,而你全局开发环 ...

  3. 【SDOJ 3741】 【poj2528】 Mayor's posters

    Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral electio ...

  4. TOJ4537: n阶行列式

    4537: n阶行列式  Time Limit(Common/Java):1000MS/3000MS     Memory Limit:65536KByteTotal Submit: 28       ...

  5. phpcms 后台也名称

    announce 公告 show.html 内容页 comment 评论 show_list.html 内容页评论列表 list.html 评论列表 content 内容模型 category.htm ...

  6. [转]如何把嵌套的python list转成一个一维的python list?

    import itertools a = [[1,2,3],[4,5,6], [7], [8,9]] out = list(itertools.chain.from_iterable(a))

  7. ibatis 动态SQL

    直接使用JDBC一个非常普遍的问题就是动态SQL.使用参数值.参数本身和数据列都是动态SQL,通常是非常困难的.典型的解决办法就是用上一堆的IF-ELSE条件语句和一连串的字符串连接.对于这个问题,I ...

  8. 九度oj 题目1358:陈博的平均主义

    题目描述: 在JOBDU团队里,陈博是最讲平均主义的人了,但并不是像梁山好汉那样能够做到有钱同花,有肉同吃,毕竟,他还是被家里的领导管着的……陈博的平均主义,就只能体现在他对数字的喜好了.陈博特别喜欢 ...

  9. 设计模式(二 & 三)工厂模式:1-简单工厂模式

    模拟场景: 需要构造一个运算器(Operation),分别负责加减乘除的运算功能. 思想: 这里需要构造四个 Operation,可以使用 Factory 去统一创建这四个对象. 所需要构造的对象是运 ...

  10. 【Luogu】P3396哈希冲突(根号算法)

    题目链接 根号算法真的是博大精深啊……明明是暴力但复杂度就是能过 这也太强了吧!!! 预处理出p<=sqrt(n)的所有情况,耗时n根n 查询: 如果p<=根n,O1查表 如果p>= ...