3

我使用这种方法处理图像,但是如果它包含高分辨率图像,超过 1000 x 1000 像素,图像处理需要很长时间并导致应用程序有一段时间没有响应,如何克服它。

处理高分辨率图像时,总是出现如图所示的 Not Responding 消息。在此处输入图像描述

type
   TRGBArray = array[0..0] of TRGBTriple;
   pRGBArray = ^TRGBArray;

var
   ARL, ALL, AOL : pRGBarray;
   TOGfx, TRGfx, TLGfx : TBitmap;


procedure TFZN.GfXColorProcessor;
var
   X, Y : integer;
begin
   TOGfx.Assign(TRGfx);
for Y := 0 to TRGfx.Height - 1 do
begin
   ARL := TOGfx.Scanline[Y];
   AOL := TLGfx.Scanline[Y];
//-------------------------
for x := 0 to TRGfx.Width - 1 do
begin
   ARL[x].RGBtRed := AOL[X].RGBtRed;
   IBG.Picture.bitmap.Assign(TOGfx);
end;

end;

end;
4

3 回答 3

3

您应该按照 TLama 的建议使用 ScanLine(),如果处理图像仍然需要很长时间,您可以使代码线程化并继续正常的应用程序流程,或者显示进度条并强制用户等待。请记住,在主线程之外使用 VCL 控件不是线程安全的,因此最好向用户显示某种通知,让他等待处理完成。

这是执行处理的简单线程的示例代码:

unit uImageProcessingThread;

interface

uses
  Winapi.Windows, System.Classes, Vcl.Graphics;

type
  TImageProcessingThread = class(TThread)
  private
    FBitmap: TBitmap;

  protected
    procedure Execute; override;

  public
    constructor Create(const ABitmap: TBitmap);

  end;

implementation

constructor TImageProcessingThread.Create(const ABitmap: TBitmap);
begin
  inherited Create(TRUE);

  FBitmap := ABitmap;
end;

procedure TImageProcessingThread.Execute;
var
  GC  : LongInt;
  H, W: Integer;
begin
  for H := 0 to FBitmap.Height do
  begin
    for W := 0 to FBitmap.Width do
    begin
      GC := ColorToRGB(FBitmap.Canvas.Pixels[W, H]);
      FBitmap.Canvas.Pixels[W, H] := RGB(GC, GC, GC);
    end;
  end;
end;

end.
于 2013-05-11T19:56:20.997 回答
3

您的GfxColorProcessor () 过程中有几个缺陷:

1) 如果不需要,将变量声明为全局变量是不好的做法。ARLAOL应该在过程中声明。你使用ALL变量吗?如果不是,则无需声明。我不确定TOGfxTLGfx变量,但如果你只在GfxColorProcessor()过程中使用它们,那么你也应该在该过程中声明它们。

2) 如果TLGfx位图的高度或宽度小于TRGfx位图,您将面临访问冲突的风险,因为您将尝试 ScanLine[] 不存在的行号或在ARL缓冲区中写入超出范围的行号。

3) 程序中的主要瓶颈是IBG.Picture.bitmap.Assign(TOGfx); 线。您应该在处理后执行它,而不是在处理期间执行。通过这样做,您将只调用一次IBG.Assign(),而不是超过 1.000.000 次 (X*Y)。

所以,你的程序应该是这样的。我假设您要将TLGfx像素红色值分配给TRGfx像素,然后将新图像分配给IBG位图,同时保持TRGfxTLGfx不变:

type
  TRGBArray = array[0..0] of TRGBTriple;
  PRGBArray = ^TRGBArray;

var
  TRGfx, TLGfx: TBitmap;

procedure TFZN.GfXColorProcessor;
var
  X, Y    : Integer;
  ARL, AOL: PRGBArray;
  tmp     : TBitmap;
begin
  Assert((TRGfx.Width = TLGfx.Width) and (TRGfx.Height = TLGfx.Height),
         'Image sizes are not equal!');

  tmp := TBitmap.Create;
  try
    tmp.Assign(TRGfx);
    for Y := 0 to tmp.Height - 1 do
    begin
      ARL := tmp.ScanLine[Y];
      AOL := TLGfx.ScanLine[Y];

      for X := 0 to tmp.Width - 1 do
        ARL[X].rgbtRed := AOL[X].rgbtRed;
    end;

    IBG.Picture.Bitmap.Assign(tmp);
  finally
    tmp.Free;
  end;
end;
于 2013-05-12T01:14:28.063 回答
0

解决此问题的一个非常简单的方法是在循环中调用Application.ProcessMessages 。此方法将让 windows 处理所有仍待处理的消息,然后返回到您的代码。

在消息处理过程中,会触发事件,例如,会发生点击。其中一次单击可能发生在用于设置变量的按钮上,该变量指示应中止进程。

我希望这有帮助。

于 2013-07-17T18:38:01.197 回答