-
Избитый вопрос, но все ответы которые я нашел меня не устраивают. Так как все же качественно (!) и быстро (!) масштабировать картинку? Главным образом уменьшить.
-
Могу дать алгоритмы очень быстрого умменьшения в 2 и 4 раза, но завтра.
-
> Так как все же качественно (!) и быстро (!) масштабировать > картинку?
Уважаемый, если бы существовал Самый_Лучший_Алгоритм, других алгоритмов бы просто не было
-
>homm Буду признателен. Буду ждать. Хотя конечно хотелось бы иметь алгоритм для произвольного k.
-
>Так как все же качественно (!) и быстро (!) масштабировать картинку?
Качественно vs. Быстро = Оптимально
Так как численных критериев нет, то оптимально - это может быть и алгоритм B-Spline, Mitchel, Bell, Triangle (см. Irfan View), т.е. что-то между Lanchos и Hermite.
-
И где найти эти алгоритмы?
-
> И где найти эти алгоритмы?
Посмотри как сделано в FastDIB. Ну можно сделать конечно и более качественно, чем там, но быстрее уже вряд ли.
-
Тогда и я говорю: посмотри Graphics32. Там, кстати, фильтронаписание поставлено на поток - все карты у пользователя-программиста.
-
> [6] DVM © (13.10.07 23:50) > но быстрее уже вряд ли.
категорически не согласен
-
> категорически не согласен
ну тогда код в студию, чего зря фразами кидаться
-
> [9] antonn © (14.10.07 09:01) > ну тогда код в студию, чего зря фразами кидаться
Блин, я изтрахал весь яндекс, но так и не могу найти этот FastDib, дабы провести тестироание.
-
Кажется нашел, нужно было сразу гугль узать :) Счас будет вам код.
-
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
public
end;
var
Form1: TForm1;
implementation
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 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; asm MOV EAX, 1
PUSH EDX
PUSH EBX
PUSH ECX
DB $0F, $A2
MOV [ I ], EDX POP ECX
POP EBX
POP EDX
end;
if (I and (1 shl 23)) <> 0 then
Result := true;
end;
-
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
db $0f, $ef, $d2
mov eax, dHeight
@LM1: push eax
mov eax, dWidth
@LM2: mov ecx, esi
db $0f, $6e, $09
db $0f, $60, $ca
db $0f, $6e, $59, $04
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $08
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $0c
db $0f, $60, $da
db $0f, $dd, $cb
add ecx, Delta
db $0f, $6e, $19
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $04
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $08
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $0c
db $0f, $60, $da
db $0f, $dd, $cb
add ecx, Delta
db $0f, $6e, $19
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $04
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $08
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $0c
db $0f, $60, $da
db $0f, $dd, $cb
add ecx, Delta
db $0f, $6e, $19
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $04
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $08
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $0c
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $71, $d1, $04
db $0f, $67, $ca
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
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;
-
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
db $0f, $ef, $d2
mov eax, dHeight
@LM1: push eax
mov eax, dWidth
@LM2: mov ecx, esi
db $0f, $6e, $09
db $0f, $60, $ca
db $0f, $6e, $59, $04
db $0f, $60, $da
db $0f, $dd, $cb
add ecx, Delta
db $0f, $6e, $19
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $6e, $59, $04
db $0f, $60, $da
db $0f, $dd, $cb
db $0f, $71, $d1, $02
db $0f, $67, $ca
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
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
db $0f, $ef, $d2
db $0f, $6e, $d8
db $0f, $60, $da
mov eax, $00404040
db $0f, $6e, $e0
db $0f, $60, $e2
db $0f, $f9, $e3
mov ecx, _Height
@LM1:
mov ebx, _Width
@LM2:
db $0f, $6e, $06
db $0f, $6e, $0f
db $0f, $60, $c2
db $0f, $60, $ca
db $0f, $d5, $c4
db $0f, $d5, $cb
db $0f, $dd, $c8
db $0f, $71, $d1, $06
db $0f, $67, $ca
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
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.
-
FastBMP — 4000 мой вариант — 1400
Естественно, что SmoothResize более универсальная…
-
> homm ©
извращенец %)
-
в хорошем смысле:)
-
> homm © (14.10.07 14:47) [15]
Ну и че такое за FastBMP?
-
> > 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 даже для более большой картинки чем у тебя. Твой же код вообще не рабочий.
|