Об ускорении работы с графикой

Материал из DRKB


Сегодня поговорим о том, как по-другому можно ускорить работу с графикой.

Иногда нужные точки изображения не находятся в одной строке, например, при повороте. Для увеличения скорости в этом случае выгодно поместить всю картинку в доступную память. Для этого используется функция GetDIB. Она копирует изображение в выделенную для этого память. А дальше, чтобы узнать цвет точки (x, y) изображения WxH нужно воспользоваться следующей "формулой":

PRGBTriple(Integer(p) + (H - y - 1) * (3 * W + dw) + x * 3)^

Эта "формула" возвращает цвет в формате TRGBTriple. TRGBTriple - это запись с тремя полями: красная, зеленая и синяя составляющие цвета. dw - это w mod 4 и нужен он для того, чтобы создавать сдвиг, связанный с шириной изображения.

Эта программа "размывает" изображение, просто находя среднее арифметическое для каждой составляющей цвета близлежащих точек. При нажатии на Button1 изображение "размывается" с использованием GetDIB, а при нажатии на Button2 используется свойство Pixels. Время работы алгоритма в миллисекундах выводится в заголовок окна.

const
  d = 5;

procedure TForm1.Button1Click(Sender: TObject);
type
  PRGBTripleArray = ^TRGBTripleArray;
  TRGBTripleArray = array [0..0] of TRGBTriple;
var
  bi: PBitmapInfo;
  InfoSize, ImageSize: Cardinal;
  bmS, bmD: TBitmap;
  p: Pointer;
  line: PRGBTripleArray;
  t: Cardinal;
  r, g, b: Integer;
  w, h, x, y, x1, y1: Integer;
  left, right, top, bottom: Integer;
  dw, norm: Integer;
begin
  bmS := TBitmap.Create;
  bmS.LoadFromFile('ex.bmp');
  bmS.PixelFormat := pf24bit;
  w := bmS.Width;
  h := bmS.Height;
  bmD := TBitmap.Create;
  bmD.Width := w;
  bmD.Height := h;
  bmD.PixelFormat := pf24bit;
  t := GetTickCount;
  dw := w mod 4;
  GetDIBSizes(bmS.Handle, InfoSize, ImageSize);
  GetMem(p, ImageSize);
  GetMem(bi, InfoSize);
  GetDIB(bmS.Handle, 0, bi^, p^);
  for y := 0 to h - 1 do
  begin
    line := bmD.ScanLine[y];
    if y > d then
      top := y - d
    else
      top := 0;
    if y + d < h - 1 then
      bottom := y + d
    else
      bottom := h - 1;
    for x := 0 to w - 1 do
    begin
      r := 0;
      g := 0;
      b := 0;
      if x > d then
        left := x - d
      else
        left := 0;
      if x + d < w - 1 then
        right := x + d
      else
        right := w - 1;
      for y1 := top to bottom do
        for x1 := left to right do
        with PRGBTriple(integer(p) + (h - y1 - 1) * (3 * w + dw) + x1 * 3)^ do
        begin
          r := r + rgbtRed;
          g := g + rgbtGreen;
          b := b + rgbtBlue;
        end;
      norm := (bottom - top + 1) * (right - left + 1);
      with line^[x] do
      begin
        rgbtRed := r div norm;
        rgbtGreen := g div norm;
        rgbtBlue := b div norm;
      end;
    end;
  end;
  Form1.Caption := IntToStr(GetTickCount - t);
  Form1.Canvas.Draw(0, 0, bmS);
  Form1.Canvas.Draw(0, h + 5, bmD);
  bmS.Destroy;
  bmD.Destroy;
  FreeMem(p, ImageSize);
  FreeMem(bi, InfoSize);
end;

procedure TForm1.Button2Click(Sender: TObject);
type
  PRGBTripleArray = ^TRGBTripleArray;
  TRGBTripleArray = array [0..0] of TRGBTriple;
var
  bmS, bmD: TBitmap;
  t: Cardinal;
  r, g, b: Integer;
  w, h, x, y, x1, y1: integer;
  left, right, top, bottom: Integer;
  norm: Integer;
  c: TColor;
begin
  bmS := TBitmap.Create;
  bmS.LoadFromFile('ex.bmp');
  bmS.PixelFormat := pf24bit;
  w := bmS.Width;
  h := bmS.Height;
  bmD := TBitmap.Create;
  bmD.Width := w;
  bmD.Height := h;
  bmD.PixelFormat := pf24bit;
  t := GetTickCount;
  for y := 0 to h - 1 do
  begin
    if y > d then
      top := y - d
    else
      top := 0;
    if y + d < h - 1 then
      bottom := y + d
    else
      bottom := h - 1;
    for x := 0 to w - 1 do
    begin
      r := 0;
      g := 0;
      b := 0;
      if x > d then
        left := x - d
      else
        left := 0;
      if x + d < w - 1 then
        right := x + d
      else
        right := w - 1;
      for y1 := top to bottom do
        for x1 := left to right do
        begin
          c := bmS.Canvas.Pixels[x1, y1];
          r := r + GetRValue(c);
          g := g + GetGValue(c);
          b := b + GetBValue(c);
        end;
      norm := (bottom - top + 1) * (right - left + 1);
      bmD.Canvas.Pixels[x, y] := RGB(r div norm, g div norm, b div norm);
    end;
  end;
  Form1.Caption := IntToStr(GetTickCount - t);
  Form1.Canvas.Draw(0, 0, bmS);
  Form1.Canvas.Draw(0, h + 5, bmD);
  bmS.Destroy;
  bmD.Destroy;
end;



ID: 03632