【原创】关于在Delphi中使用TParallel实现并行运算

前几天在做一个摄像头的程序,由于镜头本身是超广角的,所以出来的图像畸变很严重,影像了识别,所以查阅了一番资料,写了一个简单的畸变处理算法,如下:

class procedure TPic.CorrectLensDistortion(const ABitmap: TBitmap; const k1, k2: Single);
var
  x, y, cx, cy: Integer;
  u, v, r2, r4, radial_distortion: Double;
  SrcColor: TAlphaColor;
  CorrectedBitmap: TBitmap;
  DistortionCache: array of TPointF;
  SrcData, DstData: TBitmapData;
begin
  if not Assigned(ABitmap) then exit;
  CorrectedBitmap := TBitmap.Create(ABitmap.Width, ABitmap.Height);
  try
    cx := ABitmap.Width div 2;
    cy := ABitmap.Height div 2;

    SetLength(DistortionCache, ABitmap.Width * ABitmap.Height);

    // 预计算畸变缓存
    for y := 0 to ABitmap.Height - 1 do
    begin
      for x := 0 to ABitmap.Width - 1 do
      begin
        u := (x - cx) / cx;
        v := (y - cy) / cy;

        r2 := u * u + v * v;
        r4 := r2 * r2;
        radial_distortion := 1 + k1 * r2 + k2 * r4;

        u := u / radial_distortion;
        v := v / radial_distortion;

        u := u * cx + cx;
        v := v * cy + cy;

        DistortionCache[y * ABitmap.Width + x] := PointF(u, v);
      end;
    end;

    if ABitmap.Map(TMapAccess.Read, SrcData) then
    try
      if CorrectedBitmap.Map(TMapAccess.Write, DstData) then
      try
        for y := 0 to ABitmap.Height - 1 do
        begin
          for x := 0 to ABitmap.Width - 1 do
          begin
            u := DistortionCache[y * ABitmap.Width + x].X;
            v := DistortionCache[y * ABitmap.Width + x].Y;

            if (u >= 0) and (u < ABitmap.Width) and (v >= 0) and (v < ABitmap.Height) then
            begin
              SrcColor := SrcData.GetPixel(Round(u), Round(v));
              DstData.SetPixel(x, y, SrcColor);
            end
            else
            begin
              DstData.SetPixel(x, y, TAlphaColorRec.Null);
            end;
          end;
        end;
      finally
        CorrectedBitmap.Unmap(DstData);
      end;
    finally
      ABitmap.Unmap(SrcData);
    end;

    ABitmap.Assign(CorrectedBitmap);
  finally
    CorrectedBitmap.Free;
    DistortionCache:=nil;
  end;
end;

写完后试跑了一下,并调整了k1和k2的系数,基本可以矫正回来一些,但运行速度很慢,视频会变得很卡,优化了一些地方,但还是无用,改进不大,于是想用线程来处理,其实这个算法耗时的地方是需要对一个bitmap的像素进行扫描,由于现在的CPU一般都是有好几个核,如果我们启动线程池来做,是不是可以提高一下速度,于是,我在这个算法基础上使用了Delphi自带的一个类:TParallel

这个类其实挺好用的,可以自动帮你处理线程池,在我这个算法中,只要能同时扫描每一行并计算,就能提高速度了,于是,我把代码改了一下:

class procedure TPic.CorrectLensDistortionByParallel(const ABitmap: TBitmap; const k1, k2: Single);
var
  cx, cy: Integer;
  DistortionCache: array of TPointF;
  SrcData, DstData: TBitmapData;
  CorrectedBitmap: TBitmap;
begin
  if not Assigned(ABitmap) then exit;
  CorrectedBitmap := TBitmap.Create(ABitmap.Width, ABitmap.Height);
  try
    cx := ABitmap.Width div 2;
    cy := ABitmap.Height div 2;

    SetLength(DistortionCache, ABitmap.Width * ABitmap.Height);

    // 预计算畸变缓存
    TParallel.For(0, ABitmap.Height - 1, procedure(y: Integer)
    var
      x: Integer;
      u, v, r2, r4, radial_distortion: Double;
    begin
      for x := 0 to ABitmap.Width - 1 do
      begin
        u := (x - cx) / cx;
        v := (y - cy) / cy;

        r2 := u * u + v * v;
        r4 := r2 * r2;
        radial_distortion := 1 + k1 * r2 + k2 * r4;

        u := u / radial_distortion;
        v := v / radial_distortion;

        u := u * cx + cx;
        v := v * cy + cy;

        DistortionCache[y * ABitmap.Width + x] := PointF(u, v);
      end;
    end);

    if ABitmap.Map(TMapAccess.Read, SrcData) then
    try
      if CorrectedBitmap.Map(TMapAccess.Write, DstData) then
      try
        TParallel.For(0, ABitmap.Height - 1, procedure(y: Integer)
        var
          x: Integer;
          u, v: Double;
          SrcColor: TAlphaColor;
        begin
          for x := 0 to ABitmap.Width - 1 do
          begin
            u := DistortionCache[y * ABitmap.Width + x].X;
            v := DistortionCache[y * ABitmap.Width + x].Y;

            if (u >= 0) and (u < ABitmap.Width) and (v >= 0) and (v < ABitmap.Height) then
            begin
              SrcColor := SrcData.GetPixel(Round(u), Round(v));
              DstData.SetPixel(x, y, SrcColor);
            end
            else
            begin
              DstData.SetPixel(x, y, TAlphaColorRec.Null);
            end;
          end;
        end);
      finally
        CorrectedBitmap.Unmap(DstData);
      end;
    finally
      ABitmap.Unmap(SrcData);
    end;

    ABitmap.Assign(CorrectedBitmap);
  finally
    CorrectedBitmap.Free;
    DistortionCache:=nil;
  end;
end;

又跑了一下,正如我所料,并行处理后速度全面提升,整个视频就不卡顿了,非常流畅,在此分享给坚持用Delphi的朋友们。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值