Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Чёрно-белой растр. [D7, XP]


Страницы:   1 2

Б ©   (2009-12-20 00:58:00) 

Здрасти!

Появилась необходимость вывести черно-белый bmp, да по-быстрее.
Нашёл свой старых исходник, немного подравил.


Procedure XGrayBmp(var B: TBitmap);      // 24 bit.
Type
 TRGBTripleArray =  array [0..0] of TRGBTriple;
Var
 x, y: LongWord;
 Line: ^TRGBTripleArray;
begin
 For y:= 0 to B.Height - 1 do
 begin
   Line:= B.ScanLine[y];
   For x:= 0 to B.Width - 1 do
   With Line[x] do
   begin
     rgbtRed  := (rgbtRed + rgbtGreen + rgbtBlue) div 3;
     rgbtGreen:= rgbtRed;
     rgbtBlue := rgbtRed;
   end;
 end;
End;


Как бы её оптимизировать малехо?


0x00FF00   (2009-12-20 22:28:00) [21]

мм.. стоп, лучше беззнаковое:

MUL EBX
вместо
IMUL EAX, EBX

звиняюсь.

PS.
Кстати, в самом деле, стоит просить у автора "эталонную" картинку.


0x00FF00   (2009-12-20 22:25:00) [22]


> Неочевидно. Команды умножения выполняются дольше команд
> сложения или вычисления адреса.

Согласен.
Поэтому, при "коэффициентном" варианте возможна дальнейшая оптимизация:

 MOV EBX, 010101h;

...

   @inner_loop:
     MOV EDX, DWORD PTR [ESI];
     MOVZX EAX, DL;
     SHR EDX, 8;
     MOVZX EDI, DL;
     MOVZX EDX, DH;
     LEA EDI, [EDI*4+EDX];
     LEA EDI, [EDI+EDX*2];
     ADD EAX, EDI;
     IMUL EAX, EBX; // выполняется быстрее, чем 3 команды пересылки однобайтных регистров
     MOV DWORD PTR [ESI], EAX;
     add esi, k
     dec ecx
   jnz @inner_loop


Anatoly Podgoretsky   (2009-12-20 21:42:00) [23]

> Игорь Шевченко  (20.12.2009 21:37:14)  [14]

Команда LOOP очень медленная, пара команд dec ecx/jnz @inner_loop значительно быстрее.


Игорь Шевченко   (2009-12-20 21:37:00) [24]


>    dec ecx
>    jnz @inner_loop


мой комментарий:

 loop @inner_loop


> По-моему, так будет быстрее.


Неочевидно. Команды умножения выполняются дольше команд сложения или вычисления адреса.

Вообще-то практика - критерий истины, хотелось бы поиметь эталонную картинку, желательно большого размера, ну и

FlushInstructionCache;
rdtsc
код_1
rdtsc
FlushInstructionCache;
rdtsc
код_2
rdtsc
...


0x00FF00   (2009-12-20 21:16:00) [25]

Ах да. Складывается всё без коэффициентов.
Если необходимы коэффициенты, то следует:
MOV BX, 5556h;
сменить на
MOV BX, 2001h;
а
ADD EAX, EDX;
на
LEA EDI, [EDI*4+EDX];
LEA EDI, [EDI+EDX*2];

вроде так.


0x00FF00   (2009-12-20 21:06:00) [26]

Небольшой комментарий к коду antonn:

 push ebx
 push edi
 push esi

 MOV EBX, 5556h;                // (2^16)+3 div 3
 @outer_loop:

   mov esi, p
   mov ecx, i

   @inner_loop:
     MOV EDX, DWORD PTR [ESI];  // экономим два обращения к памяти
     MOVZX EAX, DL;
     SHR EDX, 8;
     MOVZX EDI, DL;
     MOVZX EDX, DH;
     ADD EAX, EDX;
     ADD EAX, EDI;              // всё складываем (при этом сумма не вылезает за WORD)
     MUL BX;                    // и делим на 3 (в итоге имеем результат не более 0FFh, влезающий в DL)
     IMUL EDX, 010101;          // затем размножаем на 3 байта то, что получилось
     MOV DWORD PTR [ESI], EDX;  // записываем всё разом
     add esi, k
   dec ecx
   jnz @inner_loop

   mov ecx, incr
   add p, ecx
   dec ii
 jnz @outer_loop

 pop esi
 pop edi
 pop ebx


Мои вставки выделены КАПСОМ.
По-моему, так будет быстрее.


Sapersky   (2009-12-20 18:43:00) [27]

antonn ©   (20.12.09 01:25) [1]

Ох уж эти маньяки-ассемблерщики... ровно то же самое на Паскале процентов на 10-15 быстрее, несмотря на "ляпы" компилятора (которых есть):

Procedure XGrayBmp(B: TBitmap);
Type
 PFColor = ^TFColor;
 TFColor = record
   b,g,r: Byte;
 end;
Var
x, y, h, Gap, dBpp : Integer;
pc : PFColor;
begin
h := B.Height-1;
If (h < 0) or (not (B.PixelFormat in [pf24bit, pf32bit])) then Exit;
If B.PixelFormat = pf24bit then dBpp := 3
                          else dBpp := 4;
pc := B.ScanLine[h];
If h > 0 then
 Gap := (Integer(B.ScanLine[h-1]) - Integer(pc)) - B.Width * dBpp;

For y:= 0 to h do begin
 For x:= 0 to B.Width - 1 do begin
   With pc^ do begin
     b := (b + g * 4 + r * 3) shr 3;
     g := b; r := b;
   end;
   Inc(PByte(pc), dBpp);
 end;
 Inc(PByte(pc), Gap);
end;
End;

Если уж маньячить по полной - то movzx eax быстрее mov al. Иногда компилятор использует movzx, но в данном случае почему-то нет.


Омлет   (2009-12-20 15:06:00) [28]

Можно еще оптимизировать мой вариант - избавиться от умножения.
Для этого нужно заранее проициализировать 3 массива с уже умноженными значениями:

var
 ArrXB, ArrXG, ArrXR: array[Byte] of Integer;
...
for I := 0 to 255 do
begin
 ArrXB[I] := I * 28;
 ArrXG[I] := I * 151;
 ArrXR[I] := I * 77;
end;


А потом использовать

N := (ArrXB[P[XB]] + ArrXG[P[XG]] + ArrXR[P[XR]]) shr 8;


Омлет   (2009-12-20 14:30:00) [29]

> [6] antonn ©   (20.12.09 09:38)
> разве битмап не одним куском идет?
> один цикл, только вычислить где находится начало последней
> строки и с нее начинать:
> for i:=0 to DIB.dsBmih.biHeight*DIB.dsBmih.biWidth-1 do
> в каждом шаге увеличение XB/Xg/Xr

Ты забываешь про выравнивание. Это же 24bit, а не 32bit.


Б   (2009-12-20 13:05:00) [30]


> Автор, а нафига var ?


Тогда out. ;)


> простое сложение и деление на три дает очень плохой вариант


Буду делать по стандарту YCbCr.


> Во первых черно-белый это когда 1 бит на пиксель


Старые фотографии называют чёрно-белыми, а не в шкале чёрного.


Anatoly Podgoretsky   (2009-12-20 12:57:00) [31]

> Б  (20.12.2009 00:58:00)  [0]

Во первых черно-белый это когда 1 бит на пиксель, а во вторых если речь идет о шкале черного, то простое сложение и деление на три дает очень плохой вариант, складывать надо по формуле и кроме того это должен быть 8 битный формат, а не 24 битный.


antonn   (2009-12-20 09:38:00) [32]


> Омлет ©   (20.12.09 02:29) [4]

разве битмап не одним куском идет?
один цикл, только вычислить где находится начало последней строки и с нее начинать:
for i:=0 to DIB.dsBmih.biHeight*DIB.dsBmih.biWidth-1 do
в каждом шаге увеличение XB/Xg/Xr


Омлет   (2009-12-20 02:30:00) [33]

> BWThreshold24Bit

Название сменить только надо


Омлет   (2009-12-20 02:29:00) [34]

procedure BWThreshold24Bit(Bmp: TBitmap);
var
 P               : PByteArray;
 X, Y, N,
 XR, XG, XB,
 BytesInScanLine : Integer;
 DIB             : TDIBSection;
begin
 if (Bmp.PixelFormat = pf24Bit) and
    (GetObject(Bmp.Handle, SizeOf(DIB), @DIB) = SizeOf(DIB)) and
    (DIB.dsBmih.biHeight > 0) then
 begin
   BytesInScanLine := (((DIB.dsBmih.biWidth * DIB.dsBmih.biBitCount) + 31) and not 31) div 8;
   P := DIB.dsBm.bmBits;
   for Y := DIB.dsBmih.biHeight - 1 downto 0 do
   begin
     XB := 0;
     XG := 1;
     XR := 2;
     for X := 0 to DIB.dsBmih.biWidth - 1 do
     begin
       N := (28*P[XB] + 151*P[XG] + 77*P[XR]) shr 8; { Это по правильной формуле серого 0.299*Red + 0.587*Green + 0.114*Blue  }
       P[XB] := N;
       P[XG] := N;
       P[XR] := N;
       Inc(XB, 3);
       Inc(XG, 3);
       Inc(XR, 3);
     end;
     Integer(P) := Integer(P) + BytesInScanLine;
   end;
 end;
end;


antonn   (2009-12-20 02:10:00) [35]

как хорошо что я пометил о "вырезке" =)


> Автор, а нафига var ?

чтобы враг не пролез


Игорь Шевченко   (2009-12-20 01:48:00) [36]

antonn ©   (20.12.09 01:25) [1]


>   xor   ebx, ebx
>        xor   edx, edx
>      @outer_loop:
>
>      @inner_loop:
>        xor   ebx, ebx
>        xor   edx, edx


это типа оптимизация такая, или в первый раз может не очиститься ? :)


>        mov   edi, eax
>        shl   ebx, 2
>        add   edi, edx
>        add   edi, ebx
>        shl   edx, 1
>        add   edi, edx
>        shr   edi, 3
>        mov   eax, edi


А если так:

      mov   al, byte ptr [esi]
      mov   bl, byte ptr [esi+1]
      mov   dl, byte ptr [esi+2]
      lea eax,[eax+ebx*4]
      lea eax,[eax+edx*2]
      add eax, edx
      shr  eax, 3
...


Не быстрее получится ? (Я может глупость сказал ?)


> Procedure XGrayBmp(var B: TBitmap);      // 24 bit.


Автор, а нафига var ?


antonn   (2009-12-20 01:25:00) [37]

такие вещи в мультимедии обычно спрашивают :)
procedure Greyscale_24_32(bt:tbitmap);
var i,ii,k:integer; p:pointer; incr:integer;
   Section:TDIBSECTION;
begin
 bt.HandleType:=bmDIB;
 GetObject(bt.Handle,sizeof(TDIBSECTION),@Section);
 i:=bt.Width;
 p:=Section.dsBm.bmBits;
 incr:=((Section.dsBmih.biBitCount * Section.dsBmih.biWidth + 31) shr 3) and $FFFFFFFC;
 ii:=bt.height;
 k:=Section.dsBmih.biBitCount shr 3;

 asm
     push  ebx
     push  edi
     push  esi

       xor   ebx, ebx
       xor   edx, edx
     @outer_loop:

       mov   esi, p
       mov   ecx, i
     @inner_loop:
       xor   eax, eax
       xor   ebx, ebx
       xor   edi, edi
       xor   edx, edx
       mov   al, byte ptr [esi]
       mov   bl, byte ptr [esi+1]
       mov   dl, byte ptr [esi+2]
       mov   edi, eax
       shl   ebx, 2
       add   edi, edx
       add   edi, ebx
       shl   edx, 1
       add   edi, edx
       shr   edi, 3
       mov   eax, edi
       mov   byte ptr [esi], al
       mov   byte ptr [esi+1], al
       mov   byte ptr [esi+2], al

       add   esi, k
       dec   ecx
       jnz   @inner_loop

       mov   ecx, incr
       add   p, ecx
       dec   ii
       jnz   @outer_loop

       pop   esi
       pop   edi
       pop   ebx
 end;
end;

код слегка вырезан из spriteutils, на моем проце в 3 раза быстрее твоей


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо