Delphi 汇编学习(八)--- 图像水平镜像垂直镜像的极致优化

17 篇文章 4 订阅
15 篇文章 2 订阅

一:水平镜像/翻转
       将一幅图像水平镜像/翻转,代码很简单,就一行代码:

procedure HorizMirror(bmp: TBitmap);
begin
  bmp.Canvas.CopyRect(bmp.Canvas.ClipRect, bmp.Canvas, Rect(bmp.Width, 0, 0, bmp.Height));
end;

简单不。看一看 CopyRect 源码,

procedure TCanvas.CopyRect(const Dest: TRect; Canvas: TCanvas; const Source: TRect);
begin
  Changing;
  RequiredState([csHandleValid, csFontValid, csBrushValid]);
  Canvas.RequiredState([csHandleValid, csBrushValid]);
  StretchBlt(FHandle, Dest.Left, Dest.Top, Dest.Right - Dest.Left,
    Dest.Bottom - Dest.Top, Canvas.FHandle, Source.Left, Source.Top,
    Source.Right - Source.Left, Source.Bottom - Source.Top, CopyMode);
  Changed;
end;

Changing / RequireState / Changed 肯定影响效率。真正起作用的是 StrectchBlt 函数。
虽然说这个 StrectchBlt 效率已经不错了。4096x4096x32 的图片,在我的机器上耗时 100 毫秒左右。
有没有可以在优化的地方呢,如果我们自己来写该如何呢?
自己写当然是用 Scanline 方法了(简单)。按中间位置,左右水平像素对调,再加上多核并行:

{ 水平翻转 并行模式,需要脱离 IDE 执行 }
procedure HorizMirror(bmp: TBitmap);
var
  StartScanLine: Integer;
  bmpWidthBytes: Integer;
begin
  StartScanLine := Integer(bmp.ScanLine[0]);
  bmpWidthBytes := Integer(bmp.ScanLine[1]) - Integer(bmp.ScanLine[0]);

  TParallel.For(0, bmp.Height - 1,
    procedure(Y: Integer)
    var
      X: Integer;
      swapColor: DWORD;
      pColor01: PDWORD;
      pColor02: PDWORD;
    begin
      pColor01 := PDWORD(StartScanLine + Y * bmpWidthBytes);
      pColor02 := PDWORD(StartScanLine + Y * bmpWidthBytes);
      Inc(pColor02, bmp.Width - 1);
      for X := 0 to bmp.Width div 2 - 1 do
      begin
        swapColor := pColor02^;
        pColor02^ := pColor01^;
        pColor01^ := swapColor;
        Inc(pColor01);
        Dec(pColor02);
      end;
    end);
end;

这段代码,在我的机器上,4096X4096X32 的图片,只需要 5 毫秒左右的时间,非常的理想了,无需进行 SSE 优化了。

二:垂直镜像/翻转
      
垂直镜像/翻转,同样也只需要一行代码:

{ 垂直翻转 }
procedure VertiMirror(bmp: TBitmap);
begin
  bmp.Canvas.CopyRect(bmp.Canvas.ClipRect, bmp.Canvas, Rect(0, bmp.Height, bmp.Width, 0));
end;

在我的机器上,4096X4096X32 的图片,耗时 100 毫秒左右。
想一想,垂直镜像,就是上下行对调。整行内存交换呀。自己写的话,效率应该比 StrectchBlt 好。来试试:

{ 垂直镜像/翻转 }
procedure VertiMirror(bmp: TBitmap);
var
  Count, Y: Integer;
  pColor01: PByte;
  pColor02: PByte;
  tmpColor: PByte;
begin
  Count    := Integer(bmp.ScanLine[0]) - Integer(bmp.ScanLine[1]);
  tmpColor := AllocMem(Count);
  try
    for Y := 0 to bmp.Height div 2 - 1 do
    begin
      pColor01 := bmp.ScanLine[Y];
      pColor02 := bmp.ScanLine[bmp.Height - Y - 1];
      Move(pColor01^, tmpColor^, Count);
      Move(pColor02^, pColor01^, Count);
      Move(tmpColor^, pColor02^, Count);
    end;
  finally
    FreeMem(tmpColor);
  end;
end;

这段代码,没有使用多核并行,也没有使用 SSE 优化。就是内存的交换。
在我的机器上耗时 15 毫秒左右。效率提高很明显呀。6倍之多!
印证了那句话:相信指令,相信编译器,不如相信自己。自己动手,丰衣足食!
当看到 AllocMem、Move,你想到了什么?
内存管理。Delphi 优化内存的有:FastMM4、FastMM5、FastMM4-AVX、FastCode、FastMove。
对。引入试试。
在工程单元文件中,第一行,添加引用:FastMove。函数不用做任何修改。再编译一下程序。
运行看看效果。在我的机器上耗时降到了 10 毫秒左右。呵呵。不错不错。
少了 5 毫秒的时间。如何少的,看看 FastMove 源码就知道了。留作课后作业了。

三:转置
即水平翻转+垂直翻转。

{ 转置翻转 并行模式,需要脱离 IDE 执行 }
procedure HAndVMirror(bmp: TBitmap);
begin
  HorizMirror(bmp);
  VertiMirror(bmp);
end;

详细代码:https://github.com/dbyoung720/ImageGray.git
qq交流群:101611228

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值