Еще об ускорении работы с графикой
Сегодня поговорим о том, как по-другому можно
ускорить работу с графикой.
Иногда нужные точки изображения не находятся в
одной строке, например, при повороте. Для увеличения скорости в этом случае
выгодно поместить всю картинку в доступную память. Для этого используется функция
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;
Снова жду ваших идей,
Даниил Карапетян.
На сайте http://delphi4all.narod.ru
Вы найдете еще более 100 советов по Delphi.
Email: delphi4all@narod.ru