GDI+ 在Delphi程序的应用 -- 调整图像亮度

来源:互联网 发布:有关人工智能的新闻 编辑:程序博客网 时间:2024/05/16 07:05
GDI+ 在Delphi程序的应用 --  调整图像亮度
        调整图像的亮度可以有很多方法,最常用的方法就是对图像像素点的R、G、B三个分量同时进行增加(减少)某个值,达到调整亮度的目的。我在这里使用GDI+图像的扫描线来处理,核心处理采用了2个相同的过程,一个是Pascal过程,一个是嵌入汇编过程,通过比较,对小的图像几乎没有什么区别,对比较大的图像处理还是有一定的区别(具体测试效果见代码中的注释),这说明Delphi的代码优化还是很好的。
        使用GDI+图像的扫描线处理必须调用TGpBitmap.LockBits和TGpBitmap.UnLockBits过程,而这2个过程的调用相当耗时,以2304 *1728大小的图片为例,耗时竟达188毫秒!而亮度调整过程最长只耗时63毫秒。由此可以看出使用GDI+图像扫描线处理图像并非十分理想。
        需要说明的是,本例子及以后GDI+ for Delphi例子的Gdiplus单元是本人自己写的,与目前网上流通的版本有一定的区别,浏览着需要测试例子,可作适当修改,或者发邮件向本人索取Gdiplus单元。
 
    说明:为了统一《GDI+ 在Delphi程序的应用》系列文章所用数据类型和图像处理格式,本文代码已重新修订,代码中所用Gdiplus单元下载地址及BUG更正见文章《GDI+ for VCL基础 -- GDI+ 与 VCL》。(2008.8.18记)
 
    数据类型:
  1. type
  2.   // 与GDI+ TBitmapData结构兼容的图像数据结构
  3.   TImageData = packed record
  4.     Width: LongWord;         // 图像宽度
  5.     Height: LongWord;        // 图像高度
  6.     Stride: LongWord;        // 图像扫描线字节长度
  7.     PixelFormat: LongWord;   // 未使用
  8.     Scan0: Pointer;          // 图像数据地址
  9.     Reserved: LongWord;      // 保留
  10.   end;
  11.   PImageData = ^TImageData;
  12. // 获取TBitmap图像的TImageData数据结构,便于处理TBitmap图像
  13. function GetImageData(Bmp: TBitmap): TImageData;
  14. begin
  15.   Bmp.PixelFormat := pf32bit;
  16.   Result.Width := Bmp.Width;
  17.   Result.Height := Bmp.Height;
  18.   Result.Scan0 := Bmp.ScanLine[Bmp.Height - 1];
  19.   Result.Stride := Result.Width shl 2;
  20. //  Result.Stride := (((32 * Bmp.Width) + 31) and $ffffffe0) shr 3;
  21. end;

    过程代码:

  1. // 调整图像亮度
  2. procedure Brightness(Data: TImageData; Value: Integer);
  3. asm
  4.     push    esi
  5.     push    edi
  6.     mov     edi, [eax + 16]
  7.     mov     esi, [eax + 4]
  8.     imul    esi, [eax]
  9.     cld
  10.   @PixelLoop:
  11.     mov     ecx, 3
  12.   @RGBLoop:
  13.     movzx   eax, [edi]
  14.     add     eax, edx
  15.     jns     @@1
  16.     xor     eax, eax
  17.     jmp     @@2
  18.   @@1:
  19.     cmp     eax, 255
  20.     jle     @@2
  21.     mov     eax, 255
  22.   @@2:
  23.     stosb
  24.     loop    @RGBLoop
  25.     inc     edi
  26.     dec     esi
  27.     jnz     @PixelLoop
  28.     pop     edi
  29.     pop     esi
  30. end;
  31. // 调整GDI+图像亮度
  32. procedure GdipBrightness(Bmp: TGpBitmap; Value: Integer);
  33. var
  34.   Data: TBitmapData;
  35. begin
  36.   if Value = 0 then Exit;
  37.   Data := Bmp.LockBits(GpRect(00, Bmp.Width, Bmp.Height), [imRead, imWrite], pf32bppARGB);
  38.   try
  39.     Brightness(TImageData(Data), Value);
  40.   finally
  41.     Bmp.UnlockBits(Data);
  42.   end;
  43. end;
  44. // 调整TBitmap图像亮度
  45. procedure BitmapBrightness(Bmp: TBitmap; Value: Integer);
  46. begin
  47.   if Value <> 0 then
  48.     Brightness(GetImageData(Bmp), Value);
  49. end;

    测试代码:

  1. // 为方便初学者理解前面的BASM代码,写了个处理GDI+图像亮度的纯Pas代码过程
  2. // 稍稍改动一下,也可用来处理TBitmap图像亮度
  3. procedure GdipBrightness_Pas(Bmp: TGpBitmap; Value: Integer);
  4.   function SetRGBValue(Rgb: Byte): Integer;
  5.   begin
  6.     Result := Value + Rgb;     // 像素颜色分量 + 亮度值
  7.     if Result < 0 then         // 像素颜色分量 >= 0 and <= 255
  8.       Result := 0
  9.     else if Result > 255 then
  10.       Result := 255;
  11.   end;
  12. var
  13.   Data: TBitmapData;
  14.   P: PRGBQuad;
  15.   I, Count: LongWord;
  16. begin
  17.   if Value = 0 then Exit;
  18.   Data := Bmp.LockBits(GpRect(00, Bmp.Width, Bmp.Height), [imRead, imWrite], pf32bppARGB);
  19.   try
  20.     Count := Data.Width * Data.Height;
  21.     P := Data.Scan0;
  22.     for I := 1 to Count do
  23.     begin
  24.       P^.rgbBlue := SetRGBValue(P^.rgbBlue);
  25.       P^.rgbGreen := SetRGBValue(P^.rgbGreen);
  26.       P^.rgbRed := SetRGBValue(P^.rgbRed);
  27.       Inc(P);
  28.     end;
  29.   finally
  30.     Bmp.UnlockBits(Data);
  31.   end;
  32. end;
  33. // 测试GDI+图像
  34. procedure TForm1.Button1Click(Sender: TObject);
  35. var
  36.   Image: TGpBitmap;
  37.   g: TGpGraphics;
  38. begin
  39.   Image := TGpBitmap.Create('D:/VclLib/GdiplusDemo/Media/20041001.jpg');
  40.   g := TGpGraphics.Create(Handle, False);
  41.   g.DrawImage(Image, 1010);
  42. //  GdipBrightness_Pas(Image, 30);
  43.   GdipBrightness(Image, 30);
  44.   g.DrawImage(Image, 10220);
  45.   Image.Free;
  46.   g.Free;
  47. end;
  48. // 测试TBitmap图像
  49. procedure TForm1.Button2Click(Sender: TObject);
  50. var
  51.   Image: TBitmap;
  52. begin
  53.   Image := TBitmap.Create;
  54.   Image.LoadFromFile('D:/VclLib/GdiplusDemo/Media/20041001.bmp');
  55.   Canvas.Draw(1010, Image);
  56.   BitmapBrightness(Image, -30);
  57.   Canvas.Draw(10220, Image);
  58.   Image.Free;
  59. end;
原创粉丝点击