-
В FastDIB вообще нет функций для быстрого уменьшения в 2xN раз. Там есть функции для такого увеличения. Только они, вроде бы без билинейной фильтрации. Но можно дописать.
Меня больше теперь интересует, результаты алгоритмов билинейной фильтрации должны быть одинаковы или нет?
-
> [80] DVM © (15.10.07 16:15) > Меня больше теперь интересует, результаты алгоритмов билинейной > фильтрации должны быть одинаковы или нет?
Должны. Ты же сам видишь, то, что получается в FastDIB, или в Pain.NET — кака полная.
-
> Ты же сам видишь, то, что получается в FastDIB, или в Pain. > NET — кака полная.
Почему у всех, даже известных и вызывающих доверие программ они разные?
Почему у Photoshop, Macromedia Fireworks, Intel OpenCV разные результаты? И у кого из них правильный?
-
Ок, пусть будут разные, но не такие говенные как у Pain.NET и FastDIB.
Можешь сделать общий png, на котором бы были представлены уменьшеные в 4 раза в Photoshop, Macromedia Fireworks, Intel OpenCV? у меня ни второго не третьего.
-
> [82] DVM © (15.10.07 16:20) > И у кого из них правильный?
У меня. И я кстати, не шучу. Суть метода — сложить и поделить. Т.к. у меня довольно частный случай в алгоритмах, определить что именно нужно сложить и на что поделить — проще всего.
-
> Можешь сделать общий png,
Сделаю. Но вечером, на работе у меня вообще ничего из перечисленного нет.
-
В FastDIB вообще нет функций для быстрого уменьшения в 2xN раз.Уменьшение в 2 раза: http://sapersky.narod.ru/files/FastSizeEx.rarТакже там имеется вариант SmoothResize, работающий примерно в 2 раза быстрее. Но SmoothResize - всё-таки скорее качественная, чем быстрая фильтрация. Сама функция рассчитана в большей степени на сложные фильтры вроде Lancros (и что немаловажно - на фильтры РАЗНОЙ длины, что вынуждает крутить "внутренний" цикл для каждого пикселя). А Bilinear, ИМХО, это неплохой компромисс между скоростью и качеством. Если кому-то не нравится - не используйте, нам больше достанется :)
-
Кстати, непонятно, какой смысл сравнивать с Photoshop. Он рекордов скорости ставить не собирается и может применить медленный, но качественный метод вроде SmoothResize c rfBilinear. Сравнивать нужно с кодом homm, который работает с любым коэффициентом масштабирования, быстрее Bilinear и даёт более качественный результат. Кстати, где он? Я что-то пропустил? :)
-
> [87] Sapersky (15.10.07 19:27) > Сравнивать нужно с кодом homm, который работает с любым > коэффициентом масштабирования, быстрее Bilinear и даёт > более качественный результат.
Еше не написан такой.
> Также там имеется вариант SmoothResize, работающий примерно > в 2 раза быстрее. Но SmoothResize - всё-таки скорее качественная, > чем быстрая фильтрация.
Какое-то противоречие.
> Кстати, непонятно, какой смысл сравнивать с Photoshop. Он > рекордов скорости ставить не собирается и может применить > медленный, но качественный метод вроде SmoothResize c rfBilinear.
Он и применяет качественный фильтр, результат использования которого равен моему результату, и он же, собственно и есть самый настоящий билинеар.
-
-
> [89] DVM © (15.10.07 21:44) > 3) Разница есть (небольшая но есть)
Ну это уже небольшие нюансы в построении… По скрину видно, что строится верно, как минимум не хуже билинейного.
-
> [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-х битные, причем вторая должна в резервном бите содержать альфаканал (легко сделать в фотошопе).
-
я наверное щас совсем оборзею, но можно попросить о помощи? :) битмапы храню в массиве 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; TPRBT = record
b1,b2,b3,b4:dword;
end;
pPRBD= ^TPRBD; 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; так вот, я понимаю, что выгрузил тут много всякого, не поможите оптимизировать? :)
-
Еше не написан такой.
Так вот сначала напиши, а потом советуй выбросить 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?
-
antonn © (16.10.07 01:07) [92]
См. SpriteUtils-2.
-
> Так вот сначала напиши, а потом советуй выбросить FastDIB.
Мне незачем искать, я и так знаю, что еше нет «кода, написаного, homm (мной), который работает с любым коэффициентом масштабирования, быстрее Bilinear и даёт более качественный результат».
> Против Фотошопа FastLib'у есть что выставить - у SmoothResize > качество ничуть не хуже, и скорость скорее всего тоже.
Просто делать делать необоснованные утверждения? Photoshop — 532 ms, SmoothResize — 2312ms.
> Но Bilinear - это специально оптимизированная на скорость > (ценой некоторой потери качества) функция.
«ИМХО» забыл добавить.
> Поэтому не стоит сравнивать её с меланхоличным Фотошопом.
«меланхоличным Фотошопом» это как понять?
-
2 antonnprocedure 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); 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
end; получилось 219мс супротив 657 с antialias_x2. BitmapAntialias4X преобразуется точно так-же, ни одна асмовская строчка не затрагивается :) Паскалевскую версию закоментировал, надеюсь ты сам с ней разберешся :) А вообще лучше бы оптимизировал загрузку изображений, толку было бы больше.
-
> [95] homm © (16.10.07 06:33) > > Так вот сначала напиши, а потом советуй выбросить FastDIB. > > Мне незачем искать
Прошу прощения, прочлось как «сначала поищи».
-
> [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]);
-
> 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; Слабо верится, что Дельфи поймет, что я тут хотел сказать, но вдруг :)
|