阅读提示:
《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。
《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。
尽可能保持二者内容一致,可相互对照。
本文代码必须包括文章《Delphi图像处理 -- 数据类型及公用过程》中的ImageData.pas单元。
前天有个朋友发邮件向我咨询,怎样使用GDI+的ImageAttributes.SetGamma方法。他说他在使用GDI+ SetGamma方法时,发现所给参数值越大,图像越暗,反之则越亮,似乎与自己理解的不一样。我测试了一下,确实如此。我查了一下.NET2.0类库文档,关于该方法参数的说明是:
gamma 参数的典型值在 1.0 到 2.2 之间;但在某些情况下,0.1 到 5.0 范围内的值也很有用。
ImageAttributes 对象维护五种调整类别的颜色和灰度设置:默认、位图、画笔、钢笔和文本。例如,可以为默认类别指定一个伽玛值,为位图类别指定另一个伽玛值,再为钢笔类别指定另一个伽玛值。
默认的颜色调整设置和灰度调整设置适用于本身没有调整设置的所有类别。例如,如果从来没有为钢笔类别指定任何调整设置,则默认设置适用于钢笔类别。
一旦为某一类别指定了颜色调整或灰度调整设置,默认调整设置就不再适用于该类别了。例如,假定您为默认类别指定了一个调整设置集合。如果通过将 Pen 传递给 SetGamma 方法来为钢笔类别设置伽玛值,则任何默认调整设置都将不会应用于钢笔。
正常范围以外的伽玛值可用于旧式 CRT 监视器,或者用于处于非一般照明条件(例如工业环境或橱窗陈设)下的监视器。
而且还有个例子,摘录在下面:
void SetGammaExample( PaintEventArgs^ e ) { // Create an Image object from the file Camera.jpg, and draw it to // the screen. Image^ myImage = Image::FromFile( "Camera.jpg" ); e->Graphics->DrawImage( myImage, 20, 20 ); // Create an ImageAttributes object and set the gamma to 2.2. ImageAttributes^ imageAttr = gcnew ImageAttributes; imageAttr->SetGamma( 2.2f ); // Draw the image with gamma set to 2.2. Rectangle rect = Rectangle(250,20,200,200); e->Graphics->DrawImage( myImage, rect, 0, 0, 200, 200, GraphicsUnit::Pixel, imageAttr ); }
按说,按照例子代码设置伽玛校正值2.2后图像显示的结果应该是比没有使用伽玛校正前要亮一些才对,可现在结果相反!是我们理解有错,还是GDI+的BUG???
带着疑惑,网上搜索了一下,果然,在MSDN论坛上发现有同样的疑问:http://social.msdn.microsoft.com/Forums/zh-HK/csharpgeneral/thread/efc76edd-adf1-4acb-aa34-fe5fdd01b183,但版主的解答却说这样的效果是正确的。
自己写了一个设置伽玛校正的函数,与GDI+的ImageAttributes.SetGamma方法一比较,也是刚好相反。但如果把GDI+的SetGamma方法参数用倒数的形式给出,倒是与我自己写的函数效果是一样的(也可以说,把我写的函数中的exponent := 1 / Gamma语句 改为exponent := Gamma,与GDI+的SetGamma方法效果一样):
procedure ImageSetGamma(var Data: TImageData; Gamma: Single); var I: Integer; exponent: Double; gammaTab: array[0..255] of byte; begin exponent := 1 / Gamma; // 这一句改为exponent := Gamma;,与GDI+的SetGamma参数效果相同 for I := 0 to 255 do begin gammaTab[I] := Round(Power((I + 0.5) / 256, exponent) * 256 - 0.5); end; asm push ebp push esi push edi push ebx mov eax, data call _SetDataRegs lea esi, gammaTab 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; end; //--------------------------------------------------------------------------- procedure TForm1.Button3Click(Sender: TObject); var bmp: TGpBitmap; g: TGpGraphics; data: TImageData; begin bmp := TGpBitmap.Create('..\media\source.bmp'); g := TGpGraphics.Create(Canvas.Handle); g.DrawImage(bmp, 0, 0); data := LockGpBitmap(bmp); ImageSetGamma(data, 2.2); UnlockGpBitmap(bmp, data); g.DrawImage(bmp, 0, data.Height); g.Free; bmp.Free; end;
《Delphi图像处理》系列使用GDI+单元下载地址和说明见文章《GDI+ for VCL基础 -- GDI+ 与 VCL》。
因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:[email protected]
这里可访问《Delphi图像处理 -- 文章索引》。