3

I use this method to process the image, but if it contains high-resolution images, more than 1000 x 1000 pixels, the image processing takes a very long time and cause the application not responding for a while, how to overcome it.

when processing high resolution images always appear Not Responding messages as in the picture.enter image description here

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;
X-88
  • 117
  • 1
  • 2
  • 10
  • 2
    Use `ScanLine` property instead. Take a look e.g. [`here`](http://stackoverflow.com/q/13583451/960757) . Anyway, what does your code should do with those bitmaps ? It makes no sense to convert pixel's `TColor` to its RGB representation and pass it back to each color component parameter of the `RGB` function. The color component parameters are `Byte` types; you'll go out of range by passing `Longint` to `Byte` parameter. – TLama May 11 '13 at 19:49
  • TRGBTripleArray = array [0 .. 4095] of TRGBTriple; what is the maximum value of 4096? ... if I change it to 65536 what could be, or what the difference is? yes indeed I would lose the image source when button1 pressed more than once @ button1 Click GRC (Image1.Picture.Bitmap); – X-88 May 11 '13 at 21:47
  • 1
    Your GUI thread is busy, Windows 6.0+ really dislike that. You should either call Application.ProcessMessages periodically or execute your code in the dedicated thread. – OnTheFly May 12 '13 at 06:36
  • http://msdn.microsoft.com/library/windows/desktop/ms633526 – OnTheFly May 12 '13 at 06:43

3 Answers3

3

You should go with ScanLine(), as TLama suggested, and if it still takes long period to process the image, you can make the code threaded and continue the normal flow of application, or show a progress bar and force the user to wait. Keep in mind that playing with VCL controls outside of main thread isn't thread safe, so it's probably best to show some kind of notification to user that he should wait for processing to be finished.

Here is sample code of simple thread that does processing:

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.
rsrx
  • 1,433
  • 1
  • 13
  • 25
  • uses Winapi.Windows, System.Classes, Vcl.Graphics; what the purpose of this line? Do I have to use additional Componnent? – X-88 May 11 '13 at 21:56
  • 1
    Later Delphi versions uses unit scope names for RTL/VCL unit references. You can remove them and use Windows,Classes,Graphics. – LU RD May 11 '13 at 22:16
3

There are couple flaws in your GfxColorProcessor() procedure:

1) It is bad practice to declare variables as global if it's not needed. ARL and AOL should be declared inside procedure. Do you use ALL variable? If not, there is no need for it to be declared. I'm not sure about TOGfx and TLGfx variables, but if you use them only inside GfxColorProcessor() procedure, then you should declare them inside that procedure as well.

2) You're risking access violation if TLGfx bitmap has smaller height or width than TRGfx one, since you would try to ScanLine[] the line number that doesn't exist or write out of range in ARL buffer.

3) Main bottleneck in your procedure is IBG.Picture.bitmap.Assign(TOGfx); line. You should execute it after processing, not during processing. By doing this, you would call IBG.Assign() only once, instead over 1.000.000 times (X*Y).

So, your procedure should look like this. I'm assuming you want to assign TLGfx pixels red value to TRGfx ones, and then assign the new image to IBG bitmap, while leaving TRGfx and TLGfx untouched:

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;
rsrx
  • 1,433
  • 1
  • 13
  • 25
  • TOGfx = Original Bitmap TLGfx = left Bimap Layer TRGfx = Right Bitmap Layers ARL = Right Path Layer ALL = Left Path Layer AOL = Original Line all of the above variables I also use the other procedure, which is not listed in the above code. after I read the reply number 3 I just realized that: IBG.Picture.bitmap.Assign (TOGfx); has been repeated many times. and now all these messages are not showing anymore. :) thank you very much for taking the time to me!... – X-88 May 12 '13 at 03:28
0

A very simple approach to fix this problem is to call Application.ProcessMessages inside your loops. This method will let windows to process all the messages still pending and then return to your code.

During the message processing, events will be fired, for isntance, clicks will happen. One of those clicks may happen on a button used to set a variable that indicates that the process should be aborted.

I hope this helps.

AlexSC
  • 1,823
  • 3
  • 28
  • 54