Конференция "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 даже для более большой картинки чем у тебя. Твой же код вообще не рабочий.
 
Конференция "Media" » Качественное и быстрое масштабирование картинки [D6, WinXP]
Есть новые Нет новых   [120174   +9][b:0][p:0.012]