Конференция "Media" » Качественное и быстрое масштабирование картинки [D6, WinXP]
 
  • Jimmy (13.10.07 21:07) [0]
    Избитый вопрос, но все ответы которые я нашел меня не устраивают. Так как все же качественно (!) и быстро (!) масштабировать картинку? Главным образом уменьшить.
  • homm © (13.10.07 21:09) [1]
    Могу дать алгоритмы очень быстрого умменьшения в 2 и 4 раза, но завтра.
  • DrPass © (13.10.07 21:09) [2]

    > Так как все же качественно (!) и быстро (!) масштабировать
    > картинку?

    Уважаемый, если бы существовал Самый_Лучший_Алгоритм, других алгоритмов бы просто не было
  • Jimmy (13.10.07 21:17) [3]
    >homm
    Буду признателен. Буду ждать. Хотя конечно хотелось бы иметь алгоритм для произвольного k.
  • Vovan #1 © (13.10.07 21:56) [4]
    >Так как все же качественно (!) и быстро (!) масштабировать картинку?

    Качественно vs. Быстро = Оптимально

    Так как численных критериев нет, то оптимально - это может быть и алгоритм B-Spline, Mitchel, Bell, Triangle (см. Irfan View), т.е. что-то между Lanchos и Hermite.
  • Jimmy (13.10.07 22:10) [5]
    И где найти эти алгоритмы?
  • DVM © (13.10.07 23:50) [6]

    > И где найти эти алгоритмы?

    Посмотри как сделано в FastDIB. Ну можно сделать конечно и более качественно, чем там, но быстрее уже вряд ли.
  • Vovan #1 © (14.10.07 00:09) [7]
    Тогда и я говорю: посмотри Graphics32. Там, кстати, фильтронаписание поставлено на поток - все карты у пользователя-программиста.
  • homm © (14.10.07 07:10) [8]
    > [6] DVM ©   (13.10.07 23:50)
    > но быстрее уже вряд ли.

    категорически не согласен
  • antonn © (14.10.07 09:01) [9]

    > категорически не согласен

    ну тогда код в студию, чего зря фразами кидаться
  • homm © (14.10.07 14:26) [10]
    > [9] antonn ©   (14.10.07 09:01)
    > ну тогда код в студию, чего зря фразами кидаться

    Блин, я изтрахал весь яндекс, но так и не могу найти этот FastDib, дабы провести тестироание.
  • homm © (14.10.07 14:29) [11]
    Кажется нашел, нужно было сразу гугль узать :) Счас будет вам код.
  • homm © (14.10.07 14:44) [12]
    unit Unit1;

    interface

    uses
     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
     jpeg, ExtCtrls, StdCtrls, fastbmp;

    type
     TForm1 = class(TForm)
       Button1: TButton;
       Image1: TImage;
       Image2: TImage;
       Button2: TButton;
       procedure Button1Click(Sender: TObject);
       procedure Button2Click(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.DFM}

    var
    CPUisMMX: Boolean;

    function NewDIBBitmap(Wi, He: DWORD; pf: TPixelFormat): TBitmap;
    begin
    Result := TBitmap.Create;
    Result.PixelFormat := pf;
    Result.HandleType := bmDIB;
    Result.Width := Wi;
    Result.Height := He;
    end;

    function DIBBits(BMP: TBitmap): Pointer;
    var
    Section: TDIBSECTION;
    begin
    BMP.HandleType := bmDIB;
    GetObject(BMP.Handle, sizeof(TDIBSECTION), @Section);
    Result := Section.dsBm.bmBits;
    end;

    function ScanLineSize(BMP: TBitmap): Integer;
    var
    Section: TDIBSECTION;
    begin
    BMP.HandleType := bmDIB;
    GetObject(BMP.Handle, sizeof(TDIBSECTION), @Section);
    Result := ((Section.dsBmih.biBitCount * Section.dsBmih.biWidth + 31) shr 3) and $FFFFFFFC;;
    end;

    function isMMX: Boolean;
    var     I: Integer;
    begin
       I := 0;
       Result := false;
       asm // check if bit 21 of EFLAGS can be set and reset
           PUSHFD
           POP     EAX
           OR      EAX, 1 shl 21
           PUSH    EAX
           POPFD
           PUSHFD
           POP     EAX
           TEST    EAX, 1 shl 21
           JZ      @@1
           AND     EAX, not( 1 shl 21 )
           PUSH    EAX
           POPFD
           PUSHFD
           POP     EAX
           TEST    EAX, 1 shl 21
           JNZ     @@1
           INC     [ I ]
       @@1:
       end;
       if I = 0 then Exit;                  // CPUID not supported
       asm // get CPU features flags using CPUID command
           MOV     EAX, 1
           PUSH    EDX
           PUSH    EBX
           PUSH    ECX
           DB $0F, $A2
           MOV     [ I ], EDX  // I := features information
           POP     ECX
           POP     EBX
           POP     EDX
       end;
       if (I and (1 shl 23)) <> 0 then
           Result := true;
    end;

  • homm © (14.10.07 14:45) [13]
    procedure BitmapAntialias4X(SrcBitmap, DstBitmap: TBitmap);
    type    AGRBQuad = array [0..0] of TRGBQuad;
          PAGRBQuad = ^AGRBQuad;
    var     yDest: integer;
          xDest: integer;
          xSrc: integer;
          i: integer;
          R: integer;
          G: integer;
          B: integer;
          rowDest: PAGRBQuad;
          rowSrc: array [0..3] of PAGRBQuad;
          _rowSrc: PAGRBQuad;
          SrcBits: DWORD;
          DstBits: DWORD;
          dHeight: DWORD;
          dWidth: DWORD;
          Delta: DWORD;
    begin
      if CPUisMMX then begin
          SrcBits := DWORD(DIBBits(SrcBitmap));
          DstBits := DWORD(DIBBits(DstBitmap));
          dHeight := DstBitmap.Height;
          dWidth := DstBitmap.Width;
          Delta := ScanLineSize(SrcBitmap);
          asm
              pushad
              mov esi, SrcBits
              mov edi, DstBits
              //pxor mm2, mm2
              db $0f, $ef, $d2

              mov eax, dHeight
    @LM1:       push eax

              mov eax, dWidth
    @LM2:       /////////
              mov ecx, esi

              //movd mm1, [ecx]
              db $0f, $6e, $09
              //punpcklbw mm1, mm2
              db $0f, $60, $ca
              //movd mm3, [ecx+4]
              db $0f, $6e, $59, $04
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+8]
              db $0f, $6e, $59, $08
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+12]
              db $0f, $6e, $59, $0c
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb

              add ecx, Delta

              //movd mm3, [ecx]
              db $0f, $6e, $19
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+4]
              db $0f, $6e, $59, $04
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+8]
              db $0f, $6e, $59, $08
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+12]
              db $0f, $6e, $59, $0c
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb

              add ecx, Delta

              //movd mm3, [ecx]
              db $0f, $6e, $19
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+4]
              db $0f, $6e, $59, $04
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+8]
              db $0f, $6e, $59, $08
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+12]
              db $0f, $6e, $59, $0c
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb

              add ecx, Delta

              //movd mm3, [ecx]
              db $0f, $6e, $19
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+4]
              db $0f, $6e, $59, $04
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+8]
              db $0f, $6e, $59, $08
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+12]
              db $0f, $6e, $59, $0c
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb

              //psrlw mm1, 4
              db $0f, $71, $d1, $04
              //packuswb mm1, mm2
              db $0f, $67, $ca
              //movd [edi], mm1
              db $0f, $7e, $0f
              /////////
              add edi, 4
              add esi, 16

              sub eax, 1
        jnz @LM2

              mov ecx, Delta
              lea esi, [esi + ecx*2]
              add esi, ecx

              pop eax
              sub eax, 1
        jnz @LM1

              //emms
              db $0f, $77

              popad
          end;
      end else
      for yDest := 0 to DstBitmap.Height -1 do begin
          rowDest := DstBitmap.ScanLine[yDest];
          for i := 0 to 3 do
              rowSrc[i] := SrcBitmap.ScanLine[yDest*4+i];
          for xDest := 0 to DstBitmap.Width-1 do begin
              xSrc := xDest*4;
              R:=0; G:=0; B:=0;
              for i := 0 to 3 do begin
                  _rowSrc := rowSrc[i];
                  R:= R+_rowSrc[xSrc+0].rgbRed
                      + _rowSrc[xSrc+1].rgbRed
                      + _rowSrc[xSrc+2].rgbRed
                      + _rowSrc[xSrc+3].rgbRed;
                  G:= G+_rowSrc[xSrc+0].rgbGreen
                      + _rowSrc[xSrc+1].rgbGreen
                      + _rowSrc[xSrc+2].rgbGreen
                      + _rowSrc[xSrc+3].rgbGreen;
                  B:= B+_rowSrc[xSrc+0].rgbBlue
                      + _rowSrc[xSrc+1].rgbBlue
                      + _rowSrc[xSrc+2].rgbBlue
                      + _rowSrc[xSrc+3].rgbBlue;
              end;
              DWORD(rowDest[xDest]) := ((R and $0ff0) shl 12) or ((G and $0ff0) shl 4) or (B shr 4);
          end;
      end;
    end;

  • homm © (14.10.07 14:45) [14]
    procedure BitmapAntialias2X(SrcBitmap, DstBitmap: TBitmap);
    type    AGRBQuad = array [0..0] of TRGBQuad;
          PAGRBQuad = ^AGRBQuad;
    var     yDest: integer;
          xDest: integer;
          xSrc: integer;
          i: integer;
          R: integer;
          G: integer;
          B: integer;
          rowDest: PAGRBQuad;
          rowSrc: array [0..3] of PAGRBQuad;
          _rowSrc: PAGRBQuad;
          SrcBits: DWORD;
          DstBits: DWORD;
          dHeight: DWORD;
          dWidth: DWORD;
          Delta: DWORD;
    begin
      if CPUisMMX then begin
          SrcBits := DWORD(DIBBits(SrcBitmap));
          DstBits := DWORD(DIBBits(DstBitmap));
          dHeight := DstBitmap.Height;
          dWidth := DstBitmap.Width;
          Delta := ScanLineSize(SrcBitmap);
          asm
              pushad
              mov esi, SrcBits
              mov edi, DstBits
              //pxor mm2, mm2
              db $0f, $ef, $d2

              mov eax, dHeight
    @LM1:       push eax

              mov eax, dWidth
    @LM2:       /////////
              mov ecx, esi

              //movd mm1, [ecx]
              db $0f, $6e, $09
              //punpcklbw mm1, mm2
              db $0f, $60, $ca
              //movd mm3, [ecx+4]
              db $0f, $6e, $59, $04
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb

              add ecx, Delta

              //movd mm3, [ecx]
              db $0f, $6e, $19
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb
              //movd mm3, [ecx+4]
              db $0f, $6e, $59, $04
              //punpcklbw mm3, mm2
              db $0f, $60, $da
              //paddusw mm1, mm3
              db $0f, $dd, $cb

              //psrlw mm1, 2
              db $0f, $71, $d1, $02
              //packuswb mm1, mm2
              db $0f, $67, $ca
              //movd [edi], mm1
              db $0f, $7e, $0f
              /////////

              add edi, 4
              add esi, 8

              sub eax, 1
        jnz @LM2

              add esi, Delta

              pop eax
              sub eax, 1
        jnz @LM1

              //emms
              db $0f, $77

              popad
          end;
      end else
      for yDest := 0 to DstBitmap.Height -1 do begin
          rowDest := DstBitmap.ScanLine[yDest];
          for i := 0 to 1 do
              rowSrc[i] := SrcBitmap.ScanLine[yDest*2+i];
          for xDest := 0 to DstBitmap.Width-1 do begin
              xSrc := xDest*2;
              R:=0; G:=0; B:=0;
              for i := 0 to 1 do begin
                  _rowSrc := rowSrc[i];
                  R:= R+_rowSrc[xSrc+0].rgbRed
                      + _rowSrc[xSrc+1].rgbRed;
                  G:= G+_rowSrc[xSrc+0].rgbGreen
                      + _rowSrc[xSrc+1].rgbGreen;
                  B:= B+_rowSrc[xSrc+0].rgbBlue
                      + _rowSrc[xSrc+1].rgbBlue;
              end;
              DWORD(rowDest[xDest]) := ((R and $03fc) shl 14) or ((G and $03fc) shl 6) or (B shr 2);
          end;
      end;
    end;

    procedure BlendBitmaps(var DestBitmap, FromBitmap, ToBitmap: TBitmap; Factor: Integer;
    ClipRect:TRect);
    type    AGRBQuad = array [0..0] of TRGBQuad;
          PAGRBQuad = ^AGRBQuad;
    var     Factor2: byte;
          i, j: integer;
          DestRow: PAGRBQuad;
          FromRow: PAGRBQuad;
          ToRow: PAGRBQuad;
          FromDibBits: DWORD;
          ToDibBits: DWORD;
          DestDibBits: DWORD;
          _Width: integer;
          _Height: integer;
          _Right: integer;
          _Top: DWORD;
    begin
      if CPUisMMX then begin
          _Top := FromBitmap.Width * 4 * ClipRect.Top + ClipRect.Left * 4;
          FromDibBits := DWORD(DIBBits(FromBitmap)) + _Top;
          ToDibBits := DWORD(DIBBits(ToBitmap)) + _Top;
          DestDibBits := DWORD(DIBBits(DestBitmap)) + _Top;
          _Width := ClipRect.Right - ClipRect.Left;
          _Height := ClipRect.Bottom - ClipRect.Top;
          _Right := (FromBitmap.Width - ClipRect.Right + ClipRect.Left) * 4;
          asm
          mov edx, Factor
          mov dh, dl
          mov ax, dx
          shl eax, 16
          mov ax, dx

          mov esi, FromDibBits
        mov edi, ToDibBits
          mov edx, DestDibBits

          //pxor mm2, mm2
          db $0f, $ef, $d2
          //movd mm3, eax
          db $0f, $6e, $d8
          //punpcklbw mm3, mm2
          db $0f, $60, $da

          mov eax, $00404040
        //movd mm4, eax
          db $0f, $6e, $e0
          //punpcklbw mm4, mm2
          db $0f, $60, $e2
        //psubw mm4, mm3
          db $0f, $f9, $e3

          mov ecx, _Height
    @LM1:
        mov ebx, _Width
    @LM2:
          //movd mm0, [esi]
          db $0f, $6e, $06
        //movd mm1, [edi]
          db $0f, $6e, $0f
          //punpcklbw mm0, mm2
          db $0f, $60, $c2
        //punpcklbw mm1, mm2
          db $0f, $60, $ca
          //pmullw mm0, mm4
          db $0f, $d5, $c4
          //pmullw mm1, mm3
          db $0f, $d5, $cb
          //paddusw mm1, mm0
          db $0f, $dd, $c8
        //psrlw mm1, 6
          db $0f, $71, $d1, $06
          //packuswb mm1, mm2
          db $0f, $67, $ca
        //movd [edx], mm1
          db $0f, $7e, $0a

          add esi, 4
        add edi, 4
          add edx, 4

        sub ebx, 1
        jnz @LM2

          add esi, _Right
          add edi, _Right
          add edx, _Right

        sub ecx, 1
        jnz @LM1
        //emms
          db $0f, $77
          end
      end else begin
          Factor2 := 64-Factor;
          for i := ClipRect.Top to ClipRect.Bottom-1 do begin
              DestRow := DestBitmap.ScanLine[i];
              FromRow := FromBitmap.ScanLine[i];
              ToRow := ToBitmap.ScanLine[i];
              for j := ClipRect.Left to (ClipRect.Right-1) do begin
                  DestRow[j].rgbBlue := ((FromRow[j].rgbBlue*Factor2)
                    + (ToRow[j].rgbBlue*Factor)) shr 6;
                  DestRow[j].rgbGreen := ((FromRow[j].rgbGreen*Factor2)
                    + (ToRow[j].rgbGreen*Factor)) shr 6;
                  DestRow[j].rgbRed := ((FromRow[j].rgbRed*Factor2)
                    + (ToRow[j].rgbRed*Factor)) shr 6;
              end;
          end;
      end;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var t,i : DWORD;
    begin

     Image1.Picture.bitmap.LoadFromFile('c:\52a.bmp');
     Image1.Picture.Bitmap.PixelFormat := pf32Bit;
     Image1.Picture.Bitmap.HandleType := bmDIB;
     Image2.Picture.Bitmap := NewDIBBitmap(512, 384, pf32bit);
     T := GetTickCount();
     for i := 0 to 999 do begin
       BitmapAntialias2x(Image1.Picture.Bitmap, Image2.Picture.Bitmap);
     end;
     ShowMessage(inttostr(Gettickcount-t));
    end;

    procedure TForm1.Button2Click(Sender: TObject);
    var
     BMP1: TFastBMP;
     BMP2: TFastBMP;
     t,i : DWORD;
    begin
     BMP1 := TFastBMP.Create;
     BMP1.LoadFromFile('c:\52a.bmp');

     BMP2 := TFastBMP.Create;
     BMP2.SetSize(512, 384);
     T := GetTickCount();
     for i := 0 to 999 do begin
       BMP1.SmoothResize(BMP2);
     end;
     ShowMessage(inttostr(Gettickcount-t));
     BMP2.Draw(image2.Canvas.Handle, 0, 0);
    end;

    initialization
     CPUisMMX := FALSE;
     CPUisMMX := isMMX();
    end.

  • homm © (14.10.07 14:47) [15]
    FastBMP — 4000
    мой вариант — 1400

    Естественно, что SmoothResize более универсальная…
  • antonn © (14.10.07 18:24) [16]

    > homm ©  

    извращенец %)
  • antonn © (14.10.07 18:24) [17]
    в хорошем смысле:)
  • DVM © (14.10.07 18:49) [18]

    > homm ©   (14.10.07 14:47) [15]

    Ну и че такое за FastBMP?
  • DVM © (14.10.07 19:01) [19]

    > > homm ©


    procedure TForm1.Button2Click(Sender: TObject);
    var
    BMP1: TFastDIB;
    BMP2: TFastDIB;
    t,i : DWORD;
    begin
    BMP1 := TFastDIB.Create;
    BMP1.LoadFromFile('c:\1.bmp');

    BMP2 := TFastDIB.Create;
    BMP2.SetSize(640, 482, 32);
    T := GetTickCount();
    for i := 0 to 999 do begin
      FastResize(BMP1,BMP2);
    end;
    ShowMessage(inttostr(Gettickcount-t));
    BMP2.Draw(image2.Canvas.Handle, 0, 0);
    end;



    Результат 1390 даже для более большой картинки чем у тебя. Твой же код вообще не рабочий.
  • DVM © (14.10.07 19:36) [20]

    > > homm ©   (14.10.07 14:47) [15]

    вот с этим сравнивай http://sourceforge.net/projects/tfastdib
  • homm © (14.10.07 19:38) [21]
    > [19] DVM ©   (14.10.07 19:01)
    > Твой же код вообще не рабочий.

    О_о Да ну?
  • DVM © (14.10.07 19:40) [22]

    > О_о Да ну?

    вот представь себе Access Violation
  • homm © (14.10.07 19:41) [23]
    За ссылку сенкс, сам только ту версию нашел, что протестировал.


    > Результат 1390 даже для более большой картинки чем у тебя.

    И какое у твоей разрешение?
  • homm © (14.10.07 19:41) [24]
    > [22] DVM ©   (14.10.07 19:40)
    > вот представь себе Access Violation

    Ты не повар :)
  • DVM © (14.10.07 19:44) [25]

    > И какое у твоей разрешение?

    а у твоей? :)


    > Ты не повар :)

    Все то, что ты написал выше вставлено в форму с двумя кнопками и двумя Image. При нажатии на кнопку 1 -   AV. Delphi 7. Искать причину мне неохота.
  • homm © (14.10.07 19:44) [26]
    > [25] DVM ©   (14.10.07 19:44)
    > Искать причину мне неохота.

    Причина в том. что разрешение должно быть у картинки 1024*768, надо пологать ?
  • DVM © (14.10.07 19:44) [27]

    > И какое у твоей разрешение?

    800 на 600
  • homm © (14.10.07 19:49) [28]
    > [27] DVM ©   (14.10.07 19:44)

    В серьез полагаешь, что 800*600 больше, чем 1024*768? :)

    У меня получилось 844 для 1024*768, НО ты чувствуешь разницу между «FastResize» и «Качественное масштабирование» ??? Я думаю имеется виду как минимум, не хуже билинейного.
  • DVM © (14.10.07 19:50) [29]

    > Причина в том. что разрешение должно быть у картинки 1024*768,
    >  надо пологать ?

    Поменял на 1024*768*32 - теперь Stream Read Error

    У FastDIB результат почти не изменился - 1400 стало при перегоне в 640*482
    Если перегонять в 512 * 384, то результат вообще 1047
  • DVM © (14.10.07 19:51) [30]

    > ты чувствуешь разницу между «FastResize» и «Качественное
    > масштабирование» ??? Я думаю имеется виду как минимум, не
    > хуже билинейного.

    И какой метод интерполяции у тебя?
  • homm © (14.10.07 19:51) [31]
    for i := 0 to 999 do begin
     Bilinear24(BMP1,BMP2);
    end;



    Имеем 4280 :-Р
  • homm © (14.10.07 19:52) [32]
    > [30] DVM ©   (14.10.07 19:51)
    > И какой метод интерполяции у тебя?

    Билинейный.
  • homm © (14.10.07 19:53) [33]
    > Поменял на 1024*768*32 - теперь Stream Read Error

    НЕ ВЕРЮ!

    Image1.Picture.bitmap.LoadFromFile('c:\52a.bmp');
    Image1.Picture.Bitmap.PixelFormat := pf32Bit;
    Image1.Picture.Bitmap.HandleType := bmDIB;
    Image2.Picture.Bitmap := NewDIBBitmap(512, 384, pf32bit);
    T := GetTickCount();
    for i := 0 to 999 do begin
      BitmapAntialias2x(Image1.Picture.Bitmap, Image2.Picture.Bitmap);
    end;



    Все ли так? Разрешение точно 1024*768 ?
  • DVM © (14.10.07 19:57) [34]

    > НЕ ВЕРЮ!


    procedure TForm1.Button1Click(Sender: TObject);
    var t,i : DWORD;
    begin
    Image1.Picture.bitmap.LoadFromFile('c:\1.bmp');
    Image1.Picture.Bitmap.PixelFormat := pf32Bit;
    Image1.Picture.Bitmap.HandleType := bmDIB;
    Image2.Picture.Bitmap := NewDIBBitmap(512, 384, pf32bit);
    T := GetTickCount();
    for i := 0 to 999 do begin
      BitmapAntialias2x(Image1.Picture.Bitmap, Image2.Picture.Bitmap);
    end;
    ShowMessage(inttostr(Gettickcount-t));
    end;

  • DVM © (14.10.07 19:59) [35]

    > homm ©

    А так ты в 2 раза уменьшаешь! Я то сразу и не заметил.
  • DVM © (14.10.07 20:01) [36]

    > > НЕ ВЕРЮ!

    вот файл на котором тестирую: http://dvmuratov.narod.ru/1.bmp
  • homm © (14.10.07 20:06) [37]
    Блин, я чуть было не стал качать :)
    3 метра, ага? Нет  уж :)

    Выбрось FastDIB, уж по крайней мере билинейную интерпляцию он нифига не делает. Можеь проверить результат, полученый в фотошопе при уменьшении в 4 раза.
  • homm © (14.10.07 20:07) [38]
    Для пущей наглядности предлагаю сравнить как один слой на другом, выставив для верхнего режим Difference.
  • DVM © (14.10.07 20:08) [39]

    > Выбрось FastDIB, уж по крайней мере билинейную интерпляцию
    > он нифига не делает

    Делает.
    SmoothResize(BMP1,BMP2, rfBilinear);
  • DVM © (14.10.07 20:10) [40]

    > homm ©  

    Сравнивать в данном случае некорректно. Функции FastDIB рассчитаны на произвольный размер, а не на уменьшение в 2 раза.
  • homm © (14.10.07 20:11) [41]
    Действительно, делает :)
    109 секунд делает :)
  • homm © (14.10.07 20:12) [42]
    А у меня за одну :)
  • DVM © (14.10.07 20:13) [43]

    > Действительно, делает :)
    > 109 секунд делает :)

    че то тут не так
  • homm © (14.10.07 20:13) [44]
    > [40] DVM ©   (14.10.07 20:10)
    > Сравнивать в данном случае некорректно.

    Я об этом сразу сказал, просто ты кое кто считает, что я «зря фразами кидаюсь» ;)
  • homm © (14.10.07 20:15) [45]
    > [43] DVM ©   (14.10.07 20:13)
    > че то тут не так

    Я итебе скажу, что тцт не так :)
    procedure SmoothResize24(Src,Dst:TFastDIB;Filter:TResizeFilter);
           if s<1 then pw^.w:=Round(f((m-pw^.pos)*s)*s*$10000)


    Вот эта вот букавка F — это вызов функции… Для каждого пикселя… естествеено это жопа.
  • DVM © (14.10.07 20:20) [46]

    > homm ©   (14.10.07 20:15) [45]

    Точно.
  • DVM © (14.10.07 21:13) [47]

    > homm ©   (14.10.07 20:07) [38]
    > Для пущей наглядности предлагаю сравнить как один слой на
    > другом, выставив для верхнего режим Difference.

    Кстати все ок. 1 к 1 как в фотошопе.
  • DVM © (14.10.07 21:15) [48]
    5200 мсек занимет 1000 масштабирований с билинейной фильтрацией
  • DVM © (14.10.07 21:20) [49]

    procedure TForm1.Button2Click(Sender: TObject);
    var
    BMP1: TFastDIB;
    BMP2: TFastDIB;
    t,i : DWORD;
    begin
    BMP1 := TFastDIB.Create;
    BMP1.LoadFromFile('c:\1.bmp');

    BMP2 := TFastDIB.Create;
    BMP2.SetSize(512, 384, 32);
    T := GetTickCount();
    for i := 0 to 999 do begin
      Bilinear32(BMP1,BMP2);
    end;
    ShowMessage(inttostr(Gettickcount-t));
    BMP2.Draw(image2.Canvas.Handle, 0, 0);
    BMP2.SaveToFile('C:\2.BMP');
    end;



    Файл 2 и полученный в фотошопе после масштабирования с билинейной фильтрацие идентичны.

    Так что не надо гнать на FastDIB. :) Если учесть, что это результат для произвольных размеров, а не для 2 или 4, то он не хуже чем твой. Следовательно FastDIB обогнать все же сложно.
  • homm © (14.10.07 21:23) [50]
    > [49] DVM ©   (14.10.07 21:20)
    > Файл 2 и полученный в фотошопе после масштабирования с билинейной
    > фильтрацие идентичны.


    > [37] homm ©   (14.10.07 20:06)
    > Можеь проверить результат, полученый в фотошопе при уменьшении в ЧЕТЫРЕ раза.
  • homm © (14.10.07 21:25) [51]
    В том, и штука, что он берет исходный пиксель и 2 соседних, результат верен только для 2-х кратного и менее-кратного ументшения :)
  • DVM © (14.10.07 21:27) [52]

    > > Можеь проверить результат, полученый в фотошопе при уменьшении
    > в ЧЕТЫРЕ раза.

    Все ок. Проверь сам. Может ты неправильно фильтрацию в фотошопе случайно выбрал?
  • DVM © (14.10.07 21:31) [53]
    уменьшил вообще до 100х100 , т.е. с изменением пропорций. Результат идентичен фотошоповскому. Увеличил до 1000х1000 - тоже идентично.
  • homm © (14.10.07 21:50) [54]
    http://homm86.narod.ru/files/resize.png (60 kb)
    1) FastDIB
    2) Photoshop
    3) Их разность :)
  • DVM © (14.10.07 21:51) [55]

    > 3) Их разность :)

    а сдвинуть слои не пробовал?
  • DVM © (14.10.07 21:53) [56]

    > homm ©   (14.10.07 21:50) [54]

    у тебя картинка какой цветности? 24 или 32?
    Функцию FastDIB берешь какую?

    я работаю с картинкой из папки мои рисунки (Закат.jpg), которую я фотошопом увеличил до 1024 на 768 32 бит цвет и сохранил в BMP.
  • homm © (14.10.07 21:54) [57]
    Куда сдвигать, они разные!! Приглядись к первой и второй картинке, они очень разные!
  • homm © (14.10.07 21:55) [58]
    > [56] DVM ©   (14.10.07 21:53)
    > у тебя картинка какой цветности? 24 или 32?

    32, Bilinear32


    > Закат.jpg
    Ты бы еше квадрат тупо красным залал…
  • antonn © (14.10.07 21:55) [59]

    > homm ©   (14.10.07 21:50) [54]

    осторожно, у меня рядом дети сидят %)
  • DVM © (14.10.07 21:59) [60]

    > Ты бы еше квадрат тупо красным залал…

    Какая разница, нормальный рисунок. Ну взял я другую фотку все ок
  • homm © (14.10.07 21:59) [61]
    > [56] DVM ©   (14.10.07 21:53)
    > Закат.jpg

    Они разные получаются!! :)
    http://homm86.narod.ru/files/resize2.png


    > [59] antonn ©   (14.10.07 21:55)
    > осторожно, у меня рядом дети сидят %)
    Оригинал слить? :)
  • homm © (14.10.07 22:00) [62]
    > [56] DVM ©   (14.10.07 21:53)
    > Закат.jpg

    Они разные получаются!! :)
    http://homm86.narod.ru/files/resize2.png


    > [59] antonn ©   (14.10.07 21:55)
    > осторожно, у меня рядом дети сидят %)
    Оригинал слить? :)
  • DVM © (14.10.07 22:04) [63]
    Итак, проведем эксперимент.

    1) Берем исходную фотку: http://dvmuratov.narod.ru/1.bmp  (3 мб)
    2) Натравливаем на фотку этот код:


    procedure TForm1.Button2Click(Sender: TObject);
    var
    BMP1: TFastDIB;
    BMP2: TFastDIB;
    t,i : DWORD;
    begin
    BMP1 := TFastDIB.Create;
    BMP1.LoadFromFile('c:\1.bmp');

    BMP2 := TFastDIB.Create;
    BMP2.SetSize(1000, 1000, 32);
    T := GetTickCount();
    for i := 0 to 0 do begin
      Bilinear32(BMP1,BMP2);
    end;
    ShowMessage(inttostr(Gettickcount-t));
    BMP2.Draw(image2.Canvas.Handle, 0, 0);
    BMP2.SaveToFile('C:\2.BMP');
    end;



    2) Открываем файл 1 в фотошопе (версия 8)
    3) Открываем файл 2 в фотошопе
    4) Меняем размеры первого файла на 1000*1000 с билинейной фильтрацией без сохранения пропорций.
    5) Перетаскиваем на первый файл слой из вторгго файла
    6) делаем сравнение

    У меня абсолютное совпадение т.е. черный квадрат
  • homm © (14.10.07 22:05) [64]
    > [63] DVM ©   (14.10.07 22:04)
    > Меняем размеры первого файла на 1000*1000

    Стоп, откуда такая цифра???


    > [53] DVM ©   (14.10.07 21:31)
    > уменьшил вообще до 100х100
  • homm © (14.10.07 22:05) [65]
    [51] прочти.
  • DVM © (14.10.07 22:06) [66]

    > homm ©

    Саш, ей богу у меня одинаковые, я уж другую фотку взял с разными цветами и бабочкой.
  • DVM © (14.10.07 22:06) [67]

    > Стоп, откуда такая цифра???

    от балды
  • homm © (14.10.07 22:08) [68]
    сравни, 100*100, как ты сказал, или уменьшеную в 4, как я сказал, не береи от балды! :)
  • DVM © (14.10.07 22:12) [69]

    > homm ©

    Получил я разницу. Но она появляется далеко не на всех изображениях и не при любых размерах.
  • homm © (14.10.07 22:14) [70]
    Н авсех изображениях (кроме залитого ккрасным цветом квадрата) на разрешениях, которые я уже оговорил, и даже причину, по которой эти ограничения получаются, тоже сказал.
  • DVM © (14.10.07 22:35) [71]

    > homm ©

    кстати, а с чего ты вообще взял, что картинки должны быть абсолютно идентичны. Алгоритмы отличаются. Но не настолько, чтобы одна картинка была заметно хуже другой.

    Вот я взял для примера две программы одна Photoshop, другая Macromedia FireWorks (теперь тоже адобе). Я думаю, ты не будешь спорить с реализацией алгоритмов сглаживания у этих компаний. Так вот, для одной и той же картинки для размера 100*100 они дают разные результаты. Причем разница между ними даже больше, чем у FastDIB и фотошопа. Так что это не показатель.
  • antonn © (14.10.07 22:56) [72]
    долго ругаться будете? :) у ветки и так мега положительная полезность :)

    homm ©
    а есть на асме блитинг (с альфой или просто "прозрачный цвет") двух битмапов (либо просто массивов)?
  • DVM © (14.10.07 23:01) [73]

    > homm ©  

    Кстати, твой вариант у меня так и не заработал.
    Вот, что он делает из 24 бит картинки, потом AV

    http://dvmuratov.narod.ru/3.BMP (500 кб)
  • homm © (14.10.07 23:33) [74]
    > [71] DVM ©   (14.10.07 22:35)
    > Но не настолько, чтобы одна картинка была заметно хуже другой.
    А он хуже ;)

    > Причем разница между ними даже больше, чем у FastDIB и фотошопа.
    Ты уверен, что в Macromedia FireWorks было именно билинейное сглаживание?


    > [72] antonn ©   (14.10.07 22:56)
    > а есть на асме блитинг
    У меня нет, хотя пора бы уже :)

    > Кстати, твой вариант у меня так и не заработал.
    http://homm86.narod.ru/files/resize.rar 130 kb.
  • DVM © (15.10.07 00:11) [75]

    > Ты уверен, что в Macromedia FireWorks было именно билинейное
    > сглаживание?

    там явно выбирается при сохранении, как и в фотошопе
  • DVM © (15.10.07 00:15) [76]

    > http://homm86.narod.ru/files/resize.rar 130 kb.

    че-то не скачивается
  • homm © (15.10.07 06:07) [77]
    > [76] DVM ©   (15.10.07 00:15)
    > че-то не скачивается

    Счас должно.
  • sdubaruhnul © (15.10.07 15:16) [78]
    Так что выяснили то, что можно реализовать 2-хкратное уменьшение быстрее, чем универсальное в FastDIB?
  • homm © (15.10.07 15:19) [79]
    > [78] sdubaruhnul ©   (15.10.07 15:16)
    > Так что выяснили то, что можно реализовать 2-хкратное уменьшение
    > быстрее, чем универсальное в FastDIB?

    Да. 2-х, 4-х, 8-и, сколько угодно кратное.
  • DVM © (15.10.07 16:15) [80]
    В FastDIB вообще нет функций для быстрого уменьшения в 2xN раз. Там есть функции для такого увеличения. Только они, вроде бы без билинейной фильтрации. Но можно дописать.

    Меня больше теперь интересует, результаты алгоритмов билинейной фильтрации должны быть одинаковы или нет?
  • homm © (15.10.07 16:17) [81]
    > [80] DVM ©   (15.10.07 16:15)
    > Меня больше теперь интересует, результаты алгоритмов билинейной
    > фильтрации должны быть одинаковы или нет?

    Должны. Ты же сам видишь, то, что получается в FastDIB, или в Pain.NET — кака полная.
  • DVM © (15.10.07 16:20) [82]

    > Ты же сам видишь, то, что получается в FastDIB, или в Pain.
    > NET — кака полная.

    Почему у всех, даже известных и вызывающих доверие программ они разные?

    Почему у Photoshop, Macromedia Fireworks, Intel OpenCV разные результаты?
    И у кого из них правильный?
  • homm © (15.10.07 16:35) [83]
    Ок, пусть будут разные, но не такие говенные как у Pain.NET и FastDIB.

    Можешь сделать общий png, на котором бы были представлены уменьшеные в 4 раза в Photoshop, Macromedia Fireworks, Intel OpenCV? у меня ни второго не третьего.
  • homm © (15.10.07 16:36) [84]
    > [82] DVM ©   (15.10.07 16:20)
    > И у кого из них правильный?

    У меня. И я кстати, не шучу. Суть метода — сложить и поделить. Т.к. у меня довольно частный случай в алгоритмах, определить что именно нужно сложить и на что поделить — проще всего.
  • DVM © (15.10.07 16:38) [85]

    > Можешь сделать общий png,

    Сделаю. Но вечером, на работе у меня вообще ничего из перечисленного нет.
  • Sapersky (15.10.07 17:24) [86]
    В FastDIB вообще нет функций для быстрого уменьшения в 2xN раз.

    Уменьшение в 2 раза:
    http://sapersky.narod.ru/files/FastSizeEx.rar
    Также там имеется вариант SmoothResize, работающий примерно в 2 раза быстрее. Но SmoothResize - всё-таки скорее качественная, чем быстрая фильтрация. Сама функция рассчитана в большей степени на сложные фильтры вроде Lancros (и что немаловажно - на фильтры РАЗНОЙ длины, что вынуждает крутить "внутренний" цикл для каждого пикселя).

    А Bilinear, ИМХО, это неплохой компромисс между скоростью и качеством. Если кому-то не нравится - не используйте, нам больше достанется :)
  • Sapersky (15.10.07 19:27) [87]
    Кстати, непонятно, какой смысл сравнивать с Photoshop. Он рекордов скорости ставить не собирается и может применить медленный, но качественный метод вроде SmoothResize c rfBilinear.
    Сравнивать нужно с кодом homm, который работает с любым коэффициентом  масштабирования, быстрее Bilinear и даёт более качественный результат.
    Кстати, где он? Я что-то пропустил? :)
  • homm © (15.10.07 21:15) [88]
    > [87] Sapersky   (15.10.07 19:27)
    > Сравнивать нужно с кодом homm, который работает с любым
    > коэффициентом  масштабирования, быстрее Bilinear и даёт
    > более качественный результат.

    Еше не написан такой.


    > Также там имеется вариант SmoothResize, работающий примерно
    > в 2 раза быстрее. Но SmoothResize - всё-таки скорее качественная,
    > чем быстрая фильтрация.

    Какое-то противоречие.


    > Кстати, непонятно, какой смысл сравнивать с Photoshop. Он
    > рекордов скорости ставить не собирается и может применить
    > медленный, но качественный метод вроде SmoothResize c rfBilinear.

    Он и применяет качественный фильтр, результат использования которого равен моему результату, и он же, собственно и есть самый настоящий билинеар.
  • DVM © (15.10.07 21:44) [89]
    Вот некоторые сравнения:

    http://dvmuratov.narod.ru/psvsfw.png

    1) Fireworks 4
    2) Photoshop 8
    3) Разница есть (FW заметно проигрывает Photoshop)

    http://dvmuratov.narod.ru/psvsulead.png

    1) Ulead PhotoImpact 11
    2) Photoshop 8
    3) Разница есть (небольшая но есть)

    http://dvmuratov.narod.ru/1.bmp - исходный файл

    Сейчас еще другие сравнения сделаю наверное
  • homm © (15.10.07 21:52) [90]
    > [89] DVM ©   (15.10.07 21:44)
    > 3) Разница есть (небольшая но есть)

    Ну это уже небольшие нюансы в построении… По скрину видно, что строится верно, как минимум не хуже билинейного.
  • homm © (15.10.07 23:59) [91]
    > [72] antonn ©   (14.10.07 22:56)
    > а есть на асме блитинг (с альфой или просто "прозрачный
    > цвет") двух битмапов (либо просто массивов)?


    Наваял без асма пока. Поучается примерно 100 кадров в секунду для 1024*768.

    procedure TForm1.Button1Click(Sender: TObject);
    type
     ARGBQuad = array [0..0] of TRGBQuad;
     PARGBQuad = ^ARGBQuad;
     AByte = array [0..0] of Byte;
     PAByte = ^AByte;
    var
     BMP1: TBitmap;
     BMP2: TBitmap;

     SL1, SL2: PARGBQuad;
     V1, V2: TRGBQuad;
     R: ^TRGBQuad;
     i, j: Integer;
     A_1, A: Integer;
     Delta: DWORD;

     T: DWORD;

    begin
     BMP1 := TBitmap.Create;
     BMP1.LoadFromFile('C:\1.bmp');
     BMP2 := TBitmap.Create;
     BMP2.LoadFromFile('C:\2.bmp');
     
    T := GetTickCount;

     SL1 := BMP1.ScanLine[0];
     SL2 := BMP2.ScanLine[0];
     Delta := DWORD(BMP1.ScanLine[1]) - DWORD(SL1);
     for i := 0 to BMP1.Height-1 do begin
       for j := 0 to BMP1.Width-1 do begin
         V1 := SL1[j];
         V2 := SL2[j];
         A := V2.rgbReserved;
         A_1 := 255-V2.rgbReserved;
         R := @SL1[j];
         R.rgbBlue := (V2.rgbBlue*A_1+V1.rgbBlue*A) shr 8;
         R.rgbGreen := (V2.rgbGreen*A_1+V1.rgbGreen*A) shr 8;
         R.rgbRed := (V2.rgbRed*A_1+V1.rgbRed*A) shr 8;
       end;
       SL1 := Pointer(DWORD(SL1) + Delta);
       SL2 := Pointer(DWORD(SL2) + Delta);
     end;

    ShowMessage(IntToStr(GetTickCount - T));

     Image1.Canvas.StretchDraw(Rect(0, 0, 1024, 768), BMP1);
     BMP1.Free;
     BMP2.Free;
    end;



    Обе картинки болжны быть 32-х битные, причем вторая должна в резервном бите содержать альфаканал (легко сделать в фотошопе).
  • antonn © (16.10.07 01:07) [92]
    я наверное щас совсем оборзею, но можно попросить о помощи? :)
    битмапы храню в массиве dword (так по идее доступ еще быстрее, и почка для асма:))
    немножко велосипеда:
    const
     MaxBTCount = MaxInt div SizeOf(dword);
    type
     BTElement = dword;
     TBTArray = array[0..MaxBTCount-1] of BTElement;

     PxlByte = array [0..2] of byte;

     LongAS = packed record
       DW: array [0..3] of dword;
     end;

     pPRBT= ^TPRBT; //для 4х уменьшения
     TPRBT = record
       b1,b2,b3,b4:dword;
     end;
     pPRBD= ^TPRBD; //это для 2х уменьшения
     TPRBD = record
       b1,b2:dword;
     end;

     TBT = Class
       private
        procedure setarrays(x,y:integer);
       public
        DIBWidth     : integer;
        DIBHeight    : integer;
        P: ^TBTArray;
        constructor Create;
        destructor Destroy; override;
        procedure loadbitmap(bitmap:tbitmap);
        procedure savebitmap2file(filename:string);
        procedure set_widthheight(w,h:integer);
     end;

    implementation

    constructor TBT.Create;
    begin
    inherited;
    DIBWidth:=0;
    DIBHeight:=0;
    end;

    destructor TBT.Destroy;
    begin
    FreeMem(P, DIBWidth*DIBHeight*SizeOf(BTElement));
    inherited;
    end;

    procedure TBT.setarrays(x,y:integer);
    begin
    FreeMem(P, DIBWidth*DIBHeight*SizeOf(BTElement));

    DIBWidth:=x;
    DIBHeight:=y;
    P:=AllocMem(DIBWidth*DIBHeight * SizeOf(BTElement));
    end;

    procedure TBT.set_widthheight(w,h:integer);
    begin
    setarrays(w,h);
    end;

    procedure TBT.loadbitmap(bitmap:tbitmap);
    var x,y,cou,n: Integer;  Row2:PRGBAArray;
    begin
    cou:=0;
    setarrays(bitmap.Width,bitmap.Height);

    for Y:=0 to bitmap.Height-1 do begin
       Row2:=bitmap.ScanLine[y];
        for x:=0 to bitmap.Width-1 do begin

          if((Row2[x].rgbRed=255) and (Row2[x].rgbGreen=0) and (Row2[x].rgbBlue=0)) then
           Row2[x].rgbReserved:=0 else
           Row2[x].rgbReserved:=255;

           P^[ y*DIBWidth+x ]:=(Row2[x].rgbRed or (Row2[x].rgbGreen shl 8) or (Row2[x].rgbBlue shl 16) or (Row2[x].rgbReserved shl 24));
        end;
     end;
    end;

    procedure TBT.savebitmap2file(filename:string);
    var bb:tbitmap; x,y,cou: Integer;  Row2:PRGBAArray; fd:dword;
    begin
    bb:=tbitmap.Create;
    try
     bb.PixelFormat:=pf32bit;
     bb.Width:=DIBWidth;
     bb.Height:=DIBHeight;
      for Y:=0 to bb.Height-1 do begin
        Row2:=bb.ScanLine[y];
        for x:=0 to bb.Width-1 do begin
          fd:=P^[ y*DIBWidth+x ];
          Row2[x].rgbBlue:=Byte(fd shr 16);
          Row2[x].rgbGreen:=Byte(fd shr 8);
          Row2[x].rgbRed:=Byte(fd);
          Row2[x].rgbReserved:=Byte(fd shr 24);
        end;
      end;
      bb.SaveToFile(filename);
    finally
     bb.Free;
    end;
    end;


    небольшой класс, грузящий битмап в массив и сохранающий как битмап. Оптимизаций загрузки/сохранения не делал, потом.
    Так вот, в асме я дуб, но хочется быстрее, выше и сильнее, особенно если с ММХ/SSE и тп:)
    кстати, код для уменьшения:)
    procedure antialias_x2(var BTSourc,BTDest:TBT);
    var x,y,cou,num,i,cxi,cx,wi,hi: Integer;  Row2:PRGBAArray; fd:dword;
      y1,y2,totr,totg,totb,tota:integer;
     yy1,yy2:pPRBD;
     wii,hii:integer;
    begin
     wii:=BTSourc.DIBWidth div 2;
     hii:=BTSourc.DIBHeight div 2;

      for Y:=0 to hii-1 do begin

        y1:=y*2*BTSourc.DIBWidth;
        y2:=y1+BTSourc.DIBWidth;

        for x:=0 to wii-1 do begin
          cx:=x*2;

          yy1:=pPRBD(@(BTSourc.P^[ y1+cx ]));
          yy2:=pPRBD(@(BTSourc.p^[ y2+cx ]));

          totb:=LongRec(yy1.b1).Bytes[2] + LongRec(yy2.b1).Bytes[2] ;
          totb:=totb+LongRec(yy1.b2).Bytes[2] + LongRec(yy2.b2).Bytes[2] ;

          totg:=LongRec(yy1.b1).Bytes[1] + LongRec(yy2.b1).Bytes[1] ;
          totg:=totg+LongRec(yy1.b2).Bytes[1] + LongRec(yy2.b2).Bytes[1] ;

          totr:=LongRec(yy1.b1).Bytes[0] + LongRec(yy2.b1).Bytes[0] ;
          totr:=totr+LongRec(yy1.b2).Bytes[0] + LongRec(yy2.b2).Bytes[0];

          tota:=LongRec(yy1.b1).Bytes[3] + LongRec(yy2.b1).Bytes[3] ;
          tota:=tota+LongRec(yy1.b2).Bytes[3] + LongRec(yy2.b2).Bytes[3] ;

          BTDest.P^[ y*wii+x ]:=((totr Shr 2) or ((totg Shr 2) shl 8) or ((totb Shr 2)  shl 16)or ((tota Shr 2) shl 24));

        end;
      end;
    end;



    альфаблитинг (с проверками на границы и произольным началом вывода):
    procedure AlfaBliting(var BTPic,BTBack:TBT; _x,_y:integer);
    var x, y,xd,yd,yyd: Integer; _r,_b,_g:integer;
       w_out,h_out,tmp,x_cor,y_cor,x_corS,y_corS: Integer;
       _d,_dd:double;
       fd,fs,fr:dword;
    begin
    w_out:=BTBack.DIBWidth;
    h_out:=BTBack.DIBHeight;
    if (_x)>w_out-1 then exit; if (_x+w_out)<0 then exit;
    if (_y)>h_out-1 then exit; if (_y+h_out)<0 then exit;
    if _x<0 then x_corS:=abs(_x) else x_corS:=0;
    if _y<0 then y_corS:=abs(_y) else y_corS:=0;
    if (_x+BTPic.DIBWidth)>w_out then x_cor:=_x+BTPic.DIBWidth-w_out else x_cor:=0;
    if (_y+BTPic.DIBHeight)>h_out then y_cor:=_y+BTPic.DIBHeight-h_out else y_cor:=0;
     y_cor:=BTPic.DIBHeight-1-y_cor;
     tmp:=BTPic.DIBWidth-1-x_cor; _dd:=(100/255)/100;
     for y:=y_corS to y_cor do begin
        yd:=y*BTPic.DIBWidth;
        yyd:=(y+_y)*BTBack.DIBWidth;
       for x:=x_corS to tmp do begin
         fd:=BTPic.P^[ yd+x ];
         if(LongRec(fd).Bytes[3]>0)then begin
             xd:=x+_x;
             fs:=BTBack.P^[ yyd +xd ];

             _d:=LongRec(fd).Bytes[3]*_dd;

            _r:= LongRec(fs).Bytes[0]+round((LongRec(fd).Bytes[0]-LongRec(fs).Bytes[0])*_d);
            if _r>255 then _r:=255 else if _r<0 then _r:=0;

            _g:= LongRec(fs).Bytes[1]+round((LongRec(fd).Bytes[1]-LongRec(fs).Bytes[1])*_d);
            if _g>255 then _g:=255 else if _g<0 then _g:=0;

            _b:= LongRec(fs).Bytes[2]+round((LongRec(fd).Bytes[2]-LongRec(fs).Bytes[2])*_d);
            if _b>255 then _b:=255 else if _b<0 then _b:=0;

          if LongRec(fs).Bytes[3]<LongRec(fd).Bytes[3] then
            BTBack.P^[ yyd +xd ]:=(_r or (_g shl 8) or (_b  shl 16)or (LongRec(fd).Bytes[3] shl 24))
          else
            BTBack.P^[ yyd +xd ]:=(_r or (_g shl 8) or (_b  shl 16)or (LongRec(fs).Bytes[3] shl 24));

           end;

     end; end;

    end;



    и "обычный" блит с "прозрачным каналом" (прозрачный канал - это альфа с значением 0):
    procedure Bliting(var BTPic,BTBack:TBT; _x,_y:integer);
    var x, y,yd,yyd: Integer;
       w_out,h_out,tmp,x_cor,y_cor,x_corS,y_corS: Integer;
    begin
    w_out:=BTBack.DIBWidth;
    h_out:=BTBack.DIBHeight;
    if (_x)>w_out-1 then exit; if (_x+w_out)<0 then exit;
    if (_y)>h_out-1 then exit; if (_y+h_out)<0 then exit;
    if _x<0 then x_corS:=abs(_x) else x_corS:=0;
    if _y<0 then y_corS:=abs(_y) else y_corS:=0;
    if (_x+BTPic.DIBWidth)>w_out then x_cor:=_x+BTPic.DIBWidth-w_out else x_cor:=0;
    if (_y+BTPic.DIBHeight)>h_out then y_cor:=_y+BTPic.DIBHeight-h_out else y_cor:=0;
     y_cor:=BTPic.DIBHeight-1-y_cor;
     tmp:=BTPic.DIBWidth-1-x_cor;
     for y:=y_corS to y_cor do begin
        yd:=y*BTPic.DIBWidth;
        yyd:=(y+_y)*BTBack.DIBWidth;
       for x:=x_corS to tmp do begin
         if(LongRec(BTPic.P^[ yd+x ]).Bytes[3]>0)then
            BTBack.P^[ yyd+x+_x ]:=BTPic.P^[ yd+x ];
       end;
     end;
    end;



    так вот, я понимаю, что выгрузил тут много всякого, не поможите оптимизировать? :)
  • Sapersky (16.10.07 02:45) [93]
    Еше не написан такой.

    Так вот сначала напиши, а потом советуй выбросить FastDIB.

    > Также там имеется вариант SmoothResize, работающий примерно
    > в 2 раза быстрее. Но SmoothResize - всё-таки скорее качественная,
    > чем быстрая фильтрация.

    Какое-то противоречие.


    Я имел в виду - быстрее, чем тот вариант SmoothResize, который в составе FastLib 3.9.9. Но медленнее, чем Bilinear.

    > Кстати, непонятно, какой смысл сравнивать с Photoshop. Он
    > рекордов скорости ставить не собирается и может применить
    > медленный, но качественный метод вроде SmoothResize c rfBilinear.

    Он и применяет качественный фильтр, результат использования которого равен моему результату, и он же, собственно и есть самый настоящий билинеар.


    Против Фотошопа FastLib'у есть что выставить - у SmoothResize качество ничуть не хуже, и скорость скорее всего тоже.
    Но Bilinear - это специально оптимизированная на скорость (ценой некоторой потери качества) функция. Поэтому не стоит сравнивать её с меланхоличным Фотошопом. С BitmapAntialias2X тоже не стоит, уж неловко напоминать почему. С чем стоит - уже писал :)

    Теперь о том, почему совмешение скорости с качеством маловероятно. Причина высокого качества, которое даёт SmoothResize - переменная длина фильтра, которая зависит не только от типа фильтра, но и от коэффициента масштабирования. И эта же переменная (и бОльшая по величине) длина, как я уже писал в [86] (а не "вызов f для каждого пикселя") - причина тормознутости функции. Ну и в какой-то степени обработка в 2 прохода (приходится создавать промежуточный буфер).
    Т.е. можно, конечно, создать некий гибрид SmoothResize/Bilinear, и он будет даже несколько быстрее первой (за счёт фиксированной функции, обработки в 1 проход и т.п.), но до 2-й по скорости всё равно не дотянет.
    Не проще ли тогда господам эстетам просто вызывать SmoothResize при K < 0.5, а в остальных случаях Bilinear?
  • Sapersky (16.10.07 02:46) [94]
    antonn ©   (16.10.07 01:07) [92]

    См. SpriteUtils-2.
  • homm © (16.10.07 06:33) [95]
    > Так вот сначала напиши, а потом советуй выбросить FastDIB.

    Мне незачем искать, я и так знаю, что еше нет «кода, написаного, homm (мной), который работает с любым коэффициентом  масштабирования, быстрее Bilinear и даёт более качественный результат».

    > Против Фотошопа FastLib'у есть что выставить - у SmoothResize
    > качество ничуть не хуже, и скорость скорее всего тоже.

    Просто делать делать необоснованные утверждения? Photoshop — 532 ms, SmoothResize — 2312ms.


    > Но Bilinear - это специально оптимизированная на скорость
    > (ценой некоторой потери качества) функция.

    «ИМХО» забыл добавить.


    > Поэтому не стоит сравнивать её с меланхоличным Фотошопом.

    «меланхоличным Фотошопом» это как понять?
  • homm © (16.10.07 07:03) [96]
    2 antonn

    procedure BitmapAntialias2X(SrcBitmap, DstBitmap: TBt);
    type    AGRBQuad = array [0..0] of TRGBQuad;
         PAGRBQuad = ^AGRBQuad;
    var     yDest: integer;
         xDest: integer;
         xSrc: integer;
         i: integer;
         R: integer;
         G: integer;
         B: integer;
         rowDest: PAGRBQuad;
         rowSrc: array [0..3] of PAGRBQuad;
         _rowSrc: PAGRBQuad;
         SrcBits: DWORD;
         DstBits: DWORD;
         dHeight: DWORD;
         dWidth: DWORD;
         Delta: DWORD;
    begin
     if CPUisMMX then begin
         SrcBits := DWORD(SrcBitmap.P);
         DstBits := DWORD(DstBitmap.P);
         dHeight := DstBitmap.DIBHeight;
         dWidth := DstBitmap.DIBWidth;
         Delta := SrcBitmap.DIBWidth*SizeOf(BTElement);//ScanLineSize(SrcBitmap);
         asm
             pushad
             mov esi, SrcBits
             mov edi, DstBits
             //pxor mm2, mm2
             db $0f, $ef, $d2

             mov eax, dHeight
    @LM1:       push eax

             mov eax, dWidth
    @LM2:       /////////
             mov ecx, esi

             //movd mm1, [ecx]
             db $0f, $6e, $09
             //punpcklbw mm1, mm2
             db $0f, $60, $ca
             //movd mm3, [ecx+4]
             db $0f, $6e, $59, $04
             //punpcklbw mm3, mm2
             db $0f, $60, $da
             //paddusw mm1, mm3
             db $0f, $dd, $cb

             add ecx, Delta

             //movd mm3, [ecx]
             db $0f, $6e, $19
             //punpcklbw mm3, mm2
             db $0f, $60, $da
             //paddusw mm1, mm3
             db $0f, $dd, $cb
             //movd mm3, [ecx+4]
             db $0f, $6e, $59, $04
             //punpcklbw mm3, mm2
             db $0f, $60, $da
             //paddusw mm1, mm3
             db $0f, $dd, $cb

             //psrlw mm1, 2
             db $0f, $71, $d1, $02
             //packuswb mm1, mm2
             db $0f, $67, $ca
             //movd [edi], mm1
             db $0f, $7e, $0f
             /////////

             add edi, 4
             add esi, 8

             sub eax, 1
       jnz @LM2

             add esi, Delta

             pop eax
             sub eax, 1
       jnz @LM1

             //emms
             db $0f, $77

             popad
         end;
     end else
     {for yDest := 0 to DstBitmap.DIBHeight -1 do begin
         rowDest := DstBitmap.ScanLine[yDest];
         for i := 0 to 1 do
             rowSrc[i] := SrcBitmap.ScanLine[yDest*2+i];
         for xDest := 0 to DstBitmap.Width-1 do begin
             xSrc := xDest*2;
             R:=0; G:=0; B:=0;
             for i := 0 to 1 do begin
                 _rowSrc := rowSrc[i];
                 R:= R+_rowSrc[xSrc+0].rgbRed
                     + _rowSrc[xSrc+1].rgbRed;
                 G:= G+_rowSrc[xSrc+0].rgbGreen
                     + _rowSrc[xSrc+1].rgbGreen;
                 B:= B+_rowSrc[xSrc+0].rgbBlue
                     + _rowSrc[xSrc+1].rgbBlue;
             end;
             DWORD(rowDest[xDest]) := ((R and $03fc) shl 14) or ((G and $03fc) shl 6) or (B shr 2);
         end;
     end;  }

    end;



    получилось 219мс супротив 657 с antialias_x2.
    BitmapAntialias4X преобразуется точно так-же, ни одна асмовская строчка не затрагивается :)

    Паскалевскую версию закоментировал, надеюсь ты сам с ней разберешся :)
    А вообще лучше бы оптимизировал загрузку изображений, толку было бы больше.
  • homm © (16.10.07 07:09) [97]
    > [95] homm ©   (16.10.07 06:33)
    > > Так вот сначала напиши, а потом советуй выбросить FastDIB.
    >
    > Мне незачем искать

    Прошу прощения, прочлось как «сначала поищи».
  • homm © (16.10.07 08:52) [98]
    > [92] antonn ©   (16.10.07 01:07)
    > if((Row2[x].rgbRed=255) and (Row2[x].rgbGreen=0) and (Row2[x].rgbBlue=0) ) then

    if ((DWORD(Row2[x]) AND $ffffff)=$ff0000) then




    > P^[ y*DIBWidth+x ]:=(Row2[x].rgbRed or (Row2[x].rgbGreen
    > shl 8) or (Row2[x].rgbBlue shl 16) or (Row2[x].rgbReserved
    > shl 24));

    P[ y*DIBWidth+x ] := DWORD(Row2[x]);
  • homm © (16.10.07 09:19) [99]
    > if((Row2[x].rgbRed=255) and (Row2[x].rgbGreen=0) and (Row2[x].rgbBlue=0)) then
    >       Row2[x].rgbReserved:=0 else
    >       Row2[x].rgbReserved:=255;

    Сечас компилятора нет под рукой, но можно попробовать избавится от условного перехода.

    Row2[x].rgbReserved := Byte(boolean( (DWORD(Row2[x]) AND $ffffff) xor $ff0000) )*$ff;



    Слабо верится, что Дельфи поймет, что я тут хотел сказать, но вдруг :)
  • Sapersky (16.10.07 09:26) [100]
    Просто делать делать необоснованные утверждения? Photoshop — 532 ms, SmoothResize — 2312ms.

    Да, сам не пробовал сравнивать. Кстати, а где у Фотошопа встроенный таймер (и какая версия нужна)?
    Версия SmoothResize моя или стандартная?
  • homm © (16.10.07 09:28) [101]
    > [100] Sapersky   (16.10.07 09:26)
    > Кстати, а где у Фотошопа встроенный таймер и какая версия нужна

    В программе ProcessExplorer. Любая.


    > Версия SmoothResize моя или стандартная?
    Из комплекта FastDIB. ([20])
  • homm © (16.10.07 09:37) [102]
    > [100] Sapersky   (16.10.07 09:26)
    > Версия SmoothResize моя или стандартная?

    Даже если твоя в 2 раза быстрее (как здявлено) она все равно в 2 раза медленнее, чем в фотошопе.
    Я склонен полагать, что в фотошопе функции всеже менее универсальны, просто их там туча, для каждого формата пикселей и фильтра своя. Соответственно они более оптимизированы.
  • Sapersky (16.10.07 19:54) [103]
    У меня получилось - в 1.5 раз медленнее Фотошопа. В принципе, приемлемо, тем более что я осознанно отказался от некоторых оптимизаций в пользу компактности кода.
    Фирме Adobe - миль пардон, недооценил её продукт.
  • Fenik © (18.10.07 16:56) [104]
    В фотошопе не только под все форматы изображений сделаны оптимизации, но и под разные процессоры и с использование MMX, SSE и т.д.
  • antonn © (27.10.07 13:24) [105]
    а кишки битмапа хранятся в нем "задом-наперед"?
  • homm © (27.10.07 14:45) [106]
    > [105] antonn ©   (27.10.07 13:24)

    Есть формат с обратным порядком строк, пиксели насколько помню всегда слева направо.
  • antonn © (27.10.07 15:00) [107]
    аа, точно, по вертикали разный  ипиксели в BGR лежат
    ну пиксели то обратно перевернуть не проблема:
    bswap eax
    ror   eax, 8


    у меня со строками какая то фигня происходит, на две больше по вертикали отсчитывает :)
  • miek (09.11.07 20:13) [108]
    вернемся к истокам

    >Так как все же качественно (!) и быстро (!) масштабировать картинку

    почему бы не попробовать directX? что-то, а скорость там будет.
  • antonn © (09.11.07 21:22) [109]

    > почему бы не попробовать directX? что-то, а скорость там
    > будет.

    а если на машине нет нужной версии DX? А если еще со встроенным решением...
  • DVM © (10.11.07 13:36) [110]

    > почему бы не попробовать directX? что-то, а скорость там
    > будет.

    Ты картинку туда загонять будешь дольше, чем масштабировать. А потом, какой смысл использовать DirectX если вывод картинки на экран не планируется.
  • antonn © (10.11.07 23:10) [111]

    > homm ©   (16.10.07 07:03) [96]

    тут какая то ерунда выяснилась...
    в коде [96]:
    jnz @LM2

            add esi, Delta

            add esi, 4

            pop eax
            sub eax, 1
      jnz @LM1


    без выделеного картинка сдвигается. а вроде ведь работало... вот теперь сижу и думаю, а код "работающий" или очень "нежный"? :)
  • antonn © (10.11.07 23:13) [112]
    хм, нет, все равно ерунда, ниче не понимаю %)
    на маленьких изображениях все пучком (64*64), на больших - сдвиг
  • antonn © (10.11.07 23:23) [113]
    аа, доперло %)
    если нечетное кол-во пикселей по Х, то сдвигается... блин :(
  • homm © (11.11.07 00:58) [114]
    > [113] antonn ©   (10.11.07 23:23)
    > если нечетное кол-во пикселей по Х, то сдвигается...

    Там вообще код спецефический, был сделан для строго определенной подачи данных, в которой ошибки быть не должно.
  • Sapersky (12.11.07 16:19) [115]
    почему бы не попробовать directX? что-то, а скорость там будет.

    Ну вот для иллюстрации выкладываю ещё раз свой тест:
    http://sapersky.narod.ru/files/GDI_vs_DDraw_vs_FastLIB.rar
    Для DX в заголовке формы после "+" пишется время создания поверхности и копирования в неё картинки.
    Претензии по качеству аппаратного масштабирования (которое, действительно, неважное, ближе к Bilinear, чем к SmoothResize/StretchBlt) просьба предъявлять производителям видеокарт.
    Бороться с плохим качеством можно выводом через 3D с использованием, например, трилинейной фильтрации, или хотя бы просто мип-мэппингом (который можно организовать и вручную с софтвером/DDraw).
  • Андрей (27.11.07 00:51) [116]
    Помогите. Необходимо запихать BitMap картинку в массив. Как это сделать?
  • homm © (27.11.07 06:50) [117]
    > [116] Андрей   (27.11.07 00:51)

    Читай про PixelFormat и ScanLine.
  • antonn © (27.11.07 08:04) [118]
    на предыдущей странице ведь есть...
  • Fenik © (27.11.07 08:59) [119]
    А битмап - это и так массив :)
  • antonn (work) (27.11.07 19:51) [120]
    но почему то с перевернутыми строками... :(
  • Romero (17.02.08 17:41) [121]
    Использую TFastDib, не для всех Jpeg получается сделать SmoothResize - AV получаю (для 256-цветной картинки, например).
  • Romero (18.02.08 18:26) [122]
    Вопрос отпал, всё получилось.
  • zgltqdjm ogxza (29.02.08 01:43) [123]
    cgwsnpbkm fqajlt laehj qimoe xcdtaoqmk gwej dpqxvyo
  • Matrena (14.02.10 00:19) [124]

    > Причина в том. что разрешение должно быть у картинки 1024*768,
    >  надо пологать ?

    homm, спасибо за код. Но скажите как с помощью вашего алгоритма уменьшить изображение в 1.5 и в 3 раза а не только в 2 и 4? Очень надо. Сама я точно так не напишу.
 
Конференция "Media" » Качественное и быстрое масштабирование картинки [D6, WinXP]
Есть новые Нет новых   [134428   +41][b:0.001][p:0.021]