6430 lines
232 KiB
Plaintext
6430 lines
232 KiB
Plaintext
// ***************************************************************
|
|
// madGraphics.pas version: 1.1.0 · date: 2012-04-03
|
|
// -------------------------------------------------------------
|
|
// gray scaling, smooth stretching, alpha blending, ...
|
|
// -------------------------------------------------------------
|
|
// Copyright (C) 1999 - 2012 www.madshi.net, All Rights Reserved
|
|
// ***************************************************************
|
|
|
|
// 2012-04-03 1.1.0 (1) added x64 support
|
|
// (2) fixed bug in GrayScale function
|
|
// 2001-03-04 1.0 initial release
|
|
|
|
unit madGraphics;
|
|
|
|
{$I mad.inc}
|
|
{$R-}{$Q-}
|
|
|
|
{ $define newantiringing}
|
|
{ $define oldantiringing}
|
|
|
|
interface
|
|
|
|
uses Windows, Graphics, madTypes, madStrings;
|
|
|
|
// ***************************************************************
|
|
|
|
type TGrayPercent = (gp100, gp75, gp50, gp0);
|
|
procedure GrayScale (bmp: TBitmap; percent: TGrayPercent = gp100);
|
|
|
|
// ***************************************************************
|
|
|
|
type
|
|
TStretchQuality = (sqLow, sqHigh, sqVeryHigh);
|
|
|
|
procedure StretchBitmap (srcBmp, dstBmp : TBitmap;
|
|
srcMsk, dstMsk : TBitmap;
|
|
quality : TStretchQuality = sqHigh); overload;
|
|
procedure StretchBitmap (bmp, msk : TBitmap;
|
|
newWidth : integer;
|
|
newHeight : integer;
|
|
quality : TStretchQuality = sqHigh); overload;
|
|
|
|
// ***************************************************************
|
|
|
|
procedure AlphaBlend (src1, src2, dst : TBitmap;
|
|
alpha : cardinal = 128); overload;
|
|
procedure AlphaBlend (src, dst : TBitmap;
|
|
alpha : cardinal = 128;
|
|
msk : TBitmap = nil;
|
|
x : integer = 0;
|
|
y : integer = 0 ); overload;
|
|
|
|
// ***************************************************************
|
|
|
|
procedure Draw (imageList, index : cardinal;
|
|
dst : TBitmap;
|
|
x : integer = 0;
|
|
y : integer = 0;
|
|
width : integer = 0;
|
|
height : integer = 0;
|
|
grayPercent : TGrayPercent = gp0;
|
|
alpha : cardinal = 256;
|
|
stretchQuality : TStretchQuality = sqHigh); overload;
|
|
|
|
procedure Draw (bmp, msk : TBitmap;
|
|
dst : TBitmap;
|
|
x : integer = 0;
|
|
y : integer = 0;
|
|
width : integer = 0;
|
|
height : integer = 0;
|
|
grayPercent : TGrayPercent = gp0;
|
|
alpha : cardinal = 256;
|
|
stretchQuality : TStretchQuality = sqHigh); overload;
|
|
|
|
// ***************************************************************
|
|
|
|
implementation
|
|
|
|
uses SysUtils, Classes, Math, CommCtrl;
|
|
|
|
// ***************************************************************
|
|
|
|
function GetPixelFormat(bmp: TBitmap) : integer;
|
|
var ds : TDibSection;
|
|
begin
|
|
result := 0;
|
|
if GetObject(bmp.handle, sizeOf(TDibSection), @ds) <> 0 then begin
|
|
result := ds.dsBmih.biBitCount;
|
|
if result = 16 then
|
|
if ds.dsBitFields[2] = $1F then begin
|
|
if (ds.dsBitFields[1] = $3E0) and (ds.dsBitFields[0] = $7C00) then
|
|
result := 15
|
|
else if (ds.dsBitFields[1] <> $7E0) or (ds.dsBitFields[0] <> $F800) then
|
|
result := 0;
|
|
end else
|
|
result := 0;
|
|
end;
|
|
end;
|
|
|
|
function ForcePixelFormat(const bmps: array of TBitmap; pixelFormat: TPixelFormat) : boolean;
|
|
var i1 : integer;
|
|
begin
|
|
result := true;
|
|
for i1 := 0 to high(bmps) do
|
|
if (bmps[i1].PixelFormat <> pixelFormat) and
|
|
((pixelFormat <> pf15bit) or (GetPixelFormat(bmps[i1]) <> 15)) then begin
|
|
bmps[i1].PixelFormat := pixelFormat;
|
|
if (bmps[i1].PixelFormat <> pixelFormat) and
|
|
((pixelFormat <> pf15bit) or (GetPixelFormat(bmps[i1]) <> 15)) then begin
|
|
result := false;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// ***************************************************************
|
|
|
|
type
|
|
TXtab32 = array [0..2 * 255 + 4 * 255 + 1 * 255] of cardinal;
|
|
TXtab16 = array [0..2 * 031 + 2 * 063 + 1 * 031] of word;
|
|
TXtab15 = array [0..2 * 031 + 4 * 031 + 1 * 031] of word;
|
|
|
|
var
|
|
xtab32 : array [TGrayPercent] of TXtab32;
|
|
xtab16 : array [TGrayPercent] of TXtab16;
|
|
xtab15 : array [TGrayPercent] of TXtab15;
|
|
xtab32Ready : array [TGrayPercent] of boolean = (false, false, false, false);
|
|
xtab16Ready : array [TGrayPercent] of boolean = (false, false, false, false);
|
|
xtab15Ready : array [TGrayPercent] of boolean = (false, false, false, false);
|
|
|
|
//32bit: 160ms -> 100ms 130 125
|
|
//24bit: 140ms -> 120ms 165 155
|
|
//16bit: 245ms (355ms for the non-asm variant) -> 100ms 130 140
|
|
//15bit: not supported by my graphics card -> 100ms 130 170
|
|
|
|
procedure GrayScale(bmp: TBitmap; percent: TGrayPercent = gp100);
|
|
|
|
{$ifdef win64}
|
|
|
|
procedure GrayScaleLine15_100(line: TPWord; width: integer; const xtab: TXtab15);
|
|
var w1 : word;
|
|
i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
w1 := line^;
|
|
line^ := xtab[(w1 shr 9) and $fe + (w1 shr 3) and $7c + w1 and $1f];
|
|
inc(line);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine15_75(line: TPWord; width: integer; const xtab: TXtab15);
|
|
var w1 : word;
|
|
i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
w1 := line^;
|
|
line^ := (w1 shr 2) and $1ce7 + xtab[(w1 shr 9) and $fe + (w1 shr 3) and $7c + w1 and $1f];
|
|
inc(line);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine15_50(line: TPWord; width: integer; const xtab: TXtab15);
|
|
var w1 : word;
|
|
i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
w1 := line^;
|
|
line^ := (w1 shr 1) and $3def + xtab[(w1 shr 9) and $fe + (w1 shr 3) and $7c + w1 and $1f];
|
|
inc(line);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine16_100(line: TPWord; width: integer; const xtab: TXtab16);
|
|
var w1 : word;
|
|
i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
w1 := line^;
|
|
line^ := xtab[(w1 shr 10) and $fe + (w1 shr 4) and $7e + w1 and $1f];
|
|
inc(line);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine16_75(line: TPWord; width: integer; const xtab: TXtab16);
|
|
var w1 : word;
|
|
i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
w1 := line^;
|
|
line^ := (w1 shr 2) and $39e7 + xtab[(w1 shr 10) and $fe + (w1 shr 4) and $7e + w1 and $1f];
|
|
inc(line);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine16_50(line: TPWord; width: integer; const xtab: TXtab16);
|
|
var w1 : word;
|
|
i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
w1 := line^;
|
|
line^ := (w1 shr 1) and $7bef + xtab[(w1 shr 10) and $fe + (w1 shr 4) and $7e + w1 and $1f];
|
|
inc(line);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine24_100(line: TPAByte; width: integer; const xtab: TXTab32);
|
|
var b1 : byte;
|
|
i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
b1 := xtab[line[0] shl 1 + line[1] shl 2 + line[2]];
|
|
line[0] := b1;
|
|
line[1] := b1;
|
|
line[2] := b1;
|
|
inc(NativeUInt(line), 3);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine24_75(line: TPAByte; width: integer; const xtab: TXTab32);
|
|
var c1 : cardinal;
|
|
i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
c1 := (TPCardinal(line)^ shr 2) and $003f3f3f + xtab[line[0] shl 1 + line[1] shl 2 + line[2]];
|
|
line[0] := byte(c1);
|
|
c1 := c1 shr 8;
|
|
line[1] := byte(c1);
|
|
c1 := c1 shr 8;
|
|
line[2] := byte(c1);
|
|
inc(NativeUInt(line), 3);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine24_50(line: TPAByte; width: integer; const xtab: TXTab32);
|
|
var c1 : cardinal;
|
|
i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
c1 := (TPCardinal(line)^ shr 1) and $007f7f7f + xtab[line[0] shl 1 + line[1] shl 2 + line[2]];
|
|
line[0] := byte(c1);
|
|
c1 := c1 shr 8;
|
|
line[1] := byte(c1);
|
|
c1 := c1 shr 8;
|
|
line[2] := byte(c1);
|
|
inc(NativeUInt(line), 3);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine32_100(line: TPAByte; width: integer; const xtab: TXTab32);
|
|
var i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
TPCardinal(line)^ := xtab[line[0] shl 1 + line[1] shl 2 + line[2]];
|
|
inc(NativeUInt(line), 4);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine32_75(line: TPAByte; width: integer; const xtab: TXTab32);
|
|
var i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
TPCardinal(line)^ := (TPCardinal(line)^ shr 2) and $003f3f3f + xtab[line[0] shl 1 + line[1] shl 2 + line[2]];
|
|
inc(NativeUInt(line), 4);
|
|
end;
|
|
end;
|
|
|
|
procedure GrayScaleLine32_50(line: TPAByte; width: integer; const xtab: TXTab32);
|
|
var i1 : integer;
|
|
begin
|
|
for i1 := 0 to width - 1 do begin
|
|
TPCardinal(line)^ := (TPCardinal(line)^ shr 1) and $007f7f7f + xtab[line[0] shl 1 + line[1] shl 2 + line[2]];
|
|
inc(NativeUInt(line), 4);
|
|
end;
|
|
end;
|
|
|
|
{$else}
|
|
|
|
procedure GrayScaleLine15_100(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov ebx, edx
|
|
shl ebx, 1
|
|
add ebx, eax
|
|
@0:
|
|
movzx eax, word[edi]
|
|
mov edx, eax
|
|
and eax, $000003E0
|
|
shr eax, 3
|
|
and edx, $0000001F
|
|
add eax, edx
|
|
movzx edx, word[edi]
|
|
shr edx, 9
|
|
and edx, $FE
|
|
add eax, edx
|
|
mov ax, [eax*2+ecx]
|
|
mov [edi], ax
|
|
add edi, 2
|
|
cmp ebx, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine15_75(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push esi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov esi, edx
|
|
shl esi, 1
|
|
add esi, eax
|
|
@0:
|
|
movzx eax, word[edi]
|
|
mov edx, eax
|
|
mov ebx, eax
|
|
shr ebx, 2
|
|
and ebx, $1CE7
|
|
and edx, $0000001F
|
|
and eax, $000003E0
|
|
shr eax, 3
|
|
add edx, eax
|
|
movzx eax, word[edi]
|
|
shr eax, 9
|
|
and eax, $FE
|
|
add edx, eax
|
|
add bx, [edx*2+ecx]
|
|
mov [edi], bx
|
|
add edi, 2
|
|
cmp esi, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop esi
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine15_50(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push esi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov esi, edx
|
|
shl esi, 1
|
|
add esi, eax
|
|
@0:
|
|
movzx eax, word[edi]
|
|
mov edx, eax
|
|
mov ebx, eax
|
|
shr ebx, 1
|
|
and ebx, $3DEF
|
|
and edx, $0000001F
|
|
and eax, $000003E0
|
|
shr eax, 3
|
|
add edx, eax
|
|
movzx eax, word[edi]
|
|
shr eax, 9
|
|
and eax, $FE
|
|
add edx, eax
|
|
add bx, [edx*2+ecx]
|
|
mov [edi], bx
|
|
add edi, 2
|
|
cmp esi, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop esi
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine16_100(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov ebx, edx
|
|
shl ebx, 1
|
|
add ebx, eax
|
|
@0:
|
|
movzx eax, word[edi]
|
|
mov edx, eax
|
|
and eax, $000007E0
|
|
shr eax, 4
|
|
and edx, $0000001F
|
|
add eax, edx
|
|
movzx edx, word[edi]
|
|
shr edx, 10
|
|
and edx, $FE
|
|
add eax, edx
|
|
mov ax, [eax*2+ecx]
|
|
mov [edi], ax
|
|
add edi, 2
|
|
cmp ebx, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine16_75(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push esi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov esi, edx
|
|
shl esi, 1
|
|
add esi, eax
|
|
@0:
|
|
movzx eax, word[edi]
|
|
mov edx, eax
|
|
mov ebx, eax
|
|
shr ebx, 2
|
|
and ebx, $39E7
|
|
and edx, $0000001F
|
|
and eax, $000007E0
|
|
shr eax, 4
|
|
add edx, eax
|
|
movzx eax, word[edi]
|
|
shr eax, 10
|
|
and eax, $FE
|
|
add edx, eax
|
|
add bx, [edx*2+ecx]
|
|
mov [edi], bx
|
|
add edi, 2
|
|
cmp esi, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop esi
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine16_50(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push esi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov esi, edx
|
|
shl esi, 1
|
|
add esi, eax
|
|
@0:
|
|
movzx eax, word[edi]
|
|
mov edx, eax
|
|
mov ebx, eax
|
|
shr ebx, 1
|
|
and ebx, $7BEF
|
|
and edx, $0000001F
|
|
and eax, $000007E0
|
|
shr eax, 4
|
|
add edx, eax
|
|
movzx eax, word[edi]
|
|
shr eax, 10
|
|
and eax, $FE
|
|
add edx, eax
|
|
add bx, [edx*2+ecx]
|
|
mov [edi], bx
|
|
add edi, 2
|
|
cmp esi, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop esi
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine24_100(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov ebx, edx
|
|
add ebx, edx
|
|
add ebx, edx
|
|
add ebx, eax
|
|
@0:
|
|
movzx edx, byte[edi+2]
|
|
movzx eax, byte[edi+1]
|
|
shl eax, 2
|
|
add edx, eax
|
|
movzx eax, byte[edi]
|
|
add edx, eax
|
|
add edx, eax
|
|
mov edx, [edx*4+ecx]
|
|
mov [edi], dl
|
|
mov [edi+1], dl
|
|
mov [edi+2], dl
|
|
add edi, 3
|
|
cmp ebx, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine24_75(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push esi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov esi, edx
|
|
add esi, edx
|
|
add esi, edx
|
|
add esi, eax
|
|
@0:
|
|
movzx eax, byte[edi+2]
|
|
mov ebx, [edi]
|
|
shr ebx, 2
|
|
and ebx, $003F3F3F
|
|
movzx edx, byte[edi+1]
|
|
shl edx, 2
|
|
add eax, edx
|
|
movzx edx, byte[edi]
|
|
add eax, edx
|
|
add eax, edx
|
|
add ebx, [eax*4+ecx]
|
|
mov [edi], bl
|
|
shr ebx, 8
|
|
mov [edi+1], bl
|
|
mov [edi+2], bh
|
|
add edi, 3
|
|
cmp esi, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop esi
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine24_50(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push esi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov esi, edx
|
|
add esi, edx
|
|
add esi, edx
|
|
add esi, eax
|
|
@0:
|
|
movzx eax, byte[edi+2]
|
|
mov ebx, [edi]
|
|
shr ebx, 1
|
|
and ebx, $007F7F7F
|
|
movzx edx, byte[edi+1]
|
|
shl edx, 2
|
|
add eax, edx
|
|
movzx edx, byte[edi]
|
|
add eax, edx
|
|
add eax, edx
|
|
add ebx, [eax*4+ecx]
|
|
mov [edi], bl
|
|
shr ebx, 8
|
|
mov [edi+1], bl
|
|
mov [edi+2], bh
|
|
add edi, 3
|
|
cmp esi, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop esi
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine32_100(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov ebx, edx
|
|
shl ebx, 2
|
|
add ebx, eax
|
|
@0:
|
|
movzx eax, byte[edi+2]
|
|
movzx edx, byte[edi+1]
|
|
shl edx, 2
|
|
add eax, edx
|
|
movzx edx, byte[edi]
|
|
add eax, edx
|
|
add eax, edx
|
|
mov eax, [eax*4+ecx]
|
|
mov [edi], eax
|
|
add edi, 4
|
|
cmp ebx, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine32_75(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push esi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov esi, edx
|
|
shl esi, 2
|
|
add esi, eax
|
|
@0:
|
|
movzx eax, byte[edi+2]
|
|
mov ebx, [edi]
|
|
shr ebx, 2
|
|
and ebx, $003F3F3F
|
|
movzx edx, byte[edi+1]
|
|
shl edx, 2
|
|
add eax, edx
|
|
movzx edx, byte[edi]
|
|
add eax, edx
|
|
add eax, edx
|
|
add ebx, [eax*4+ecx]
|
|
mov [edi], ebx
|
|
add edi, 4
|
|
cmp esi, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop esi
|
|
pop edi
|
|
end;
|
|
|
|
procedure GrayScaleLine32_50(line: pointer; width: integer; var xtab);
|
|
asm
|
|
push edi
|
|
push esi
|
|
push ebx
|
|
|
|
mov edi, eax
|
|
mov esi, edx
|
|
shl esi, 2
|
|
add esi, eax
|
|
@0:
|
|
movzx eax, byte[edi+2]
|
|
mov ebx, [edi]
|
|
shr ebx, 1
|
|
and ebx, $007F7F7F
|
|
movzx edx, byte[edi+1]
|
|
shl edx, 2
|
|
add eax, edx
|
|
movzx edx, byte[edi]
|
|
add eax, edx
|
|
add eax, edx
|
|
add ebx, [eax*4+ecx]
|
|
mov [edi], ebx
|
|
add edi, 4
|
|
cmp esi, edi
|
|
jnz @0
|
|
|
|
pop ebx
|
|
pop esi
|
|
pop edi
|
|
end;
|
|
|
|
{$endif}
|
|
|
|
procedure CheckXTab32(gp: TGrayPercent);
|
|
var i1 : integer;
|
|
gray : integer;
|
|
begin
|
|
if not xtab32Ready[gp] then begin
|
|
for i1 := 0 to high(xtab32[gp]) do begin
|
|
gray := round(i1 / 7);
|
|
case gp of
|
|
gp50 : gray := gray div 2;
|
|
gp75 : gray := gray - gray div 4;
|
|
end;
|
|
xtab32[gp][i1] := gray shl 16 + gray shl 8 + gray;
|
|
end;
|
|
xtab32Ready[gp] := true;
|
|
end;
|
|
end;
|
|
|
|
procedure CheckXTab16(gp: TGrayPercent);
|
|
var i1 : integer;
|
|
gray : integer;
|
|
begin
|
|
if not xtab16Ready[gp] then begin
|
|
for i1 := 0 to high(xtab16[gp]) do begin
|
|
gray := round(i1 * 31 / high(xtab16[gp]));
|
|
case gp of
|
|
gp50 : gray := gray div 2;
|
|
gp75 : gray := gray - gray div 4;
|
|
end;
|
|
xtab16[gp][i1] := gray shl 11 + gray shl 6 + gray;
|
|
end;
|
|
xtab16Ready[gp] := true;
|
|
end;
|
|
end;
|
|
|
|
procedure CheckXTab15(gp: TGrayPercent);
|
|
var i1 : integer;
|
|
gray : integer;
|
|
begin
|
|
if not xtab15Ready[gp] then begin
|
|
for i1 := 0 to high(xtab15[gp]) do begin
|
|
gray := round(i1 * 31 / high(xtab15[gp]));
|
|
case gp of
|
|
gp50 : gray := gray div 2;
|
|
gp75 : gray := gray - gray div 4;
|
|
end;
|
|
xtab15[gp][i1] := gray shl 10 + gray shl 5 + gray;
|
|
end;
|
|
xtab15Ready[gp] := true;
|
|
end;
|
|
end;
|
|
|
|
var iy, iw, ih : integer;
|
|
line : pointer;
|
|
lineDif : integer;
|
|
casei : integer;
|
|
begin
|
|
if percent <> gp0 then
|
|
with bmp do begin
|
|
iw := Width;
|
|
ih := Height;
|
|
if (iw > 0) and (ih > 0) then begin
|
|
if GetPixelFormat(bmp) < 15 then PixelFormat := pf32bit;
|
|
case GetPixelFormat(bmp) of
|
|
15 : begin casei := $150; CheckXTab15(percent) end;
|
|
16 : begin casei := $160; CheckXTab16(percent) end;
|
|
24 : begin casei := $240; CheckXTab32(percent) end;
|
|
32 : begin casei := $320; CheckXtab32(percent) end;
|
|
else exit;
|
|
end;
|
|
inc(casei, ord(percent));
|
|
line := ScanLine[0];
|
|
if ih > 1 then
|
|
lineDif := NativeInt(ScanLine[1]) - NativeInt(line)
|
|
else
|
|
lineDif := 0;
|
|
for iy := 0 to Height - 1 do begin
|
|
case casei of
|
|
$150 : GrayScaleLine15_100(line, iw, xtab15[gp100]);
|
|
$151 : GrayScaleLine15_75 (line, iw, xtab15[gp75 ]);
|
|
$152 : GrayScaleLine15_50 (line, iw, xtab15[gp50 ]);
|
|
$160 : GrayScaleLine16_100(line, iw, xtab16[gp100]);
|
|
$161 : GrayScaleLine16_75 (line, iw, xtab16[gp75 ]);
|
|
$162 : GrayScaleLine16_50 (line, iw, xtab16[gp50 ]);
|
|
$240 : GrayScaleLine24_100(line, iw, xtab32[gp100]);
|
|
$241 : GrayScaleLine24_75 (line, iw, xtab32[gp75 ]);
|
|
$242 : GrayScaleLine24_50 (line, iw, xtab32[gp50 ]);
|
|
$320 : GrayScaleLine32_100(line, iw, xtab32[gp100]);
|
|
$321 : GrayScaleLine32_75 (line, iw, xtab32[gp75 ]);
|
|
$322 : GrayScaleLine32_50 (line, iw, xtab32[gp50 ]);
|
|
end;
|
|
inc(NativeInt(line), lineDif);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// ***************************************************************
|
|
|
|
type
|
|
TContributorPixel = record
|
|
pixel : integer; // source pixel
|
|
weight : integer; // weight of this source pixel
|
|
end;
|
|
|
|
// list of source pixels contributing to the destination pixel
|
|
TContributorPixels = record
|
|
itemCount : integer;
|
|
items : array of TContributorPixel;
|
|
end;
|
|
|
|
// list for the full width/height of a bitmap
|
|
TContributorList = array of TContributorPixels;
|
|
|
|
// which resampling filter shall be used?
|
|
TResamplingFilter = (
|
|
// 1 tap
|
|
rfNearest, // Nearest Neighbor, aka. Point Sampling
|
|
// - additional ringing = 0
|
|
// - hide source ringing = 0
|
|
// - aliasing = 10
|
|
// - sharpness = 10
|
|
|
|
// 2 tap
|
|
rfBilinear, // Bilinear
|
|
// - additional ringing = 0
|
|
// - hide source ringing = 3
|
|
// - aliasing = 5
|
|
// - sharpness = 5
|
|
|
|
rfBicubic50, rfBicubic60, rfBicubic75,
|
|
// Bicubic, aka. Catmull-Rom (rfBicubic50)
|
|
// - additional ringing = 1, 2, 3.5
|
|
// - hide source ringing = 0
|
|
// - aliasing = 4.5, 3.5, 3
|
|
// - sharpness = 7.25, 7.50, 7.75
|
|
|
|
rfMitchell, // Mitchell-Netravali
|
|
// - additional ringing = 1
|
|
// - hide source ringing = 1
|
|
// - aliasing = 4
|
|
// - sharpness = 5
|
|
|
|
rfSoftCubic100, rfSoftCubic80, rfSoftCubic70, rfSoftCubic60, rfSoftCubic50,
|
|
// Cubic B-Spline
|
|
// - additional ringing = 0, 0, 0.25, 0.5, 0.75
|
|
// - hide source ringing = 9, 7, 6, 3, 1
|
|
// - aliasing = 0, 0.25, 1, 2, 2.5
|
|
// - sharpness = 0.5, 2, 3, 3.5, 4
|
|
|
|
// 3-4 tap
|
|
rfLanczos3, rfLanczos4,
|
|
// Lanczos
|
|
// - additional ringing = 6, 8
|
|
// - hide source ringing = 0
|
|
// - aliasing = 2, 1
|
|
// - sharpness = 8.5, 9
|
|
rfSpline36, rfSpline64
|
|
// Spline
|
|
// - additional ringing = 4.5, 5
|
|
// - hide source ringing = 0
|
|
// - aliasing = 2.5, 2.3
|
|
// - sharpness = 8, 8.1
|
|
|
|
// spline16 -> bicubic50
|
|
// blackman3 -> bicubic60
|
|
// blackman4 -> spline36
|
|
// gaussian -> softCubic
|
|
);
|
|
|
|
// full list structure including src and dst information
|
|
TScaleList = record
|
|
filter : TResamplingFilter;
|
|
src, dst : integer;
|
|
contributorList : TContributorList;
|
|
end;
|
|
|
|
const
|
|
CResamplingFilterNames : array [TResamplingFilter] of AnsiString =
|
|
('Nearest',
|
|
'Bilinear',
|
|
'Bicubic50', 'Bicubic60', 'Bicubic75',
|
|
'Mitchell',
|
|
'SoftCubic100', 'SoftCubic80', 'SoftCubic70', 'SoftCubic60', 'SoftCubic50',
|
|
'Lanczos3', 'Lanczos4',
|
|
'Spline36', 'Spline64');
|
|
|
|
var
|
|
ScaleListCache : array of TScaleList;
|
|
ScaleListSection : TRTLCriticalSection;
|
|
|
|
procedure StretchBitmap_(srcBmp, dstBmp : TBitmap;
|
|
srcMsk, dstMsk : TBitmap;
|
|
quality : TStretchQuality = sqHigh;
|
|
filter : TResamplingFilter = rfLanczos4); overload;
|
|
|
|
procedure GetContributorList(var result: TContributorList; src_, dst_: integer; filter: TResamplingFilter);
|
|
|
|
function Cubic(weight, param1, param2: double) : double;
|
|
var P0, P1, P2, P3 : double;
|
|
begin
|
|
result := 0;
|
|
if weight <= 2 then begin
|
|
if weight < 1 then begin
|
|
P0 := (+ 1 - 1/3 * param1 - 0 * param2);
|
|
P1 := 0;
|
|
P2 := (- 3 + 2 * param1 + 1 * param2);
|
|
P3 := (+ 2 - 3/2 * param1 - 1 * param2);
|
|
end else begin
|
|
P0 := (- 0 + 4/3 * param1 + 4 * param2);
|
|
P1 := (+ 0 - 2 * param1 - 8 * param2);
|
|
P2 := (- 0 + 1 * param1 + 5 * param2);
|
|
P3 := (+ 0 - 1/6 * param1 - 1 * param2);
|
|
end;
|
|
result := P0 + P1 * weight + P2 * weight * weight + P3 * weight * weight * weight;
|
|
end;
|
|
end;
|
|
|
|
function GetFilterCoeffs(weight: double; filter: TResamplingFilter) : double;
|
|
begin
|
|
result := 0;
|
|
case filter of
|
|
rfNearest : if weight < 1 then
|
|
result := 1 - weight;
|
|
rfBilinear : if weight < 1 then
|
|
result := 1 - weight;
|
|
rfBicubic50 : result := Cubic(weight, 0.00, 0.50);
|
|
rfBicubic60 : result := Cubic(weight, 0.00, 0.60);
|
|
rfBicubic75 : result := Cubic(weight, 0.00, 0.75);
|
|
rfSoftCubic100 : result := Cubic(weight, 1.00, 0.00);
|
|
rfSoftCubic80 : result := Cubic(weight, 0.80, 0.20);
|
|
rfSoftCubic70 : result := Cubic(weight, 0.70, 0.30);
|
|
rfSoftCubic60 : result := Cubic(weight, 0.60, 0.40);
|
|
rfSoftCubic50 : result := Cubic(weight, 0.50, 0.50);
|
|
rfMitchell : result := Cubic(weight, 1/3, 1/3);
|
|
rfLanczos3 : if weight = 0 then
|
|
result := 1
|
|
else
|
|
if weight < 3 then begin
|
|
weight := weight * Pi;
|
|
result := (sin(weight) / weight) * (sin(weight / 3) / (weight / 3)); // result := 3 * sin(weight) * sin(weight / 3) / (weight * weight);
|
|
end;
|
|
rfLanczos4 : if weight = 0 then
|
|
result := 1
|
|
else
|
|
if weight < 4 then begin
|
|
weight := weight * Pi;
|
|
result := (sin(weight) / weight) * (sin(weight / 4) / (weight / 4));
|
|
end;
|
|
rfSpline36 : if weight < 3 then
|
|
if weight < 1 then
|
|
result := ((13 / 11 * weight - 453 / 209) * weight - 3 / 209) * weight + 1
|
|
else
|
|
if weight < 2 then
|
|
result := ((-6 / 11 * (weight - 1) + 270 / 209) * (weight - 1) - 156 / 209) * (weight - 1)
|
|
else
|
|
result := ((1 / 11 * (weight - 2) - 45 / 209) * (weight - 2) + 26 / 209) * (weight - 2);
|
|
rfSpline64 : if weight < 4 then
|
|
if weight < 1 then
|
|
result := ((49 / 41 * weight - 6387 / 2911) * weight - 3 / 2911) * weight + 1
|
|
else
|
|
if weight < 2 then
|
|
result := ((-24 / 41 * (weight - 1) + 4032 / 2911) * (weight - 1) - 2328 / 2911) * (weight - 1)
|
|
else
|
|
if weight < 3 then
|
|
result := ((6 / 41 * (weight - 2) - 1008 / 2911) * (weight - 2) + 582 / 2911) * (weight - 2)
|
|
else
|
|
result := ((-1 / 41 * (weight - 3) + 168 / 2911) * (weight - 3) - 97 / 2911) * (weight - 3);
|
|
// rfGaussian25 : if weight < 4 then
|
|
// result := Power(2, - 2.5 * weight * weight);
|
|
end;
|
|
end;
|
|
|
|
type TDADouble = array of double;
|
|
|
|
procedure OptimizeItems(var result: TContributorList; index: integer; const floatWeights: TDADouble);
|
|
var totalI : integer;
|
|
totalF : double;
|
|
highest : integer;
|
|
i1, i2 : integer;
|
|
begin
|
|
with result[index] do begin
|
|
totalF := 0;
|
|
for i2 := 0 to itemCount - 1 do
|
|
totalF := totalF + floatWeights[i2];
|
|
totalI := 0;
|
|
highest := -1;
|
|
i1 := 0;
|
|
for i2 := 0 to itemCount - 1 do begin
|
|
items[i1].weight := round(floatWeights[i2] / totalF * $10000);
|
|
if abs(items[i1].weight) > 1 then begin
|
|
items[i1].pixel := items[i2].pixel;
|
|
inc(totalI, items[i1].weight);
|
|
if (highest = -1) or (items[i1].weight > items[highest].weight) then
|
|
highest := i1;
|
|
inc(i1);
|
|
end;
|
|
end;
|
|
itemCount := i1;
|
|
if totalI <> $10000 then
|
|
dec(items[highest].weight, totalI - $10000);
|
|
end;
|
|
end;
|
|
|
|
procedure AddItem(var result: TContributorList; index: integer; pixel, maxPixel: integer; var floatWeights, offsets: TDADouble; offset: double; filter: TResamplingFilter);
|
|
var i1, i2 : integer;
|
|
weight : double;
|
|
begin
|
|
with result[index] do begin
|
|
weight := GetFilterCoeffs(offset, filter);
|
|
if weight <> 0 then begin
|
|
if pixel < 0 then
|
|
pixel := 0
|
|
else
|
|
if pixel >= maxPixel then
|
|
pixel := maxPixel - 1;
|
|
floatWeights[itemCount] := weight;
|
|
offsets[itemCount] := offset;
|
|
items[itemCount].pixel := pixel;
|
|
for i1 := 0 to itemCount - 1 do
|
|
if abs(offsets[i1]) > abs(offset) then begin
|
|
for i2 := itemCount downto i1 + 1 do begin
|
|
floatWeights[i2] := floatWeights[i2 - 1];
|
|
offsets[i2] := offsets[i2 - 1];
|
|
items[i2].pixel := items[i2 - 1].pixel;
|
|
end;
|
|
floatWeights[i1] := weight;
|
|
offsets[i1] := offset;
|
|
items[i1].pixel := pixel;
|
|
break;
|
|
end;
|
|
inc(itemCount);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var scale : double;
|
|
capacity : integer;
|
|
i1, i2 : integer;
|
|
floatWeights : TDADouble;
|
|
offsets : TDADouble;
|
|
begin
|
|
if ScaleListCache = nil then
|
|
InitializeCriticalSection(ScaleListSection);
|
|
EnterCriticalSection(ScaleListSection);
|
|
try
|
|
for i1 := 0 to high(ScaleListCache) do
|
|
if (ScaleListCache[i1].filter = filter) and (ScaleListCache[i1].src = src_) and (ScaleListCache[i1].dst = dst_) then begin
|
|
result := ScaleListCache[i1].contributorList;
|
|
exit;
|
|
end;
|
|
if dst_ < src_ then begin
|
|
SetLength(result, dst_);
|
|
capacity := 8 * src_ div dst_ + 1;
|
|
SetLength(floatWeights, capacity);
|
|
SetLength(offsets, capacity);
|
|
scale := dst_ / src_;
|
|
for i1 := 0 to dst_ - 1 do
|
|
with result[i1] do begin
|
|
SetLength(items, capacity);
|
|
itemCount := 0;
|
|
for i2 := ((i1 - 4) * src_ - dst_ + 1) div dst_ to ((i1 + 4) * src_ + dst_ - 1) div dst_ do
|
|
AddItem(result, i1, i2, src_, floatWeights, offsets, abs(i1 + 0.5 - (i2 + 0.5) * scale), filter);
|
|
if filter = rfNearest then
|
|
itemCount := 1;
|
|
OptimizeItems(result, i1, floatWeights);
|
|
end;
|
|
end else begin
|
|
SetLength(result, dst_);
|
|
SetLength(floatWeights, 9);
|
|
SetLength(offsets, 9);
|
|
scale := src_ / dst_;
|
|
for i1 := 0 to dst_ - 1 do
|
|
with result[i1] do begin
|
|
SetLength(items, 17);
|
|
itemCount := 0;
|
|
for i2 := (i1 * src_ - 5 * dst_ + 1) div dst_ to (i1 * src_ + 5 * dst_ - 1) div dst_ do
|
|
AddItem(result, i1, i2, src_, floatWeights, offsets, abs((i1 + 0.5) * scale - (i2 + 0.5)), filter);
|
|
if filter = rfNearest then
|
|
itemCount := 1;
|
|
OptimizeItems(result, i1, floatWeights);
|
|
end;
|
|
end;
|
|
i1 := Length(ScaleListCache);
|
|
SetLength(ScaleListCache, i1 + 1);
|
|
ScaleListCache[i1].filter := filter;
|
|
ScaleListCache[i1].src := src_;
|
|
ScaleListCache[i1].dst := dst_;
|
|
ScaleListCache[i1].contributorList := result;
|
|
finally LeaveCriticalSection(ScaleListSection) end;
|
|
end;
|
|
|
|
procedure Resampling15; // 370 / 195
|
|
var ix, iy, ic : integer;
|
|
weight : integer;
|
|
clx, cly : TContributorList;
|
|
fr, fg, fb, fm : integer;
|
|
sbBits, dbBits : NativeInt;
|
|
smBits, dmBits : NativeInt;
|
|
sbDif, dbDif : integer;
|
|
smDif, dmDif : integer;
|
|
sbLine, tbBuf : PWordArray;
|
|
smLine, tmBuf : PByteArray;
|
|
dbPix : ^word;
|
|
dmPix : ^byte;
|
|
pcp : ^TContributorPixel;
|
|
dw1 : integer;
|
|
begin
|
|
GetContributorList(clx, srcBmp.Width, dstBmp.Width, rfMitchell);
|
|
GetContributorList(cly, srcBmp.Height, dstBmp.Height, rfMitchell);
|
|
tbBuf := AllocMem(srcBmp.Height * 2 + srcBmp.Height * 1);
|
|
sbBits := NativeInt(srcBmp.ScanLine[0]);
|
|
dbBits := NativeInt(dstBmp.ScanLine[0]);
|
|
if srcBmp.Height > 1 then
|
|
sbDif := NativeInt(srcBmp.ScanLine[1]) - sbBits
|
|
else
|
|
sbDif := 0;
|
|
if dstBmp.Height > 1 then
|
|
dbDif := NativeInt(dstBmp.ScanLine[1]) - dbBits
|
|
else
|
|
dbDif := 0;
|
|
if srcMsk <> nil then begin
|
|
tmBuf := pointer(NativeInt(tbBuf) + srcBmp.Height * 2);
|
|
smBits := NativeInt(srcMsk.ScanLine[0]);
|
|
dmBits := NativeInt(dstMsk.ScanLine[0]);
|
|
if srcMsk.Height > 1 then
|
|
smDif := NativeInt(srcMsk.ScanLine[1]) - smBits
|
|
else
|
|
smDif := 0;
|
|
if dstMsk.Height > 1 then
|
|
dmDif := NativeInt(dstMsk.ScanLine[1]) - dmBits
|
|
else
|
|
dmDif := 0;
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
dbPix := pointer(tbBuf );
|
|
dmPix := pointer(tmBuf );
|
|
sbLine := pointer(sbBits);
|
|
smLine := pointer(smBits);
|
|
for iy := 0 to srcBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
fm := 0;
|
|
pcp := @clx[ix].items[0];
|
|
for ic := 0 to clx[ix].itemCount - 1 do begin
|
|
weight := (pcp^.weight * (256 - smLine^[pcp^.pixel])) div 256;
|
|
inc(fm, weight);
|
|
dw1 := sbLine^[pcp^.pixel];
|
|
inc(fr, (dw1 shr 10 ) * weight);
|
|
inc(fg, (dw1 and $03E0) * weight);
|
|
inc(fb, (dw1 and $001F) * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fr < 0 then fr := 0
|
|
else if fr > $001F0000 then fr := $7C00
|
|
else fr := (fr shr 6) and $7C00;
|
|
if fg < 0 then
|
|
else if fg > $03E00000 then inc(fr, $03E0)
|
|
else inc(fr, (fg shr 16) and $03E0);
|
|
if fb < 0 then
|
|
else if fb > $001F0000 then inc(fr, $001F)
|
|
else inc(fr, fb shr 16);
|
|
dbPix^ := word(fr);
|
|
inc(dbPix);
|
|
if fm < 0 then dmPix^ := 255
|
|
else if fm > $0000FF00 then dmPix^ := 0
|
|
else dmPix^ := 255 - fm shr 8;
|
|
inc(dmPix);
|
|
inc(NativeInt(sbLine), sbDif);
|
|
inc(NativeInt(smLine), smDif);
|
|
end;
|
|
dbPix := pointer(dbBits + ix * 2);
|
|
dmPix := pointer(dmBits + ix );
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
fm := 0;
|
|
pcp := @cly[iy].items[0];
|
|
for ic := 0 to cly[iy].itemCount - 1 do begin
|
|
weight := (pcp^.weight * (256 - tmBuf^[pcp^.pixel])) div 256;
|
|
inc(fm, weight);
|
|
dw1 := tbBuf^[pcp^.pixel];
|
|
inc(fr, (dw1 shr 10 ) * weight);
|
|
inc(fg, (dw1 and $03E0) * weight);
|
|
inc(fb, (dw1 and $001F) * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fr < 0 then fr := 0
|
|
else if fr > $001F0000 then fr := $7C00
|
|
else fr := (fr shr 6) and $7C00;
|
|
if fg < 0 then
|
|
else if fg > $03E00000 then inc(fr, $03E0)
|
|
else inc(fr, (fg shr 16) and $03E0);
|
|
if fb < 0 then
|
|
else if fb > $001F0000 then inc(fr, $001F)
|
|
else inc(fr, fb shr 16);
|
|
dbPix^ := word(fr);
|
|
inc(NativeInt(dbPix), dbDif);
|
|
if fm < 0 then dmPix^ := 255
|
|
else if fm > $0000FF00 then dmPix^ := 0
|
|
else dmPix^ := 255 - fm shr 8;
|
|
inc(dmPix, dmDif);
|
|
end;
|
|
end;
|
|
end else
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
dbPix := pointer(tbBuf );
|
|
sbLine := pointer(sbBits);
|
|
for iy := 0 to srcBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
pcp := @clx[ix].items[0];
|
|
for ic := 0 to clx[ix].itemCount - 1 do begin
|
|
weight := pcp^.weight;
|
|
dw1 := sbLine^[pcp^.pixel];
|
|
inc(fr, (dw1 shr 10 ) * weight);
|
|
inc(fg, (dw1 and $03E0) * weight);
|
|
inc(fb, (dw1 and $001F) * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fr < 0 then fr := 0
|
|
else if fr > $001F0000 then fr := $7C00
|
|
else fr := (fr shr 6) and $7C00;
|
|
if fg < 0 then
|
|
else if fg > $03E00000 then inc(fr, $03E0)
|
|
else inc(fr, (fg shr 16) and $03E0);
|
|
if fb < 0 then
|
|
else if fb > $001F0000 then inc(fr, $001F)
|
|
else inc(fr, fb shr 16);
|
|
dbPix^ := word(fr);
|
|
inc(dbPix);
|
|
inc(NativeInt(sbLine), sbDif);
|
|
end;
|
|
dbPix := pointer(dbBits + ix * 2);
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
pcp := @cly[iy].items[0];
|
|
for ic := 0 to cly[iy].itemCount - 1 do begin
|
|
weight := pcp^.weight;
|
|
dw1 := tbBuf^[pcp^.pixel];
|
|
inc(fr, (dw1 shr 10 ) * weight);
|
|
inc(fg, (dw1 and $03E0) * weight);
|
|
inc(fb, (dw1 and $001F) * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fr < 0 then fr := 0
|
|
else if fr > $001F0000 then fr := $7C00
|
|
else fr := (fr shr 6) and $7C00;
|
|
if fg < 0 then
|
|
else if fg > $03E00000 then inc(fr, $03E0)
|
|
else inc(fr, (fg shr 16) and $03E0);
|
|
if fb < 0 then
|
|
else if fb > $001F0000 then inc(fr, $001F)
|
|
else inc(fr, fb shr 16);
|
|
dbPix^ := word(fr);
|
|
inc(NativeInt(dbPix), dbDif);
|
|
end;
|
|
end;
|
|
FreeMem(tbBuf);
|
|
end;
|
|
|
|
procedure Resampling16; // 370 / 195
|
|
var ix, iy, ic : integer;
|
|
weight : integer;
|
|
clx, cly : TContributorList;
|
|
fr, fg, fb, fm : integer;
|
|
sbBits, dbBits : NativeInt;
|
|
smBits, dmBits : NativeInt;
|
|
sbDif, dbDif : integer;
|
|
smDif, dmDif : integer;
|
|
sbLine, tbBuf : PWordArray;
|
|
smLine, tmBuf : PByteArray;
|
|
dbPix : ^word;
|
|
dmPix : ^byte;
|
|
pcp : ^TContributorPixel;
|
|
dw1 : integer;
|
|
begin
|
|
GetContributorList(clx, srcBmp.Width, dstBmp.Width, rfMitchell);
|
|
GetContributorList(cly, srcBmp.Height, dstBmp.Height, rfMitchell);
|
|
tbBuf := AllocMem(srcBmp.Height * 2 + srcBmp.Height * 1);
|
|
sbBits := NativeUInt(srcBmp.ScanLine[0]);
|
|
dbBits := NativeUInt(dstBmp.ScanLine[0]);
|
|
if srcBmp.Height > 1 then
|
|
sbDif := NativeInt(srcBmp.ScanLine[1]) - sbBits
|
|
else
|
|
sbDif := 0;
|
|
if dstBmp.Height > 1 then
|
|
dbDif := NativeInt(dstBmp.ScanLine[1]) - dbBits
|
|
else
|
|
dbDif := 0;
|
|
if srcMsk <> nil then begin
|
|
tmBuf := pointer(NativeInt(tbBuf) + srcBmp.Height * 2);
|
|
smBits := NativeInt(srcMsk.ScanLine[0]);
|
|
dmBits := NativeInt(dstMsk.ScanLine[0]);
|
|
if srcMsk.Height > 1 then
|
|
smDif := NativeInt(srcMsk.ScanLine[1]) - smBits
|
|
else
|
|
smDif := 0;
|
|
if dstMsk.Height > 1 then
|
|
dmDif := NativeInt(dstMsk.ScanLine[1]) - dmBits
|
|
else
|
|
dmDif := 0;
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
dbPix := pointer(tbBuf );
|
|
dmPix := pointer(tmBuf );
|
|
sbLine := pointer(sbBits);
|
|
smLine := pointer(smBits);
|
|
for iy := 0 to srcBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
fm := 0;
|
|
pcp := @clx[ix].items[0];
|
|
for ic := 0 to clx[ix].itemCount - 1 do begin
|
|
weight := (pcp^.weight * (256 - smLine^[pcp^.pixel])) div 256;
|
|
inc(fm, weight);
|
|
dw1 := sbLine^[pcp^.pixel];
|
|
inc(fr, (dw1 shr 11 ) * weight);
|
|
inc(fg, (dw1 and $07E0) * weight);
|
|
inc(fb, (dw1 and $001F) * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fr < 0 then fr := 0
|
|
else if fr > $001F0000 then fr := $F800
|
|
else fr := (fr shr 5) and $F800;
|
|
if fg < 0 then
|
|
else if fg > $07E00000 then inc(fr, $07E0)
|
|
else inc(fr, (fg shr 16) and $07E0);
|
|
if fb < 0 then
|
|
else if fb > $001F0000 then inc(fr, $001F)
|
|
else inc(fr, fb shr 16);
|
|
dbPix^ := word(fr);
|
|
inc(dbPix);
|
|
if fm < 0 then dmPix^ := 255
|
|
else if fm > $0000FF00 then dmPix^ := 0
|
|
else dmPix^ := 255 - fm shr 8;
|
|
inc(dmPix);
|
|
inc(NativeInt(sbLine), sbDif);
|
|
inc(NativeInt(smLine), smDif);
|
|
end;
|
|
dbPix := pointer(dbBits + ix * 2);
|
|
dmPix := pointer(dmBits + ix );
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
fm := 0;
|
|
pcp := @cly[iy].items[0];
|
|
for ic := 0 to cly[iy].itemCount - 1 do begin
|
|
weight := (pcp^.weight * (256 - tmBuf^[pcp^.pixel])) div 256;
|
|
inc(fm, weight);
|
|
dw1 := tbBuf^[pcp^.pixel];
|
|
inc(fr, (dw1 shr 11 ) * weight);
|
|
inc(fg, (dw1 and $07E0) * weight);
|
|
inc(fb, (dw1 and $001F) * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fr < 0 then fr := 0
|
|
else if fr > $001F0000 then fr := $F800
|
|
else fr := (fr shr 5) and $F800;
|
|
if fg < 0 then
|
|
else if fg > $07E00000 then inc(fr, $07E0)
|
|
else inc(fr, (fg shr 16) and $07E0);
|
|
if fb < 0 then
|
|
else if fb > $001F0000 then inc(fr, $001F)
|
|
else inc(fr, fb shr 16);
|
|
dbPix^ := word(fr);
|
|
inc(NativeInt(dbPix), dbDif);
|
|
if fm < 0 then dmPix^ := 255
|
|
else if fm > $0000FF00 then dmPix^ := 0
|
|
else dmPix^ := 255 - fm shr 8;
|
|
inc(dmPix, dmDif);
|
|
end;
|
|
end;
|
|
end else
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
dbPix := pointer(tbBuf );
|
|
sbLine := pointer(sbBits);
|
|
for iy := 0 to srcBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
pcp := @clx[ix].items[0];
|
|
for ic := 0 to clx[ix].itemCount - 1 do begin
|
|
weight := pcp^.weight;
|
|
dw1 := sbLine^[pcp^.pixel];
|
|
inc(fr, (dw1 shr 11 ) * weight);
|
|
inc(fg, (dw1 and $07E0) * weight);
|
|
inc(fb, (dw1 and $001F) * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fr < 0 then fr := 0
|
|
else if fr > $001F0000 then fr := $F800
|
|
else fr := (fr shr 5) and $F800;
|
|
if fg < 0 then
|
|
else if fg > $07E00000 then inc(fr, $07E0)
|
|
else inc(fr, (fg shr 16) and $07E0);
|
|
if fb < 0 then
|
|
else if fb > $001F0000 then inc(fr, $001F)
|
|
else inc(fr, fb shr 16);
|
|
dbPix^ := word(fr);
|
|
inc(dbPix);
|
|
inc(NativeInt(sbLine), sbDif);
|
|
end;
|
|
dbPix := pointer(dbBits + ix * 2);
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
pcp := @cly[iy].items[0];
|
|
for ic := 0 to cly[iy].itemCount - 1 do begin
|
|
weight := pcp^.weight;
|
|
dw1 := tbBuf^[pcp^.pixel];
|
|
inc(fr, (dw1 shr 11 ) * weight);
|
|
inc(fg, (dw1 and $07E0) * weight);
|
|
inc(fb, (dw1 and $001F) * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fr < 0 then fr := 0
|
|
else if fr > $001F0000 then fr := $F800
|
|
else fr := (fr shr 5) and $F800;
|
|
if fg < 0 then
|
|
else if fg > $07E00000 then inc(fr, $07E0)
|
|
else inc(fr, (fg shr 16) and $07E0);
|
|
if fb < 0 then
|
|
else if fb > $001F0000 then inc(fr, $001F)
|
|
else inc(fr, fb shr 16);
|
|
dbPix^ := word(fr);
|
|
inc(NativeInt(dbPix), dbDif);
|
|
end;
|
|
end;
|
|
FreeMem(tbBuf);
|
|
end;
|
|
|
|
procedure Resampling24; // 385 / 200
|
|
type TRGB = packed record b, g, r: byte; end;
|
|
var ix, iy, ic : integer;
|
|
weight : integer;
|
|
clx, cly : TContributorList;
|
|
artx, arty : integer; // anti ringing threshold x/y
|
|
fr, fg, fb, fm : integer;
|
|
rl, gl, bl : integer;
|
|
rh, gh, bh : integer;
|
|
sbBits, dbBits : NativeInt;
|
|
smBits, dmBits : NativeInt;
|
|
sbDif, dbDif : integer;
|
|
smDif, dmDif : integer;
|
|
sbLine, tbBuf : PByteArray;
|
|
hBuf, lBuf : PByteArray;
|
|
smLine, tmBuf : PByteArray;
|
|
dbPix : ^byte;
|
|
hPix, lPix : ^byte;
|
|
dmPix : ^byte;
|
|
pcp : ^TContributorPixel;
|
|
rgb : TRGB;
|
|
begin
|
|
tbBuf := AllocMem(srcBmp.Height * 4 + srcBmp.Height * 1);
|
|
sbBits := NativeInt(srcBmp.ScanLine[0]);
|
|
dbBits := NativeInt(dstBmp.ScanLine[0]);
|
|
if srcBmp.Height > 1 then
|
|
sbDif := NativeInt(srcBmp.ScanLine[1]) - sbBits
|
|
else
|
|
sbDif := 0;
|
|
if dstBmp.Height > 1 then
|
|
dbDif := NativeInt(dstBmp.ScanLine[1]) - dbBits - 2
|
|
else
|
|
dbDif := 0;
|
|
if srcMsk <> nil then begin
|
|
GetContributorList(clx, srcBmp.Width, dstBmp.Width, rfMitchell);
|
|
GetContributorList(cly, srcBmp.Height, dstBmp.Height, rfMitchell);
|
|
tmBuf := pointer(NativeInt(tbBuf) + srcBmp.Height * 4);
|
|
smBits := NativeInt(srcMsk.ScanLine[0]);
|
|
dmBits := NativeInt(dstMsk.ScanLine[0]);
|
|
if srcMsk.Height > 1 then
|
|
smDif := NativeInt(srcMsk.ScanLine[1]) - smBits
|
|
else
|
|
smDif := 0;
|
|
if dstMsk.Height > 1 then
|
|
dmDif := NativeInt(dstMsk.ScanLine[1]) - dmBits
|
|
else
|
|
dmDif := 0;
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
dbPix := pointer(tbBuf );
|
|
sbLine := pointer(sbBits);
|
|
dmPix := pointer(tmBuf );
|
|
smLine := pointer(smBits);
|
|
for iy := 0 to srcBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
fm := 0;
|
|
pcp := @clx[ix].items[0];
|
|
for ic := 0 to clx[ix].itemCount - 1 do begin
|
|
weight := (pcp^.weight * (256 - smLine^[pcp^.pixel])) div 256;
|
|
inc(fm, weight);
|
|
rgb := TRGB(pointer(@sbLine^[pcp^.pixel * 3])^);
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fb < 0 then dbPix^ := 0
|
|
else if fb > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fb shr 16;
|
|
inc(dbPix);
|
|
if fg < 0 then dbPix^ := 0
|
|
else if fg > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fg shr 16;
|
|
inc(dbPix);
|
|
if fr < 0 then dbPix^ := 0
|
|
else if fr > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fr shr 16;
|
|
inc(dbPix, 2);
|
|
if fm < 0 then dmPix^ := 255
|
|
else if fm > $00FF00 then dmPix^ := 0
|
|
else dmPix^ := 255 - fm shr 8;
|
|
inc(dmPix);
|
|
inc(NativeInt(sbLine), sbDif);
|
|
inc(NativeInt(smLine), smDif);
|
|
end;
|
|
dbPix := pointer(dbBits + ix * 3);
|
|
dmPix := pointer(dmBits + ix );
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
fm := 0;
|
|
pcp := @cly[iy].items[0];
|
|
for ic := 0 to cly[iy].itemCount - 1 do begin
|
|
weight := (pcp^.weight * (256 - tmBuf^[pcp^.pixel])) div 256;
|
|
inc(fm, weight);
|
|
rgb := TRGB(pointer(@tbBuf^[pcp^.pixel * 4])^);
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fb < 0 then dbPix^ := 0
|
|
else if fb > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fb shr 16;
|
|
inc(dbPix);
|
|
if fg < 0 then dbPix^ := 0
|
|
else if fg > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fg shr 16;
|
|
inc(dbPix);
|
|
if fr < 0 then dbPix^ := 0
|
|
else if fr > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fr shr 16;
|
|
inc(dbPix, dbDif);
|
|
if fm < 0 then dmPix^ := 255
|
|
else if fm > $00FF00 then dmPix^ := 0
|
|
else dmPix^ := 255 - fm shr 8;
|
|
inc(dmPix, dmDif);
|
|
end;
|
|
end;
|
|
end else begin
|
|
hBuf := AllocMem(srcBmp.Height * 4 + srcBmp.Height * 1);
|
|
lBuf := AllocMem(srcBmp.Height * 4 + srcBmp.Height * 1);
|
|
if srcBmp.Width = dstBmp.Width then
|
|
GetContributorList(clx, srcBmp.Width, dstBmp.Width, rfNearest)
|
|
else
|
|
GetContributorList(clx, srcBmp.Width, dstBmp.Width, filter);
|
|
if srcBmp.Height = dstBmp.Height then
|
|
GetContributorList(cly, srcBmp.Height, dstBmp.Height, rfNearest)
|
|
else
|
|
GetContributorList(cly, srcBmp.Height, dstBmp.Height, filter);
|
|
if srcBmp.Width < dstBmp.Width then
|
|
artx := 2
|
|
else
|
|
artx := Ceil(srcBmp.Width / dstBmp.Width);
|
|
if srcBmp.Height < dstBmp.Height then
|
|
arty := 2
|
|
else
|
|
arty := Ceil(srcBmp.Height / dstBmp.Height);
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
dbPix := pointer(tbBuf );
|
|
hPix := pointer(hBuf );
|
|
lPix := pointer(lBuf );
|
|
sbLine := pointer(sbBits);
|
|
for iy := 0 to srcBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
rl := 255;
|
|
gl := 255;
|
|
bl := 255;
|
|
rh := 0;
|
|
gh := 0;
|
|
bh := 0;
|
|
pcp := @clx[ix].items[0];
|
|
for ic := 0 to clx[ix].itemCount - 1 do begin
|
|
weight := pcp^.weight;
|
|
rgb := TRGB(pointer(@sbLine^[pcp^.pixel * 3])^);
|
|
if ic < artx then begin
|
|
if rgb.r > rh then
|
|
rh := rgb.r;
|
|
if rgb.r < rl then
|
|
rl := rgb.r;
|
|
if rgb.g > gh then
|
|
gh := rgb.g;
|
|
if rgb.g < gl then
|
|
gl := rgb.g;
|
|
if rgb.b > bh then
|
|
bh := rgb.b;
|
|
if rgb.b < bl then
|
|
bl := rgb.b;
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
end else begin
|
|
{$ifndef newantiringing}
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
{$else}
|
|
if rh - rl > 32 then
|
|
inc(fr, rgb.r * weight)
|
|
else
|
|
if rgb.r > rh then
|
|
inc(fr, (rh + (rgb.r - rh) * (rh - rl) div 32) * weight)
|
|
else
|
|
if rgb.r < rl then
|
|
inc(fr, (rl - (rl - rgb.r) * (rh - rl) div 32) * weight)
|
|
else
|
|
inc(fr, rgb.r * weight);
|
|
if gh - gl > 32 then
|
|
inc(fg, rgb.g * weight)
|
|
else
|
|
if rgb.g > gh then
|
|
inc(fg, (gh + (rgb.g - gh) * (gh - gl) div 32) * weight)
|
|
else
|
|
if rgb.g < gl then
|
|
inc(fg, (gl - (gl - rgb.g) * (gh - gl) div 32) * weight)
|
|
else
|
|
inc(fg, rgb.g * weight);
|
|
if bh - bl > 32 then
|
|
inc(fb, rgb.b * weight)
|
|
else
|
|
if rgb.b > bh then
|
|
inc(fb, (bh + (rgb.b - bh) * (bh - bl) div 32) * weight)
|
|
else
|
|
if rgb.b < bl then
|
|
inc(fb, (bl - (bl - rgb.b) * (bh - bl) div 32) * weight)
|
|
else
|
|
inc(fb, rgb.b * weight);
|
|
{$endif}
|
|
end;
|
|
inc(pcp);
|
|
end;
|
|
if fb < 0 then fb := 0
|
|
else if fb > $FF0000 then fb := 255
|
|
else fb := (fb + $8000) shr 16;
|
|
dbPix^ := fb;
|
|
inc(dbPix);
|
|
hPix^ := bh;
|
|
lPix^ := bl;
|
|
inc(hPix);
|
|
inc(lPix);
|
|
if fg < 0 then fg := 0
|
|
else if fg > $FF0000 then fg := 255
|
|
else fg := (fg + $8000) shr 16;
|
|
dbPix^ := fg;
|
|
inc(dbPix);
|
|
hPix^ := gh;
|
|
lPix^ := gl;
|
|
inc(hPix);
|
|
inc(lPix);
|
|
if fr < 0 then fr := 0
|
|
else if fr > $FF0000 then fr := 255
|
|
else fr := (fr + $8000) shr 16;
|
|
dbPix^ := fr;
|
|
inc(dbPix, 2);
|
|
hPix^ := rh;
|
|
lPix^ := rl;
|
|
inc(hPix, 2);
|
|
inc(lPix, 2);
|
|
inc(NativeInt(sbLine), sbDif);
|
|
end;
|
|
dbPix := pointer(dbBits + ix * 3);
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
rl := 255;
|
|
gl := 255;
|
|
bl := 255;
|
|
rh := 0;
|
|
gh := 0;
|
|
bh := 0;
|
|
pcp := @cly[iy].items[0];
|
|
for ic := 0 to cly[iy].itemCount - 1 do begin
|
|
weight := pcp^.weight;
|
|
rgb := TRGB(pointer(@tbBuf^[pcp^.pixel * 4])^);
|
|
if ic < arty then begin
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
rgb := TRGB(pointer(@hBuf^[pcp^.pixel * 4])^);
|
|
if rgb.r > rh then
|
|
rh := rgb.r;
|
|
if rgb.g > gh then
|
|
gh := rgb.g;
|
|
if rgb.b > bh then
|
|
bh := rgb.b;
|
|
rgb := TRGB(pointer(@lBuf^[pcp^.pixel * 4])^);
|
|
if rgb.r < rl then
|
|
rl := rgb.r;
|
|
if rgb.g < gl then
|
|
gl := rgb.g;
|
|
if rgb.b < bl then
|
|
bl := rgb.b;
|
|
end else begin
|
|
{$ifndef newantiringing}
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
{$else}
|
|
if rh - rl > 32 then
|
|
inc(fr, rgb.r * weight)
|
|
else
|
|
if rgb.r > rh then
|
|
inc(fr, (rh + (rgb.r - rh) * (rh - rl) div 32) * weight)
|
|
else
|
|
if rgb.r < rl then
|
|
inc(fr, (rl - (rl - rgb.r) * (rh - rl) div 32) * weight)
|
|
else
|
|
inc(fr, rgb.r * weight);
|
|
if gh - gl > 32 then
|
|
inc(fg, rgb.g * weight)
|
|
else
|
|
if rgb.g > gh then
|
|
inc(fg, (gh + (rgb.g - gh) * (gh - gl) div 32) * weight)
|
|
else
|
|
if rgb.g < gl then
|
|
inc(fg, (gl - (gl - rgb.g) * (gh - gl) div 32) * weight)
|
|
else
|
|
inc(fg, rgb.g * weight);
|
|
if bh - bl > 32 then
|
|
inc(fb, rgb.b * weight)
|
|
else
|
|
if rgb.b > bh then
|
|
inc(fb, (bh + (rgb.b - bh) * (bh - bl) div 32) * weight)
|
|
else
|
|
if rgb.b < bl then
|
|
inc(fb, (bl - (bl - rgb.b) * (bh - bl) div 32) * weight)
|
|
else
|
|
inc(fb, rgb.b * weight);
|
|
{$endif}
|
|
end;
|
|
inc(pcp);
|
|
end;
|
|
if fb < 0 then fb := 0
|
|
else if fb > $FF0000 then fb := 255
|
|
else fb := (fb + $8000) shr 16;
|
|
{$ifdef oldantiringing}
|
|
if fb > bh then
|
|
fb := bh
|
|
else
|
|
if fb < bl then
|
|
fb := bl;
|
|
{$endif}
|
|
dbPix^ := fb;
|
|
inc(dbPix);
|
|
if fg < 0 then fg := 0
|
|
else if fg > $FF0000 then fg := 255
|
|
else fg := (fg + $8000) shr 16;
|
|
{$ifdef oldantiringing}
|
|
if fg > gh then
|
|
fg := gh
|
|
else
|
|
if fg < gl then
|
|
fg := gl;
|
|
{$endif}
|
|
dbPix^ := fg;
|
|
inc(dbPix);
|
|
if fr < 0 then fr := 0
|
|
else if fr > $FF0000 then fr := 255
|
|
else fr := (fr + $8000) shr 16;
|
|
{$ifdef oldantiringing}
|
|
if fr > rh then
|
|
fr := rh
|
|
else
|
|
if fr < rl then
|
|
fr := rl;
|
|
{$endif}
|
|
dbPix^ := fr;
|
|
inc(dbPix, dbDif);
|
|
end;
|
|
end;
|
|
FreeMem(lBuf);
|
|
FreeMem(hBuf);
|
|
end;
|
|
FreeMem(tbBuf);
|
|
end;
|
|
|
|
procedure Resampling32; // 375 / 200
|
|
type TRGB = packed record b, g, r, a: byte; end;
|
|
var ix, iy, ic : integer;
|
|
weight : integer;
|
|
clx, cly : TContributorList;
|
|
artx, arty : integer; // anti ringing threshold x/y
|
|
fr, fg, fb, fm : integer;
|
|
rl, gl, bl : integer;
|
|
rh, gh, bh : integer;
|
|
sbBits, dbBits : NativeInt;
|
|
smBits, dmBits : NativeInt;
|
|
sbDif, dbDif : integer;
|
|
smDif, dmDif : integer;
|
|
sbLine, tbBuf : PByteArray;
|
|
hBuf, lBuf : PByteArray;
|
|
smLine, tmBuf : PByteArray;
|
|
dbPix : ^byte;
|
|
hPix, lPix : ^byte;
|
|
dmPix : ^byte;
|
|
pcp : ^TContributorPixel;
|
|
rgb : TRGB;
|
|
begin
|
|
tbBuf := AllocMem(srcBmp.Height * 4 + srcBmp.Height * 1);
|
|
sbBits := NativeInt(srcBmp.ScanLine[0]);
|
|
dbBits := NativeInt(dstBmp.ScanLine[0]);
|
|
if srcBmp.Height > 1 then
|
|
sbDif := NativeInt(srcBmp.ScanLine[1]) - sbBits
|
|
else
|
|
sbDif := 0;
|
|
if dstBmp.Height > 1 then
|
|
dbDif := NativeInt(dstBmp.ScanLine[1]) - dbBits - 2
|
|
else
|
|
dbDif := 0;
|
|
if srcMsk <> nil then begin
|
|
GetContributorList(clx, srcBmp.Width, dstBmp.Width, rfMitchell);
|
|
GetContributorList(cly, srcBmp.Height, dstBmp.Height, rfMitchell);
|
|
tmBuf := pointer(NativeInt(tbBuf) + srcBmp.Height * 4);
|
|
smBits := NativeInt(srcMsk.ScanLine[0]);
|
|
dmBits := NativeInt(dstMsk.ScanLine[0]);
|
|
if srcMsk.Height > 1 then
|
|
smDif := NativeInt(srcMsk.ScanLine[1]) - smBits
|
|
else
|
|
smDif := 0;
|
|
if dstMsk.Height > 1 then
|
|
dmDif := NativeInt(dstMsk.ScanLine[1]) - dmBits
|
|
else
|
|
dmDif := 0;
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
dbPix := pointer(tbBuf );
|
|
sbLine := pointer(sbBits);
|
|
dmPix := pointer(tmBuf );
|
|
smLine := pointer(smBits);
|
|
for iy := 0 to srcBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
fm := 0;
|
|
pcp := @clx[ix].items[0];
|
|
for ic := 0 to clx[ix].itemCount - 1 do begin
|
|
weight := (pcp^.weight * (256 - smLine^[pcp^.pixel])) div 256;
|
|
inc(fm, weight);
|
|
rgb := TRGB(pointer(@sbLine^[pcp^.pixel * 4])^);
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fb < 0 then dbPix^ := 0
|
|
else if fb > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fb shr 16;
|
|
inc(dbPix);
|
|
if fg < 0 then dbPix^ := 0
|
|
else if fg > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fg shr 16;
|
|
inc(dbPix);
|
|
if fr < 0 then dbPix^ := 0
|
|
else if fr > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fr shr 16;
|
|
inc(dbPix, 2);
|
|
if fm < 0 then dmPix^ := 255
|
|
else if fm > $00FF00 then dmPix^ := 0
|
|
else dmPix^ := 255 - fm shr 8;
|
|
inc(dmPix);
|
|
inc(NativeInt(sbLine), sbDif);
|
|
inc(NativeInt(smLine), smDif);
|
|
end;
|
|
dbPix := pointer(dbBits + ix * 4);
|
|
dmPix := pointer(dmBits + ix );
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
fm := 0;
|
|
pcp := @cly[iy].items[0];
|
|
for ic := 0 to cly[iy].itemCount - 1 do begin
|
|
weight := (pcp^.weight * (256 - tmBuf^[pcp^.pixel])) div 256;
|
|
inc(fm, weight);
|
|
rgb := TRGB(pointer(@tbBuf^[pcp^.pixel * 4])^);
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fb < 0 then dbPix^ := 0
|
|
else if fb > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fb shr 16;
|
|
inc(dbPix);
|
|
if fg < 0 then dbPix^ := 0
|
|
else if fg > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fg shr 16;
|
|
inc(dbPix);
|
|
if fr < 0 then dbPix^ := 0
|
|
else if fr > $FF0000 then dbPix^ := 255
|
|
else dbPix^ := fr shr 16;
|
|
inc(dbPix, dbDif);
|
|
if fm < 0 then dmPix^ := 255
|
|
else if fm > $00FF00 then dmPix^ := 0
|
|
else dmPix^ := 255 - fm shr 8;
|
|
inc(dmPix, dmDif);
|
|
end;
|
|
end;
|
|
end else begin
|
|
hBuf := AllocMem(srcBmp.Height * 4 + srcBmp.Height * 1);
|
|
lBuf := AllocMem(srcBmp.Height * 4 + srcBmp.Height * 1);
|
|
if srcBmp.Width = dstBmp.Width then
|
|
GetContributorList(clx, srcBmp.Width, dstBmp.Width, rfNearest)
|
|
else
|
|
GetContributorList(clx, srcBmp.Width, dstBmp.Width, filter);
|
|
if srcBmp.Height = dstBmp.Height then
|
|
GetContributorList(cly, srcBmp.Height, dstBmp.Height, rfNearest)
|
|
else
|
|
GetContributorList(cly, srcBmp.Height, dstBmp.Height, filter);
|
|
if srcBmp.Width < dstBmp.Width then
|
|
artx := 2
|
|
else
|
|
artx := srcBmp.Width div dstBmp.Width + 1;
|
|
if srcBmp.Height < dstBmp.Height then
|
|
arty := 2
|
|
else
|
|
arty := srcBmp.Height div dstBmp.Height + 1;
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
dbPix := pointer(tbBuf );
|
|
hPix := pointer(hBuf );
|
|
lPix := pointer(lBuf );
|
|
sbLine := pointer(sbBits);
|
|
for iy := 0 to srcBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
rl := 255;
|
|
gl := 255;
|
|
bl := 255;
|
|
rh := 0;
|
|
gh := 0;
|
|
bh := 0;
|
|
pcp := @clx[ix].items[0];
|
|
for ic := 0 to clx[ix].itemCount - 1 do begin
|
|
weight := pcp^.weight;
|
|
rgb := TRGB(pointer(@sbLine^[pcp^.pixel * 4])^);
|
|
if ic < artx then begin
|
|
if rgb.r > rh then
|
|
rh := rgb.r;
|
|
if rgb.r < rl then
|
|
rl := rgb.r;
|
|
if rgb.g > gh then
|
|
gh := rgb.g;
|
|
if rgb.g < gl then
|
|
gl := rgb.g;
|
|
if rgb.b > bh then
|
|
bh := rgb.b;
|
|
if rgb.b < bl then
|
|
bl := rgb.b;
|
|
end;
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
inc(pcp);
|
|
end;
|
|
if fb < 0 then fb := 0
|
|
else if fb > $FF0000 then fb := 255
|
|
else fb := (fb + $8000) shr 16;
|
|
dbPix^ := fb;
|
|
inc(dbPix);
|
|
hPix^ := bh;
|
|
lPix^ := bl;
|
|
inc(hPix);
|
|
inc(lPix);
|
|
if fg < 0 then fg := 0
|
|
else if fg > $FF0000 then fg := 255
|
|
else fg := (fg + $8000) shr 16;
|
|
dbPix^ := fg;
|
|
inc(dbPix);
|
|
hPix^ := gh;
|
|
lPix^ := gl;
|
|
inc(hPix);
|
|
inc(lPix);
|
|
if fr < 0 then fr := 0
|
|
else if fr > $FF0000 then fr := 255
|
|
else fr := (fr + $8000) shr 16;
|
|
dbPix^ := fr;
|
|
inc(dbPix, 2);
|
|
hPix^ := rh;
|
|
lPix^ := rl;
|
|
inc(hPix, 2);
|
|
inc(lPix, 2);
|
|
inc(NativeInt(sbLine), sbDif);
|
|
end;
|
|
dbPix := pointer(dbBits + ix * 4);
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
fr := 0;
|
|
fg := 0;
|
|
fb := 0;
|
|
rl := 255;
|
|
gl := 255;
|
|
bl := 255;
|
|
rh := 0;
|
|
gh := 0;
|
|
bh := 0;
|
|
pcp := @cly[iy].items[0];
|
|
for ic := 0 to cly[iy].itemCount - 1 do begin
|
|
weight := pcp^.weight;
|
|
rgb := TRGB(pointer(@tbBuf^[pcp^.pixel * 4])^);
|
|
inc(fr, rgb.r * weight);
|
|
inc(fg, rgb.g * weight);
|
|
inc(fb, rgb.b * weight);
|
|
if ic < arty then begin
|
|
rgb := TRGB(pointer(@hBuf^[pcp^.pixel * 4])^);
|
|
if rgb.r > rh then
|
|
rh := rgb.r;
|
|
if rgb.g > gh then
|
|
gh := rgb.g;
|
|
if rgb.b > bh then
|
|
bh := rgb.b;
|
|
rgb := TRGB(pointer(@lBuf^[pcp^.pixel * 4])^);
|
|
if rgb.r < rl then
|
|
rl := rgb.r;
|
|
if rgb.g < gl then
|
|
gl := rgb.g;
|
|
if rgb.b < bl then
|
|
bl := rgb.b;
|
|
end;
|
|
inc(pcp);
|
|
end;
|
|
if fb < 0 then fb := 0
|
|
else if fb > $FF0000 then fb := 255
|
|
else fb := (fb + $8000) shr 16;
|
|
{$ifdef antiringing}
|
|
if fb > bh then
|
|
fb := bh
|
|
else
|
|
if fb < bl then
|
|
fb := bl;
|
|
{$endif}
|
|
dbPix^ := fb;
|
|
inc(dbPix);
|
|
if fg < 0 then fg := 0
|
|
else if fg > $FF0000 then fg := 255
|
|
else fg := (fg + $8000) shr 16;
|
|
{$ifdef antiringing}
|
|
if fg > gh then
|
|
fg := gh
|
|
else
|
|
if fg < gl then
|
|
fg := gl;
|
|
{$endif}
|
|
dbPix^ := fg;
|
|
inc(dbPix);
|
|
if fr < 0 then fr := 0
|
|
else if fr > $FF0000 then fr := 255
|
|
else fr := (fr + $8000) shr 16;
|
|
{$ifdef antiringing}
|
|
if fr > rh then
|
|
fr := rh
|
|
else
|
|
if fr < rl then
|
|
fr := rl;
|
|
{$endif}
|
|
dbPix^ := fr;
|
|
inc(dbPix, dbDif);
|
|
end;
|
|
end;
|
|
FreeMem(lBuf);
|
|
FreeMem(hBuf);
|
|
end;
|
|
FreeMem(tbBuf);
|
|
end;
|
|
|
|
procedure Bilinear15; // 2820 -> 540
|
|
var ix, iy : integer;
|
|
x, y, xdif, ydif : integer;
|
|
xp1, xp2, yp : integer;
|
|
wy, wyi, wx : integer;
|
|
w11, w21, w12, w22 : integer;
|
|
sbBits, sbLine1, sbLine2 : NativeInt;
|
|
smBits, smLine1, smLine2 : PByteArray;
|
|
dbLine : NativeInt;
|
|
dmLine : ^byte;
|
|
sbLineDif, dbLineDif : integer;
|
|
smLineDif, dmLineDif : integer;
|
|
w : integer;
|
|
begin
|
|
y := 0;
|
|
xdif := (srcBmp.Width shl 16) div dstBmp.Width;
|
|
ydif := (srcBmp.Height shl 16) div dstBmp.Height;
|
|
sbBits := NativeInt(srcBmp.ScanLine[0]);
|
|
if srcBmp.Height > 1 then
|
|
sbLineDif := NativeInt(srcBmp.ScanLine[1]) - sbBits
|
|
else
|
|
sbLineDif := 0;
|
|
dbLine := NativeInt(dstBmp.ScanLine[0]);
|
|
if dstBmp.Height > 1 then
|
|
dbLineDif := NativeInt(dstBmp.ScanLine[1]) - dbLine - 2 * dstBmp.Width
|
|
else
|
|
dbLineDif := 0;
|
|
if srcMsk <> nil then begin
|
|
smBits := srcMsk.ScanLine[0];
|
|
if srcMsk.Height > 1 then
|
|
smLineDif := NativeInt(srcMsk.ScanLine[1]) - NativeInt(smBits)
|
|
else
|
|
smLineDif := 0;
|
|
dmLine := dstMsk.ScanLine[0];
|
|
if dstMsk.Height > 1 then
|
|
dmLineDif := NativeInt(dstMsk.ScanLine[1]) - NativeInt(dmLine) - 1 * dstBmp.Width
|
|
else
|
|
dmLineDif := 0;
|
|
end else begin
|
|
smBits := nil;
|
|
smLineDif := 0;
|
|
dmLine := nil;
|
|
dmLineDif := 0;
|
|
end;
|
|
w := srcBmp.Width - 1;
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
yp := y shr 16;
|
|
sbLine1 := NativeInt(sbBits) + sbLineDif * yp;
|
|
smLine1 := pointer(NativeInt(smBits) + smLineDif * yp);
|
|
if yp < srcBmp.Height - 1 then begin
|
|
sbLine2 := NativeInt(sbLine1) + sbLineDif;
|
|
smLine2 := pointer(NativeInt(smLine1) + smLineDif);
|
|
end else begin
|
|
sbLine2 := sbLine1;
|
|
smLine2 := smLine1;
|
|
end;
|
|
x := 0;
|
|
wy := y and $FFFF;
|
|
wyi := (not y) and $FFFF;
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
xp1 := x shr 16;
|
|
if xp1 < w then
|
|
xp2 := xp1 + 1
|
|
else
|
|
xp2 := xp1;
|
|
wx := x and $FFFF;
|
|
w21 := (wyi * wx) shr 16; w11 := wyi - w21;
|
|
w22 := (wy * wx) shr 16; w12 := wy - w22;
|
|
if smLine1 <> nil then begin
|
|
w11 := (w11 * (256 - smLine1^[xp1])) shr 8;
|
|
w21 := (w21 * (256 - smLine1^[xp2])) shr 8;
|
|
w12 := (w12 * (256 - smLine2^[xp1])) shr 8;
|
|
w22 := (w22 * (256 - smLine2^[xp2])) shr 8;
|
|
dmLine^ := 255 - byte((w11 + w21 + w12 + w22) shr 8);
|
|
end;
|
|
xp1 := xp1 * 2;
|
|
xp2 := xp2 * 2;
|
|
PWord(dbLine)^ := ( ( ( (PWord(sbLine1 + xp1)^ and $001F) * w11 + (PWord(sbLine1 + xp2)^ and $001F) * w21 +
|
|
(PWord(sbLine2 + xp1)^ and $001F) * w12 + (PWord(sbLine2 + xp2)^ and $001F) * w22 ) shr 16) and $001F) or
|
|
( ( ( (PWord(sbLine1 + xp1)^ and $03E0) * w11 + (PWord(sbLine1 + xp2)^ and $03E0) * w21 +
|
|
(PWord(sbLine2 + xp1)^ and $03E0) * w12 + (PWord(sbLine2 + xp2)^ and $03E0) * w22 ) shr 16) and $03E0) or
|
|
( ( ( (PWord(sbLine1 + xp1)^ and $7C00) * w11 + (PWord(sbLine1 + xp2)^ and $7C00) * w21 +
|
|
(PWord(sbLine2 + xp1)^ and $7C00) * w12 + (PWord(sbLine2 + xp2)^ and $7C00) * w22 ) shr 16) and $7C00);
|
|
inc(dbLine, 2);
|
|
inc(dmLine);
|
|
inc(x, xdif);
|
|
end;
|
|
inc(NativeInt(dbLine), dbLineDif);
|
|
inc(NativeInt(dmLine), dmLineDif);
|
|
inc(y, ydif);
|
|
end;
|
|
end;
|
|
|
|
procedure Bilinear16; // 2440 -> 540
|
|
var ix, iy : integer;
|
|
x, y, xdif, ydif : integer;
|
|
xp1, xp2, yp : integer;
|
|
wy, wyi, wx : integer;
|
|
w11, w21, w12, w22 : integer;
|
|
sbBits, sbLine1, sbLine2 : NativeInt;
|
|
smBits, smLine1, smLine2 : PByteArray;
|
|
dbLine : NativeInt;
|
|
dmLine : ^byte;
|
|
sbLineDif, dbLineDif : integer;
|
|
smLineDif, dmLineDif : integer;
|
|
w : integer;
|
|
begin
|
|
y := 0;
|
|
xdif := (srcBmp.Width shl 16) div dstBmp.Width;
|
|
ydif := (srcBmp.Height shl 16) div dstBmp.Height;
|
|
sbBits := NativeInt(srcBmp.ScanLine[0]);
|
|
if srcBmp.Height > 1 then
|
|
sbLineDif := NativeInt(srcBmp.ScanLine[1]) - sbBits
|
|
else
|
|
sbLineDif := 0;
|
|
dbLine := NativeInt(dstBmp.ScanLine[0]);
|
|
if dstBmp.Height > 1 then
|
|
dbLineDif := NativeInt(dstBmp.ScanLine[1]) - dbLine - 2 * dstBmp.Width
|
|
else
|
|
dbLineDif := 0;
|
|
if srcMsk <> nil then begin
|
|
smBits := srcMsk.ScanLine[0];
|
|
if srcMsk.Height > 1 then
|
|
smLineDif := NativeInt(srcMsk.ScanLine[1]) - NativeInt(smBits)
|
|
else
|
|
smLineDif := 0;
|
|
dmLine := dstMsk.ScanLine[0];
|
|
if dstMsk.Height > 1 then
|
|
dmLineDif := NativeInt(dstMsk.ScanLine[1]) - NativeInt(dmLine) - 1 * dstBmp.Width
|
|
else
|
|
dmLineDif := 0;
|
|
end else begin
|
|
smBits := nil;
|
|
smLineDif := 0;
|
|
dmLine := nil;
|
|
dmLineDif := 0;
|
|
end;
|
|
w := srcBmp.Width - 1;
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
yp := y shr 16;
|
|
sbLine1 := NativeInt(sbBits) + sbLineDif * yp;
|
|
smLine1 := pointer(NativeInt(smBits) + smLineDif * yp);
|
|
if yp < srcBmp.Height - 1 then begin
|
|
sbLine2 := NativeInt(sbLine1) + sbLineDif;
|
|
smLine2 := pointer(NativeInt(smLine1) + smLineDif);
|
|
end else begin
|
|
sbLine2 := sbLine1;
|
|
smLine2 := smLine1;
|
|
end;
|
|
x := 0;
|
|
wy := y and $FFFF;
|
|
wyi := (not y) and $FFFF;
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
xp1 := x shr 16;
|
|
if xp1 < w then
|
|
xp2 := xp1 + 1
|
|
else
|
|
xp2 := xp1;
|
|
wx := x and $FFFF;
|
|
w21 := (wyi * wx) shr 16; w11 := wyi - w21;
|
|
w22 := (wy * wx) shr 16; w12 := wy - w22;
|
|
if smLine1 <> nil then begin
|
|
w11 := (w11 * (256 - smLine1^[xp1])) shr 8;
|
|
w21 := (w21 * (256 - smLine1^[xp2])) shr 8;
|
|
w12 := (w12 * (256 - smLine2^[xp1])) shr 8;
|
|
w22 := (w22 * (256 - smLine2^[xp2])) shr 8;
|
|
dmLine^ := 255 - byte((w11 + w21 + w12 + w22) shr 8);
|
|
end;
|
|
xp1 := xp1 * 2;
|
|
xp2 := xp2 * 2;
|
|
PWord(dbLine)^ := ( ( ( (PWord(sbLine1 + xp1)^ and $001F) * w11 + (PWord(sbLine1 + xp2)^ and $001F) * w21 +
|
|
(PWord(sbLine2 + xp1)^ and $001F) * w12 + (PWord(sbLine2 + xp2)^ and $001F) * w22 ) shr 16) and $001F) or
|
|
( ( ( (PWord(sbLine1 + xp1)^ and $07E0) * w11 + (PWord(sbLine1 + xp2)^ and $07E0) * w21 +
|
|
(PWord(sbLine2 + xp1)^ and $07E0) * w12 + (PWord(sbLine2 + xp2)^ and $07E0) * w22 ) shr 16) and $07E0) or
|
|
( ( ( (PWord(sbLine1 + xp1)^ and $F800) * w11 + (PWord(sbLine1 + xp2)^ and $F800) * w21 +
|
|
(PWord(sbLine2 + xp1)^ and $F800) * w12 + (PWord(sbLine2 + xp2)^ and $F800) * w22 ) shr 16) and $F800);
|
|
inc(dbLine, 2);
|
|
inc(dmLine);
|
|
inc(x, xdif);
|
|
end;
|
|
inc(NativeInt(dbLine), dbLineDif);
|
|
inc(NativeInt(dmLine), dmLineDif);
|
|
inc(y, ydif);
|
|
end;
|
|
end;
|
|
|
|
procedure Bilinear24; // 550 -> 310
|
|
var ix, iy : integer;
|
|
x, y, xdif, ydif : integer;
|
|
xp1, xp2, yp : integer;
|
|
wy, wyi, wx : integer;
|
|
w11, w21, w12, w22 : integer;
|
|
sbBits, sbLine1, sbLine2 : PByteArray;
|
|
smBits, smLine1, smLine2 : PByteArray;
|
|
dbLine : PByteArray;
|
|
dmLine : ^byte;
|
|
sbLineDif, dbLineDif : integer;
|
|
smLineDif, dmLineDif : integer;
|
|
w : integer;
|
|
begin
|
|
y := 0;
|
|
xdif := (srcBmp.Width shl 16) div dstBmp.Width;
|
|
ydif := (srcBmp.Height shl 16) div dstBmp.Height;
|
|
sbBits := srcBmp.ScanLine[0];
|
|
if srcBmp.Height > 1 then
|
|
sbLineDif := NativeInt(srcBmp.ScanLine[1]) - NativeInt(sbBits)
|
|
else
|
|
sbLineDif := 0;
|
|
dbLine := dstBmp.ScanLine[0];
|
|
if dstBmp.Height > 1 then
|
|
dbLineDif := NativeInt(dstBmp.ScanLine[1]) - NativeInt(dbLine) - 3 * dstBmp.Width
|
|
else
|
|
dbLineDif := 0;
|
|
if srcMsk <> nil then begin
|
|
smBits := srcMsk.ScanLine[0];
|
|
if srcMsk.Height > 1 then
|
|
smLineDif := NativeInt(srcMsk.ScanLine[1]) - NativeInt(smBits)
|
|
else
|
|
smLineDif := 0;
|
|
dmLine := dstMsk.ScanLine[0];
|
|
if dstMsk.Height > 1 then
|
|
dmLineDif := NativeInt(dstMsk.ScanLine[1]) - NativeInt(dmLine) - 1 * dstBmp.Width
|
|
else
|
|
dmLineDif := 0;
|
|
end else begin
|
|
smBits := nil;
|
|
smLineDif := 0;
|
|
dmLine := nil;
|
|
dmLineDif := 0;
|
|
end;
|
|
w := srcBmp.Width - 1;
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
yp := y shr 16;
|
|
sbLine1 := pointer(NativeInt(sbBits) + sbLineDif * yp);
|
|
smLine1 := pointer(NativeInt(smBits) + smLineDif * yp);
|
|
if yp < srcBmp.Height - 1 then begin
|
|
sbLine2 := pointer(NativeInt(sbLine1) + sbLineDif);
|
|
smLine2 := pointer(NativeInt(smLine1) + smLineDif);
|
|
end else begin
|
|
sbLine2 := sbLine1;
|
|
smLine2 := smLine1;
|
|
end;
|
|
x := 0;
|
|
wy := y and $FFFF;
|
|
wyi := (not y) and $FFFF;
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
xp1 := x shr 16;
|
|
if xp1 < w then
|
|
xp2 := xp1 + 1
|
|
else
|
|
xp2 := xp1;
|
|
wx := x and $FFFF;
|
|
w21 := (wyi * wx) shr 16; w11 := wyi - w21;
|
|
w22 := (wy * wx) shr 16; w12 := wy - w22;
|
|
if smLine1 <> nil then begin
|
|
w11 := (w11 * (256 - smLine1^[xp1])) shr 8;
|
|
w21 := (w21 * (256 - smLine1^[xp2])) shr 8;
|
|
w12 := (w12 * (256 - smLine2^[xp1])) shr 8;
|
|
w22 := (w22 * (256 - smLine2^[xp2])) shr 8;
|
|
dmLine^ := 255 - byte((w11 + w21 + w12 + w22) shr 8);
|
|
end;
|
|
xp1 := xp1 * 3;
|
|
xp2 := xp2 * 3;
|
|
dbLine^[0] := (sbLine1[xp1 ] * w11 + sbLine1[xp2 ] * w21 + sbLine2[xp1 ] * w12 + sbLine2[xp2 ] * w22) shr 16;
|
|
dbLine^[1] := (sbLine1[xp1 + 1] * w11 + sbLine1[xp2 + 1] * w21 + sbLine2[xp1 + 1] * w12 + sbLine2[xp2 + 1] * w22) shr 16;
|
|
dbLine^[2] := (sbLine1[xp1 + 2] * w11 + sbLine1[xp2 + 2] * w21 + sbLine2[xp1 + 2] * w12 + sbLine2[xp2 + 2] * w22) shr 16;
|
|
inc(NativeInt(dbLine), 3);
|
|
inc(dmLine);
|
|
inc(x, xdif);
|
|
end;
|
|
inc(NativeInt(dbLine), dbLineDif);
|
|
inc(NativeInt(dmLine), dmLineDif);
|
|
inc(y, ydif);
|
|
end;
|
|
end;
|
|
|
|
procedure Bilinear32; // 525 -> 305
|
|
var ix, iy : integer;
|
|
x, y, xdif, ydif : integer;
|
|
xp1, xp2, yp : integer;
|
|
wy, wyi, wx : integer;
|
|
w11, w21, w12, w22 : integer;
|
|
sbBits, sbLine1, sbLine2 : PByteArray;
|
|
smBits, smLine1, smLine2 : PByteArray;
|
|
dbLine : PByteArray;
|
|
dmLine : ^byte;
|
|
sbLineDif, dbLineDif : integer;
|
|
smLineDif, dmLineDif : integer;
|
|
w : integer;
|
|
begin
|
|
y := 0;
|
|
xdif := (srcBmp.Width shl 16) div dstBmp.Width;
|
|
ydif := (srcBmp.Height shl 16) div dstBmp.Height;
|
|
sbBits := srcBmp.ScanLine[0];
|
|
if srcBmp.Height > 1 then
|
|
sbLineDif := NativeInt(srcBmp.ScanLine[1]) - NativeInt(sbBits)
|
|
else
|
|
sbLineDif := 0;
|
|
dbLine := dstBmp.ScanLine[0];
|
|
if dstBmp.Height > 1 then
|
|
dbLineDif := NativeInt(dstBmp.ScanLine[1]) - NativeInt(dbLine) - 4 * dstBmp.Width
|
|
else
|
|
dbLineDif := 0;
|
|
if srcMsk <> nil then begin
|
|
smBits := srcMsk.ScanLine[0];
|
|
if srcMsk.Height > 1 then
|
|
smLineDif := NativeInt(srcMsk.ScanLine[1]) - NativeInt(smBits)
|
|
else
|
|
smLineDif := 0;
|
|
dmLine := dstMsk.ScanLine[0];
|
|
if dstMsk.Height > 1 then
|
|
dmLineDif := NativeInt(dstMsk.ScanLine[1]) - NativeInt(dmLine) - 1 * dstBmp.Width
|
|
else
|
|
dmLineDif := 0;
|
|
end else begin
|
|
smBits := nil;
|
|
smLineDif := 0;
|
|
dmLine := nil;
|
|
dmLineDif := 0;
|
|
end;
|
|
w := srcBmp.Width - 1;
|
|
for iy := 0 to dstBmp.Height - 1 do begin
|
|
yp := y shr 16;
|
|
sbLine1 := pointer(NativeInt(sbBits) + sbLineDif * yp);
|
|
smLine1 := pointer(NativeInt(smBits) + smLineDif * yp);
|
|
if yp < srcBmp.Height - 1 then begin
|
|
sbLine2 := pointer(NativeInt(sbLine1) + sbLineDif);
|
|
smLine2 := pointer(NativeInt(smLine1) + smLineDif);
|
|
end else begin
|
|
sbLine2 := sbLine1;
|
|
smLine2 := smLine1;
|
|
end;
|
|
x := 0;
|
|
wy := y and $FFFF;
|
|
wyi := (not y) and $FFFF;
|
|
for ix := 0 to dstBmp.Width - 1 do begin
|
|
xp1 := x shr 16;
|
|
if xp1 < w then
|
|
xp2 := xp1 + 1
|
|
else
|
|
xp2 := xp1;
|
|
wx := x and $FFFF;
|
|
w21 := (wyi * wx) shr 16; w11 := wyi - w21;
|
|
w22 := (wy * wx) shr 16; w12 := wy - w22;
|
|
if smLine1 <> nil then begin
|
|
w11 := (w11 * (256 - smLine1^[xp1])) shr 8;
|
|
w21 := (w21 * (256 - smLine1^[xp2])) shr 8;
|
|
w12 := (w12 * (256 - smLine2^[xp1])) shr 8;
|
|
w22 := (w22 * (256 - smLine2^[xp2])) shr 8;
|
|
dmLine^ := 255 - byte((w11 + w21 + w12 + w22) shr 8);
|
|
end;
|
|
xp1 := xp1 * 4;
|
|
xp2 := xp2 * 4;
|
|
dbLine^[0] := (sbLine1[xp1 ] * w11 + sbLine1[xp2 ] * w21 + sbLine2[xp1 ] * w12 + sbLine2[xp2 ] * w22) shr 16;
|
|
dbLine^[1] := (sbLine1[xp1 + 1] * w11 + sbLine1[xp2 + 1] * w21 + sbLine2[xp1 + 1] * w12 + sbLine2[xp2 + 1] * w22) shr 16;
|
|
dbLine^[2] := (sbLine1[xp1 + 2] * w11 + sbLine1[xp2 + 2] * w21 + sbLine2[xp1 + 2] * w12 + sbLine2[xp2 + 2] * w22) shr 16;
|
|
inc(NativeInt(dbLine), 4);
|
|
inc(dmLine);
|
|
inc(x, xdif);
|
|
end;
|
|
inc(NativeInt(dbLine), dbLineDif);
|
|
inc(NativeInt(dmLine), dmLineDif);
|
|
inc(y, ydif);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if (srcMsk <> nil) and
|
|
((dstMsk = nil) or
|
|
(srcMsk.PixelFormat <> pf8Bit) or (srcMsk.Width <> srcBmp.Width) or (srcMsk.Height <> srcBmp.Height) ) then
|
|
srcMsk := nil;
|
|
if srcMsk <> nil then begin
|
|
dstMsk.PixelFormat := pf8bit;
|
|
dstMsk.Width := dstBmp.Width;
|
|
dstMsk.Height := dstBmp.Height;
|
|
end else
|
|
dstMsk := nil;
|
|
case quality of
|
|
sqLow : dstBmp.Canvas.StretchDraw(Rect(0, 0, dstBmp.Width, dstBmp.Height), srcBmp);
|
|
sqHigh : case GetPixelFormat(dstBmp) of
|
|
15 : if ForcePixelFormat([srcBmp], pf15bit) then Bilinear15;
|
|
16 : if ForcePixelFormat([srcBmp], pf16bit) then Bilinear16;
|
|
24 : if ForcePixelFormat([srcBmp], pf24bit) then Bilinear24;
|
|
32 : if ForcePixelFormat([srcBmp], pf32bit) then Bilinear32;
|
|
end;
|
|
sqVeryHigh : case GetPixelFormat(dstBmp) of
|
|
15 : if ForcePixelFormat([srcBmp], pf15bit) then Resampling15;
|
|
16 : if ForcePixelFormat([srcBmp], pf16bit) then Resampling16;
|
|
24 : if ForcePixelFormat([srcBmp], pf24bit) then Resampling24;
|
|
32 : if ForcePixelFormat([srcBmp], pf32bit) then Resampling32;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure StretchBitmap(srcBmp, dstBmp : TBitmap;
|
|
srcMsk, dstMsk : TBitmap;
|
|
quality : TStretchQuality = sqHigh);
|
|
begin
|
|
StretchBitmap_(srcBmp, dstBmp, srcMsk, dstMsk, quality);
|
|
end;
|
|
|
|
procedure StretchBitmap_(bmp, msk : TBitmap;
|
|
newWidth : integer;
|
|
newHeight : integer;
|
|
quality : TStretchQuality = sqHigh;
|
|
filter : TResamplingFilter = rfLanczos4); overload;
|
|
var newBmp, newMsk : TBitmap;
|
|
begin
|
|
newBmp := TBitmap.Create;
|
|
try
|
|
if GetPixelFormat(bmp) = 15 then
|
|
newBmp.PixelFormat := pf15Bit
|
|
else
|
|
newBmp.PixelFormat := bmp.PixelFormat;
|
|
newBmp.Width := newWidth;
|
|
newBmp.Height := newHeight;
|
|
newMsk := nil;
|
|
try
|
|
if (msk <> nil) and ((msk.PixelFormat <> pf8Bit) or (msk.Width <> bmp.Width) or (msk.Height <> bmp.Height)) then
|
|
msk := nil;
|
|
if msk <> nil then
|
|
newMsk := TBitmap.Create;
|
|
StretchBitmap_(bmp, newBmp, msk, newMsk, quality, filter);
|
|
bmp.Assign(newBmp);
|
|
if msk <> nil then
|
|
msk.Assign(newMsk);
|
|
finally newMsk.Free end;
|
|
finally newBmp.Free end;
|
|
end;
|
|
|
|
procedure StretchBitmap(bmp, msk : TBitmap;
|
|
newWidth : integer;
|
|
newHeight : integer;
|
|
quality : TStretchQuality = sqHigh);
|
|
begin
|
|
StretchBitmap_(bmp, msk, newWidth, newHeight, quality);
|
|
end;
|
|
|
|
// ***************************************************************
|
|
|
|
procedure AlphaBlend_(src1, src2, msk, dst : TBitmap;
|
|
alpha : cardinal = 128;
|
|
x : integer = 0;
|
|
y : integer = 0 );
|
|
var w, h, s1x, s1y, s1ld, s2x, s2y, s2ld, dx, dy, dld, mld : integer;
|
|
|
|
procedure AlphaBlend15(src1, src2, dst: TBitmap; alpha: cardinal); // 395
|
|
var src1Line, src2Line, dstLine : ^cardinal;
|
|
mskLine : ^byte;
|
|
ix, iy, iw : integer;
|
|
i1, i2 : cardinal;
|
|
begin
|
|
src1Line := src1.ScanLine[s1y];
|
|
src2Line := src2.ScanLine[s2y];
|
|
dstLine := dst .ScanLine[ dy];
|
|
if msk <> nil then begin
|
|
mskLine := msk.ScanLine[s1y];
|
|
if h > 1 then begin
|
|
s1ld := NativeInt(src1.ScanLine[s1y + 1]) - NativeInt(src1Line) - w * 2;
|
|
s2ld := NativeInt(src2.ScanLine[s2y + 1]) - NativeInt(src2Line) - w * 2;
|
|
dld := NativeInt(dst .ScanLine[ dy + 1]) - NativeInt( dstLine) - w * 2;
|
|
mld := NativeInt(msk .ScanLine[s1y + 1]) - NativeInt( mskLine) - w;
|
|
end else begin
|
|
s1ld := 0;
|
|
s2ld := 0;
|
|
dld := 0;
|
|
mld := 0;
|
|
end;
|
|
inc(NativeInt(src1Line), s1x * 2);
|
|
inc(NativeInt(src2Line), s2x * 2);
|
|
inc(NativeInt( dstLine), dx * 2);
|
|
inc(NativeInt( mskLine), s1x );
|
|
for iy := 0 to h - 1 do begin
|
|
for ix := 0 to w - 1 do begin
|
|
if mskLine^ < 255 then begin
|
|
i1 := 256 - (((cardinal(256) - mskLine^) * alpha) shr 8);
|
|
i2 := ((alpha * (PWord(src1Line)^ and $001F) + i1 * (PWord(src2Line)^ and $001F)) shr 8) and $001F;
|
|
i2 := i2 + ((alpha * (PWord(src1Line)^ and $03E0) + i1 * (PWord(src2Line)^ and $03E0)) shr 8) and $03E0;
|
|
i2 := i2 + ((alpha * (PWord(src1Line)^ and $7C00) + i1 * (PWord(src2Line)^ and $7C00)) shr 8) and $7C00;
|
|
PWord(dstLine)^ := i2;
|
|
end;
|
|
inc(NativeInt(src1Line), 2);
|
|
inc(NativeInt(src2Line), 2);
|
|
inc(NativeInt( dstLine), 2);
|
|
inc(mskLine);
|
|
end;
|
|
inc(NativeInt(src1Line), s1ld);
|
|
inc(NativeInt(src2Line), s2ld);
|
|
inc(NativeInt( dstLine), dld);
|
|
inc(NativeInt( mskLine), mld);
|
|
end;
|
|
end else begin
|
|
iw := w div 2;
|
|
if h > 1 then begin
|
|
s1ld := NativeInt(src1.ScanLine[s1y + 1]) - NativeInt(src1Line) - iw * 4;
|
|
s2ld := NativeInt(src2.ScanLine[s2y + 1]) - NativeInt(src2Line) - iw * 4;
|
|
dld := NativeInt(dst .ScanLine[ dy + 1]) - NativeInt( dstLine) - iw * 4;
|
|
end else begin
|
|
s1ld := 0;
|
|
s2ld := 0;
|
|
dld := 0;
|
|
end;
|
|
inc(NativeInt(src1Line), s1x * 2);
|
|
inc(NativeInt(src2Line), s2x * 2);
|
|
inc(NativeInt( dstLine), dx * 2);
|
|
for iy := 0 to h - 1 do begin
|
|
for ix := 0 to iw - 1 do begin
|
|
i1 := (src2Line^ and $001F001F);
|
|
i2 := (((((src1Line^ and $001F001F) - i1) * alpha) shr 8 + i1) ) and $001F001F;
|
|
i1 := (src2Line^ and $03E003E0) shr 4;
|
|
i2 := i2 + (((((src1Line^ and $03E003E0) shr 4 - i1) * alpha) shr 8 + i1) shl 4) and $03E003E0;
|
|
i1 := (src2Line^ and $7C007C00) shr 8;
|
|
i2 := i2 + (((((src1Line^ and $7C007C00) shr 8 - i1) * alpha) shr 8 + i1) shl 8) and $7C007C00;
|
|
dstLine^ := i2;
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
end;
|
|
inc(NativeInt(src1Line), s1ld);
|
|
inc(NativeInt(src2Line), s2ld);
|
|
inc(NativeInt( dstLine), dld);
|
|
end;
|
|
if odd(w) then begin
|
|
src1Line := pointer(NativeInt(src1.ScanLine[s1y]) + iw * 4 + s1x * 2);
|
|
src2Line := pointer(NativeInt(src2.ScanLine[s2y]) + iw * 4 + s2x * 2);
|
|
dstLine := pointer(NativeInt(dst .ScanLine[ dy]) + iw * 4 + dx * 2);
|
|
inc(s1ld, iw * 4);
|
|
inc(s2ld, iw * 4);
|
|
inc( dld, iw * 4);
|
|
for iy := 0 to h - 1 do begin
|
|
i1 := PWord(src2Line)^ and $001F;
|
|
i2 := ((((PWord(src1Line)^ and $001F) - i1) * alpha) shr 8 + i1) and $001F;
|
|
i1 := PWord(src2Line)^ and $03E0;
|
|
i2 := i2 + ((((PWord(src1Line)^ and $03E0) - i1) * alpha) shr 8 + i1) and $03E0;
|
|
i1 := PWord(src2Line)^ and $7C00;
|
|
i2 := i2 + ((((PWord(src1Line)^ and $7C00) - i1) * alpha) shr 8 + i1) and $7C00;
|
|
PWord(dstLine)^ := i2;
|
|
inc(NativeInt(src1Line), s1ld);
|
|
inc(NativeInt(src2Line), s2ld);
|
|
inc(NativeInt( dstLine), dld);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure AlphaBlend16(src1, src2, dst: TBitmap; alpha: cardinal); // 395
|
|
var src1Line, src2Line, dstLine : ^cardinal;
|
|
mskLine : ^byte;
|
|
ix, iy, iw : integer;
|
|
i1, i2 : cardinal;
|
|
begin
|
|
src1Line := src1.ScanLine[s1y];
|
|
src2Line := src2.ScanLine[s2y];
|
|
dstLine := dst .ScanLine[ dy];
|
|
if msk <> nil then begin
|
|
mskLine := msk.ScanLine[s1y];
|
|
if h > 1 then begin
|
|
s1ld := NativeInt(src1.ScanLine[s1y + 1]) - NativeInt(src1Line) - w * 2;
|
|
s2ld := NativeInt(src2.ScanLine[s2y + 1]) - NativeInt(src2Line) - w * 2;
|
|
dld := NativeInt(dst .ScanLine[ dy + 1]) - NativeInt( dstLine) - w * 2;
|
|
mld := NativeInt(msk .ScanLine[s1y + 1]) - NativeInt( mskLine) - w;
|
|
end else begin
|
|
s1ld := 0;
|
|
s2ld := 0;
|
|
dld := 0;
|
|
mld := 0;
|
|
end;
|
|
inc(NativeInt(src1Line), s1x * 2);
|
|
inc(NativeInt(src2Line), s2x * 2);
|
|
inc(NativeInt( dstLine), dx * 2);
|
|
inc(NativeInt( mskLine), s1x );
|
|
for iy := 0 to h - 1 do begin
|
|
for ix := 0 to w - 1 do begin
|
|
if mskLine^ < 255 then begin
|
|
i1 := 256 - (((cardinal(256) - mskLine^) * alpha) shr 8);
|
|
i2 := ((alpha * (PWord(src1Line)^ and $001F) + i1 * (PWord(src2Line)^ and $001F)) shr 8) and $001F;
|
|
i2 := i2 + ((alpha * (PWord(src1Line)^ and $07E0) + i1 * (PWord(src2Line)^ and $07E0)) shr 8) and $07E0;
|
|
i2 := i2 + ((alpha * (PWord(src1Line)^ and $F800) + i1 * (PWord(src2Line)^ and $F800)) shr 8) and $F800;
|
|
PWord(dstLine)^ := i2;
|
|
end;
|
|
inc(NativeInt(src1Line), 2);
|
|
inc(NativeInt(src2Line), 2);
|
|
inc(NativeInt( dstLine), 2);
|
|
inc(mskLine);
|
|
end;
|
|
inc(NativeInt(src1Line), s1ld);
|
|
inc(NativeInt(src2Line), s2ld);
|
|
inc(NativeInt( dstLine), dld);
|
|
inc(NativeInt( mskLine), mld);
|
|
end;
|
|
end else begin
|
|
iw := w div 2;
|
|
if h > 1 then begin
|
|
s1ld := NativeInt(src1.ScanLine[s1y + 1]) - NativeInt(src1Line) - iw * 4;
|
|
s2ld := NativeInt(src2.ScanLine[s2y + 1]) - NativeInt(src2Line) - iw * 4;
|
|
dld := NativeInt(dst .ScanLine[ dy + 1]) - NativeInt( dstLine) - iw * 4;
|
|
end else begin
|
|
s1ld := 0;
|
|
s2ld := 0;
|
|
dld := 0;
|
|
end;
|
|
inc(NativeInt(src1Line), s1x * 2);
|
|
inc(NativeInt(src2Line), s2x * 2);
|
|
inc(NativeInt( dstLine), dx * 2);
|
|
for iy := 0 to h - 1 do begin
|
|
for ix := 0 to iw - 1 do begin
|
|
i1 := (src2Line^ and $001F001F);
|
|
i2 := (((((src1Line^ and $001F001F) - i1) * alpha) shr 8 + i1) ) and $001F001F;
|
|
i1 := (src2Line^ and $07E007E0) shr 4;
|
|
i2 := i2 + (((((src1Line^ and $07E007E0) shr 4 - i1) * alpha) shr 8 + i1) shl 4) and $07E007E0;
|
|
i1 := (src2Line^ and $F800F800) shr 8;
|
|
i2 := i2 + (((((src1Line^ and $F800F800) shr 8 - i1) * alpha) shr 8 + i1) shl 8) and $F800F800;
|
|
dstLine^ := i2;
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
end;
|
|
inc(NativeInt(src1Line), s1ld);
|
|
inc(NativeInt(src2Line), s2ld);
|
|
inc(NativeInt( dstLine), dld);
|
|
end;
|
|
if odd(w) then begin
|
|
src1Line := pointer(NativeInt(src1.ScanLine[s1y]) + iw * 4 + s1x * 2);
|
|
src2Line := pointer(NativeInt(src2.ScanLine[s2y]) + iw * 4 + s2x * 2);
|
|
dstLine := pointer(NativeInt(dst .ScanLine[ dy]) + iw * 4 + dx * 2);
|
|
inc(s1ld, iw * 4);
|
|
inc(s2ld, iw * 4);
|
|
inc( dld, iw * 4);
|
|
for iy := 0 to h - 1 do begin
|
|
i1 := PWord(src2Line)^ and $001F;
|
|
i2 := ((((PWord(src1Line)^ and $001F) - i1) * alpha) shr 8 + i1) and $001F;
|
|
i1 := PWord(src2Line)^ and $07E0;
|
|
i2 := i2 + ((((PWord(src1Line)^ and $07E0) - i1) * alpha) shr 8 + i1) and $07E0;
|
|
i1 := PWord(src2Line)^ and $F800;
|
|
i2 := i2 + ((((PWord(src1Line)^ and $F800) - i1) * alpha) shr 8 + i1) and $F800;
|
|
PWord(dstLine)^ := i2;
|
|
inc(NativeInt(src1Line), s1ld);
|
|
inc(NativeInt(src2Line), s2ld);
|
|
inc(NativeInt( dstLine), dld);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure AlphaBlend24(src1, src2, dst: TBitmap; alpha: cardinal); // 770
|
|
var src1Line, src2Line, dstLine : PByte;
|
|
mskLine : ^byte;
|
|
ix, iy, iw : integer;
|
|
i1 : cardinal;
|
|
begin
|
|
src1Line := src1.ScanLine[s1y];
|
|
src2Line := src2.ScanLine[s2y];
|
|
dstLine := dst .ScanLine[ dy];
|
|
iw := w - 1;
|
|
if h > 1 then begin
|
|
s1ld := NativeInt(src1.ScanLine[s1y + 1]) - NativeInt(src1Line) - w * 3;
|
|
s2ld := NativeInt(src2.ScanLine[s2y + 1]) - NativeInt(src2Line) - w * 3;
|
|
dld := NativeInt(dst .ScanLine[ dy + 1]) - NativeInt( dstLine) - w * 3;
|
|
end else begin
|
|
s1ld := 0;
|
|
s2ld := 0;
|
|
dld := 0;
|
|
end;
|
|
inc(NativeInt(src1Line), s1x * 3);
|
|
inc(NativeInt(src2Line), s2x * 3);
|
|
inc(NativeInt( dstLine), dx * 3);
|
|
if msk <> nil then begin
|
|
mskLine := msk.ScanLine[s1y];
|
|
if h > 1 then
|
|
mld := NativeInt(msk.ScanLine[s1y + 1]) - NativeInt( mskLine) - w
|
|
else
|
|
mld := 0;
|
|
inc(NativeInt(mskLine), s1x);
|
|
end else begin
|
|
mskLine := nil;
|
|
mld := 0;
|
|
end;
|
|
for iy := 0 to h - 1 do begin
|
|
if mskLine <> nil then begin
|
|
for ix := 0 to iw do begin
|
|
if mskLine^ < 255 then begin
|
|
i1 := 256 - (((cardinal(256) - mskLine^) * alpha) shr 8);
|
|
dstLine^ := byte((alpha * src1Line^ + i1 * src2Line^) shr 8);
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
dstLine^ := byte((alpha * src1Line^ + i1 * src2Line^) shr 8);
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
dstLine^ := byte((alpha * src1Line^ + i1 * src2Line^) shr 8);
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
end else begin
|
|
inc(src1Line, 3);
|
|
inc(src2Line, 3);
|
|
inc( dstLine, 3);
|
|
end;
|
|
inc(mskLine);
|
|
end;
|
|
end else
|
|
for ix := 0 to iw do begin
|
|
i1 := src2Line^;
|
|
dstLine^ := byte(((src1Line^ - i1) * alpha) shr 8 + i1);
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
i1 := src2Line^;
|
|
dstLine^ := byte(((src1Line^ - i1) * alpha) shr 8 + i1);
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
i1 := src2Line^;
|
|
dstLine^ := byte(((src1Line^ - i1) * alpha) shr 8 + i1);
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
end;
|
|
inc(NativeInt(src1Line), s1ld);
|
|
inc(NativeInt(src2Line), s2ld);
|
|
inc(NativeInt( dstLine), dld);
|
|
inc(NativeInt( mskLine), mld);
|
|
end;
|
|
end;
|
|
|
|
procedure AlphaBlend32(src1, src2, dst: TBitmap; alpha: cardinal); // 630
|
|
var src1Line, src2Line, dstLine : ^cardinal;
|
|
mskLine : ^byte;
|
|
ix, iy, iw : integer;
|
|
i1, i2 : cardinal;
|
|
begin
|
|
src1Line := src1.ScanLine[s1y];
|
|
src2Line := src2.ScanLine[s2y];
|
|
dstLine := dst .ScanLine[ dy];
|
|
iw := w - 1;
|
|
if h > 1 then begin
|
|
s1ld := NativeInt(src1.ScanLine[s1y + 1]) - NativeInt(src1Line) - w * 4;
|
|
s2ld := NativeInt(src2.ScanLine[s2y + 1]) - NativeInt(src2Line) - w * 4;
|
|
dld := NativeInt(dst .ScanLine[ dy + 1]) - NativeInt( dstLine) - w * 4;
|
|
end else begin
|
|
s1ld := 0;
|
|
s2ld := 0;
|
|
dld := 0;
|
|
end;
|
|
inc(NativeInt(src1Line), s1x * 4);
|
|
inc(NativeInt(src2Line), s2x * 4);
|
|
inc(NativeInt( dstLine), dx * 4);
|
|
if msk <> nil then begin
|
|
mskLine := msk.ScanLine[s1y];
|
|
if h > 1 then
|
|
mld := NativeInt(msk.ScanLine[s1y + 1]) - NativeInt( mskLine) - w
|
|
else
|
|
mld := 0;
|
|
inc(NativeInt(mskLine), s1x);
|
|
end else begin
|
|
mskLine := nil;
|
|
mld := 0;
|
|
end;
|
|
for iy := 0 to h - 1 do begin
|
|
if mskLine <> nil then begin
|
|
for ix := 0 to iw do begin
|
|
if mskLine^ < 255 then begin
|
|
i1 := 256 - (((cardinal(256) - mskLine^) * alpha) shr 8);
|
|
i2 := ((alpha * (src1Line^ and $00FF00FF) + i1 * (src2Line^ and $00FF00FF)) shr 8) and $00FF00FF;
|
|
i2 := i2 + ((alpha * (src1Line^ and $0000FF00) + i1 * (src2Line^ and $0000FF00)) shr 8) and $0000FF00;
|
|
dstLine^ := i2;
|
|
end;
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
inc( mskLine);
|
|
end;
|
|
end else
|
|
for ix := 0 to iw do begin
|
|
i1 := src2Line^ and $00FF00FF;
|
|
i2 := ((((src1Line^ and $00FF00FF) - i1) * alpha) shr 8 + i1) and $00FF00FF;
|
|
i1 := src2Line^ and $0000FF00;
|
|
i2 := i2 + ((((src1Line^ and $0000FF00) - i1) * alpha) shr 8 + i1) and $0000FF00;
|
|
dstLine^ := i2;
|
|
inc(src1Line);
|
|
inc(src2Line);
|
|
inc( dstLine);
|
|
end;
|
|
inc(NativeInt(src1Line), s1ld);
|
|
inc(NativeInt(src2Line), s2ld);
|
|
inc(NativeInt( dstLine), dld);
|
|
inc(NativeInt( mskLine), mld);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if dst = src2 then begin
|
|
if x < 0 then begin
|
|
w := Min(src1.Width + x, dst.Width);
|
|
s1x := -x;
|
|
dx := 0;
|
|
end else begin
|
|
w := Min(src1.Width, dst.Width - x);
|
|
s1x := 0;
|
|
dx := x;
|
|
end;
|
|
if y < 0 then begin
|
|
h := Min(src1.Height + y, dst.Height);
|
|
s1y := -y;
|
|
dy := 0;
|
|
end else begin
|
|
h := Min(src1.Height, dst.Height - y);
|
|
s1y := 0;
|
|
dy := y;
|
|
end;
|
|
s2x := dx;
|
|
s2y := dy;
|
|
if (msk <> nil) and ((msk.PixelFormat <> pf8Bit) or (msk.Width <> src1.Width) or (msk.Height <> src1.Height)) then
|
|
msk := nil;
|
|
end else begin
|
|
w := Min(src1.Width, Min(src2.Width, dst.Width ));
|
|
h := Min(src1.Height, Min(src2.Height, dst.Height));
|
|
s1x := 0; s2x := 0; dx := 0;
|
|
s1y := 0; s2y := 0; dy := 0;
|
|
end;
|
|
case GetPixelFormat(dst) of
|
|
15 : if ForcePixelFormat([src1, src2], pf15bit) then AlphaBlend15(src1, src2, dst, alpha);
|
|
16 : if ForcePixelFormat([src1, src2], pf16bit) then AlphaBlend16(src1, src2, dst, alpha);
|
|
24 : if ForcePixelFormat([src1, src2], pf24bit) then AlphaBlend24(src1, src2, dst, alpha);
|
|
32 : if ForcePixelFormat([src1, src2], pf32bit) then AlphaBlend32(src1, src2, dst, alpha);
|
|
end;
|
|
end;
|
|
|
|
procedure AlphaBlend(src1, src2, dst : TBitmap;
|
|
alpha : cardinal = 128);
|
|
begin
|
|
AlphaBlend_(src1, src2, nil, dst, alpha);
|
|
end;
|
|
|
|
procedure AlphaBlend(src, dst : TBitmap;
|
|
alpha : cardinal = 128;
|
|
msk : TBitmap = nil;
|
|
x : integer = 0;
|
|
y : integer = 0 );
|
|
begin
|
|
AlphaBlend_(src, dst, msk, dst, alpha, x, y);
|
|
end;
|
|
|
|
// ***************************************************************
|
|
|
|
procedure Draw(imageList, index : cardinal;
|
|
dst : TBitmap;
|
|
x : integer = 0;
|
|
y : integer = 0;
|
|
width : integer = 0;
|
|
height : integer = 0;
|
|
grayPercent : TGrayPercent = gp0;
|
|
alpha : cardinal = 256;
|
|
stretchQuality : TStretchQuality = sqHigh);
|
|
var bmp, msk : TBitmap;
|
|
ii : TImageInfo;
|
|
begin
|
|
if ImageList_GetImageInfo(imageList, index, ii) then begin
|
|
bmp := TBitmap.Create;
|
|
try
|
|
case GetPixelFormat(dst) of
|
|
15 : bmp.PixelFormat := pf15bit;
|
|
16 : bmp.PixelFormat := pf16bit;
|
|
24 : bmp.PixelFormat := pf24bit;
|
|
else bmp.PixelFormat := pf32bit;
|
|
end;
|
|
bmp.Width := ii.rcImage.Right - ii.rcImage.Left;
|
|
bmp.Height := ii.rcImage.Bottom - ii.rcImage.Top;
|
|
ImageList_Draw(imageList, index, bmp.Canvas.Handle, 0, 0, ILD_NORMAL);
|
|
msk := nil;
|
|
try
|
|
if ii.hbmMask <> 0 then begin
|
|
msk := TBitmap.Create;
|
|
msk.PixelFormat := pf8bit;
|
|
msk.Width := ii.rcImage.Right - ii.rcImage.Left;
|
|
msk.Height := ii.rcImage.Bottom - ii.rcImage.Top;
|
|
ImageList_Draw(imageList, index, msk.Canvas.Handle, 0, 0, ILD_MASK);
|
|
end;
|
|
if ((width <> 0) and (width <> bmp.Width)) or ((height <> 0) and (height <> bmp.Height)) then begin
|
|
if width = 0 then width := bmp.Width;
|
|
if height = 0 then height := bmp.Height;
|
|
StretchBitmap(bmp, msk, width, height, stretchQuality);
|
|
end;
|
|
GrayScale(bmp, grayPercent);
|
|
AlphaBlend(bmp, dst, alpha, msk, x, y);
|
|
finally msk.Free end;
|
|
finally bmp.Free end;
|
|
end;
|
|
end;
|
|
|
|
procedure Draw(bmp, msk : TBitmap;
|
|
dst : TBitmap;
|
|
x : integer = 0;
|
|
y : integer = 0;
|
|
width : integer = 0;
|
|
height : integer = 0;
|
|
grayPercent : TGrayPercent = gp0;
|
|
alpha : cardinal = 256;
|
|
stretchQuality : TStretchQuality = sqHigh);
|
|
begin
|
|
if width = 0 then width := bmp.Width;
|
|
if height = 0 then height := bmp.Height;
|
|
if (width <> bmp.Width) or (height <> bmp.Height) then
|
|
StretchBitmap(bmp, msk, width, height, stretchQuality);
|
|
GrayScale(bmp, grayPercent);
|
|
AlphaBlend(bmp, dst, alpha, msk, x, y);
|
|
end;
|
|
|
|
// ***************************************************************
|
|
|
|
type
|
|
TYCbCr = packed record y, cb, cr, helper : single end;
|
|
TAYCbCr = array [0..maxInt shr 4 - 1] of TYCbCr;
|
|
TPAYCbCr = ^TAYCbCr;
|
|
|
|
function Sign(const value: double) : integer;
|
|
begin
|
|
if ((PInt64(@value)^ and $7FFFFFFFFFFFFFFF) = $0000000000000000) then
|
|
result := 0
|
|
else
|
|
if ((PInt64(@value)^ and $8000000000000000) = $8000000000000000) then
|
|
result := -1
|
|
else
|
|
result := +1;
|
|
end;
|
|
|
|
procedure ICBI1Plane(src, dst: TPAYCbCr; width, height: integer; const stepSizes: array of integer; coef1, coef2: double);
|
|
const
|
|
GM = 5.0; // Weight for Isophote smoothing energy (default = 5.0 -> 19.0)
|
|
BT = -1.0; // Weight for Curvature enhancement energy (default = -1.0 -> -3.0)
|
|
AL = 1.0; // Weight for Curvature Continuity energy (default = 1.0 -> 0.7)
|
|
TS = 100; // Threshold on image change for stopping iterations (default = 100)
|
|
|
|
var D1, D2, D3, C1, C2 : array of array of single;
|
|
pixels : array of array of TYCbCr;
|
|
i1, i2 : integer;
|
|
p1, p2 : single;
|
|
step : integer;
|
|
g : integer;
|
|
diff : integer;
|
|
EN1, EN2, EN3, EN4, EN5, EN6 : single;
|
|
EA1, EA2, EA3, EA4, EA5, EA6 : single;
|
|
ES1, ES2, ES3, ES4, ES5, ES6 : single;
|
|
EN, EA, ES : single;
|
|
EISO : double;
|
|
newWidth, newHeight : integer;
|
|
ix, iy : integer;
|
|
maxValue, testValue : single;
|
|
begin
|
|
newWidth := width * 2 - 1;
|
|
newHeight := height * 2 - 1;
|
|
|
|
SetLength(D1, newWidth, newHeight);
|
|
SetLength(D2, newWidth, newHeight);
|
|
SetLength(D3, newWidth, newHeight);
|
|
SetLength(C1, newWidth, newHeight);
|
|
SetLength(C2, newWidth, newHeight);
|
|
|
|
SetLength(pixels, newWidth, newHeight);
|
|
for ix := 0 to width - 1 do
|
|
for iy := 0 to height - 1 do
|
|
pixels[ix * 2, iy * 2] := src[iy * width + ix];
|
|
|
|
ix := 1;
|
|
iy := newHeight - 1;
|
|
for i1 := 1 to width - 1 do begin
|
|
pixels[ix, 0 ].y := (pixels[ix + 1, 0 ].y + pixels[ix - 1, 0 ].y ) / 2;
|
|
pixels[ix, 0 ].cb := (pixels[ix + 1, 0 ].cb + pixels[ix - 1, 0 ].cb) / 2;
|
|
pixels[ix, 0 ].cr := (pixels[ix + 1, 0 ].cr + pixels[ix - 1, 0 ].cr) / 2;
|
|
pixels[ix, iy].y := (pixels[ix + 1, iy].y + pixels[ix - 1, iy].y ) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix + 1, iy].cb + pixels[ix - 1, iy].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix + 1, iy].cr + pixels[ix - 1, iy].cr) / 2;
|
|
inc(ix, 2);
|
|
end;
|
|
ix := newWidth - 1;
|
|
iy := 1;
|
|
for i1 := 1 to height - 1 do begin
|
|
pixels[0, iy].y := (pixels[0, iy + 1].y + pixels[0, iy - 1].y ) / 2;
|
|
pixels[0, iy].cb := (pixels[0, iy + 1].cb + pixels[0, iy - 1].cb) / 2;
|
|
pixels[0, iy].cr := (pixels[0, iy + 1].cr + pixels[0, iy - 1].cr) / 2;
|
|
pixels[ix, iy].y := (pixels[ix, iy + 1].y + pixels[ix, iy - 1].y ) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix, iy + 1].cb + pixels[ix, iy - 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix, iy + 1].cr + pixels[ix, iy - 1].cr) / 2;
|
|
inc(iy, 2);
|
|
end;
|
|
|
|
ix := 1;
|
|
for i1 := 1 to width - 1 do begin
|
|
iy := 1;
|
|
for i2 := 1 to height - 1 do begin
|
|
p1 := (pixels[ix - 1, iy - 1].y + pixels[ix + 1, iy + 1].y) / 2;
|
|
p2 := (pixels[ix + 1, iy - 1].y + pixels[ix - 1, iy + 1].y) / 2;
|
|
if (i1 > 1) and (i1 < width - 1) and (i2 > 1) and (i2 < height - 1) then begin
|
|
if abs(pixels[ix - 1, iy - 3].y + pixels[ix - 3, iy - 1].y + pixels[ix + 1, iy + 3].y + pixels[ix + 3, iy + 1].y + (2 * p2) - (6 * p1)) >
|
|
abs(pixels[ix - 3, iy + 1].y + pixels[ix - 1, iy + 3].y + pixels[ix + 3, iy - 1].y + pixels[ix + 1, iy - 3].y + (2 * p1) - (6 * p2)) then begin
|
|
if (ix > 2) and (iy > 2) and (ix < newWidth - 3) and (iy < newHeight - 3) then
|
|
p1 := (pixels[ix - 1, iy - 1].y + pixels[ix + 1, iy + 1].y) * coef1 +
|
|
(pixels[ix - 3, iy - 3].y + pixels[ix + 3, iy + 3].y) * coef2;
|
|
pixels[ix, iy].y := p1;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy - 1].cb + pixels[ix + 1, iy + 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy - 1].cr + pixels[ix + 1, iy + 1].cr) / 2;
|
|
end else begin
|
|
if (ix > 2) and (iy > 2) and (ix < newWidth - 3) and (iy < newHeight - 3) then
|
|
p2 := (pixels[ix + 1, iy - 1].y + pixels[ix - 1, iy + 1].y) * coef1 +
|
|
(pixels[ix + 3, iy - 3].y + pixels[ix - 3, iy + 3].y) * coef2;
|
|
pixels[ix, iy].y := p2;
|
|
pixels[ix, iy].cb := (pixels[ix + 1, iy - 1].cb + pixels[ix - 1, iy + 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix + 1, iy - 1].cr + pixels[ix - 1, iy + 1].cr) / 2;
|
|
end;
|
|
end else
|
|
if abs(pixels[ix - 1, iy - 1].y - pixels[ix + 1, iy + 1].y) < abs(pixels[ix + 1, iy - 1].y - pixels[ix - 1, iy + 1].y) then begin
|
|
pixels[ix, iy].y := p1;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy - 1].cb + pixels[ix + 1, iy + 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy - 1].cr + pixels[ix + 1, iy + 1].cr) / 2;
|
|
end else begin
|
|
pixels[ix, iy].y := p2;
|
|
pixels[ix, iy].cb := (pixels[ix + 1, iy - 1].cb + pixels[ix - 1, iy + 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix + 1, iy - 1].cr + pixels[ix - 1, iy + 1].cr) / 2;
|
|
end;
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
// iterative refinement
|
|
for g := 0 to high(stepSizes) do begin
|
|
diff := 0;
|
|
step := stepSizes[g];
|
|
|
|
// computation of derivatives
|
|
for ix := 3 to newWidth - 4 do begin
|
|
iy := 4 - (ix and 1);
|
|
for i2 := 2 to height - 2 do begin
|
|
C1[ix, iy] := (pixels[ix - 1, iy - 1].y - pixels[ix + 1, iy + 1].y) / 2;
|
|
C2[ix, iy] := (pixels[ix + 1, iy - 1].y - pixels[ix - 1, iy + 1].y) / 2;
|
|
D1[ix, iy] := pixels[ix - 1, iy - 1].y + pixels[ix + 1, iy + 1].y - 2 * pixels[ix, iy].y;
|
|
D2[ix, iy] := pixels[ix + 1, iy - 1].y + pixels[ix - 1, iy + 1].y - 2 * pixels[ix, iy].y;
|
|
D3[ix, iy] := (pixels[ix, iy - 2].y - pixels[ix - 2, iy].y + pixels[ix, iy + 2].y - pixels[ix + 2, iy].y) / 2;
|
|
inc(iy, 2);
|
|
end;
|
|
end;
|
|
|
|
ix := 5;
|
|
for i1 := 3 to width - 3 do begin
|
|
iy := 5;
|
|
for i2 := 3 to height - 3 do begin
|
|
EN1 := abs(D1[ix, iy] - D1[ix + 1, iy + 1]) + abs(D1[ix, iy] - D1[ix - 1, iy - 1]);
|
|
EN2 := abs(D1[ix, iy] - D1[ix + 1, iy - 1]) + abs(D1[ix, iy] - D1[ix - 1, iy + 1]);
|
|
EN3 := abs(D2[ix, iy] - D2[ix + 1, iy + 1]) + abs(D2[ix, iy] - D2[ix - 1, iy - 1]);
|
|
EN4 := abs(D2[ix, iy] - D2[ix + 1, iy - 1]) + abs(D2[ix, iy] - D2[ix - 1, iy + 1]);
|
|
EN5 := abs(pixels[ix - 2, iy - 2].y + pixels[ix + 2, iy + 2].y - 2 * pixels[ix, iy].y);
|
|
EN6 := abs(pixels[ix + 2, iy - 2].y + pixels[ix - 2, iy + 2].y - 2 * pixels[ix, iy].y);
|
|
|
|
EA1 := abs(D1[ix, iy] - D1[ix + 1, iy + 1] - 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy - 1] - 3 * step);
|
|
EA2 := abs(D1[ix, iy] - D1[ix + 1, iy - 1] - 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy + 1] - 3 * step);
|
|
EA3 := abs(D2[ix, iy] - D2[ix + 1, iy + 1] - 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy - 1] - 3 * step);
|
|
EA4 := abs(D2[ix, iy] - D2[ix + 1, iy - 1] - 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy + 1] - 3 * step);
|
|
EA5 := abs(pixels[ix - 2, iy - 2].y + pixels[ix + 2, iy + 2].y - 2 * pixels[ix, iy].y - 2 * step);
|
|
EA6 := abs(pixels[ix + 2, iy - 2].y + pixels[ix - 2, iy + 2].y - 2 * pixels[ix, iy].y - 2 * step);
|
|
|
|
ES1 := abs(D1[ix, iy] - D1[ix + 1, iy + 1] + 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy - 1] + 3 * step);
|
|
ES2 := abs(D1[ix, iy] - D1[ix + 1, iy - 1] + 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy + 1] + 3 * step);
|
|
ES3 := abs(D2[ix, iy] - D2[ix + 1, iy + 1] + 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy - 1] + 3 * step);
|
|
ES4 := abs(D2[ix, iy] - D2[ix + 1, iy - 1] + 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy + 1] + 3 * step);
|
|
ES5 := abs(pixels[ix - 2, iy - 2].y + pixels[ix + 2, iy + 2].y - 2 * pixels[ix, iy].y + 2 * step);
|
|
ES6 := abs(pixels[ix + 2, iy - 2].y + pixels[ix - 2, iy + 2].y - 2 * pixels[ix, iy].y + 2 * step);
|
|
|
|
if (C1[ix, iy] <> 0) or (C2[ix, iy] <> 0) then begin
|
|
EISO := (C1[ix, iy] * C1[ix, iy] * D2[ix, iy] - 2 * C1[ix, iy] * C2[ix, iy] * D3[ix, iy] + C2[ix, iy] * C2[ix, iy] * D1[ix, iy]) / (C1[ix, iy] * C1[ix, iy] + C2[ix, iy] * C2[ix, iy]);
|
|
if abs(EISO) < 0.2 then
|
|
EISO := 0;
|
|
end else
|
|
EISO := 0;
|
|
|
|
EN := (AL * (EN1 + EN2 + EN3 + EN4)) + (BT * (EN5 + EN6));
|
|
EA := (AL * (EA1 + EA2 + EA3 + EA4)) + (BT * (EA5 + EA6)) - (GM * sign(EISO));
|
|
ES := (AL * (ES1 + ES2 + ES3 + ES4)) + (BT * (ES5 + ES6)) + (GM * sign(EISO));
|
|
|
|
if (EN > EA) and (ES > EA) then begin
|
|
if pixels[ix, iy].y + step > 255 then
|
|
pixels[ix, iy].y := 255
|
|
else
|
|
pixels[ix, iy].y := pixels[ix, iy].y + step;
|
|
|
|
maxValue := pixels[ix - 1, iy - 1].y;
|
|
testValue := pixels[ix - 1, iy + 1].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy + 1].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy - 1].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
if pixels[ix, iy].y > maxValue then
|
|
pixels[ix, iy].y := maxValue;
|
|
|
|
diff := diff + step;
|
|
end else
|
|
if (EN > ES) and (EA > ES) then begin
|
|
if pixels[ix, iy].y <= step then
|
|
pixels[ix, iy].y := 0
|
|
else
|
|
pixels[ix, iy].y := pixels[ix, iy].y - step;
|
|
|
|
maxValue := pixels[ix - 1, iy - 1].y;
|
|
testValue := pixels[ix - 1, iy + 1].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy + 1].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy - 1].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
if pixels[ix, iy].y < maxValue then
|
|
pixels[ix, iy].y := maxValue;
|
|
|
|
diff := diff + step;
|
|
end;
|
|
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
if diff < TS then
|
|
break;
|
|
end;
|
|
|
|
for ix := 1 to newWidth - 2 do begin
|
|
iy := 1 + (ix and 1);
|
|
for i2 := 1 to height - 1 do begin
|
|
p1 := (pixels[ix - 1, iy].y + pixels[ix + 1, iy].y) / 2;
|
|
p2 := (pixels[ix, iy - 1].y + pixels[ix, iy + 1].y) / 2;
|
|
if (ix > 1) and (ix < newWidth - 3) and (iy > 1) and (iy < height - 3) then begin
|
|
if abs(pixels[ix - 2, iy - 1].y + pixels[ix - 2, iy + 1].y + pixels[ix + 2, iy + 1].y + pixels[ix + 2, iy - 1].y + (2 * p2) - (6 * p1)) >
|
|
abs(pixels[ix - 1, iy + 2].y + pixels[ix + 1, iy + 2].y + pixels[ix + 1, iy - 2].y + pixels[ix - 1, iy - 2].y + (2 * p1) - (6 * p2)) then begin
|
|
if (ix > 2) and (iy > 2) and (ix < newWidth - 3) and (iy < newHeight - 3) then
|
|
p1 := (pixels[ix - 1, iy].y + pixels[ix + 1, iy].y) * coef1 +
|
|
(pixels[ix - 3, iy].y + pixels[ix + 3, iy].y) * coef2;
|
|
pixels[ix, iy].y := p1;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy].cb + pixels[ix + 1, iy].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy].cr + pixels[ix + 1, iy].cr) / 2;
|
|
end else begin
|
|
if (ix > 2) and (iy > 2) and (ix < newWidth - 3) and (iy < newHeight - 3) then
|
|
p2 := (pixels[ix, iy - 1].y + pixels[ix, iy + 1].y) * coef1 +
|
|
(pixels[ix, iy - 3].y + pixels[ix, iy + 3].y) * coef2;
|
|
pixels[ix, iy].y := p2;
|
|
pixels[ix, iy].cb := (pixels[ix, iy - 1].cb + pixels[ix, iy + 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix, iy - 1].cr + pixels[ix, iy + 1].cr) / 2;
|
|
end;
|
|
end else
|
|
if abs(pixels[ix - 1, iy].y - pixels[ix + 1, iy].y) < abs(pixels[ix, iy - 1].y - pixels[ix, iy + 1].y) then begin
|
|
pixels[ix, iy].y := p1;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy].cb + pixels[ix + 1, iy].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy].cr + pixels[ix + 1, iy].cr) / 2;
|
|
end else begin
|
|
pixels[ix, iy].y := p2;
|
|
pixels[ix, iy].cb := (pixels[ix, iy - 1].cb + pixels[ix, iy + 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix, iy - 1].cr + pixels[ix, iy + 1].cr) / 2;
|
|
end;
|
|
inc(iy, 2);
|
|
end;
|
|
end;
|
|
|
|
// iterative refinement
|
|
for g := 0 to high(stepSizes) do begin
|
|
diff := 0;
|
|
step := stepSizes[g];
|
|
|
|
// computation of derivatives
|
|
for ix := 1 to newWidth - 3 do
|
|
for iy := 1 to newHeight - 3 do begin
|
|
C1[ix, iy] := (pixels[ix, iy - 1].y - pixels[ix, iy + 1].y) / 2;
|
|
C2[ix, iy] := (pixels[ix - 1, iy].y - pixels[ix + 1, iy].y) / 2;
|
|
D1[ix, iy] := pixels[ix, iy - 1].y + pixels[ix, iy + 1].y - 2 * pixels[ix, iy].y;
|
|
D2[ix, iy] := pixels[ix + 1, iy].y + pixels[ix - 1, iy].y - 2 * pixels[ix, iy].y;
|
|
D3[ix, iy] := (pixels[ix - 1, iy - 1].y - pixels[ix - 1, iy + 1].y + pixels[ix + 1, iy + 1].y - pixels[ix + 1, iy - 1].y) / 2;
|
|
end;
|
|
|
|
for ix := 2 to newWidth - 3 do begin
|
|
iy := 3 - (ix and 1);
|
|
for i2 := 1 to height - 2 do begin
|
|
EN1 := abs(D1[ix, iy] - D1[ix, iy + 1]) + abs(D1[ix, iy] - D1[ix, iy - 1]);
|
|
EN2 := abs(D1[ix, iy] - D1[ix + 1, iy]) + abs(D1[ix, iy] - D1[ix - 1, iy]);
|
|
EN3 := abs(D2[ix, iy] - D2[ix, iy + 1]) + abs(D2[ix, iy] - D2[ix, iy - 1]);
|
|
EN4 := abs(D2[ix, iy] - D2[ix + 1, iy]) + abs(D2[ix, iy] - D2[ix - 1, iy]);
|
|
EN5 := abs(pixels[ix, iy - 2].y + pixels[ix, iy + 2].y - 2 * pixels[ix, iy].y);
|
|
EN6 := abs(pixels[ix + 2, iy].y + pixels[ix - 2, iy].y - 2 * pixels[ix, iy].y);
|
|
|
|
EA1 := abs(D1[ix, iy] - D1[ix, iy + 1] - 3 * step) + abs(D1[ix, iy] - D1[ix, iy - 1] - 3 * step);
|
|
EA2 := abs(D1[ix, iy] - D1[ix + 1, iy] - 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy] - 3 * step);
|
|
EA3 := abs(D2[ix, iy] - D2[ix, iy + 1] - 3 * step) + abs(D2[ix, iy] - D2[ix, iy - 1] - 3 * step);
|
|
EA4 := abs(D2[ix, iy] - D2[ix + 1, iy] - 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy] - 3 * step);
|
|
EA5 := abs(pixels[ix, iy - 2].y + pixels[ix, iy + 2].y - 2 * pixels[ix, iy].y - 2 * step);
|
|
EA6 := abs(pixels[ix + 2, iy].y + pixels[ix - 2, iy].y - 2 * pixels[ix, iy].y - 2 * step);
|
|
|
|
ES1 := abs(D1[ix, iy] - D1[ix, iy + 1] + 3 * step) + abs(D1[ix, iy] - D1[ix, iy - 1] + 3 * step);
|
|
ES2 := abs(D1[ix, iy] - D1[ix + 1, iy] + 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy] + 3 * step);
|
|
ES3 := abs(D2[ix, iy] - D2[ix, iy + 1] + 3 * step) + abs(D2[ix, iy] - D2[ix, iy - 1] + 3 * step);
|
|
ES4 := abs(D2[ix, iy] - D2[ix + 1, iy] + 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy] + 3 * step);
|
|
ES5 := abs(pixels[ix, iy - 2].y + pixels[ix, iy + 2].y - 2 * pixels[ix, iy].y + 2 * step);
|
|
ES6 := abs(pixels[ix + 2, iy].y + pixels[ix - 2, iy].y - 2 * pixels[ix, iy].y + 2 * step);
|
|
|
|
if (C1[ix, iy] <> 0) or (C2[ix, iy] <> 0) then begin
|
|
EISO := (C1[ix, iy] * C1[ix, iy] * D2[ix, iy] - 2 * C1[ix, iy] * C2[ix, iy] * D3[ix, iy] + C2[ix, iy] * C2[ix, iy] * D1[ix, iy]) / (C1[ix, iy] * C1[ix, iy] + C2[ix, iy] * C2[ix, iy]);
|
|
if abs(EISO) < 0.2 then
|
|
EISO := 0;
|
|
end else
|
|
EISO := 0;
|
|
|
|
EN := (AL * (EN1 + EN2 + EN3 + EN4)) + (BT * (EN5 + EN6));
|
|
EA := (AL * (EA1 + EA2 + EA3 + EA4)) + (BT * (EA5 + EA6)) - (GM * sign(EISO));
|
|
ES := (AL * (ES1 + ES2 + ES3 + ES4)) + (BT * (ES5 + ES6)) + (GM * sign(EISO));
|
|
|
|
if (EN > EA) and (ES > EA) then begin
|
|
if pixels[ix, iy].y + step > 255 then
|
|
pixels[ix, iy].y := 255
|
|
else
|
|
pixels[ix, iy].y := pixels[ix, iy].y + step;
|
|
|
|
maxValue := pixels[ix, iy - 1].y;
|
|
testValue := pixels[ix - 1, iy].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
testValue := pixels[ix, iy + 1].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
if pixels[ix, iy].y > maxValue then
|
|
pixels[ix, iy].y := maxValue;
|
|
|
|
diff := diff + step;
|
|
end else
|
|
if (EN > ES) and (EA > ES) then begin
|
|
if pixels[ix, iy].y <= step then
|
|
pixels[ix, iy].y := 0
|
|
else
|
|
pixels[ix, iy].y := pixels[ix, iy].y - step;
|
|
|
|
maxValue := pixels[ix, iy - 1].y;
|
|
testValue := pixels[ix - 1, iy].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
testValue := pixels[ix, iy + 1].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
if pixels[ix, iy].y < maxValue then
|
|
pixels[ix, iy].y := maxValue;
|
|
|
|
diff := diff + step;
|
|
end;
|
|
|
|
inc(iy, 2);
|
|
end;
|
|
end;
|
|
|
|
if diff < TS then
|
|
break;
|
|
end;
|
|
|
|
for ix := 0 to newWidth - 1 do
|
|
for iy := 0 to newHeight - 1 do
|
|
dst[iy * newWidth + ix] := pixels[ix, iy];
|
|
end;
|
|
|
|
procedure GeometricPlane(src, dst: TPAYCbCr; width, height: integer);
|
|
|
|
function CalcMedian(var median: array of single; count: integer) : single;
|
|
|
|
procedure InternalQuickSort(l, r: integer);
|
|
var i1, i2, i3 : integer;
|
|
swap : single;
|
|
begin
|
|
repeat
|
|
i1 := l;
|
|
i2 := r;
|
|
i3 := (l + r) shr 1;
|
|
repeat
|
|
while true do begin
|
|
if median[i1] >= median[i3] then
|
|
break;
|
|
inc(i1);
|
|
end;
|
|
while true do begin
|
|
if median[i2] <= median[i3] then
|
|
break;
|
|
dec(i2);
|
|
end;
|
|
if i1 <= i2 then begin
|
|
swap := median[i1];
|
|
median[i1] := median[i2];
|
|
median[i2] := swap;
|
|
if i3 = i1 then i3 := i2
|
|
else if i3 = i2 then i3 := i1;
|
|
inc(i1);
|
|
dec(i2);
|
|
end;
|
|
until i1 > i2;
|
|
if l < i2 then InternalQuickSort(l, i2);
|
|
l := i1;
|
|
until i1 >= r;
|
|
end;
|
|
|
|
begin
|
|
InternalQuickSort(0, count - 1);
|
|
if odd(count) then
|
|
result := median[count div 2]
|
|
else
|
|
result := (median[count div 2 - 1] + median[count div 2]) / 2;
|
|
end;
|
|
|
|
const threshold = 8;
|
|
var pixels : array of array of TYCbCr;
|
|
i1, i2 : integer;
|
|
p00, p01, p10, p11 : single;
|
|
meanY, meanCb, meanCr, dev1 : single;
|
|
newWidth, newHeight : integer;
|
|
ix, iy : integer;
|
|
medianY, medianCb, medianCr : array [0..7] of single;
|
|
mcY, mcCb, mcCr : integer;
|
|
begin
|
|
newWidth := width * 2 - 1;
|
|
newHeight := height * 2 - 1;
|
|
|
|
// step 1: spread source pixels to destination raster
|
|
|
|
SetLength(pixels, newWidth, newHeight);
|
|
for ix := 0 to newWidth - 1 do
|
|
for iy := 0 to newHeight - 1 do begin
|
|
pixels[ix, iy].y := -1;
|
|
pixels[ix, iy].cb := -1;
|
|
pixels[ix, iy].cr := -1;
|
|
end;
|
|
for ix := 0 to width - 1 do
|
|
for iy := 0 to height - 1 do
|
|
pixels[ix * 2, iy * 2] := src[iy * width + ix];
|
|
|
|
// step 2: first interpolation based on geometrical shapes
|
|
|
|
ix := 1;
|
|
for i1 := 1 to width - 1 do begin
|
|
iy := 1;
|
|
for i2 := 1 to height - 1 do begin
|
|
p00 := pixels[ix - 1, iy - 1].y;
|
|
p01 := pixels[ix - 1, iy + 1].y;
|
|
p10 := pixels[ix + 1, iy - 1].y;
|
|
p11 := pixels[ix + 1, iy + 1].y;
|
|
if max(max(max(p00, p01), p10), p11) - min(min(min(p00, p01), p10), p11) < threshold then begin
|
|
// constant region
|
|
meanY := (p00 + p01 + p10 + p11) / 4;
|
|
meanCb := (pixels[ix - 1, iy - 1].cb + pixels[ix - 1, iy + 1].cb + pixels[ix + 1, iy - 1].cb + pixels[ix + 1, iy + 1].cb) / 4;
|
|
meanCr := (pixels[ix - 1, iy - 1].cr + pixels[ix - 1, iy + 1].cr + pixels[ix + 1, iy - 1].cr + pixels[ix + 1, iy + 1].cr) / 4;
|
|
pixels[ix, iy].y := meanY;
|
|
pixels[ix, iy].cb := meanCb;
|
|
pixels[ix, iy].cr := meanCr;
|
|
if pixels[ix - 1, iy].y = -1 then begin
|
|
pixels[ix - 1, iy].y := meanY;
|
|
pixels[ix - 1, iy].cb := meanCb;
|
|
pixels[ix - 1, iy].cr := meanCr;
|
|
end;
|
|
if pixels[ix + 1, iy].y = -1 then begin
|
|
pixels[ix + 1, iy].y := meanY;
|
|
pixels[ix + 1, iy].cb := meanCb;
|
|
pixels[ix + 1, iy].cr := meanCr;
|
|
end;
|
|
if pixels[ix, iy - 1].y = -1 then begin
|
|
pixels[ix, iy - 1].y := meanY;
|
|
pixels[ix, iy - 1].cb := meanCb;
|
|
pixels[ix, iy - 1].cr := meanCr;
|
|
end;
|
|
if pixels[ix, iy + 1].y = -1 then begin
|
|
pixels[ix, iy + 1].y := meanY;
|
|
pixels[ix, iy + 1].cb := meanCb;
|
|
pixels[ix, iy + 1].cr := meanCr;
|
|
end;
|
|
end else
|
|
if (abs(p00 - p11) > threshold) and (abs(p00 - p11) > abs(p01 - p10)) then begin
|
|
// top left corner
|
|
meanY := (p01 + p10 + p11) / 3;
|
|
meanCb := (pixels[ix - 1, iy + 1].cb + pixels[ix + 1, iy - 1].cb + pixels[ix + 1, iy + 1].cb) / 3;
|
|
meanCr := (pixels[ix - 1, iy + 1].cr + pixels[ix + 1, iy - 1].cr + pixels[ix + 1, iy + 1].cr) / 3;
|
|
pixels[ix, iy].y := (p01 + p10) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy + 1].cb + pixels[ix + 1, iy - 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy + 1].cr + pixels[ix + 1, iy - 1].cr) / 2;
|
|
dev1 := abs(sqrt(((meanY - p01) * (meanY - p01) + (meanY - p10) * (meanY - p10) + (meanY - p11) * (meanY - p11)) / 3));
|
|
if dev1 * 2 < threshold then begin
|
|
if pixels[ix, iy + 1].y = -1 then begin
|
|
pixels[ix, iy + 1].y := meanY;
|
|
pixels[ix, iy + 1].cb := meanCb;
|
|
pixels[ix, iy + 1].cr := meanCr;
|
|
end;
|
|
if pixels[ix + 1, iy].y = -1 then begin
|
|
pixels[ix + 1, iy].y := meanY;
|
|
pixels[ix + 1, iy].cb := meanCb;
|
|
pixels[ix + 1, iy].cr := meanCr;
|
|
end;
|
|
end;
|
|
end else
|
|
if (abs(p01 - p10) > threshold) and (abs(p01 - p10) > abs(p00 - p11)) then begin
|
|
// top right corner
|
|
meanY := (p11 + p10 + p00) / 3;
|
|
meanCb := (pixels[ix + 1, iy + 1].cb + pixels[ix + 1, iy - 1].cb + pixels[ix - 1, iy - 1].cb) / 3;
|
|
meanCr := (pixels[ix + 1, iy + 1].cr + pixels[ix + 1, iy - 1].cr + pixels[ix - 1, iy - 1].cr) / 3;
|
|
pixels[ix, iy].y := (p00 + p11) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy + 1].cb + pixels[ix + 1, iy - 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy + 1].cr + pixels[ix + 1, iy - 1].cr) / 2;
|
|
dev1 := abs(sqrt(((meanY - p11) * (meanY - p11) + (meanY - p10) * (meanY - p10) + (meanY - p00) * (meanY - p00)) / 3));
|
|
if dev1 * 2 < threshold then begin
|
|
if pixels[ix, iy - 1].y = -1 then begin
|
|
pixels[ix, iy - 1].y := meanY;
|
|
pixels[ix, iy - 1].cb := meanCb;
|
|
pixels[ix, iy - 1].cr := meanCr;
|
|
end;
|
|
if pixels[ix + 1, iy].y = -1 then begin
|
|
pixels[ix + 1, iy].y := meanY;
|
|
pixels[ix + 1, iy].cb := meanCb;
|
|
pixels[ix + 1, iy].cr := meanCr;
|
|
end;
|
|
end;
|
|
end else
|
|
if abs(p00 - p11) > threshold then begin
|
|
// bottom right corner
|
|
meanY := (p01 + p10 + p00) / 3;
|
|
meanCb := (pixels[ix - 1, iy + 1].cb + pixels[ix + 1, iy - 1].cb + pixels[ix - 1, iy - 1].cb) / 3;
|
|
meanCr := (pixels[ix - 1, iy + 1].cr + pixels[ix + 1, iy - 1].cr + pixels[ix - 1, iy - 1].cr) / 3;
|
|
// pixels[ix, iy].y := meanY;
|
|
// pixels[ix, iy].cb := meanCb;
|
|
// pixels[ix, iy].cr := meanCr;
|
|
pixels[ix, iy].y := (p01 + p10) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy + 1].cb + pixels[ix + 1, iy - 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy + 1].cr + pixels[ix + 1, iy - 1].cr) / 2;
|
|
dev1 := abs(sqrt(((meanY - p01) * (meanY - p01) + (meanY - p10) * (meanY - p10) + (meanY - p00) * (meanY - p00)) / 3));
|
|
if dev1 * 2 < threshold then begin
|
|
if pixels[ix, iy - 1].y = -1 then begin
|
|
pixels[ix, iy - 1].y := meanY;
|
|
pixels[ix, iy - 1].cb := meanCb;
|
|
pixels[ix, iy - 1].cr := meanCr;
|
|
end;
|
|
if pixels[ix - 1, iy].y = -1 then begin
|
|
pixels[ix - 1, iy].y := meanY;
|
|
pixels[ix - 1, iy].cb := meanCb;
|
|
pixels[ix - 1, iy].cr := meanCr;
|
|
end;
|
|
end;
|
|
end else
|
|
if abs(p01 - p10) > threshold then begin
|
|
// bottom left corner
|
|
meanY := (p00 + p11 + p01) / 3;
|
|
meanCb := (pixels[ix - 1, iy - 1].cb + pixels[ix + 1, iy + 1].cb + pixels[ix - 1, iy + 1].cb) / 3;
|
|
meanCr := (pixels[ix - 1, iy - 1].cr + pixels[ix + 1, iy + 1].cr + pixels[ix - 1, iy + 1].cr) / 3;
|
|
// pixels[ix, iy].y := meanY;
|
|
// pixels[ix, iy].cb := meanCb;
|
|
// pixels[ix, iy].cr := meanCr;
|
|
pixels[ix, iy].y := (p00 + p11) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy + 1].cb + pixels[ix + 1, iy - 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy + 1].cr + pixels[ix + 1, iy - 1].cr) / 2;
|
|
dev1 := abs(sqrt(((meanY - p00) * (meanY - p00) + (meanY - p11) * (meanY - p11) + (meanY - p01) * (meanY - p01)) / 3));
|
|
if dev1 * 2 < threshold then begin
|
|
if pixels[ix, iy + 1].y = -1 then begin
|
|
pixels[ix, iy + 1].y := meanY;
|
|
pixels[ix, iy + 1].cb := meanCb;
|
|
pixels[ix, iy + 1].cr := meanCr;
|
|
end;
|
|
if pixels[ix - 1, iy].y = -1 then begin
|
|
pixels[ix - 1, iy].y := meanY;
|
|
pixels[ix - 1, iy].cb := meanCb;
|
|
pixels[ix - 1, iy].cr := meanCr;
|
|
end;
|
|
end;
|
|
end else
|
|
if (abs(p00 - p11) > threshold) and (abs(p01 - p10) > threshold) and ((p00 - p11) * (p01 - p10) > 0) then begin
|
|
// horizontal half square
|
|
pixels[ix, iy].y := (p00 + p01) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy - 1].cb + pixels[ix - 1, iy + 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy - 1].cr + pixels[ix - 1, iy + 1].cr) / 2;
|
|
if pixels[ix - 1, iy].y = -1 then begin
|
|
pixels[ix - 1, iy].y := (p00 + p01) / 2;
|
|
pixels[ix - 1, iy].cb := (pixels[ix - 1, iy - 1].cb + pixels[ix - 1, iy + 1].cb) / 2;
|
|
pixels[ix - 1, iy].cr := (pixels[ix - 1, iy - 1].cr + pixels[ix - 1, iy + 1].cr) / 2;
|
|
end;
|
|
if pixels[ix, iy - 1].y = -1 then begin
|
|
pixels[ix, iy - 1].y := p00;
|
|
pixels[ix, iy - 1].cb := pixels[ix - 1, iy - 1].cb;
|
|
pixels[ix, iy - 1].cr := pixels[ix - 1, iy - 1].cr;
|
|
end;
|
|
if pixels[ix, iy + 1].y = -1 then begin
|
|
pixels[ix, iy + 1].y := p01;
|
|
pixels[ix, iy + 1].cb := pixels[ix - 1, iy + 1].cb;
|
|
pixels[ix, iy + 1].cr := pixels[ix - 1, iy + 1].cr;
|
|
end;
|
|
if pixels[ix + 1, iy].y = -1 then begin
|
|
pixels[ix + 1, iy].y := (p10 + p11) / 2;
|
|
pixels[ix + 1, iy].cb := (pixels[ix + 1, iy - 1].cb + pixels[ix + 1, iy + 1].cb) / 2;
|
|
pixels[ix + 1, iy].cr := (pixels[ix + 1, iy - 1].cr + pixels[ix + 1, iy + 1].cr) / 2;
|
|
end;
|
|
end else
|
|
if (abs(p00 - p11) > threshold) and (abs(p01 - p10) > threshold) and ((p00 - p11) * (p01 - p10) < 0) then begin
|
|
// vertical half square
|
|
pixels[ix, iy].y := (p00 + p10) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy - 1].cb + pixels[ix + 1, iy - 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy - 1].cr + pixels[ix + 1, iy - 1].cr) / 2;
|
|
if pixels[ix, iy - 1].y = -1 then begin
|
|
pixels[ix, iy - 1].y := (p00 + p10) / 2;
|
|
pixels[ix, iy - 1].cb := (pixels[ix - 1, iy - 1].cb + pixels[ix + 1, iy - 1].cb) / 2;
|
|
pixels[ix, iy - 1].cr := (pixels[ix - 1, iy - 1].cr + pixels[ix + 1, iy - 1].cr) / 2;
|
|
end;
|
|
if pixels[ix - 1, iy].y = -1 then begin
|
|
pixels[ix - 1, iy].y := p00;
|
|
pixels[ix - 1, iy].cb := pixels[ix - 1, iy - 1].cb;
|
|
pixels[ix - 1, iy].cr := pixels[ix - 1, iy - 1].cr;
|
|
end;
|
|
if pixels[ix + 1, iy].y = -1 then begin
|
|
pixels[ix + 1, iy].y := p10;
|
|
pixels[ix + 1, iy].cb := pixels[ix + 1, iy - 1].cb;
|
|
pixels[ix + 1, iy].cr := pixels[ix + 1, iy - 1].cr;
|
|
end;
|
|
if pixels[ix, iy + 1].y = -1 then begin
|
|
pixels[ix, iy + 1].y := (p01 + p11) / 2;
|
|
pixels[ix, iy + 1].cb := (pixels[ix - 1, iy + 1].cb + pixels[ix + 1, iy + 1].cb) / 2;
|
|
pixels[ix, iy + 1].cr := (pixels[ix - 1, iy + 1].cr + pixels[ix + 1, iy + 1].cr) / 2;
|
|
end;
|
|
end;
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
// step 3: 2nd phase interpolation
|
|
|
|
for ix := 1 to newWidth - 2 do
|
|
for iy := 1 to newHeight - 2 do
|
|
if (pixels[ix, iy].y = -1) and
|
|
(pixels[ix - 1, iy].y <> -1) and (pixels[ix + 1, iy].y <> -1) and (pixels[ix, iy - 1].y <> -1) and (pixels[ix, iy + 1].y <> -1) and
|
|
(abs( max(max(max(pixels[ix - 1, iy].y, pixels[ix + 1, iy].y), pixels[ix, iy - 1].y), pixels[ix, iy + 1].y) -
|
|
min(min(min(pixels[ix - 1, iy].y, pixels[ix + 1, iy].y), pixels[ix, iy - 1].y), pixels[ix, iy + 1].y) ) < 14) then begin
|
|
pixels[ix, iy].y := (pixels[ix - 1, iy].y + pixels[ix + 1, iy].y + pixels[ix, iy - 1].y + pixels[ix, iy + 1].y ) / 4;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy].cb + pixels[ix + 1, iy].cb + pixels[ix, iy - 1].cb + pixels[ix, iy + 1].cb) / 4;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy].cr + pixels[ix + 1, iy].cr + pixels[ix, iy - 1].cr + pixels[ix, iy + 1].cr) / 4;
|
|
end;
|
|
|
|
for ix := 1 to newWidth - 2 do
|
|
for iy := 1 to newHeight - 2 do
|
|
if pixels[ix, iy].y = -1 then
|
|
if (pixels[ix - 1, iy].y <> -1) and (pixels[ix + 1, iy].y <> -1) and (pixels[ix, iy - 1].y = -1) and (pixels[ix, iy + 1].y = -1) then begin
|
|
if abs(pixels[ix - 1, iy].y - pixels[ix + 1, iy].y) < 14 then begin
|
|
pixels[ix, iy].y := (pixels[ix - 1, iy].y + pixels[ix + 1, iy].y ) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix - 1, iy].cb + pixels[ix + 1, iy].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix - 1, iy].cr + pixels[ix + 1, iy].cr) / 2;
|
|
end;
|
|
end else
|
|
if (pixels[ix, iy - 1].y <> -1) and (pixels[ix, iy + 1].y <> -1) and (pixels[ix - 1, iy].y = -1) and (pixels[ix + 1, iy].y = -1) and
|
|
(abs(pixels[ix, iy - 1].y - pixels[ix, iy + 1].y) < 14) then begin
|
|
pixels[ix, iy].y := (pixels[ix, iy - 1].y + pixels[ix, iy + 1].y ) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix, iy - 1].cb + pixels[ix, iy + 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix, iy - 1].cr + pixels[ix, iy + 1].cr) / 2;
|
|
end else
|
|
if (pixels[ix, iy - 1].y <> -1) and (pixels[ix, iy + 1].y <> -1) and (pixels[ix - 1, iy].y <> -1) and (pixels[ix + 1, iy].y <> -1) then
|
|
if (abs(pixels[ix, iy - 1].y - pixels[ix, iy + 1].y) > 4) and
|
|
(abs(pixels[ix, iy - 1].y - pixels[ix, iy + 1].y) > abs(pixels[ix - 1, iy].y - pixels[ix + 1, iy].y)) then begin
|
|
pixels[ix, iy].y := (pixels[ix + 1, iy].y + pixels[ix - 1, iy].y ) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix + 1, iy].cb + pixels[ix - 1, iy].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix + 1, iy].cr + pixels[ix - 1, iy].cr) / 2;
|
|
end else
|
|
if (abs(pixels[ix + 1, iy].y - pixels[ix - 1, iy].y) > 4) and
|
|
(abs(pixels[ix + 1, iy].y - pixels[ix - 1, iy].y) > abs(pixels[ix, iy + 1].y - pixels[ix, iy - 1].y)) then begin
|
|
pixels[ix, iy].y := (pixels[ix, iy + 1].y + pixels[ix, iy - 1].y ) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix, iy + 1].cb + pixels[ix, iy - 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix, iy + 1].cr + pixels[ix, iy - 1].cr) / 2;
|
|
end;
|
|
|
|
// step 4: fill remaining pixels with median of surrounding pixels
|
|
|
|
for ix := 0 to newWidth - 1 do begin
|
|
for iy := 0 to newHeight - 1 do begin
|
|
if pixels[ix, iy].y < 0 then begin
|
|
mcY := 0;
|
|
mcCb := 0;
|
|
mcCr := 0;
|
|
if ix > 0 then begin
|
|
medianY[mcY] := pixels[ix - 1, iy].y;
|
|
if medianY[mcY] >= 0 then inc(mcY);
|
|
medianCb[mcCb] := pixels[ix - 1, iy].cb;
|
|
if medianCb[mcCb] >= 0 then inc(mcCb);
|
|
medianCr[mcCr] := pixels[ix - 1, iy].cr;
|
|
if medianCr[mcCr] >= 0 then inc(mcCr);
|
|
end;
|
|
if ix < newWidth - 1 then begin
|
|
medianY[mcY] := pixels[ix + 1, iy].y;
|
|
if medianY[mcY] >= 0 then inc(mcY);
|
|
medianCb[mcCb] := pixels[ix + 1, iy].cb;
|
|
if medianCb[mcCb] >= 0 then inc(mcCb);
|
|
medianCr[mcCr] := pixels[ix + 1, iy].cr;
|
|
if medianCr[mcCr] >= 0 then inc(mcCr);
|
|
end;
|
|
if iy > 0 then begin
|
|
medianY[mcY] := pixels[ix, iy - 1].y;
|
|
if medianY[mcY] >= 0 then inc(mcY);
|
|
medianCb[mcCb] := pixels[ix, iy - 1].cb;
|
|
if medianCb[mcCb] >= 0 then inc(mcCb);
|
|
medianCr[mcCr] := pixels[ix, iy - 1].cr;
|
|
if medianCr[mcCr] >= 0 then inc(mcCr);
|
|
end;
|
|
if iy < newHeight - 1 then begin
|
|
medianY[mcY] := pixels[ix, iy + 1].y;
|
|
if medianY[mcY] >= 0 then inc(mcY);
|
|
medianCb[mcCb] := pixels[ix, iy + 1].cb;
|
|
if medianCb[mcCb] >= 0 then inc(mcCb);
|
|
medianCr[mcCr] := pixels[ix, iy + 1].cr;
|
|
if medianCr[mcCr] >= 0 then inc(mcCr);
|
|
end;
|
|
if mcY < 3 then begin
|
|
if (ix > 0) and (iy > 0) then begin
|
|
medianY[mcY] := pixels[ix - 1, iy - 1].y;
|
|
if medianY[mcY] >= 0 then inc(mcY);
|
|
end;
|
|
if (ix > 0) and (iy < newHeight - 1) then begin
|
|
medianY[mcY] := pixels[ix - 1, iy + 1].y;
|
|
if medianY[mcY] >= 0 then inc(mcY);
|
|
end;
|
|
if (ix < newWidth - 1) and (iy > 0) then begin
|
|
medianY[mcY] := pixels[ix + 1, iy - 1].y;
|
|
if medianY[mcY] >= 0 then inc(mcY);
|
|
end;
|
|
if (ix < newWidth - 1) and (iy < newHeight - 1) then begin
|
|
medianY[mcY] := pixels[ix + 1, iy + 1].y;
|
|
if medianY[mcY] >= 0 then inc(mcY);
|
|
end;
|
|
end;
|
|
if mcCb < 3 then begin
|
|
if (ix > 0) and (iy > 0) then begin
|
|
medianCb[mcCb] := pixels[ix - 1, iy - 1].cb;
|
|
if medianCb[mcCb] >= 0 then inc(mcCb);
|
|
end;
|
|
if (ix > 0) and (iy < newHeight - 1) then begin
|
|
medianCb[mcCb] := pixels[ix - 1, iy + 1].cb;
|
|
if medianCb[mcCb] >= 0 then inc(mcCb);
|
|
end;
|
|
if (ix < newWidth - 1) and (iy > 0) then begin
|
|
medianCb[mcCb] := pixels[ix + 1, iy - 1].cb;
|
|
if medianCb[mcCb] >= 0 then inc(mcCb);
|
|
end;
|
|
if (ix < newWidth - 1) and (iy < newHeight - 1) then begin
|
|
medianCb[mcCb] := pixels[ix + 1, iy + 1].cb;
|
|
if medianCb[mcCb] >= 0 then inc(mcCb);
|
|
end;
|
|
end;
|
|
if mcCr < 3 then begin
|
|
if (ix > 0) and (iy > 0) then begin
|
|
medianCr[mcCr] := pixels[ix - 1, iy - 1].cr;
|
|
if medianCr[mcCr] >= 0 then inc(mcCr);
|
|
end;
|
|
if (ix > 0) and (iy < newHeight - 1) then begin
|
|
medianCr[mcCr] := pixels[ix - 1, iy + 1].cr;
|
|
if medianCr[mcCr] >= 0 then inc(mcCr);
|
|
end;
|
|
if (ix < newWidth - 1) and (iy > 0) then begin
|
|
medianCr[mcCr] := pixels[ix + 1, iy - 1].cr;
|
|
if medianCr[mcCr] >= 0 then inc(mcCr);
|
|
end;
|
|
if (ix < newWidth - 1) and (iy < newHeight - 1) then begin
|
|
medianCr[mcCr] := pixels[ix + 1, iy + 1].cr;
|
|
if medianCr[mcCr] >= 0 then inc(mcCr);
|
|
end;
|
|
end;
|
|
if mcY > 0 then
|
|
pixels[ix, iy].y := CalcMedian(medianY, mcY);
|
|
if mcCb > 0 then
|
|
pixels[ix, iy].cb := CalcMedian(medianCb, mcCb);
|
|
if mcCr > 0 then
|
|
pixels[ix, iy].cr := CalcMedian(medianCr, mcCr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
for ix := 0 to newWidth - 1 do
|
|
for iy := 0 to newHeight - 1 do
|
|
dst[iy * newWidth + ix] := pixels[ix, iy];
|
|
end;
|
|
|
|
procedure FuzzyElaPlane(src, dst: TPAYCbCr; width, height: integer);
|
|
|
|
function verySmall(value: single) : single;
|
|
begin
|
|
result := 1.0 - value / 8.0;
|
|
if result < 0.0 then
|
|
result := 0.0;
|
|
end;
|
|
|
|
function small(value: single) : single;
|
|
begin
|
|
result := 1.0 - value / 16.0;
|
|
if result < 0.0 then
|
|
result := 0.0;
|
|
end;
|
|
|
|
function large(value: single) : single;
|
|
begin
|
|
result := value / 64.0;
|
|
if result > 1.0 then
|
|
result := 1.0;
|
|
end;
|
|
|
|
var pixels : array of array of TYCbCr;
|
|
i1, i2 : integer;
|
|
pa, pb, pc, pd, pe, pf : single;
|
|
paf, pbe, pcd : single;
|
|
p1, p2, p3, p4 : single;
|
|
newWidth, newHeight : integer;
|
|
ix, iy : integer;
|
|
begin
|
|
newWidth := width * 2 - 1;
|
|
newHeight := height * 2 - 1;
|
|
|
|
// step 1: spread source pixels to destination raster
|
|
|
|
SetLength(pixels, newWidth, newHeight);
|
|
for ix := 0 to newWidth - 1 do
|
|
for iy := 0 to newHeight - 1 do begin
|
|
pixels[ix, iy].y := -1;
|
|
pixels[ix, iy].cb := -1;
|
|
pixels[ix, iy].cr := -1;
|
|
end;
|
|
for ix := 0 to width - 1 do
|
|
for iy := 0 to height - 1 do
|
|
pixels[ix * 2, iy * 2] := src[iy * width + ix];
|
|
for iy := 1 to newHeight - 2 do
|
|
if odd(iy) then begin
|
|
pixels[0, iy].y := (pixels[0, iy - 1].y + pixels[0, iy + 1].y ) / 2.0;
|
|
pixels[0, iy].cb := (pixels[0, iy - 1].cb + pixels[0, iy + 1].cb) / 2.0;
|
|
pixels[0, iy].cr := (pixels[0, iy - 1].cr + pixels[0, iy + 1].cr) / 2.0;
|
|
pixels[newWidth - 1, iy].y := (pixels[newWidth - 1, iy - 1].y + pixels[newWidth - 1, iy + 1].y ) / 2.0;
|
|
pixels[newWidth - 1, iy].cb := (pixels[newWidth - 1, iy - 1].cb + pixels[newWidth - 1, iy + 1].cb) / 2.0;
|
|
pixels[newWidth - 1, iy].cr := (pixels[newWidth - 1, iy - 1].cr + pixels[newWidth - 1, iy + 1].cr) / 2.0;
|
|
end;
|
|
for ix := 1 to newWidth - 2 do
|
|
if odd(ix) then begin
|
|
pixels[ix, 0].y := (pixels[ix - 1, 0].y + pixels[ix + 1, 0].y ) / 2.0;
|
|
pixels[ix, 0].cb := (pixels[ix - 1, 0].cb + pixels[ix + 1, 0].cb) / 2.0;
|
|
pixels[ix, 0].cr := (pixels[ix - 1, 0].cr + pixels[ix + 1, 0].cr) / 2.0;
|
|
pixels[ix, newHeight - 1].y := (pixels[ix - 1, newHeight - 1].y + pixels[ix + 1, newHeight - 1].y ) / 2.0;
|
|
pixels[ix, newHeight - 1].cb := (pixels[ix - 1, newHeight - 1].cb + pixels[ix + 1, newHeight - 1].cb) / 2.0;
|
|
pixels[ix, newHeight - 1].cr := (pixels[ix - 1, newHeight - 1].cr + pixels[ix + 1, newHeight - 1].cr) / 2.0;
|
|
end;
|
|
|
|
// step 2: first interpolation
|
|
|
|
ix := 2;
|
|
for i1 := ix to width - 1 do begin
|
|
iy := 1;
|
|
for i2 := iy to height - 1 do begin
|
|
pa := pixels[ix - 2, iy - 1].y;
|
|
pb := pixels[ix, iy - 1].y;
|
|
pc := pixels[ix + 2, iy - 1].y;
|
|
pd := pixels[ix - 2, iy + 1].y;
|
|
pe := pixels[ix, iy + 1].y;
|
|
pf := pixels[ix + 2, iy + 1].y;
|
|
paf := abs(pa - pf);
|
|
pbe := abs(pb - pe);
|
|
pcd := abs(pc - pd);
|
|
p1 := min(min(small(paf), large(pbe)), large(pcd));
|
|
p2 := min(min(large(paf), large(pbe)), small(pcd));
|
|
p3 := min(min(verySmall(paf), large(pbe)), verySmall(pcd));
|
|
p4 := 1 - p1 - p2 - p3;
|
|
pixels[ix, iy].y := p1 * (pa + pf ) / 2.0 +
|
|
p2 * ( pc + pd ) / 2.0 +
|
|
p3 * (pa + pf + pc + pd ) / 4.0 +
|
|
p4 * ( pb + pe) / 2.0;
|
|
pa := pixels[ix - 2, iy - 1].cb;
|
|
pb := pixels[ix, iy - 1].cb;
|
|
pc := pixels[ix + 2, iy - 1].cb;
|
|
pd := pixels[ix - 2, iy + 1].cb;
|
|
pe := pixels[ix, iy + 1].cb;
|
|
pf := pixels[ix + 2, iy + 1].cb;
|
|
paf := abs(pa - pf);
|
|
pbe := abs(pb - pe);
|
|
pcd := abs(pc - pd);
|
|
p1 := min(min(small(paf), large(pbe)), large(pcd));
|
|
p2 := min(min(large(paf), large(pbe)), small(pcd));
|
|
p3 := min(min(verySmall(paf), large(pbe)), verySmall(pcd));
|
|
p4 := 1 - p1 - p2 - p3;
|
|
pixels[ix, iy].cb := p1 * (pa + pf ) / 2.0 +
|
|
p2 * ( pc + pd ) / 2.0 +
|
|
p3 * (pa + pf + pc + pd ) / 4.0 +
|
|
p4 * ( pb + pe) / 2.0;
|
|
pa := pixels[ix - 2, iy - 1].cr;
|
|
pb := pixels[ix, iy - 1].cr;
|
|
pc := pixels[ix + 2, iy - 1].cr;
|
|
pd := pixels[ix - 2, iy + 1].cr;
|
|
pe := pixels[ix, iy + 1].cr;
|
|
pf := pixels[ix + 2, iy + 1].cr;
|
|
paf := abs(pa - pf);
|
|
pbe := abs(pb - pe);
|
|
pcd := abs(pc - pd);
|
|
p1 := min(min(small(paf), large(pbe)), large(pcd));
|
|
p2 := min(min(large(paf), large(pbe)), small(pcd));
|
|
p3 := min(min(verySmall(paf), large(pbe)), verySmall(pcd));
|
|
p4 := 1 - p1 - p2 - p3;
|
|
pixels[ix, iy].cr := p1 * (pa + pf ) / 2.0 +
|
|
p2 * ( pc + pd ) / 2.0 +
|
|
p3 * (pa + pf + pc + pd ) / 4.0 +
|
|
p4 * ( pb + pe) / 2.0;
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
// step 3: 2nd phase interpolation
|
|
|
|
ix := 1;
|
|
for i1 := ix to width - 1 do begin
|
|
for iy := 1 to newHeight - 2 do begin
|
|
pa := pixels[ix - 1, iy + 1].y;
|
|
pb := pixels[ix - 1, iy ].y;
|
|
pc := pixels[ix - 1, iy - 1].y;
|
|
pd := pixels[ix + 1, iy + 1].y;
|
|
pe := pixels[ix + 1, iy ].y;
|
|
pf := pixels[ix + 1, iy - 1].y;
|
|
paf := abs(pa - pf);
|
|
pbe := abs(pb - pe);
|
|
pcd := abs(pc - pd);
|
|
p1 := min(min(small(paf), large(pbe)), large(pcd));
|
|
p2 := min(min(large(paf), large(pbe)), small(pcd));
|
|
p3 := min(min(verySmall(paf), large(pbe)), verySmall(pcd));
|
|
p4 := 1 - p1 - p2 - p3;
|
|
pixels[ix, iy].y := p1 * (pa + pf ) / 2.0 +
|
|
p2 * ( pc + pd ) / 2.0 +
|
|
p3 * (pa + pf + pc + pd ) / 4.0 +
|
|
p4 * ( pb + pe) / 2.0;
|
|
pa := pixels[ix - 1, iy + 1].cb;
|
|
pb := pixels[ix - 1, iy ].cb;
|
|
pc := pixels[ix - 1, iy - 1].cb;
|
|
pd := pixels[ix + 1, iy + 1].cb;
|
|
pe := pixels[ix + 1, iy ].cb;
|
|
pf := pixels[ix + 1, iy - 1].cb;
|
|
paf := abs(pa - pf);
|
|
pbe := abs(pb - pe);
|
|
pcd := abs(pc - pd);
|
|
p1 := min(min(small(paf), large(pbe)), large(pcd));
|
|
p2 := min(min(large(paf), large(pbe)), small(pcd));
|
|
p3 := min(min(verySmall(paf), large(pbe)), verySmall(pcd));
|
|
p4 := 1 - p1 - p2 - p3;
|
|
pixels[ix, iy].cb := p1 * (pa + pf ) / 2.0 +
|
|
p2 * ( pc + pd ) / 2.0 +
|
|
p3 * (pa + pf + pc + pd ) / 4.0 +
|
|
p4 * ( pb + pe) / 2.0;
|
|
pa := pixels[ix - 1, iy + 1].cr;
|
|
pb := pixels[ix - 1, iy ].cr;
|
|
pc := pixels[ix - 1, iy - 1].cr;
|
|
pd := pixels[ix + 1, iy + 1].cr;
|
|
pe := pixels[ix + 1, iy ].cr;
|
|
pf := pixels[ix + 1, iy - 1].cr;
|
|
paf := abs(pa - pf);
|
|
pbe := abs(pb - pe);
|
|
pcd := abs(pc - pd);
|
|
p1 := min(min(small(paf), large(pbe)), large(pcd));
|
|
p2 := min(min(large(paf), large(pbe)), small(pcd));
|
|
p3 := min(min(verySmall(paf), large(pbe)), verySmall(pcd));
|
|
p4 := 1 - p1 - p2 - p3;
|
|
pixels[ix, iy].cr := p1 * (pa + pf ) / 2.0 +
|
|
p2 * ( pc + pd ) / 2.0 +
|
|
p3 * (pa + pf + pc + pd ) / 4.0 +
|
|
p4 * ( pb + pe) / 2.0;
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
for ix := 0 to newWidth - 1 do
|
|
for iy := 0 to newHeight - 1 do
|
|
dst[iy * newWidth + ix] := pixels[ix, iy];
|
|
end;
|
|
|
|
procedure PRPlane(src, dst: TPAYCbCr; width, height: integer; const icbiStepSizes: array of integer; sharpenIterations: integer);
|
|
|
|
type
|
|
TMatrix2 = record case boolean of
|
|
false : (arr: array [0..1] of array [0..1] of double);
|
|
true : (flt: array [0..3] of double);
|
|
end;
|
|
|
|
type
|
|
TA9Int = array [0..8] of double;
|
|
TA9x2Int = array [0..8] of array [0..1] of double;
|
|
|
|
function solve(var p: TA9Int; var n: TA9x2Int; size: integer; var pixel: single) : boolean;
|
|
var i, j, k, final : integer;
|
|
a, r : array [0..1] of double;
|
|
CtC, CtCi : TMatrix2;
|
|
s : double;
|
|
det : double;
|
|
min, max : double;
|
|
begin
|
|
min := 255;
|
|
max := 0;
|
|
|
|
// apply weights
|
|
for i := 0 to size - 1 do begin
|
|
if p[i] > max then
|
|
max := p[i];
|
|
if p[i] < min then
|
|
min := p[i];
|
|
p[i] := p[i] * n[i, 1];
|
|
n[i, 0] := n[i, 0] * n[i, 1];
|
|
end;
|
|
|
|
// compute covariance matrix CtC := Ct * C (2x9 * 9x2 = 2x2)
|
|
for i := 0 to 1 do
|
|
for j := i to 1 do begin
|
|
s := 0;
|
|
for k := 0 to size - 1 do
|
|
s := s + n[k][i] * n[k][j];
|
|
CtC.arr[i][j] := s;
|
|
CtC.arr[j][i] := s;
|
|
end;
|
|
|
|
det := CtC.arr[0, 0] * CtC.arr[1, 1] - CtC.arr[0, 1] * CtC.arr[1, 0];
|
|
if det > 1.0 then begin
|
|
// determinate is big enough
|
|
|
|
// invert matrix
|
|
det := 1 / det;
|
|
CtCi.arr[0, 0] := + CtC.arr[1, 1] * det;
|
|
CtCi.arr[0, 1] := - CtC.arr[0, 1] * det;
|
|
CtCi.arr[1, 0] := - CtC.arr[1, 0] * det;
|
|
CtCi.arr[1, 1] := + CtC.arr[0, 0] * det;
|
|
|
|
// compute matrix r[] := Ct * p (2x9 * 9x1 = 2x1)
|
|
for i := 0 to 1 do begin
|
|
s := 0;
|
|
for k := 0 to size - 1 do
|
|
s := s + n[k][i] * p[k];
|
|
r[i] := s;
|
|
end;
|
|
|
|
// compute weights (CtCi[] * r[]) (2x2 * 2x1 = 2x1)
|
|
for i := 0 to 1 do begin
|
|
s := 0;
|
|
for k := 0 to 1 do
|
|
s := s + CtCi.arr[i][k] * r[k];
|
|
a[i] := s;
|
|
end;
|
|
|
|
end else begin
|
|
// determinate is dangerously small (weird results)
|
|
// so we set alpha to 1 and calculate beta, only
|
|
|
|
a[0] := 1;
|
|
a[1] := 0;
|
|
for i := 0 to size - 1 do
|
|
a[1] := a[1] + p[i] - n[i, 0];
|
|
end;
|
|
|
|
// calculate interpolated pixel
|
|
pixel := a[0] * pixel + a[1];
|
|
if pixel > max then
|
|
pixel := max
|
|
else
|
|
if pixel < min then
|
|
pixel := min;
|
|
final := round(pixel);
|
|
if final > 255 then
|
|
final := 255
|
|
else
|
|
if final < 0 then
|
|
final := 0;
|
|
|
|
pixel := final;
|
|
result := true;
|
|
end;
|
|
|
|
procedure CalcWeights(var weights: TA9Int; size: integer);
|
|
var i1 : integer;
|
|
biggest : double;
|
|
sum : double;
|
|
begin
|
|
biggest := 0;
|
|
sum := 0;
|
|
for i1 := 0 to size - 1 do begin
|
|
weights[i1] := weights[i1] / 2;
|
|
if weights[i1] < 1 then
|
|
weights[i1] := 3 * weights[i1] * weights[i1] * weights[i1] - 6 * weights[i1] * weights[i1] + 4
|
|
else
|
|
weights[i1] := - weights[i1] * weights[i1] * weights[i1] + 6 * weights[i1] * weights[i1] - 12 * weights[i1] + 8;
|
|
sum := sum + weights[i1];
|
|
if weights[i1] > biggest then
|
|
biggest := weights[i1];
|
|
end;
|
|
for i1 := 0 to size - 1 do
|
|
weights[i1] := weights[i1] / sum;
|
|
end;
|
|
|
|
var pixels : array of array of TYCbCr;
|
|
i1, i2, i4 : integer;
|
|
p00, p02, p20, p22 : double;
|
|
p10, p01, p12, p21 : double;
|
|
w0022, w0220 : double;
|
|
w1012, w0121 : double;
|
|
newWidth, newHeight : integer;
|
|
ix, iy : integer;
|
|
|
|
const
|
|
GM = 5.0; // Weight for Isophote smoothing energy (default = 5.0 -> 19.0)
|
|
BT = -1.0; // Weight for Curvature enhancement energy (default = -1.0 -> -3.0)
|
|
AL = 1.0; // Weight for Curvature Continuity energy (default = 1.0 -> 0.7)
|
|
TS = 100; // Threshold on image change for stopping iterations (default = 100)
|
|
|
|
var D1, D2, D3, C1, C2 : array of array of single;
|
|
i3 : integer;
|
|
step : integer;
|
|
g : integer;
|
|
diff : integer;
|
|
EN1, EN2, EN3, EN4, EN5, EN6 : single;
|
|
EA1, EA2, EA3, EA4, EA5, EA6 : single;
|
|
ES1, ES2, ES3, ES4, ES5, ES6 : single;
|
|
EN, EA, ES : single;
|
|
EISO : double;
|
|
maxValue, testValue : single;
|
|
orgPixels : TA9Int;
|
|
newPixels : TA9x2Int;
|
|
weights : TA9Int;
|
|
begin
|
|
newWidth := width * 2 - 1;
|
|
newHeight := height * 2 - 1;
|
|
|
|
// step 1: spread source pixels to destination raster
|
|
SetLength(pixels, newWidth, newHeight);
|
|
for ix := 0 to width - 1 do
|
|
for iy := 0 to height - 1 do
|
|
pixels[ix * 2, iy * 2] := src[iy * width + ix];
|
|
|
|
ix := 1;
|
|
iy := newHeight - 1;
|
|
for i1 := 1 to width - 1 do begin
|
|
pixels[ix, 0 ].y := (pixels[ix + 1, 0 ].y + pixels[ix - 1, 0 ].y ) / 2;
|
|
pixels[ix, 0 ].cb := (pixels[ix + 1, 0 ].cb + pixels[ix - 1, 0 ].cb) / 2;
|
|
pixels[ix, 0 ].cr := (pixels[ix + 1, 0 ].cr + pixels[ix - 1, 0 ].cr) / 2;
|
|
pixels[ix, iy].y := (pixels[ix + 1, iy].y + pixels[ix - 1, iy].y ) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix + 1, iy].cb + pixels[ix - 1, iy].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix + 1, iy].cr + pixels[ix - 1, iy].cr) / 2;
|
|
inc(ix, 2);
|
|
end;
|
|
ix := newWidth - 1;
|
|
iy := 1;
|
|
for i1 := 1 to height - 1 do begin
|
|
pixels[0, iy].y := (pixels[0, iy + 1].y + pixels[0, iy - 1].y ) / 2;
|
|
pixels[0, iy].cb := (pixels[0, iy + 1].cb + pixels[0, iy - 1].cb) / 2;
|
|
pixels[0, iy].cr := (pixels[0, iy + 1].cr + pixels[0, iy - 1].cr) / 2;
|
|
pixels[ix, iy].y := (pixels[ix, iy + 1].y + pixels[ix, iy - 1].y ) / 2;
|
|
pixels[ix, iy].cb := (pixels[ix, iy + 1].cb + pixels[ix, iy - 1].cb) / 2;
|
|
pixels[ix, iy].cr := (pixels[ix, iy + 1].cr + pixels[ix, iy - 1].cr) / 2;
|
|
inc(iy, 2);
|
|
end;
|
|
|
|
// step 2: interpolate +1+1 pixels
|
|
ix := 1;
|
|
for i1 := 1 to width - 1 do begin
|
|
iy := 1;
|
|
for i2 := 1 to height - 1 do begin
|
|
p00 := pixels[ix - 1, iy - 1].y;
|
|
p02 := pixels[ix - 1, iy + 1].y;
|
|
p20 := pixels[ix + 1, iy - 1].y;
|
|
p22 := pixels[ix + 1, iy + 1].y;
|
|
w0022 := (p00 - p22) / 255;
|
|
w0022 := exp(- w0022 * w0022);
|
|
w0220 := (p02 - p20) / 255;
|
|
w0220 := exp(- w0220 * w0220);
|
|
if (w0022 <> 0) or (w0220 <> 0) then begin
|
|
pixels[ix, iy].y := (w0022 * p00 + w0022 * p22 + w0220 * p02 + w0220 * p20) / (w0022 * 2 + w0220 * 2);
|
|
pixels[ix, iy].cb := (w0022 * pixels[ix - 1, iy - 1].cb + w0022 * pixels[ix + 1, iy + 1].cb + w0220 * pixels[ix - 1, iy + 1].cb + w0220 * pixels[ix + 1, iy - 1].cb) / (w0022 * 2 + w0220 * 2);
|
|
pixels[ix, iy].cr := (w0022 * pixels[ix - 1, iy - 1].cr + w0022 * pixels[ix + 1, iy + 1].cr + w0220 * pixels[ix - 1, iy + 1].cr + w0220 * pixels[ix + 1, iy - 1].cr) / (w0022 * 2 + w0220 * 2);
|
|
end else begin
|
|
pixels[ix, iy].y := p00;
|
|
pixels[ix, iy].cb := pixels[ix - 1, iy - 1].cb;
|
|
pixels[ix, iy].cr := pixels[ix - 1, iy - 1].cr;
|
|
end;
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
// step 3: interpolate +1+0 and +0+1 pixels
|
|
for ix := 1 to newWidth - 2 do begin
|
|
iy := 1 + (ix and 1);
|
|
for i2 := 1 to height - 1 do begin
|
|
p10 := pixels[ix, iy - 1].y;
|
|
p01 := pixels[ix - 1, iy].y;
|
|
p21 := pixels[ix + 1, iy].y;
|
|
p12 := pixels[ix, iy + 1].y;
|
|
w1012 := (p10 - p12) / 255;
|
|
w1012 := exp(- w1012 * w1012);
|
|
w0121 := (p01 - p21) / 255;
|
|
w0121 := exp(- w0121 * w0121);
|
|
if (w1012 <> 0) or (w0121 <> 0) then begin
|
|
pixels[ix, iy].y := (w1012 * p10 + w1012 * p12 + w0121 * p01 + w0121 * p21) / (w1012 * 2 + w0121 * 2);
|
|
pixels[ix, iy].cb := (w1012 * pixels[ix, iy - 1].cb + w1012 * pixels[ix, iy + 1].cb + w0121 * pixels[ix - 1, iy].cb + w0121 * pixels[ix + 1, iy].cb) / (w1012 * 2 + w0121 * 2);
|
|
pixels[ix, iy].cr := (w1012 * pixels[ix, iy - 1].cr + w1012 * pixels[ix, iy + 1].cr + w0121 * pixels[ix - 1, iy].cr + w0121 * pixels[ix + 1, iy].cr) / (w1012 * 2 + w0121 * 2);
|
|
end else begin
|
|
pixels[ix, iy].y := p10;
|
|
pixels[ix, iy].cb := pixels[ix, iy - 1].cb;
|
|
pixels[ix, iy].cr := pixels[ix, iy - 1].cr;
|
|
end;
|
|
inc(iy, 2);
|
|
end;
|
|
end;
|
|
|
|
// step 4: reinterpolate +0+0 pixels
|
|
ix := 2;
|
|
for i1 := 2 to width - 2 do begin
|
|
iy := 2;
|
|
for i2 := 2 to height - 2 do begin
|
|
p00 := pixels[ix - 1, iy - 1].y;
|
|
p02 := pixels[ix - 1, iy + 1].y;
|
|
p20 := pixels[ix + 1, iy - 1].y;
|
|
p22 := pixels[ix + 1, iy + 1].y;
|
|
w0022 := (p00 - p22) / 255;
|
|
w0022 := exp(- w0022 * w0022);
|
|
w0220 := (p02 - p20) / 255;
|
|
w0220 := exp(- w0220 * w0220);
|
|
p10 := pixels[ix, iy - 1].y;
|
|
p01 := pixels[ix - 1, iy].y;
|
|
p21 := pixels[ix + 1, iy].y;
|
|
p12 := pixels[ix, iy + 1].y;
|
|
w1012 := (p10 - p12) / 255;
|
|
w1012 := exp(- w1012 * w1012);
|
|
w0121 := (p01 - p21) / 255;
|
|
w0121 := exp(- w0121 * w0121);
|
|
if (w0022 <> 0) or (w0220 <> 0) or (w1012 <> 0) or (w0121 <> 0) then begin
|
|
pixels[ix, iy].y := (w0022 * p00 + w0022 * p22 + w0220 * p02 + w0220 * p20 + w1012 * p10 + w1012 * p12 + w0121 * p01 + w0121 * p21) / (w0022 * 2 + w0220 * 2 + w1012 * 2 + w0121 * 2);
|
|
pixels[ix, iy].cb := (w0022 * pixels[ix - 1, iy - 1].cb + w0022 * pixels[ix + 1, iy + 1].cb + w0220 * pixels[ix - 1, iy + 1].cb + w0220 * pixels[ix + 1, iy - 1].cb + w1012 * pixels[ix, iy - 1].cb + w1012 * pixels[ix, iy + 1].cb + w0121 * pixels[ix - 1, iy].cb + w0121 * pixels[ix + 1, iy].cb) / (w0022 * 2 + w0220 * 2 + w1012 * 2 + w0121 * 2);
|
|
pixels[ix, iy].cr := (w0022 * pixels[ix - 1, iy - 1].cr + w0022 * pixels[ix + 1, iy + 1].cr + w0220 * pixels[ix - 1, iy + 1].cr + w0220 * pixels[ix + 1, iy - 1].cr + w1012 * pixels[ix, iy - 1].cr + w1012 * pixels[ix, iy + 1].cr + w0121 * pixels[ix - 1, iy].cr + w0121 * pixels[ix + 1, iy].cr) / (w0022 * 2 + w0220 * 2 + w1012 * 2 + w0121 * 2);
|
|
end else begin
|
|
pixels[ix, iy].y := p00;
|
|
pixels[ix, iy].cb := pixels[ix - 1, iy - 1].cb;
|
|
pixels[ix, iy].cr := pixels[ix - 1, iy - 1].cr;
|
|
end;
|
|
pixels[ix, iy].helper := pixels[ix, iy].y;
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
for i4 := 1 to sharpenIterations do begin
|
|
|
|
// step 5: sharpen +1+1 pixels
|
|
weights[0] := 1;
|
|
weights[1] := 1;
|
|
weights[2] := 1;
|
|
weights[3] := 1;
|
|
CalcWeights(weights, 4);
|
|
ix := 1;
|
|
for i1 := 1 to width - 1 do begin
|
|
iy := 1;
|
|
for i2 := 1 to height - 1 do begin
|
|
i3 := (ix - 1) shr 1 + (iy - 1) shr 1 * width;
|
|
// distances: Sqrt(2)
|
|
orgPixels[0] := src[i3 ].y;
|
|
orgPixels[1] := src[i3 + width].y;
|
|
orgPixels[2] := src[i3 + 1 ].y;
|
|
orgPixels[3] := src[i3 + 1 + width].y;
|
|
newPixels[0, 0] := pixels[ix - 1, iy - 1].y;
|
|
newPixels[1, 0] := pixels[ix - 1, iy + 1].y;
|
|
newPixels[2, 0] := pixels[ix + 1, iy - 1].y;
|
|
newPixels[3, 0] := pixels[ix + 1, iy + 1].y;
|
|
newPixels[0, 1] := weights[0];
|
|
newPixels[1, 1] := weights[1];
|
|
newPixels[2, 1] := weights[2];
|
|
newPixels[3, 1] := weights[3];
|
|
solve(orgPixels, newPixels, 4, pixels[ix, iy].y);
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
// step 6: sharpen +1+0 pixels
|
|
weights[0] := Sqrt(5);
|
|
weights[1] := Sqrt(5);
|
|
weights[2] := 1;
|
|
weights[3] := 1;
|
|
weights[4] := Sqrt(5);
|
|
weights[5] := Sqrt(5);
|
|
CalcWeights(weights, 6);
|
|
ix := 1;
|
|
for i1 := 1 to width - 1 do begin
|
|
iy := 2;
|
|
for i2 := 1 to height - 3 do begin
|
|
i3 := (ix - 1) shr 1 + (iy - 2) shr 1 * width;
|
|
// distances: 1, Sqrt(5)
|
|
orgPixels[0] := src[i3 ].y;
|
|
orgPixels[1] := src[i3 + 1 ].y;
|
|
orgPixels[2] := src[i3 + width ].y;
|
|
orgPixels[3] := src[i3 + 1 + width ].y;
|
|
orgPixels[4] := src[i3 + width shl 1].y;
|
|
orgPixels[5] := src[i3 + 1 + width shl 1].y;
|
|
newPixels[0, 0] := pixels[ix - 1, iy - 2].y;
|
|
newPixels[1, 0] := pixels[ix + 1, iy - 2].y;
|
|
newPixels[2, 0] := pixels[ix - 1, iy ].y;
|
|
newPixels[3, 0] := pixels[ix + 1, iy ].y;
|
|
newPixels[4, 0] := pixels[ix - 1, iy + 2].y;
|
|
newPixels[5, 0] := pixels[ix + 1, iy + 2].y;
|
|
newPixels[0, 1] := weights[0];
|
|
newPixels[1, 1] := weights[1];
|
|
newPixels[2, 1] := weights[2];
|
|
newPixels[3, 1] := weights[3];
|
|
newPixels[4, 1] := weights[4];
|
|
newPixels[5, 1] := weights[5];
|
|
solve(orgPixels, newPixels, 6, pixels[ix, iy].y);
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
// step 7: sharpen +0+1 pixels
|
|
weights[0] := Sqrt(5);
|
|
weights[1] := 1;
|
|
weights[2] := Sqrt(5);
|
|
weights[3] := Sqrt(5);
|
|
weights[4] := 1;
|
|
weights[5] := Sqrt(5);
|
|
CalcWeights(weights, 6);
|
|
ix := 2;
|
|
for i1 := 1 to width - 3 do begin
|
|
iy := 1;
|
|
for i2 := 1 to height - 1 do begin
|
|
i3 := (ix - 2) shr 1 + (iy - 1) shr 1 * width;
|
|
orgPixels[0] := src[i3 ].y;
|
|
orgPixels[1] := src[i3 + 1 ].y;
|
|
orgPixels[2] := src[i3 + 2 ].y;
|
|
orgPixels[3] := src[i3 + width].y;
|
|
orgPixels[4] := src[i3 + 1 + width].y;
|
|
orgPixels[5] := src[i3 + 2 + width].y;
|
|
newPixels[0, 0] := pixels[ix - 2, iy - 1].y;
|
|
newPixels[1, 0] := pixels[ix, iy - 1].y;
|
|
newPixels[2, 0] := pixels[ix + 2, iy - 1].y;
|
|
newPixels[3, 0] := pixels[ix - 2, iy + 1].y;
|
|
newPixels[4, 0] := pixels[ix, iy + 1].y;
|
|
newPixels[5, 0] := pixels[ix + 2, iy + 1].y;
|
|
newPixels[0, 1] := weights[0];
|
|
newPixels[1, 1] := weights[1];
|
|
newPixels[2, 1] := weights[2];
|
|
newPixels[3, 1] := weights[3];
|
|
newPixels[4, 1] := weights[4];
|
|
newPixels[5, 1] := weights[5];
|
|
solve(orgPixels, newPixels, 6, pixels[ix, iy].y);
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
// step 8: save current +0+0 pixels to helper field
|
|
ix := 2;
|
|
for i1 := 2 to width - 2 do begin
|
|
iy := 2;
|
|
for i2 := 2 to height - 2 do begin
|
|
pixels[ix, iy].helper := pixels[ix, iy].y;
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
// step 9: sharpen +0+0 pixels
|
|
weights[0] := Sqrt(8);
|
|
weights[1] := 2;
|
|
weights[2] := Sqrt(8);
|
|
weights[3] := 2;
|
|
weights[4] := 0;
|
|
weights[5] := 2;
|
|
weights[6] := Sqrt(8);
|
|
weights[7] := 2;
|
|
weights[8] := Sqrt(8);
|
|
CalcWeights(weights, 9);
|
|
ix := 2;
|
|
for i1 := 2 to width - 2 do begin
|
|
iy := 2;
|
|
for i2 := 2 to height - 2 do begin
|
|
i3 := (ix - 2) shr 1 + (iy - 2) shr 1 * width;
|
|
// distances: 0, 2, Sqrt(8)
|
|
orgPixels[0] := src[i3 ].y;
|
|
orgPixels[1] := src[i3 + 1 ].y;
|
|
orgPixels[2] := src[i3 + 2 ].y;
|
|
orgPixels[3] := src[i3 + width ].y;
|
|
orgPixels[4] := src[i3 + 1 + width ].y;
|
|
orgPixels[5] := src[i3 + 2 + width ].y;
|
|
orgPixels[6] := src[i3 + width shl 1].y;
|
|
orgPixels[7] := src[i3 + 1 + width shl 1].y;
|
|
orgPixels[8] := src[i3 + 2 + width shl 1].y;
|
|
newPixels[0, 0] := pixels[ix - 2, iy - 2].helper;
|
|
newPixels[1, 0] := pixels[ix, iy - 2].helper;
|
|
newPixels[2, 0] := pixels[ix + 2, iy - 2].helper;
|
|
newPixels[3, 0] := pixels[ix - 2, iy ].helper;
|
|
newPixels[4, 0] := pixels[ix, iy ].helper;
|
|
newPixels[5, 0] := pixels[ix + 2, iy ].helper;
|
|
newPixels[6, 0] := pixels[ix - 2, iy + 2].helper;
|
|
newPixels[7, 0] := pixels[ix, iy + 2].helper;
|
|
newPixels[8, 0] := pixels[ix + 2, iy + 2].helper;
|
|
newPixels[0, 1] := weights[0];
|
|
newPixels[1, 1] := weights[1];
|
|
newPixels[2, 1] := weights[2];
|
|
newPixels[3, 1] := weights[3];
|
|
newPixels[4, 1] := weights[4];
|
|
newPixels[5, 1] := weights[5];
|
|
newPixels[6, 1] := weights[6];
|
|
newPixels[7, 1] := weights[7];
|
|
newPixels[8, 1] := weights[8];
|
|
solve(orgPixels, newPixels, 9, pixels[ix, iy].y);
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
end;
|
|
|
|
SetLength(D1, newWidth, newHeight);
|
|
SetLength(D2, newWidth, newHeight);
|
|
SetLength(D3, newWidth, newHeight);
|
|
SetLength(C1, newWidth, newHeight);
|
|
SetLength(C2, newWidth, newHeight);
|
|
|
|
// ICBI - iterative refinement (1)
|
|
for g := 0 to high(icbiStepSizes) do begin
|
|
diff := 0;
|
|
step := icbiStepSizes[g];
|
|
|
|
// computation of derivatives
|
|
for ix := 3 to newWidth - 4 do begin
|
|
iy := 4 - (ix and 1);
|
|
for i2 := 2 to height - 2 do begin
|
|
C1[ix, iy] := (pixels[ix - 1, iy - 1].y - pixels[ix + 1, iy + 1].y) / 2;
|
|
C2[ix, iy] := (pixels[ix + 1, iy - 1].y - pixels[ix - 1, iy + 1].y) / 2;
|
|
D1[ix, iy] := pixels[ix - 1, iy - 1].y + pixels[ix + 1, iy + 1].y - 2 * pixels[ix, iy].y;
|
|
D2[ix, iy] := pixels[ix + 1, iy - 1].y + pixels[ix - 1, iy + 1].y - 2 * pixels[ix, iy].y;
|
|
D3[ix, iy] := (pixels[ix, iy - 2].y - pixels[ix - 2, iy].y + pixels[ix, iy + 2].y - pixels[ix + 2, iy].y) / 2;
|
|
inc(iy, 2);
|
|
end;
|
|
end;
|
|
|
|
ix := 5;
|
|
for i1 := 3 to width - 3 do begin
|
|
iy := 5;
|
|
for i2 := 3 to height - 3 do begin
|
|
EN1 := abs(D1[ix, iy] - D1[ix + 1, iy + 1]) + abs(D1[ix, iy] - D1[ix - 1, iy - 1]);
|
|
EN2 := abs(D1[ix, iy] - D1[ix + 1, iy - 1]) + abs(D1[ix, iy] - D1[ix - 1, iy + 1]);
|
|
EN3 := abs(D2[ix, iy] - D2[ix + 1, iy + 1]) + abs(D2[ix, iy] - D2[ix - 1, iy - 1]);
|
|
EN4 := abs(D2[ix, iy] - D2[ix + 1, iy - 1]) + abs(D2[ix, iy] - D2[ix - 1, iy + 1]);
|
|
EN5 := abs(pixels[ix - 2, iy - 2].y + pixels[ix + 2, iy + 2].y - 2 * pixels[ix, iy].y);
|
|
EN6 := abs(pixels[ix + 2, iy - 2].y + pixels[ix - 2, iy + 2].y - 2 * pixels[ix, iy].y);
|
|
|
|
EA1 := abs(D1[ix, iy] - D1[ix + 1, iy + 1] - 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy - 1] - 3 * step);
|
|
EA2 := abs(D1[ix, iy] - D1[ix + 1, iy - 1] - 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy + 1] - 3 * step);
|
|
EA3 := abs(D2[ix, iy] - D2[ix + 1, iy + 1] - 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy - 1] - 3 * step);
|
|
EA4 := abs(D2[ix, iy] - D2[ix + 1, iy - 1] - 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy + 1] - 3 * step);
|
|
EA5 := abs(pixels[ix - 2, iy - 2].y + pixels[ix + 2, iy + 2].y - 2 * pixels[ix, iy].y - 2 * step);
|
|
EA6 := abs(pixels[ix + 2, iy - 2].y + pixels[ix - 2, iy + 2].y - 2 * pixels[ix, iy].y - 2 * step);
|
|
|
|
ES1 := abs(D1[ix, iy] - D1[ix + 1, iy + 1] + 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy - 1] + 3 * step);
|
|
ES2 := abs(D1[ix, iy] - D1[ix + 1, iy - 1] + 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy + 1] + 3 * step);
|
|
ES3 := abs(D2[ix, iy] - D2[ix + 1, iy + 1] + 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy - 1] + 3 * step);
|
|
ES4 := abs(D2[ix, iy] - D2[ix + 1, iy - 1] + 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy + 1] + 3 * step);
|
|
ES5 := abs(pixels[ix - 2, iy - 2].y + pixels[ix + 2, iy + 2].y - 2 * pixels[ix, iy].y + 2 * step);
|
|
ES6 := abs(pixels[ix + 2, iy - 2].y + pixels[ix - 2, iy + 2].y - 2 * pixels[ix, iy].y + 2 * step);
|
|
|
|
if (C1[ix, iy] <> 0) or (C2[ix, iy] <> 0) then begin
|
|
EISO := (C1[ix, iy] * C1[ix, iy] * D2[ix, iy] - 2 * C1[ix, iy] * C2[ix, iy] * D3[ix, iy] + C2[ix, iy] * C2[ix, iy] * D1[ix, iy]) / (C1[ix, iy] * C1[ix, iy] + C2[ix, iy] * C2[ix, iy]);
|
|
if abs(EISO) < 0.2 then
|
|
EISO := 0;
|
|
end else
|
|
EISO := 0;
|
|
|
|
EN := (AL * (EN1 + EN2 + EN3 + EN4)) + (BT * (EN5 + EN6));
|
|
EA := (AL * (EA1 + EA2 + EA3 + EA4)) + (BT * (EA5 + EA6)) - (GM * sign(EISO));
|
|
ES := (AL * (ES1 + ES2 + ES3 + ES4)) + (BT * (ES5 + ES6)) + (GM * sign(EISO));
|
|
|
|
if (EN > EA) and (ES > EA) then begin
|
|
if pixels[ix, iy].y + step > 255 then
|
|
pixels[ix, iy].y := 255
|
|
else
|
|
pixels[ix, iy].y := pixels[ix, iy].y + step;
|
|
|
|
maxValue := pixels[ix - 1, iy - 1].y;
|
|
testValue := pixels[ix - 1, iy + 1].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy + 1].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy - 1].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
if pixels[ix, iy].y > maxValue then
|
|
pixels[ix, iy].y := maxValue;
|
|
|
|
diff := diff + step;
|
|
end else
|
|
if (EN > ES) and (EA > ES) then begin
|
|
if pixels[ix, iy].y <= step then
|
|
pixels[ix, iy].y := 0
|
|
else
|
|
pixels[ix, iy].y := pixels[ix, iy].y - step;
|
|
|
|
maxValue := pixels[ix - 1, iy - 1].y;
|
|
testValue := pixels[ix - 1, iy + 1].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy + 1].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy - 1].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
if pixels[ix, iy].y < maxValue then
|
|
pixels[ix, iy].y := maxValue;
|
|
|
|
diff := diff + step;
|
|
end;
|
|
|
|
inc(iy, 2);
|
|
end;
|
|
inc(ix, 2);
|
|
end;
|
|
|
|
if diff < TS then
|
|
break;
|
|
end;
|
|
|
|
// ICBI - iterative refinement (2)
|
|
for g := 0 to high(icbiStepSizes) do begin
|
|
diff := 0;
|
|
step := icbiStepSizes[g];
|
|
|
|
// computation of derivatives
|
|
for ix := 1 to newWidth - 3 do
|
|
for iy := 1 to newHeight - 3 do begin
|
|
C1[ix, iy] := (pixels[ix, iy - 1].y - pixels[ix, iy + 1].y) / 2;
|
|
C2[ix, iy] := (pixels[ix - 1, iy].y - pixels[ix + 1, iy].y) / 2;
|
|
D1[ix, iy] := pixels[ix, iy - 1].y + pixels[ix, iy + 1].y - 2 * pixels[ix, iy].y;
|
|
D2[ix, iy] := pixels[ix + 1, iy].y + pixels[ix - 1, iy].y - 2 * pixels[ix, iy].y;
|
|
D3[ix, iy] := (pixels[ix - 1, iy - 1].y - pixels[ix - 1, iy + 1].y + pixels[ix + 1, iy + 1].y - pixels[ix + 1, iy - 1].y) / 2;
|
|
end;
|
|
|
|
for ix := 2 to newWidth - 3 do begin
|
|
iy := 3 - (ix and 1);
|
|
for i2 := 1 to height - 2 do begin
|
|
EN1 := abs(D1[ix, iy] - D1[ix, iy + 1]) + abs(D1[ix, iy] - D1[ix, iy - 1]);
|
|
EN2 := abs(D1[ix, iy] - D1[ix + 1, iy]) + abs(D1[ix, iy] - D1[ix - 1, iy]);
|
|
EN3 := abs(D2[ix, iy] - D2[ix, iy + 1]) + abs(D2[ix, iy] - D2[ix, iy - 1]);
|
|
EN4 := abs(D2[ix, iy] - D2[ix + 1, iy]) + abs(D2[ix, iy] - D2[ix - 1, iy]);
|
|
EN5 := abs(pixels[ix, iy - 2].y + pixels[ix, iy + 2].y - 2 * pixels[ix, iy].y);
|
|
EN6 := abs(pixels[ix + 2, iy].y + pixels[ix - 2, iy].y - 2 * pixels[ix, iy].y);
|
|
|
|
EA1 := abs(D1[ix, iy] - D1[ix, iy + 1] - 3 * step) + abs(D1[ix, iy] - D1[ix, iy - 1] - 3 * step);
|
|
EA2 := abs(D1[ix, iy] - D1[ix + 1, iy] - 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy] - 3 * step);
|
|
EA3 := abs(D2[ix, iy] - D2[ix, iy + 1] - 3 * step) + abs(D2[ix, iy] - D2[ix, iy - 1] - 3 * step);
|
|
EA4 := abs(D2[ix, iy] - D2[ix + 1, iy] - 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy] - 3 * step);
|
|
EA5 := abs(pixels[ix, iy - 2].y + pixels[ix, iy + 2].y - 2 * pixels[ix, iy].y - 2 * step);
|
|
EA6 := abs(pixels[ix + 2, iy].y + pixels[ix - 2, iy].y - 2 * pixels[ix, iy].y - 2 * step);
|
|
|
|
ES1 := abs(D1[ix, iy] - D1[ix, iy + 1] + 3 * step) + abs(D1[ix, iy] - D1[ix, iy - 1] + 3 * step);
|
|
ES2 := abs(D1[ix, iy] - D1[ix + 1, iy] + 3 * step) + abs(D1[ix, iy] - D1[ix - 1, iy] + 3 * step);
|
|
ES3 := abs(D2[ix, iy] - D2[ix, iy + 1] + 3 * step) + abs(D2[ix, iy] - D2[ix, iy - 1] + 3 * step);
|
|
ES4 := abs(D2[ix, iy] - D2[ix + 1, iy] + 3 * step) + abs(D2[ix, iy] - D2[ix - 1, iy] + 3 * step);
|
|
ES5 := abs(pixels[ix, iy - 2].y + pixels[ix, iy + 2].y - 2 * pixels[ix, iy].y + 2 * step);
|
|
ES6 := abs(pixels[ix + 2, iy].y + pixels[ix - 2, iy].y - 2 * pixels[ix, iy].y + 2 * step);
|
|
|
|
if (C1[ix, iy] <> 0) or (C2[ix, iy] <> 0) then begin
|
|
EISO := (C1[ix, iy] * C1[ix, iy] * D2[ix, iy] - 2 * C1[ix, iy] * C2[ix, iy] * D3[ix, iy] + C2[ix, iy] * C2[ix, iy] * D1[ix, iy]) / (C1[ix, iy] * C1[ix, iy] + C2[ix, iy] * C2[ix, iy]);
|
|
if abs(EISO) < 0.2 then
|
|
EISO := 0;
|
|
end else
|
|
EISO := 0;
|
|
|
|
EN := (AL * (EN1 + EN2 + EN3 + EN4)) + (BT * (EN5 + EN6));
|
|
EA := (AL * (EA1 + EA2 + EA3 + EA4)) + (BT * (EA5 + EA6)) - (GM * sign(EISO));
|
|
ES := (AL * (ES1 + ES2 + ES3 + ES4)) + (BT * (ES5 + ES6)) + (GM * sign(EISO));
|
|
|
|
if (EN > EA) and (ES > EA) then begin
|
|
if pixels[ix, iy].y + step > 255 then
|
|
pixels[ix, iy].y := 255
|
|
else
|
|
pixels[ix, iy].y := pixels[ix, iy].y + step;
|
|
|
|
maxValue := pixels[ix, iy - 1].y;
|
|
testValue := pixels[ix - 1, iy].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
testValue := pixels[ix, iy + 1].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy].y;
|
|
if testValue > maxValue then maxValue := testValue;
|
|
if pixels[ix, iy].y > maxValue then
|
|
pixels[ix, iy].y := maxValue;
|
|
|
|
diff := diff + step;
|
|
end else
|
|
if (EN > ES) and (EA > ES) then begin
|
|
if pixels[ix, iy].y <= step then
|
|
pixels[ix, iy].y := 0
|
|
else
|
|
pixels[ix, iy].y := pixels[ix, iy].y - step;
|
|
|
|
maxValue := pixels[ix, iy - 1].y;
|
|
testValue := pixels[ix - 1, iy].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
testValue := pixels[ix, iy + 1].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
testValue := pixels[ix + 1, iy].y;
|
|
if testValue < maxValue then maxValue := testValue;
|
|
if pixels[ix, iy].y < maxValue then
|
|
pixels[ix, iy].y := maxValue;
|
|
|
|
diff := diff + step;
|
|
end;
|
|
|
|
inc(iy, 2);
|
|
end;
|
|
end;
|
|
|
|
if diff < TS then
|
|
break;
|
|
end;
|
|
|
|
for ix := 0 to newWidth - 1 do
|
|
for iy := 0 to newHeight - 1 do
|
|
dst[iy * newWidth + ix] := pixels[ix, iy];
|
|
end;
|
|
|
|
procedure ICBI(bmp: TBitmap; steps: integer);
|
|
var src : array of TYCbCr;
|
|
dst : array of TYCbCr;
|
|
i1, i2 : integer;
|
|
pixel : integer;
|
|
red, green, blue : integer;
|
|
y, cb, cr : single;
|
|
begin
|
|
SetLength(src, bmp.Width * bmp.Height);
|
|
SetLength(dst, bmp.Width * 2 * bmp.Height * 2);
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
pixel := bmp.Canvas.Pixels[i1, i2];
|
|
red := pixel and $ff;
|
|
green := (pixel shr 8) and $ff;
|
|
blue := (pixel shr 16) and $ff;
|
|
y := red * 0.299 + green * 0.587 + blue * 0.114;
|
|
cb := $80 + red * -0.1687358916478555 + green * -0.3312641083521445 + blue * 0.5;
|
|
cr := $80 + red * 0.5 + green * -0.4186875891583452 + blue * -0.0813124108416548;
|
|
if y < 0 then
|
|
y := 0
|
|
else
|
|
if y > 255 then
|
|
y := 255;
|
|
if cb < 0 then
|
|
cb := 0
|
|
else
|
|
if cb > 255 then
|
|
cb := 255;
|
|
if cr < 0 then
|
|
cr := 0
|
|
else
|
|
if cr >= 255 then
|
|
cr := 255;
|
|
src[i2 * bmp.Width + i1].y := y;
|
|
src[i2 * bmp.Width + i1].cb := cb;
|
|
src[i2 * bmp.Width + i1].cr := cr;
|
|
end;
|
|
case steps of
|
|
0 : ICBI1Plane(@src[0], @dst[0], bmp.Width, bmp.Height, [], 0.5625, -0.0625);
|
|
1 : ICBI1Plane(@src[0], @dst[0], bmp.Width, bmp.Height, [8], 0.5625, -0.0625);
|
|
2 : ICBI1Plane(@src[0], @dst[0], bmp.Width, bmp.Height, [6, 10], 0.5625, -0.0625);
|
|
3 : ICBI1Plane(@src[0], @dst[0], bmp.Width, bmp.Height, [3, 6, 10], 0.5625, -0.0625);
|
|
else ICBI1Plane(@src[0], @dst[0], bmp.Width, bmp.Height, [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 6, 6, 6, 6, 10, 10, 10, 10], 0.5625, -0.0625);
|
|
end;
|
|
bmp.Width := bmp.Width * 2 - 1;
|
|
bmp.Height := bmp.Height * 2 - 1;
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
y := dst[i2 * bmp.Width + i1].y;
|
|
cb := dst[i2 * bmp.Width + i1].cb - $80;
|
|
cr := dst[i2 * bmp.Width + i1].cr - $80;
|
|
red := round(y + cr * 1.402);
|
|
green := round(y + cb * -0.3441362862010221 + cr * -0.7141362862010221);
|
|
blue := round(y + cb * 1.772);
|
|
if red < 0 then
|
|
red := 0
|
|
else
|
|
if red > 255 then
|
|
red := 255;
|
|
if green < 0 then
|
|
green := 0
|
|
else
|
|
if green > 255 then
|
|
green := 255;
|
|
if blue < 0 then
|
|
blue := 0
|
|
else
|
|
if blue > 255 then
|
|
blue := 255;
|
|
bmp.Canvas.Pixels[i1, i2] := blue shl 16 + green shl 8 + red;
|
|
end;
|
|
end;
|
|
|
|
procedure PR(bmp: TBitmap; icbiSteps, sharpenIterations: integer);
|
|
var src, dst : array of TYCbCr;
|
|
srcY, dstY : array of byte;
|
|
i1, i2 : integer;
|
|
pixel : integer;
|
|
red, green, blue : integer;
|
|
y, cb, cr : single;
|
|
begin
|
|
SetLength(src, bmp.Width * bmp.Height);
|
|
SetLength(dst, bmp.Width * 2 * bmp.Height * 2);
|
|
SetLength(srcY, bmp.Width * bmp.Height);
|
|
SetLength(dstY, bmp.Width * 2 * bmp.Height * 2);
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
pixel := bmp.Canvas.Pixels[i1, i2];
|
|
red := pixel and $ff;
|
|
green := (pixel shr 8) and $ff;
|
|
blue := (pixel shr 16) and $ff;
|
|
y := red * 0.299 + green * 0.587 + blue * 0.114;
|
|
cb := $80 + red * -0.1687358916478555 + green * -0.3312641083521445 + blue * 0.5;
|
|
cr := $80 + red * 0.5 + green * -0.4186875891583452 + blue * -0.0813124108416548;
|
|
if y < 0 then
|
|
y := 0
|
|
else
|
|
if y > 255 then
|
|
y := 255;
|
|
if cb < 0 then
|
|
cb := 0
|
|
else
|
|
if cb > 255 then
|
|
cb := 255;
|
|
if cr < 0 then
|
|
cr := 0
|
|
else
|
|
if cr >= 255 then
|
|
cr := 255;
|
|
src[i2 * bmp.Width + i1].y := y;
|
|
src[i2 * bmp.Width + i1].cb := cb;
|
|
src[i2 * bmp.Width + i1].cr := cr;
|
|
srcY[i2 * bmp.Width + i1] := round(y);
|
|
end;
|
|
|
|
case icbiSteps of
|
|
0 : PRPlane(@src[0], @dst[0], bmp.Width, bmp.Height, [], sharpenIterations);
|
|
1 : PRPlane(@src[0], @dst[0], bmp.Width, bmp.Height, [8], sharpenIterations);
|
|
2 : PRPlane(@src[0], @dst[0], bmp.Width, bmp.Height, [6, 10], sharpenIterations);
|
|
3 : PRPlane(@src[0], @dst[0], bmp.Width, bmp.Height, [3, 6, 10], sharpenIterations);
|
|
else PRPlane(@src[0], @dst[0], bmp.Width, bmp.Height, [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 6, 6, 6, 6, 10, 10, 10, 10], sharpenIterations);
|
|
end;
|
|
|
|
bmp.Width := bmp.Width * 2 - 1;
|
|
bmp.Height := bmp.Height * 2 - 1;
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
y := dst[i2 * bmp.Width + i1].y;
|
|
if y < 0 then
|
|
y := 0;
|
|
cb := dst[i2 * bmp.Width + i1].cb;
|
|
if cb < 0 then
|
|
cb := -$80
|
|
else
|
|
cb := cb - $80;
|
|
cr := dst[i2 * bmp.Width + i1].cr;
|
|
if cr < 0 then
|
|
cr := -$80
|
|
else
|
|
cr := cr - $80;
|
|
red := round(y + cr * 1.402);
|
|
green := round(y + cb * -0.3441362862010221 + cr * -0.7141362862010221);
|
|
blue := round(y + cb * 1.772);
|
|
if red < 0 then
|
|
red := 0
|
|
else
|
|
if red > 255 then
|
|
red := 255;
|
|
if green < 0 then
|
|
green := 0
|
|
else
|
|
if green > 255 then
|
|
green := 255;
|
|
if blue < 0 then
|
|
blue := 0
|
|
else
|
|
if blue > 255 then
|
|
blue := 255;
|
|
bmp.Canvas.Pixels[i1, i2] := blue shl 16 + green shl 8 + red;
|
|
end;
|
|
end;
|
|
|
|
procedure Geometric(bmp: TBitmap);
|
|
var src, dst : array of TYCbCr;
|
|
srcY, dstY : array of byte;
|
|
i1, i2 : integer;
|
|
pixel : integer;
|
|
red, green, blue : integer;
|
|
y, cb, cr : single;
|
|
begin
|
|
SetLength(src, bmp.Width * bmp.Height);
|
|
SetLength(dst, bmp.Width * 2 * bmp.Height * 2);
|
|
SetLength(srcY, bmp.Width * bmp.Height);
|
|
SetLength(dstY, bmp.Width * 2 * bmp.Height * 2);
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
pixel := bmp.Canvas.Pixels[i1, i2];
|
|
red := pixel and $ff;
|
|
green := (pixel shr 8) and $ff;
|
|
blue := (pixel shr 16) and $ff;
|
|
y := red * 0.299 + green * 0.587 + blue * 0.114;
|
|
cb := $80 + red * -0.1687358916478555 + green * -0.3312641083521445 + blue * 0.5;
|
|
cr := $80 + red * 0.5 + green * -0.4186875891583452 + blue * -0.0813124108416548;
|
|
if y < 0 then
|
|
y := 0
|
|
else
|
|
if y > 255 then
|
|
y := 255;
|
|
if cb < 0 then
|
|
cb := 0
|
|
else
|
|
if cb > 255 then
|
|
cb := 255;
|
|
if cr < 0 then
|
|
cr := 0
|
|
else
|
|
if cr >= 255 then
|
|
cr := 255;
|
|
src[i2 * bmp.Width + i1].y := y;
|
|
src[i2 * bmp.Width + i1].cb := cb;
|
|
src[i2 * bmp.Width + i1].cr := cr;
|
|
srcY[i2 * bmp.Width + i1] := round(y);
|
|
end;
|
|
|
|
GeometricPlane(@src[0], @dst[0], bmp.Width, bmp.Height);
|
|
|
|
bmp.Width := bmp.Width * 2 - 1;
|
|
bmp.Height := bmp.Height * 2 - 1;
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
y := dst[i2 * bmp.Width + i1].y;
|
|
if y < 0 then
|
|
y := 0;
|
|
cb := dst[i2 * bmp.Width + i1].cb;
|
|
if cb < 0 then
|
|
cb := 0
|
|
else
|
|
cb := cb - $80;
|
|
cr := dst[i2 * bmp.Width + i1].cr;
|
|
if cr < 0 then
|
|
cr := 0
|
|
else
|
|
cr := cr - $80;
|
|
red := round(y + cr * 1.402);
|
|
green := round(y + cb * -0.3441362862010221 + cr * -0.7141362862010221);
|
|
blue := round(y + cb * 1.772);
|
|
if red < 0 then
|
|
red := 0
|
|
else
|
|
if red > 255 then
|
|
red := 255;
|
|
if green < 0 then
|
|
green := 0
|
|
else
|
|
if green > 255 then
|
|
green := 255;
|
|
if blue < 0 then
|
|
blue := 0
|
|
else
|
|
if blue > 255 then
|
|
blue := 255;
|
|
bmp.Canvas.Pixels[i1, i2] := blue shl 16 + green shl 8 + red;
|
|
end;
|
|
end;
|
|
|
|
procedure FuzzyEla(bmp: TBitmap);
|
|
var src, dst : array of TYCbCr;
|
|
srcY, dstY : array of byte;
|
|
i1, i2 : integer;
|
|
pixel : integer;
|
|
red, green, blue : integer;
|
|
y, cb, cr : single;
|
|
begin
|
|
SetLength(src, bmp.Width * bmp.Height);
|
|
SetLength(dst, bmp.Width * 2 * bmp.Height * 2);
|
|
SetLength(srcY, bmp.Width * bmp.Height);
|
|
SetLength(dstY, bmp.Width * 2 * bmp.Height * 2);
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
pixel := bmp.Canvas.Pixels[i1, i2];
|
|
red := pixel and $ff;
|
|
green := (pixel shr 8) and $ff;
|
|
blue := (pixel shr 16) and $ff;
|
|
y := red * 0.299 + green * 0.587 + blue * 0.114;
|
|
cb := $80 + red * -0.1687358916478555 + green * -0.3312641083521445 + blue * 0.5;
|
|
cr := $80 + red * 0.5 + green * -0.4186875891583452 + blue * -0.0813124108416548;
|
|
if y < 0 then
|
|
y := 0
|
|
else
|
|
if y > 255 then
|
|
y := 255;
|
|
if cb < 0 then
|
|
cb := 0
|
|
else
|
|
if cb > 255 then
|
|
cb := 255;
|
|
if cr < 0 then
|
|
cr := 0
|
|
else
|
|
if cr >= 255 then
|
|
cr := 255;
|
|
src[i2 * bmp.Width + i1].y := y;
|
|
src[i2 * bmp.Width + i1].cb := cb;
|
|
src[i2 * bmp.Width + i1].cr := cr;
|
|
srcY[i2 * bmp.Width + i1] := round(y);
|
|
end;
|
|
|
|
FuzzyElaPlane(@src[0], @dst[0], bmp.Width, bmp.Height);
|
|
|
|
bmp.Width := bmp.Width * 2 - 1;
|
|
bmp.Height := bmp.Height * 2 - 1;
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
y := dst[i2 * bmp.Width + i1].y;
|
|
if y < 0 then
|
|
y := 0;
|
|
cb := dst[i2 * bmp.Width + i1].cb;
|
|
if cb < 0 then
|
|
cb := 0
|
|
else
|
|
cb := cb - $80;
|
|
cr := dst[i2 * bmp.Width + i1].cr;
|
|
if cr < 0 then
|
|
cr := 0
|
|
else
|
|
cr := cr - $80;
|
|
red := round(y + cr * 1.402);
|
|
green := round(y + cb * -0.3441362862010221 + cr * -0.7141362862010221);
|
|
blue := round(y + cb * 1.772);
|
|
if red < 0 then
|
|
red := 0
|
|
else
|
|
if red > 255 then
|
|
red := 255;
|
|
if green < 0 then
|
|
green := 0
|
|
else
|
|
if green > 255 then
|
|
green := 255;
|
|
if blue < 0 then
|
|
blue := 0
|
|
else
|
|
if blue > 255 then
|
|
blue := 255;
|
|
bmp.Canvas.Pixels[i1, i2] := blue shl 16 + green shl 8 + red;
|
|
end;
|
|
end;
|
|
|
|
procedure NediPlane(src: TPAByte; width, height, srcPitch: integer; dst: TPAByte; dstPitch: integer);
|
|
|
|
const
|
|
threshold4 : double = 1000;
|
|
threshold8 : double = 2000;
|
|
threshold16 : double = 4000;
|
|
constraint : integer = 2;
|
|
mvar : integer = 16 shl 4;
|
|
coef1 : double = 0.5625;
|
|
coef2 : double = -0.0625;
|
|
|
|
function CheckVariance(const pc: array of integer) : boolean;
|
|
var sum, sumsq : integer;
|
|
begin
|
|
sum := pc[0] + pc[1] + pc[2] + pc[3];
|
|
sumsq := pc[0] * pc[0] + pc[1] * pc[1] + pc[2] * pc[2] + pc[3] * pc[3];
|
|
result := sumsq shl 2 - sum * sum > mvar;
|
|
end;
|
|
|
|
function Interpolate(p1, p2, p3, p4: byte) : byte;
|
|
var i1 : integer;
|
|
begin
|
|
i1 := Round((p2 + p3) * coef1 + (p1 + p4) * coef2);
|
|
if i1 < 0 then
|
|
i1 := 0
|
|
else
|
|
if i1 > 255 then
|
|
i1 := 255;
|
|
result := i1;
|
|
end;
|
|
|
|
type
|
|
TMatrix4 = record case boolean of
|
|
false : (arr: array [0..3] of array [0..3] of double);
|
|
true : (flt: array [0..15] of double);
|
|
end;
|
|
TMatrix8 = record case boolean of
|
|
false : (arr: array [0..7] of array [0..7] of double);
|
|
true : (flt: array [0..63] of double);
|
|
end;
|
|
|
|
function InvertMatrix4(var src: TMatrix4; var dst: TMatrix4) : boolean;
|
|
// from doom3 sdk
|
|
const MATRIX_INVERSE_EPSILON = 1e-14;
|
|
var r0, r1, r2, r3 : array [0..1] of array [0..1] of double;
|
|
a, det, invDet : double;
|
|
begin
|
|
result := false;
|
|
|
|
// inverse r0
|
|
det := src.flt[0*4+0] * src.flt[1*4+1] - src.flt[0*4+1] * src.flt[1*4+0];
|
|
if abs(det) < MATRIX_INVERSE_EPSILON then
|
|
exit;
|
|
|
|
invDet := 1 / det;
|
|
r0[0][0] := src.flt[1*4+1] * invDet;
|
|
r0[0][1] := - src.flt[0*4+1] * invDet;
|
|
r0[1][0] := - src.flt[1*4+0] * invDet;
|
|
r0[1][1] := src.flt[0*4+0] * invDet;
|
|
|
|
// r1 := r0 * m1;
|
|
r1[0][0] := r0[0][0] * src.flt[0*4+2] + r0[0][1] * src.flt[1*4+2];
|
|
r1[0][1] := r0[0][0] * src.flt[0*4+3] + r0[0][1] * src.flt[1*4+3];
|
|
r1[1][0] := r0[1][0] * src.flt[0*4+2] + r0[1][1] * src.flt[1*4+2];
|
|
r1[1][1] := r0[1][0] * src.flt[0*4+3] + r0[1][1] * src.flt[1*4+3];
|
|
|
|
// r2 := m2 * r1;
|
|
r2[0][0] := src.flt[2*4+0] * r1[0][0] + src.flt[2*4+1] * r1[1][0];
|
|
r2[0][1] := src.flt[2*4+0] * r1[0][1] + src.flt[2*4+1] * r1[1][1];
|
|
r2[1][0] := src.flt[3*4+0] * r1[0][0] + src.flt[3*4+1] * r1[1][0];
|
|
r2[1][1] := src.flt[3*4+0] * r1[0][1] + src.flt[3*4+1] * r1[1][1];
|
|
|
|
// r3 := r2 - m3;
|
|
r3[0][0] := r2[0][0] - src.flt[2*4+2];
|
|
r3[0][1] := r2[0][1] - src.flt[2*4+3];
|
|
r3[1][0] := r2[1][0] - src.flt[3*4+2];
|
|
r3[1][1] := r2[1][1] - src.flt[3*4+3];
|
|
|
|
// inverse r3
|
|
det := r3[0][0] * r3[1][1] - r3[0][1] * r3[1][0];
|
|
if det < MATRIX_INVERSE_EPSILON then
|
|
exit;
|
|
|
|
invDet := 1 / det;
|
|
a := r3[0][0];
|
|
r3[0][0] := r3[1][1] * invDet;
|
|
r3[0][1] := - r3[0][1] * invDet;
|
|
r3[1][0] := - r3[1][0] * invDet;
|
|
r3[1][1] := a * invDet;
|
|
|
|
// r2 := m2 * r0;
|
|
r2[0][0] := src.flt[2*4+0] * r0[0][0] + src.flt[2*4+1] * r0[1][0];
|
|
r2[0][1] := src.flt[2*4+0] * r0[0][1] + src.flt[2*4+1] * r0[1][1];
|
|
r2[1][0] := src.flt[3*4+0] * r0[0][0] + src.flt[3*4+1] * r0[1][0];
|
|
r2[1][1] := src.flt[3*4+0] * r0[0][1] + src.flt[3*4+1] * r0[1][1];
|
|
|
|
// m2 := r3 * r2;
|
|
dst.flt[2*4+0] := r3[0][0] * r2[0][0] + r3[0][1] * r2[1][0];
|
|
dst.flt[2*4+1] := r3[0][0] * r2[0][1] + r3[0][1] * r2[1][1];
|
|
dst.flt[3*4+0] := r3[1][0] * r2[0][0] + r3[1][1] * r2[1][0];
|
|
dst.flt[3*4+1] := r3[1][0] * r2[0][1] + r3[1][1] * r2[1][1];
|
|
|
|
// m0 := r0 - r1 * m2;
|
|
dst.flt[0*4+0] := r0[0][0] - r1[0][0] * dst.flt[2*4+0] - r1[0][1] * dst.flt[3*4+0];
|
|
dst.flt[0*4+1] := r0[0][1] - r1[0][0] * dst.flt[2*4+1] - r1[0][1] * dst.flt[3*4+1];
|
|
dst.flt[1*4+0] := r0[1][0] - r1[1][0] * dst.flt[2*4+0] - r1[1][1] * dst.flt[3*4+0];
|
|
dst.flt[1*4+1] := r0[1][1] - r1[1][0] * dst.flt[2*4+1] - r1[1][1] * dst.flt[3*4+1];
|
|
|
|
// m1 := r1 * r3;
|
|
dst.flt[0*4+2] := r1[0][0] * r3[0][0] + r1[0][1] * r3[1][0];
|
|
dst.flt[0*4+3] := r1[0][0] * r3[0][1] + r1[0][1] * r3[1][1];
|
|
dst.flt[1*4+2] := r1[1][0] * r3[0][0] + r1[1][1] * r3[1][0];
|
|
dst.flt[1*4+3] := r1[1][0] * r3[0][1] + r1[1][1] * r3[1][1];
|
|
|
|
// m3 := -r3;
|
|
dst.flt[2*4+2] := -r3[0][0];
|
|
dst.flt[2*4+3] := -r3[0][1];
|
|
dst.flt[3*4+2] := -r3[1][0];
|
|
dst.flt[3*4+3] := -r3[1][1];
|
|
|
|
result := true;
|
|
end;
|
|
|
|
function InvertMatrix8(const src: TMatrix8; var dst: TMatrix8) : boolean;
|
|
const initdst : TMatrix8 = (flt: (1, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 1, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 1, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 1, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 1, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 1, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 1));
|
|
var ctc : TMatrix8;
|
|
best, i1, i2, i3 : integer;
|
|
temp, scale : double;
|
|
begin
|
|
result := false;
|
|
ctc := src;
|
|
dst := initdst;
|
|
for i1 := 0 to 7 do begin
|
|
best := i1;
|
|
for i2 := i1 + 1 to 7 do
|
|
if abs(ctc.arr[best][i1]) < abs(ctc.arr[i2][i1]) then
|
|
best := i2;
|
|
if best <> i1 then
|
|
for i3 := 0 to 7 do begin
|
|
temp := ctc.arr[i1][i3];
|
|
ctc.arr[i1][i3] := ctc.arr[best][i3];
|
|
ctc.arr[best][i3] := temp;
|
|
temp := dst.arr[i1][i3];
|
|
dst.arr[i1][i3] := dst.arr[best][i3];
|
|
dst.arr[best][i3] := temp;
|
|
end;
|
|
if ctc.arr[i1][i1] = 0 then
|
|
exit;
|
|
|
|
temp := ctc.arr[i1][i1];
|
|
for i3 := 0 to 7 do
|
|
if i3 <> i1 then begin
|
|
scale := -(ctc.arr[i3][i1]/temp);
|
|
for i2 := 0 to 7 do begin
|
|
ctc.arr[i3][i2] := ctc.arr[i3][i2] + (ctc.arr[i1][i2] * scale);
|
|
dst.arr[i3][i2] := dst.arr[i3][i2] + (dst.arr[i1][i2] * scale);
|
|
end;
|
|
ctc.arr[i3][i1] := 0;
|
|
end;
|
|
end;
|
|
for i1 := 0 to 7 do
|
|
if ctc.arr[i1][i1] <> 1 then begin
|
|
scale := 1 / ctc.arr[i1][i1];
|
|
for i3 := 0 to 7 do
|
|
dst.arr[i1][i3] := dst.arr[i1][i3] * scale;
|
|
ctc.arr[i1][i1] := 1;
|
|
end;
|
|
|
|
result := true;
|
|
end;
|
|
|
|
type
|
|
TA256Int = array [0..255] of integer;
|
|
TA256x4Int = array [0..255] of array [0..3] of integer;
|
|
|
|
function ConditionNumber(const CtC, CtCi: TMatrix4) : double;
|
|
// uses the max row sum norm since its easy to compute
|
|
var highest1, highest2, temp : double;
|
|
i : integer;
|
|
begin
|
|
highest1 := abs(CtCi.arr[0][0]) + abs(CtCi.arr[0][1]) + abs(CtCi.arr[0][2]) + abs(CtCi.arr[0][3]);
|
|
highest2 := abs(CtC.arr[0][0]) + abs(CtC.arr[0][1]) + abs(CtC.arr[0][2]) + abs(CtC.arr[0][3]);
|
|
for i := 1 to 3 do begin
|
|
temp := abs(CtCi.arr[i][0]) + abs(CtCi.arr[i][1]) + abs(CtCi.arr[i][2]) + abs(CtCi.arr[i][3]);
|
|
if temp > highest1 then
|
|
highest1 := temp;
|
|
temp := abs(CtC.arr[i][0]) + abs(CtC.arr[i][1]) + abs(CtC.arr[i][2]) + abs(CtC.arr[i][3]);
|
|
if temp > highest2 then
|
|
highest2 := temp;
|
|
end;
|
|
result := highest1 * highest2;
|
|
end;
|
|
|
|
function NEDI_4x4(const p: TA256Int; const n: TA256x4Int; var output: byte) : boolean;
|
|
var i, j, k, final : integer;
|
|
a, r : array [0..3] of double;
|
|
CtC, CtCi : TMatrix4;
|
|
s : double;
|
|
begin
|
|
result := false;
|
|
|
|
// compute covariance matrix CtC := Ct * C (4x16 * 16x4 = 4x4)
|
|
for i := 0 to 3 do
|
|
for j := i to 3 do begin
|
|
s := 0;
|
|
for k := 0 to 15 do
|
|
s := s + n[k][i] * n[k][j];
|
|
CtC.arr[i][j] := s;
|
|
CtC.arr[j][i] := s;
|
|
end;
|
|
|
|
// compute CtCi (CtC inverse)
|
|
if not InvertMatrix4(CtC, CtCi) then
|
|
exit;
|
|
|
|
// compute condition number
|
|
if (threshold4 > 0) and (ConditionNumber(CtC, CtCi) >= threshold4) then
|
|
exit;
|
|
|
|
// compute matrix r[] := Ct * p (4x16 * 16x1 = 4x1)
|
|
for i := 0 to 3 do begin
|
|
s := 0;
|
|
for k := 0 to 15 do
|
|
s := s + n[k][i] * p[k];
|
|
r[i] := s;
|
|
end;
|
|
|
|
// compute weights (CtCi[] * r[]) (4x4 * 4x1 = 4x1)
|
|
for i := 0 to 3 do begin
|
|
s := 0;
|
|
for k := 0 to 3 do
|
|
s := s + CtCi.arr[i][k] * r[k];
|
|
a[i] := s;
|
|
end;
|
|
|
|
// calculate interpolated pixel
|
|
final := round(p[3] * a[0] + p[6] * a[1] + p[9] * a[2] + p[12] * a[3]);
|
|
if ( (constraint = 1) and
|
|
((final > 255) or (final < 0)) ) or
|
|
( (constraint = 2) and
|
|
( (final > max(max(p[3], p[6]), max(p[9], p[12])) + 5) or
|
|
(final < min(min(p[3], p[6]), min(p[9], p[12])) - 5) ) ) then
|
|
exit;
|
|
|
|
if final > 255 then
|
|
final := 255
|
|
else
|
|
if final < 0 then
|
|
final := 0;
|
|
|
|
output := final;
|
|
result := true;
|
|
end;
|
|
|
|
function NEDI_8x8(const p: TA256Int; const n: TA256x4Int; var output: byte) : boolean;
|
|
var i, j, k, final : integer;
|
|
a, r : array [0..3] of double;
|
|
CtC, CtCi : TMatrix4;
|
|
s : double;
|
|
begin
|
|
result := false;
|
|
|
|
// compute covariance matrix CtC := Ct * C (4x64 * 64x4 = 4x4)
|
|
for i := 0 to 3 do
|
|
for j := i to 3 do begin
|
|
s := 0;
|
|
for k := 0 to 63 do
|
|
s := s + n[k][i] * n[k][j];
|
|
CtC.arr[i][j] := s;
|
|
CtC.arr[j][i] := s;
|
|
end;
|
|
|
|
// compute CtCi (CtC inverse)
|
|
if not InvertMatrix4(CtC, CtCi) then
|
|
exit;
|
|
|
|
// compute condition number
|
|
if (threshold8 > 0) and (ConditionNumber(CtC, CtCi) >= threshold8) then
|
|
exit;
|
|
|
|
// compute matrix r[] := Ct * p (4x64 * 64x1 = 4x1)
|
|
for i := 0 to 3 do begin
|
|
s := 0;
|
|
for k := 0 to 63 do
|
|
s := s + n[k][i] * p[k];
|
|
r[i] := s;
|
|
end;
|
|
|
|
// compute weights (CtCi[] * r[]) (4x4 * 4x1 = 4x1)
|
|
for i := 0 to 3 do begin
|
|
s := 0;
|
|
for k := 0 to 3 do
|
|
s := s + CtCi.arr[i][k] * r[k];
|
|
a[i] := s;
|
|
end;
|
|
|
|
// calculate interpolated pixel
|
|
final := round(p[15] * a[0] + p[26] * a[1] + p[37] * a[2] + p[48] * a[3]);
|
|
if ( (constraint = 1) and
|
|
((final > 255) or (final < 0)) ) or
|
|
( (constraint = 2) and
|
|
( (final > max(max(p[15], p[26]), max(p[37], p[48])) + 5) or
|
|
(final < min(min(p[15], p[26]), min(p[37], p[48])) - 5) ) ) then
|
|
exit;
|
|
|
|
if final > 255 then
|
|
final := 255
|
|
else
|
|
if final < 0 then
|
|
final := 0;
|
|
|
|
output := final;
|
|
result := true;
|
|
end;
|
|
|
|
function NEDI_16x16(const p: TA256Int; const n: TA256x4Int; var output: byte) : boolean;
|
|
var i, j, k, final : integer;
|
|
a, r : array [0..3] of double;
|
|
CtC, CtCi : TMatrix4;
|
|
s : double;
|
|
begin
|
|
result := false;
|
|
|
|
// compute covariance matrix CtC := Ct * C (4x256 * 256x4 = 4x4)
|
|
for i := 0 to 3 do
|
|
for j := i to 3 do begin
|
|
s := 0;
|
|
for k := 0 to 255 do
|
|
s := s + n[k][i] * n[k][j];
|
|
CtC.arr[i][j] := s;
|
|
CtC.arr[j][i] := s;
|
|
end;
|
|
|
|
// compute CtCi (CtC inverse)
|
|
if not InvertMatrix4(CtC, CtCi) then
|
|
exit;
|
|
|
|
// compute condition number
|
|
if (threshold16 > 0) and (ConditionNumber(CtC, CtCi) >= threshold16) then
|
|
exit;
|
|
|
|
// compute matrix r[] := Ct * p (4x256 * 256x1 = 4x1)
|
|
for i := 0 to 3 do begin
|
|
s := 0;
|
|
for k := 0 to 255 do
|
|
s := s + n[k][i] * p[k];
|
|
r[i] := s;
|
|
end;
|
|
|
|
// compute weights (CtCi[] * r[]) (4x4 * 4x1 = 4x1)
|
|
for i := 0 to 3 do begin
|
|
s := 0;
|
|
for k := 0 to 3 do
|
|
s := s + CtCi.arr[i][k] * r[k];
|
|
a[i] := s;
|
|
end;
|
|
|
|
// windowPat256:
|
|
// 000 001 004 005 016 017 020 021 064 065 068 069 080 081 084 085
|
|
// 002 003 006 007 018 019 022 023 066 067 070 071 082 083 086 087
|
|
// 008 009 012 013 024 025 028 029 072 073 076 077 088 089 092 093
|
|
// 010 011 014 015 026 027 030 031 074 075 078 079 090 091 094 095
|
|
// 032 033 036 037 048 049 052 053 096 097 100 101 112 113 116 117
|
|
// 034 035 038 039 050 051 054 055 098 099 102 103 114 115 118 119
|
|
// 040 041 044 045 056 057 060 061 104 105 108 109 120 121 124 125
|
|
// 042 043 046 047 058 059 062 063_106 107 110 111 122 123 126 127
|
|
// 128 129 132 133 144 145 148 149 192 193 196 197 208 209 212 213
|
|
// 130 131 134 135 146 147 150 151 194 195 198 199 210 211 214 215
|
|
// 136 137 140 141 152 153 156 157 200 201 204 205 216 217 220 221
|
|
// 138 139 142 143 154 155 158 159 202 203 206 207 218 219 222 223
|
|
// 160 161 164 165 176 177 180 181 224 225 228 229 240 241 244 245
|
|
// 162 163 166 167 178 179 182 183 226 227 230 231 242 243 246 247
|
|
// 168 169 172 173 184 185 188 189 232 233 236 237 248 249 252 253
|
|
// 170 171 174 175 186 187 190 191 234 235 238 239 250 251 254 255
|
|
|
|
// calculate interpolated pixel
|
|
final := round(p[63] * a[0] + p[106] * a[1] + p[149] * a[2] + p[192] * a[3]);
|
|
if ( (constraint = 1) and
|
|
((final > 255) or (final < 0)) ) or
|
|
( (constraint = 2) and
|
|
( (final > max(max(p[63], p[106]), max(p[149], p[192])) + 5) or
|
|
(final < min(min(p[63], p[106]), min(p[149], p[192])) - 5) ) ) then
|
|
exit;
|
|
|
|
if final > 255 then
|
|
final := 255
|
|
else
|
|
if final < 0 then
|
|
final := 0;
|
|
|
|
output := final;
|
|
result := true;
|
|
end;
|
|
|
|
var dstPitch2, dstPitch3 : integer;
|
|
x, y, u, v, temp, temp1, temp2 : integer;
|
|
dst2, dstp, dstpp, dstn, dstnn : TPAByte;
|
|
width2, height2 : integer;
|
|
p : TA256Int;
|
|
n : TA256x4Int;
|
|
localPat1, localPat2 : array [0..3] of integer;
|
|
windowPat161, windowPat162 : array [0..15] of integer;
|
|
windowPat641, windowPat642 : array [0..63] of integer;
|
|
windowPat2561, windowPat2562 : array [0..255] of integer;
|
|
success : boolean;
|
|
begin
|
|
width2 := width shl 1;
|
|
height2 := height shl 1;
|
|
dstPitch2 := dstPitch * 2;
|
|
dstPitch3 := dstPitch * 3;
|
|
|
|
// copy over original pixels
|
|
dst2 := dst;
|
|
for y := 0 to height - 1 do begin
|
|
for x := 0 to width - 1 do
|
|
dst2[x shl 1] := src[x];
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
src := pointer(NativeInt(src ) + srcPitch);
|
|
end;
|
|
|
|
// interpolate areas where NEDI can't be used
|
|
dst2 := dst;
|
|
temp2 := width2 - 4;
|
|
y := 0;
|
|
while y < 11 do begin
|
|
dst2[1] := (dst2[0] + dst2[2] + 1) shr 1;
|
|
x := 3;
|
|
while x < temp2 do begin
|
|
dst2[x] := Interpolate(dst2[x - 3], dst2[x - 1], dst2[x + 1], dst2[x + 3]);
|
|
inc(x, 2);
|
|
end;
|
|
dst2[x] := (dst2[x - 1] + dst2[x + 1] + 1) shr 1;
|
|
inc(x, 2);
|
|
dst2[x] := dst2[x - 1];
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
temp1 := height2 - 12;
|
|
temp2 := width2 - 4;
|
|
while y < temp1 do begin
|
|
dst2[1] := (dst2[0] + dst2[2] + 1) shr 1;
|
|
x := 3;
|
|
while x < 9 do begin
|
|
dst2[x] := Interpolate(dst2[x - 3], dst2[x - 1], dst2[x + 1], dst2[x + 3]);
|
|
inc(x, 2);
|
|
end;
|
|
x := width2 - 9;
|
|
while x < temp2 do begin
|
|
dst2[x] := Interpolate(dst2[x - 3], dst2[x - 1], dst2[x + 1], dst2[x + 3]);
|
|
inc(x, 2);
|
|
end;
|
|
dst2[x] := (dst2[x - 1] + dst2[x + 1] + 1) shr 1;
|
|
inc(x, 2);
|
|
dst2[x] := dst2[x - 1];
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
temp2 := width2 - 4;
|
|
while y < height2 do begin
|
|
dst2[1] := (dst2[0] + dst2[2] + 1) shr 1;
|
|
x := 3;
|
|
while x < temp2 do begin
|
|
dst2[x] := Interpolate(dst2[x - 3], dst2[x - 1], dst2[x + 1], dst2[x + 3]);
|
|
inc(x, 2);
|
|
end;
|
|
dst2[x] := (dst2[x - 1] + dst2[x + 1] + 1) shr 1;
|
|
inc(x, 2);
|
|
dst2[x] := dst2[x - 1];
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
dst2 := pointer(NativeInt(dst ) + dstPitch);
|
|
dstp := pointer(NativeInt(dst2) - dstPitch);
|
|
dstn := pointer(NativeInt(dst2) + dstPitch);
|
|
// dstpp := pointer(NativeInt(dstp) - dstPitch2);
|
|
dstnn := pointer(NativeInt(dstn) + dstPitch2);
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := (dstp[x] + dstn[x] + 1) shr 1;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstpp := dstp;
|
|
dstp := dstn;
|
|
dstn := dstnn;
|
|
dstnn := pointer(NativeInt(dstnn) + dstPitch2);
|
|
y := 3;
|
|
while y < 9 do begin
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := Interpolate(dstpp[x], dstp[x], dstn[x], dstnn[x]);
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstpp := dstp;
|
|
dstp := dstn;
|
|
dstn := dstnn;
|
|
dstnn := pointer(NativeInt(dstnn) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
temp1 := height2 - 10;
|
|
while y < temp1 do begin
|
|
for x := 0 to 8 do
|
|
dst2[x] := Interpolate(dstpp[x], dstp[x], dstn[x], dstnn[x]);
|
|
for x := width2 - 9 to width2 - 1 do
|
|
dst2[x] := Interpolate(dstpp[x], dstp[x], dstn[x], dstnn[x]);
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstpp := dstp;
|
|
dstp := dstn;
|
|
dstn := dstnn;
|
|
dstnn := pointer(NativeInt(dstnn) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
temp1 := height2 - 4;
|
|
while y < temp1 do begin
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := Interpolate(dstpp[x], dstp[x], dstn[x], dstnn[x]);
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstpp := dstp;
|
|
dstp := dstn;
|
|
dstn := dstnn;
|
|
dstnn := pointer(NativeInt(dstnn) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := (dstp[x] + dstn[x] + 1) shr 1;
|
|
dstp := dstn;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := dstp[x];
|
|
|
|
// NEDI
|
|
localPat1[0] := -dstPitch2 - 2;
|
|
localPat1[1] := -dstPitch2 + 2;
|
|
localPat1[2] := dstPitch2 - 2;
|
|
localPat1[3] := dstPitch2 + 2;
|
|
localPat2[0] := -2;
|
|
localPat2[1] := -dstPitch2;
|
|
localPat2[2] := dstPitch2;
|
|
localPat2[3] := 2;
|
|
windowPat161[0] := -dstPitch3 - 3;
|
|
windowPat161[1] := -dstPitch3 - 1;
|
|
windowPat161[2] := -dstPitch - 3;
|
|
windowPat161[3] := -dstPitch - 1;
|
|
windowPat161[4] := -dstPitch3 + 1;
|
|
windowPat161[5] := -dstPitch3 + 3;
|
|
windowPat161[6] := -dstPitch + 1;
|
|
windowPat161[7] := -dstPitch + 3;
|
|
windowPat161[8] := dstPitch - 3;
|
|
windowPat161[9] := dstPitch - 1;
|
|
windowPat161[10] := dstPitch3 - 3;
|
|
windowPat161[11] := dstPitch3 - 1;
|
|
windowPat161[12] := dstPitch + 1;
|
|
windowPat161[13] := dstPitch + 3;
|
|
windowPat161[14] := dstPitch3 + 1;
|
|
windowPat161[15] := dstPitch3 + 3;
|
|
windowPat162[0] := -3;
|
|
windowPat162[1] := -dstPitch - 2;
|
|
windowPat162[2] := dstPitch - 2;
|
|
windowPat162[3] := -1;
|
|
windowPat162[4] := -dstPitch2 - 1;
|
|
windowPat162[5] := -dstPitch3;
|
|
windowPat162[6] := -dstPitch;
|
|
windowPat162[7] := -dstPitch2 + 1;
|
|
windowPat162[8] := dstPitch2 - 1;
|
|
windowPat162[9] := dstPitch;
|
|
windowPat162[10] := dstPitch3;
|
|
windowPat162[11] := dstPitch2 + 1;
|
|
windowPat162[12] := 1;
|
|
windowPat162[13] := -dstPitch + 2;
|
|
windowPat162[14] := dstPitch + 2;
|
|
windowPat162[15] := 3;
|
|
for v := 0 to 3 do
|
|
for u := 0 to 15 do begin
|
|
windowPat641[v shl 4 + u] := windowPat161[u] + localPat1[v] shl 1;
|
|
windowPat642[v shl 4 + u] := windowPat162[u] + localPat2[v] shl 1;
|
|
end;
|
|
for v := 0 to 3 do
|
|
for u := 0 to 63 do begin
|
|
windowPat2561[v shl 6 + u] := windowPat641[u] + localPat1[v] shl 2;
|
|
windowPat2562[v shl 6 + u] := windowPat642[u] + localPat2[v] shl 2;
|
|
end;
|
|
dst2 := pointer(NativeInt(dst) + 9 * dstPitch);
|
|
temp1 := height2 - 9;
|
|
temp2 := width2 - 9;
|
|
y := 9;
|
|
while y < temp1 do begin
|
|
x := 9;
|
|
while x < temp2 do begin
|
|
success := false;
|
|
if CheckVariance([dst2[x + windowPat161[3]], dst2[x + windowPat161[6]], dst2[x + windowPat161[9]], dst2[x + windowPat161[12]]]) then begin
|
|
for u := 0 to 15 do begin
|
|
p[u] := dst2[x + windowPat161[u]];
|
|
n[u][0] := dst2[x + windowPat161[u] + localPat1[0]];
|
|
n[u][1] := dst2[x + windowPat161[u] + localPat1[1]];
|
|
n[u][2] := dst2[x + windowPat161[u] + localPat1[2]];
|
|
n[u][3] := dst2[x + windowPat161[u] + localPat1[3]];
|
|
end;
|
|
success := NEDI_4x4(p, n, dst2[x]);
|
|
if not success then begin
|
|
for u := 0 to 63 do begin
|
|
p[u] := dst2[x + windowPat641[u]];
|
|
n[u][0] := dst2[x + windowPat641[u] + localPat1[0]];
|
|
n[u][1] := dst2[x + windowPat641[u] + localPat1[1]];
|
|
n[u][2] := dst2[x + windowPat641[u] + localPat1[2]];
|
|
n[u][3] := dst2[x + windowPat641[u] + localPat1[3]];
|
|
end;
|
|
success := NEDI_8x8(p, n, dst2[x]);
|
|
if (not success) and (x > 16) and (y > 16) and (x + 16 < width2) and (y + 16 < height2) then begin
|
|
for u := 0 to 255 do begin
|
|
p[u] := dst2[x + windowPat2561[u]];
|
|
n[u][0] := dst2[x + windowPat2561[u] + localPat1[0]];
|
|
n[u][1] := dst2[x + windowPat2561[u] + localPat1[1]];
|
|
n[u][2] := dst2[x + windowPat2561[u] + localPat1[2]];
|
|
n[u][3] := dst2[x + windowPat2561[u] + localPat1[3]];
|
|
end;
|
|
success := NEDI_16x16(p, n, dst2[x]);
|
|
end;
|
|
end;
|
|
end;
|
|
if not success then
|
|
dst2[x] := Interpolate(Interpolate(dst2[x + windowPat161[ 0]], dst2[x + windowPat161[ 1]], dst2[x + windowPat161[ 4]], dst2[x + windowPat161[ 5]]),
|
|
Interpolate(dst2[x + windowPat161[ 2]], dst2[x + windowPat161[ 3]], dst2[x + windowPat161[ 6]], dst2[x + windowPat161[ 7]]),
|
|
Interpolate(dst2[x + windowPat161[ 8]], dst2[x + windowPat161[ 9]], dst2[x + windowPat161[12]], dst2[x + windowPat161[13]]),
|
|
Interpolate(dst2[x + windowPat161[10]], dst2[x + windowPat161[11]], dst2[x + windowPat161[14]], dst2[x + windowPat161[15]]));
|
|
inc(x, 2);
|
|
end;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
dst2 := pointer(NativeInt(dst) + 9 * dstPitch);
|
|
for y := 9 to temp1 - 1 do begin
|
|
temp := y and 1;
|
|
x := 9 + temp;
|
|
while x < temp2 do begin
|
|
success := false;
|
|
if CheckVariance([dst2[x + windowPat162[3]], dst2[x + windowPat162[6]], dst2[x + windowPat162[9]], dst2[x + windowPat162[12]]]) then begin
|
|
for u := 0 to 15 do begin
|
|
p[u] := dst2[x + windowPat162[u]];
|
|
n[u][0] := dst2[x + windowPat162[u] + localPat2[0]];
|
|
n[u][1] := dst2[x + windowPat162[u] + localPat2[1]];
|
|
n[u][2] := dst2[x + windowPat162[u] + localPat2[2]];
|
|
n[u][3] := dst2[x + windowPat162[u] + localPat2[3]];
|
|
end;
|
|
success := NEDI_4x4(p, n, dst2[x]);
|
|
if not success then begin
|
|
for u := 0 to 63 do begin
|
|
p[u] := dst2[x + windowPat642[u]];
|
|
n[u][0] := dst2[x + windowPat642[u] + localPat2[0]];
|
|
n[u][1] := dst2[x + windowPat642[u] + localPat2[1]];
|
|
n[u][2] := dst2[x + windowPat642[u] + localPat2[2]];
|
|
n[u][3] := dst2[x + windowPat642[u] + localPat2[3]];
|
|
end;
|
|
success := NEDI_8x8(p, n, dst2[x]);
|
|
if (not success) and (x > 16) and (y > 16) and (x + 16 < width2) and (y + 16 < height2) then begin
|
|
for u := 0 to 255 do begin
|
|
p[u] := dst2[x + windowPat2562[u]];
|
|
n[u][0] := dst2[x + windowPat2562[u] + localPat2[0]];
|
|
n[u][1] := dst2[x + windowPat2562[u] + localPat2[1]];
|
|
n[u][2] := dst2[x + windowPat2562[u] + localPat2[2]];
|
|
n[u][3] := dst2[x + windowPat2562[u] + localPat2[3]];
|
|
end;
|
|
success := NEDI_16x16(p, n, dst2[x]);
|
|
end;
|
|
end;
|
|
end;
|
|
if not success then
|
|
if temp <> 0 then
|
|
dst2[x] := Interpolate(dst2[x + windowPat162[5]], dst2[x + windowPat162[6]], dst2[x + windowPat162[9]], dst2[x + windowPat162[10]])
|
|
else
|
|
dst2[x] := Interpolate(dst2[x - 3], dst2[x - 1], dst2[x + 1], dst2[x + 3]);
|
|
inc(x, 2);
|
|
end;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch);
|
|
end;
|
|
end;
|
|
|
|
procedure ZhaoXinLiPlane(src: TPAByte; width, height, srcPitch: integer; dst: TPAByte; dstPitch: integer);
|
|
|
|
const
|
|
mvar : integer = 8 shl 4;
|
|
coef1 : double = 0.5625;
|
|
coef2 : double = -0.0625;
|
|
|
|
function CheckVariance(const pc: array of integer) : boolean;
|
|
var sum, sumsq : integer;
|
|
begin
|
|
sum := pc[0] + pc[1] + pc[2] + pc[3];
|
|
sumsq := pc[0] * pc[0] + pc[1] * pc[1] + pc[2] * pc[2] + pc[3] * pc[3];
|
|
result := sumsq shl 2 - sum * sum > mvar;
|
|
end;
|
|
|
|
function Interpolate(p1, p2, p3, p4: byte) : byte;
|
|
var i1 : integer;
|
|
begin
|
|
i1 := Round((p2 + p3) * coef1 + (p1 + p4) * coef2);
|
|
if i1 < 0 then
|
|
i1 := 0
|
|
else
|
|
if i1 > 255 then
|
|
i1 := 255;
|
|
result := i1;
|
|
end;
|
|
|
|
type
|
|
TMatrix12 = record case boolean of
|
|
false : (arr: array [0..11] of array [0..11] of double);
|
|
true : (flt: array [0..143] of double);
|
|
end;
|
|
|
|
function InvertMatrix12(const src: TMatrix12; var dst: TMatrix12) : boolean;
|
|
const initdst : TMatrix12 = (flt: (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1));
|
|
var ctc : TMatrix12;
|
|
best, i1, i2, i3 : integer;
|
|
temp, scale : double;
|
|
begin
|
|
result := false;
|
|
ctc := src;
|
|
dst := initdst;
|
|
for i1 := 0 to 11 do begin
|
|
best := i1;
|
|
for i2 := i1 + 1 to 11 do
|
|
if abs(ctc.arr[best][i1]) < abs(ctc.arr[i2][i1]) then
|
|
best := i2;
|
|
if best <> i1 then
|
|
for i3 := 0 to 11 do begin
|
|
temp := ctc.arr[i1][i3];
|
|
ctc.arr[i1][i3] := ctc.arr[best][i3];
|
|
ctc.arr[best][i3] := temp;
|
|
temp := dst.arr[i1][i3];
|
|
dst.arr[i1][i3] := dst.arr[best][i3];
|
|
dst.arr[best][i3] := temp;
|
|
end;
|
|
if ctc.arr[i1][i1] = 0 then
|
|
exit;
|
|
|
|
temp := ctc.arr[i1][i1];
|
|
for i3 := 0 to 11 do
|
|
if i3 <> i1 then begin
|
|
scale := -(ctc.arr[i3][i1]/temp);
|
|
for i2 := 0 to 11 do begin
|
|
ctc.arr[i3][i2] := ctc.arr[i3][i2] + (ctc.arr[i1][i2] * scale);
|
|
dst.arr[i3][i2] := dst.arr[i3][i2] + (dst.arr[i1][i2] * scale);
|
|
end;
|
|
ctc.arr[i3][i1] := 0;
|
|
end;
|
|
end;
|
|
for i1 := 0 to 11 do
|
|
if ctc.arr[i1][i1] <> 1 then begin
|
|
scale := 1 / ctc.arr[i1][i1];
|
|
for i3 := 0 to 11 do
|
|
dst.arr[i1][i3] := dst.arr[i1][i3] * scale;
|
|
ctc.arr[i1][i1] := 1;
|
|
end;
|
|
|
|
result := true;
|
|
end;
|
|
|
|
type
|
|
TA60Int = array [0..59] of integer;
|
|
TA60x12Int = array [0..59] of array [0..11] of integer;
|
|
|
|
function NEDI_8x8(var p, q: TA60Int; var n: TA60x12Int; var output: byte) : boolean;
|
|
var i, j, k, final : integer;
|
|
a, r : array [0..11] of double;
|
|
CtC, CtCi : TMatrix12;
|
|
s : double;
|
|
begin
|
|
result := false;
|
|
|
|
// compute covariance matrix CtC := Ct * C (12x60 * 60x12 = 12x12)
|
|
for i := 0 to 11 do
|
|
for j := i to 11 do begin
|
|
s := 0;
|
|
for k := 0 to 59 do
|
|
s := s + n[k][i] * n[k][j];
|
|
CtC.arr[i][j] := s;
|
|
CtC.arr[j][i] := s;
|
|
end;
|
|
|
|
// compute CtCi (CtC inverse)
|
|
if not InvertMatrix12(CtC, CtCi) then
|
|
exit;
|
|
|
|
// compute matrix r[] := Ct * p (12x60 * 60x1 = 12x1)
|
|
for i := 0 to 11 do begin
|
|
s := 0;
|
|
for k := 0 to 59 do
|
|
s := s + n[k][i] * p[k];
|
|
r[i] := s;
|
|
end;
|
|
|
|
// compute weights (CtCi[] * r[]) (12x12 * 12x1 = 12x1)
|
|
for i := 0 to 11 do begin
|
|
s := 0;
|
|
for k := 0 to 11 do
|
|
s := s + CtCi.arr[i][k] * r[k];
|
|
a[i] := s;
|
|
end;
|
|
|
|
// windowPat64:
|
|
// 00 01 02 03 04 05 06 07
|
|
// 08 09 10 11 12 13 14 15
|
|
// 16 17 18 19 20 21 22 23
|
|
// 24 25 26 27_28 29 30 31
|
|
// 32 33 34 35 36 37 38 39
|
|
// 40 41 42 43 44 45 46 47
|
|
// 48 49 50 51 52 53 54 55
|
|
// 56 57 58 59 60 61 62 63
|
|
|
|
// windowPat60:
|
|
// 00 01 02 03 04 05
|
|
// 06 07 08 09 10 11 12 13
|
|
// 14 15 16 17 18 19 20 21
|
|
// 22 23 24 25_26 27 28 29
|
|
// 30 31 32 33 34 35 36 37
|
|
// 38 39 40 41 42 43 44 45
|
|
// 46 47 48 49 50 51 52 53
|
|
// 54 55 56 57 58 59
|
|
|
|
// calculate interpolated pixel
|
|
final := round( q[25] * a[ 0] +
|
|
q[26] * a[ 1] +
|
|
q[33] * a[ 2] +
|
|
q[34] * a[ 3] +
|
|
(q[24] + q[25] + 1) div 2 * a[ 4] +
|
|
(q[26] + q[27] + 1) div 2 * a[ 5] +
|
|
(q[32] + q[33] + 1) div 2 * a[ 6] +
|
|
(q[34] + q[35] + 1) div 2 * a[ 7] +
|
|
(q[17] + q[25] + 1) div 2 * a[ 8] +
|
|
(q[18] + q[26] + 1) div 2 * a[ 9] +
|
|
(q[33] + q[41] + 1) div 2 * a[10] +
|
|
(q[34] + q[42] + 1) div 2 * a[11] );
|
|
if final > 255 then
|
|
final := 255
|
|
else
|
|
if final < 0 then
|
|
final := 0;
|
|
|
|
output := final;
|
|
result := true;
|
|
end;
|
|
|
|
var dstPitch2, dstPitch3 : integer;
|
|
dstLowPass, dstlp2 : TPAByte;
|
|
x, y, u, v, temp, temp1, temp2 : integer;
|
|
dst2, dstp, dstpp, dstn, dstnn : TPAByte;
|
|
width2, height2 : integer;
|
|
p, q : TA60Int;
|
|
n : TA60x12Int;
|
|
localPat1, localPat2 : array [0..11] of integer;
|
|
windowPat1, windowPat2 : array [0..59] of integer;
|
|
success : boolean;
|
|
index : integer;
|
|
weights : array [0..10] of double;
|
|
weight1, weight2 : double;
|
|
sum : double;
|
|
f1, f2 : integer;
|
|
begin
|
|
width2 := width shl 1;
|
|
height2 := height shl 1;
|
|
dstPitch2 := dstPitch * 2;
|
|
dstPitch3 := dstPitch * 3;
|
|
dstLowPass := pointer(LocalAlloc(LPTR, width2 * height2));
|
|
|
|
// copy over original pixels
|
|
dst2 := dst;
|
|
for y := 0 to height - 1 do begin
|
|
for x := 0 to width - 1 do
|
|
dst2[x shl 1] := src[x];
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
src := pointer(NativeInt(src ) + srcPitch);
|
|
end;
|
|
|
|
// interpolate areas where NEDI can't be used
|
|
dst2 := dst;
|
|
temp2 := width2 - 4;
|
|
y := 0;
|
|
while y < 11 do begin
|
|
dst2[1] := (dst2[0] + dst2[2] + 1) shr 1;
|
|
x := 3;
|
|
while x < temp2 do begin
|
|
dst2[x] := Interpolate(dst2[x - 3], dst2[x - 1], dst2[x + 1], dst2[x + 3]);
|
|
inc(x, 2);
|
|
end;
|
|
dst2[x] := (dst2[x - 1] + dst2[x + 1] + 1) shr 1;
|
|
inc(x, 2);
|
|
dst2[x] := dst2[x - 1];
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
temp1 := height2 - 12;
|
|
temp2 := width2 - 4;
|
|
while y < temp1 do begin
|
|
dst2[1] := (dst2[0] + dst2[2] + 1) shr 1;
|
|
x := 3;
|
|
while x < 9 do begin
|
|
dst2[x] := Interpolate(dst2[x - 3], dst2[x - 1], dst2[x + 1], dst2[x + 3]);
|
|
inc(x, 2);
|
|
end;
|
|
x := width2 - 9;
|
|
while x < temp2 do begin
|
|
dst2[x] := Interpolate(dst2[x - 3], dst2[x - 1], dst2[x + 1], dst2[x + 3]);
|
|
inc(x, 2);
|
|
end;
|
|
dst2[x] := (dst2[x - 1] + dst2[x + 1] + 1) shr 1;
|
|
inc(x, 2);
|
|
dst2[x] := dst2[x - 1];
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
temp2 := width2 - 4;
|
|
while y < height2 do begin
|
|
dst2[1] := (dst2[0] + dst2[2] + 1) shr 1;
|
|
x := 3;
|
|
while x < temp2 do begin
|
|
dst2[x] := Interpolate(dst2[x - 3], dst2[x - 1], dst2[x + 1], dst2[x + 3]);
|
|
inc(x, 2);
|
|
end;
|
|
dst2[x] := (dst2[x - 1] + dst2[x + 1] + 1) shr 1;
|
|
inc(x, 2);
|
|
dst2[x] := dst2[x - 1];
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
dst2 := pointer(NativeInt(dst ) + dstPitch);
|
|
dstp := pointer(NativeInt(dst2) - dstPitch);
|
|
dstn := pointer(NativeInt(dst2) + dstPitch);
|
|
dstpp := pointer(NativeInt(dstp) - dstPitch2);
|
|
dstnn := pointer(NativeInt(dstn) + dstPitch2);
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := (dstp[x] + dstn[x] + 1) shr 1;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstpp := dstp;
|
|
dstp := dstn;
|
|
dstn := dstnn;
|
|
dstnn := pointer(NativeInt(dstnn) + dstPitch2);
|
|
y := 3;
|
|
while y < 9 do begin
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := Interpolate(dstpp[x], dstp[x], dstn[x], dstnn[x]);
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstpp := dstp;
|
|
dstp := dstn;
|
|
dstn := dstnn;
|
|
dstnn := pointer(NativeInt(dstnn) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
temp1 := height2 - 10;
|
|
while y < temp1 do begin
|
|
for x := 0 to 8 do
|
|
dst2[x] := Interpolate(dstpp[x], dstp[x], dstn[x], dstnn[x]);
|
|
for x := width2 - 9 to width2 - 1 do
|
|
dst2[x] := Interpolate(dstpp[x], dstp[x], dstn[x], dstnn[x]);
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstpp := dstp;
|
|
dstp := dstn;
|
|
dstn := dstnn;
|
|
dstnn := pointer(NativeInt(dstnn) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
temp1 := height2 - 4;
|
|
while y < temp1 do begin
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := Interpolate(dstpp[x], dstp[x], dstn[x], dstnn[x]);
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstpp := dstp;
|
|
dstp := dstn;
|
|
dstn := dstnn;
|
|
dstnn := pointer(NativeInt(dstnn) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := (dstp[x] + dstn[x] + 1) shr 1;
|
|
dstp := dstn;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
for x := 0 to width2 - 1 do
|
|
dst2[x] := dstp[x];
|
|
|
|
// NEDI
|
|
weights[ 0] := Power(2, - 0.5 * 5 * 5);
|
|
weights[ 1] := Power(2, - 0.5 * 4 * 4);
|
|
weights[ 2] := Power(2, - 0.5 * 3 * 3);
|
|
weights[ 3] := Power(2, - 0.5 * 2 * 2);
|
|
weights[ 4] := Power(2, - 0.5 * 1 * 1);
|
|
weights[ 5] := Power(2, - 0.5 * 0 * 0);
|
|
weights[ 6] := Power(2, - 0.5 * 1 * 1);
|
|
weights[ 7] := Power(2, - 0.5 * 2 * 2);
|
|
weights[ 8] := Power(2, - 0.5 * 3 * 3);
|
|
weights[ 9] := Power(2, - 0.5 * 4 * 4);
|
|
weights[10] := Power(2, - 0.5 * 5 * 5);
|
|
localPat1[ 0] := - 2 - dstPitch * 2;
|
|
localPat1[ 1] := + 2 - dstPitch * 2;
|
|
localPat1[ 2] := - 2 + dstPitch * 2;
|
|
localPat1[ 3] := + 2 + dstPitch * 2;
|
|
localPat1[ 4] := - 4 - dstPitch * 2;
|
|
localPat1[ 5] := + 4 - dstPitch * 2;
|
|
localPat1[ 6] := - 4 + dstPitch * 2;
|
|
localPat1[ 7] := + 4 + dstPitch * 2;
|
|
localPat1[ 8] := - 2 - dstPitch * 4;
|
|
localPat1[ 9] := + 2 - dstPitch * 4;
|
|
localPat1[10] := - 2 + dstPitch * 4;
|
|
localPat1[11] := + 2 + dstPitch * 4;
|
|
localPat2[ 0] := - 2 - dstPitch * 0;
|
|
localPat2[ 1] := + 0 - dstPitch * 2;
|
|
localPat2[ 2] := - 0 + dstPitch * 2;
|
|
localPat2[ 3] := + 2 + dstPitch * 0;
|
|
localPat2[ 4] := - 4 + dstPitch * 2;
|
|
localPat2[ 5] := + 2 - dstPitch * 4;
|
|
localPat2[ 6] := - 2 + dstPitch * 4;
|
|
localPat2[ 7] := + 4 - dstPitch * 2;
|
|
localPat2[ 8] := - 4 - dstPitch * 2;
|
|
localPat2[ 9] := - 2 - dstPitch * 4;
|
|
localPat2[10] := + 2 + dstPitch * 4;
|
|
localPat2[11] := + 4 + dstPitch * 2;
|
|
windowPat1[ 0] := - 5 - dstPitch * 7;
|
|
windowPat1[ 1] := - 3 - dstPitch * 7;
|
|
windowPat1[ 2] := - 1 - dstPitch * 7;
|
|
windowPat1[ 3] := + 1 - dstPitch * 7;
|
|
windowPat1[ 4] := + 3 - dstPitch * 7;
|
|
windowPat1[ 5] := + 5 - dstPitch * 7;
|
|
windowPat1[ 6] := - 7 - dstPitch * 5;
|
|
windowPat1[ 7] := - 5 - dstPitch * 5;
|
|
windowPat1[ 8] := - 3 - dstPitch * 5;
|
|
windowPat1[ 9] := - 1 - dstPitch * 5;
|
|
windowPat1[10] := + 1 - dstPitch * 5;
|
|
windowPat1[11] := + 3 - dstPitch * 5;
|
|
windowPat1[12] := + 5 - dstPitch * 5;
|
|
windowPat1[13] := + 7 - dstPitch * 5;
|
|
windowPat1[14] := - 7 - dstPitch * 3;
|
|
windowPat1[15] := - 5 - dstPitch * 3;
|
|
windowPat1[16] := - 3 - dstPitch * 3;
|
|
windowPat1[17] := - 1 - dstPitch * 3;
|
|
windowPat1[18] := + 1 - dstPitch * 3;
|
|
windowPat1[19] := + 3 - dstPitch * 3;
|
|
windowPat1[20] := + 5 - dstPitch * 3;
|
|
windowPat1[21] := + 7 - dstPitch * 3;
|
|
windowPat1[22] := - 7 - dstPitch * 1;
|
|
windowPat1[23] := - 5 - dstPitch * 1;
|
|
windowPat1[24] := - 3 - dstPitch * 1;
|
|
windowPat1[25] := - 1 - dstPitch * 1;
|
|
windowPat1[26] := + 1 - dstPitch * 1;
|
|
windowPat1[27] := + 3 - dstPitch * 1;
|
|
windowPat1[28] := + 5 - dstPitch * 1;
|
|
windowPat1[29] := + 7 - dstPitch * 1;
|
|
windowPat1[30] := - 7 + dstPitch * 1;
|
|
windowPat1[31] := - 5 + dstPitch * 1;
|
|
windowPat1[32] := - 3 + dstPitch * 1;
|
|
windowPat1[33] := - 1 + dstPitch * 1;
|
|
windowPat1[34] := + 1 + dstPitch * 1;
|
|
windowPat1[35] := + 3 + dstPitch * 1;
|
|
windowPat1[36] := + 5 + dstPitch * 1;
|
|
windowPat1[37] := + 7 + dstPitch * 1;
|
|
windowPat1[38] := - 7 + dstPitch * 3;
|
|
windowPat1[39] := - 5 + dstPitch * 3;
|
|
windowPat1[40] := - 3 + dstPitch * 3;
|
|
windowPat1[41] := - 1 + dstPitch * 3;
|
|
windowPat1[42] := + 1 + dstPitch * 3;
|
|
windowPat1[43] := + 3 + dstPitch * 3;
|
|
windowPat1[44] := + 5 + dstPitch * 3;
|
|
windowPat1[45] := + 7 + dstPitch * 3;
|
|
windowPat1[46] := - 7 + dstPitch * 5;
|
|
windowPat1[47] := - 5 + dstPitch * 5;
|
|
windowPat1[48] := - 3 + dstPitch * 5;
|
|
windowPat1[49] := - 1 + dstPitch * 5;
|
|
windowPat1[50] := + 1 + dstPitch * 5;
|
|
windowPat1[51] := + 3 + dstPitch * 5;
|
|
windowPat1[52] := + 5 + dstPitch * 5;
|
|
windowPat1[53] := + 7 + dstPitch * 5;
|
|
windowPat1[54] := - 5 + dstPitch * 7;
|
|
windowPat1[55] := - 3 + dstPitch * 7;
|
|
windowPat1[56] := - 1 + dstPitch * 7;
|
|
windowPat1[57] := + 1 + dstPitch * 7;
|
|
windowPat1[58] := + 3 + dstPitch * 7;
|
|
windowPat1[59] := + 5 + dstPitch * 7;
|
|
windowPat2[ 0] := - 6 - dstPitch * 1;
|
|
windowPat2[ 1] := - 5 - dstPitch * 2;
|
|
windowPat2[ 2] := - 4 - dstPitch * 3;
|
|
windowPat2[ 3] := - 3 - dstPitch * 4;
|
|
windowPat2[ 4] := - 2 - dstPitch * 5;
|
|
windowPat2[ 5] := - 1 - dstPitch * 6;
|
|
windowPat2[ 6] := - 6 + dstPitch * 1;
|
|
windowPat2[ 7] := - 5 - dstPitch * 0;
|
|
windowPat2[ 8] := - 4 - dstPitch * 1;
|
|
windowPat2[ 9] := - 3 - dstPitch * 2;
|
|
windowPat2[10] := - 2 - dstPitch * 3;
|
|
windowPat2[11] := - 1 - dstPitch * 4;
|
|
windowPat2[12] := - 0 - dstPitch * 5;
|
|
windowPat2[13] := + 1 - dstPitch * 6;
|
|
windowPat2[14] := - 5 + dstPitch * 2;
|
|
windowPat2[15] := - 4 + dstPitch * 1;
|
|
windowPat2[16] := - 3 - dstPitch * 0;
|
|
windowPat2[17] := - 2 - dstPitch * 1;
|
|
windowPat2[18] := - 1 - dstPitch * 2;
|
|
windowPat2[19] := - 0 - dstPitch * 3;
|
|
windowPat2[20] := + 1 - dstPitch * 4;
|
|
windowPat2[21] := + 2 - dstPitch * 5;
|
|
windowPat2[22] := - 4 + dstPitch * 3;
|
|
windowPat2[23] := - 3 + dstPitch * 2;
|
|
windowPat2[24] := - 2 + dstPitch * 1;
|
|
windowPat2[25] := - 1 - dstPitch * 0;
|
|
windowPat2[26] := - 0 - dstPitch * 1;
|
|
windowPat2[27] := + 1 - dstPitch * 2;
|
|
windowPat2[28] := + 2 - dstPitch * 3;
|
|
windowPat2[29] := + 3 - dstPitch * 4;
|
|
windowPat2[30] := - 3 + dstPitch * 4;
|
|
windowPat2[31] := - 2 + dstPitch * 3;
|
|
windowPat2[32] := - 1 + dstPitch * 2;
|
|
windowPat2[33] := - 0 + dstPitch * 1;
|
|
windowPat2[34] := + 1 - dstPitch * 0;
|
|
windowPat2[35] := + 2 - dstPitch * 1;
|
|
windowPat2[36] := + 3 - dstPitch * 2;
|
|
windowPat2[37] := + 4 - dstPitch * 3;
|
|
windowPat2[38] := - 2 + dstPitch * 5;
|
|
windowPat2[39] := - 1 + dstPitch * 4;
|
|
windowPat2[40] := - 0 + dstPitch * 3;
|
|
windowPat2[41] := + 1 + dstPitch * 2;
|
|
windowPat2[42] := + 2 + dstPitch * 1;
|
|
windowPat2[43] := + 3 - dstPitch * 0;
|
|
windowPat2[44] := + 4 - dstPitch * 1;
|
|
windowPat2[45] := + 5 - dstPitch * 2;
|
|
windowPat2[46] := - 1 + dstPitch * 6;
|
|
windowPat2[47] := - 0 + dstPitch * 5;
|
|
windowPat2[48] := + 1 + dstPitch * 4;
|
|
windowPat2[49] := + 2 + dstPitch * 3;
|
|
windowPat2[50] := + 3 + dstPitch * 2;
|
|
windowPat2[51] := + 4 + dstPitch * 1;
|
|
windowPat2[52] := + 5 - dstPitch * 0;
|
|
windowPat2[53] := + 6 - dstPitch * 1;
|
|
windowPat2[54] := + 1 + dstPitch * 6;
|
|
windowPat2[55] := + 2 + dstPitch * 5;
|
|
windowPat2[56] := + 3 + dstPitch * 4;
|
|
windowPat2[57] := + 4 + dstPitch * 3;
|
|
windowPat2[58] := + 5 + dstPitch * 2;
|
|
windowPat2[59] := + 6 + dstPitch * 1;
|
|
|
|
// low pass filter
|
|
dst2 := pointer(NativeInt(dst));
|
|
dstlp2 := pointer(NativeInt(dstLowPass));
|
|
y := 0;
|
|
while y < height2 do begin
|
|
x := 0;
|
|
while x < width2 do begin
|
|
sum := 0;
|
|
weight2 := 0;
|
|
for f1 := -5 to +5 do
|
|
if (x + f1 * 2 >= 0) and (x + f1 * 2 < width2) then
|
|
for f2 := -5 to +5 do
|
|
if (y + f2 * 2 >= 0) and (y + f2 * 2 < height2) then begin
|
|
weight1 := weights[f1 + 5] * weights[f2 + 5];
|
|
weight2 := weight2 + weight1;
|
|
sum := sum + dst2[x + f1 * 2 + f2 * dstPitch2] * weight1;
|
|
end;
|
|
u := Round(sum / weight2);
|
|
if u < 0 then
|
|
dstlp2[x] := 0
|
|
else
|
|
if u > 255 then
|
|
dstlp2[x] := 255
|
|
else
|
|
dstlp2[x] := u;
|
|
inc(x, 2);
|
|
end;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstlp2 := pointer(NativeInt(dstlp2) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
|
|
// first interpolation step
|
|
dst2 := pointer(NativeInt(dst) + 9 * dstPitch);
|
|
dstlp2 := pointer(NativeInt(dstLowPass) + 9 * dstPitch);
|
|
temp1 := height2 - 9;
|
|
temp2 := width2 - 9;
|
|
y := 9;
|
|
while y < temp1 do begin
|
|
x := 9;
|
|
while x < temp2 do begin
|
|
success := false;
|
|
if CheckVariance([dstlp2[x + windowPat1[25]], dstlp2[x + windowPat1[26]], dstlp2[x + windowPat1[33]], dstlp2[x + windowPat1[34]]]) then begin
|
|
for u := 0 to 59 do begin
|
|
index := x + windowPat1[u];
|
|
p[u] := dstlp2[index];
|
|
q[u] := dst2[index];
|
|
for v := 0 to 11 do
|
|
try
|
|
n[u][v] := dstlp2[x + windowPat1[u] + localPat1[v]];
|
|
except
|
|
n[u][v] := 0;
|
|
end;
|
|
end;
|
|
success := NEDI_8x8(p, q, n, dst2[x]);
|
|
end;
|
|
if not success then
|
|
dst2[x] := Interpolate(Interpolate(dst2[x + windowPat1[16]], dst2[x + windowPat1[17]], dst2[x + windowPat1[18]], dst2[x + windowPat1[19]]),
|
|
Interpolate(dst2[x + windowPat1[24]], dst2[x + windowPat1[25]], dst2[x + windowPat1[26]], dst2[x + windowPat1[27]]),
|
|
Interpolate(dst2[x + windowPat1[32]], dst2[x + windowPat1[33]], dst2[x + windowPat1[34]], dst2[x + windowPat1[35]]),
|
|
Interpolate(dst2[x + windowPat1[40]], dst2[x + windowPat1[41]], dst2[x + windowPat1[42]], dst2[x + windowPat1[43]]));
|
|
inc(x, 2);
|
|
end;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch2);
|
|
dstlp2 := pointer(NativeInt(dstlp2) + dstPitch2);
|
|
inc(y, 2);
|
|
end;
|
|
|
|
// low pass filter
|
|
dst2 := pointer(NativeInt(dst));
|
|
dstlp2 := pointer(NativeInt(dstLowPass));
|
|
for y := 0 to height2 - 1 do begin
|
|
x := 0 + y and 1;
|
|
while x < width2 do begin
|
|
sum := 0;
|
|
weight2 := 0;
|
|
for f1 := -5 to +5 do
|
|
for f2 := -5 to +5 do
|
|
if (x + f1 + f2 >= 0) and (x + f1 + f2 < width2 ) and
|
|
(y - f1 + f2 >= 0) and (y - f1 + f2 < height2) then begin
|
|
weight1 := weights[f1 + 5] * weights[f2 + 5];
|
|
weight2 := weight2 + weight1;
|
|
sum := sum + dst2[x + f1 * (1 - dstPitch) + f2 * (1 + dstPitch)] * weight1;
|
|
end;
|
|
u := Round(sum / weight2);
|
|
if u < 0 then
|
|
dstlp2[x] := 0
|
|
else
|
|
if u > 255 then
|
|
dstlp2[x] := 255
|
|
else
|
|
dstlp2[x] := u;
|
|
inc(x, 2);
|
|
end;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch);
|
|
dstlp2 := pointer(NativeInt(dstlp2) + dstPitch);
|
|
end;
|
|
|
|
// second interpolation step
|
|
dst2 := pointer(NativeInt(dst) + 9 * dstPitch);
|
|
dstlp2 := pointer(NativeInt(dstLowPass) + 9 * dstPitch);
|
|
temp1 := height2 - 9;
|
|
temp2 := width2 - 9;
|
|
for y := 9 to temp1 - 1 do begin
|
|
temp := y and 1;
|
|
x := 9 + temp;
|
|
while x < temp2 do begin
|
|
success := false;
|
|
if CheckVariance([dstlp2[x + windowPat2[25]], dstlp2[x + windowPat2[26]], dstlp2[x + windowPat2[33]], dstlp2[x + windowPat2[34]]]) then begin
|
|
for u := 0 to 59 do begin
|
|
index := x + windowPat2[u];
|
|
p[u] := dstlp2[index];
|
|
q[u] := dst2[index];
|
|
for v := 0 to 11 do
|
|
try
|
|
n[u][v] := dstlp2[x + windowPat2[u] + localPat2[v]];
|
|
except
|
|
n[u][v] := 0;
|
|
end;
|
|
end;
|
|
success := NEDI_8x8(p, q, n, dst2[x]);
|
|
end;
|
|
if not success then
|
|
dst2[x] := Interpolate(Interpolate(dst2[x + windowPat2[16]], dst2[x + windowPat2[17]], dst2[x + windowPat2[18]], dst2[x + windowPat2[19]]),
|
|
Interpolate(dst2[x + windowPat2[24]], dst2[x + windowPat2[25]], dst2[x + windowPat2[26]], dst2[x + windowPat2[27]]),
|
|
Interpolate(dst2[x + windowPat2[32]], dst2[x + windowPat2[33]], dst2[x + windowPat2[34]], dst2[x + windowPat2[35]]),
|
|
Interpolate(dst2[x + windowPat2[40]], dst2[x + windowPat2[41]], dst2[x + windowPat2[42]], dst2[x + windowPat2[43]]));
|
|
inc(x, 2);
|
|
end;
|
|
dst2 := pointer(NativeInt(dst2) + dstPitch);
|
|
dstlp2 := pointer(NativeInt(dstlp2) + dstPitch);
|
|
end;
|
|
|
|
LocalFree(NativeUInt(dstLowPass));
|
|
end;
|
|
|
|
procedure Nedi(bmp: TBitmap);
|
|
var srcY, srcCb, srcCr, dstY, dstCb, dstCr : TPAByte;
|
|
i1, i2 : integer;
|
|
pixel : integer;
|
|
red, green, blue : integer;
|
|
y, cb, cr : single;
|
|
begin
|
|
srcY := pointer(LocalAlloc(LPTR, bmp.Width * bmp.Height));
|
|
srcCb := pointer(LocalAlloc(LPTR, bmp.Width * bmp.Height));
|
|
srcCr := pointer(LocalAlloc(LPTR, bmp.Width * bmp.Height));
|
|
dstY := pointer(LocalAlloc(LPTR, bmp.Width * bmp.Height * 4));
|
|
dstCb := pointer(LocalAlloc(LPTR, bmp.Width * bmp.Height * 4));
|
|
dstCr := pointer(LocalAlloc(LPTR, bmp.Width * bmp.Height * 4));
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
pixel := bmp.Canvas.Pixels[i1, i2];
|
|
red := pixel and $ff;
|
|
green := (pixel shr 8) and $ff;
|
|
blue := (pixel shr 16) and $ff;
|
|
y := red * 0.299 + green * 0.587 + blue * 0.114;
|
|
cb := $80 + red * -0.1687358916478555 + green * -0.3312641083521445 + blue * 0.5;
|
|
cr := $80 + red * 0.5 + green * -0.4186875891583452 + blue * -0.0813124108416548;
|
|
y := round(y);
|
|
cb := round(cb);
|
|
cr := round(cr);
|
|
if y < 0 then
|
|
y := 0
|
|
else
|
|
if y > 255 then
|
|
y := 255;
|
|
if cb < 0 then
|
|
cb := 0
|
|
else
|
|
if cb > 255 then
|
|
cb := 255;
|
|
if cr < 0 then
|
|
cr := 0
|
|
else
|
|
if cr >= 255 then
|
|
cr := 255;
|
|
srcY [i2 * bmp.Width + i1] := trunc(y);
|
|
srcCb[i2 * bmp.Width + i1] := trunc(cb);
|
|
srcCr[i2 * bmp.Width + i1] := trunc(cr);
|
|
end;
|
|
|
|
ZhaoXinLiPlane(srcY, bmp.Width, bmp.Height, bmp.Width, dstY, bmp.Width * 2);
|
|
ZhaoXinLiPlane(srcCb, bmp.Width, bmp.Height, bmp.Width, dstCb, bmp.Width * 2);
|
|
ZhaoXinLiPlane(srcCr, bmp.Width, bmp.Height, bmp.Width, dstCr, bmp.Width * 2);
|
|
|
|
bmp.Width := bmp.Width * 2;
|
|
bmp.Height := bmp.Height * 2;
|
|
for i1 := 0 to bmp.Width - 1 do
|
|
for i2 := 0 to bmp.Height - 1 do begin
|
|
y := dstY [i2 * bmp.Width + i1];
|
|
cb := dstCb[i2 * bmp.Width + i1] - $80;
|
|
cr := dstCr[i2 * bmp.Width + i1] - $80;
|
|
red := round(y + cr * 1.402);
|
|
green := round(y + cb * -0.3441362862010221 + cr * -0.7141362862010221);
|
|
blue := round(y + cb * 1.772);
|
|
if red < 0 then
|
|
red := 0
|
|
else
|
|
if red > 255 then
|
|
red := 255;
|
|
if green < 0 then
|
|
green := 0
|
|
else
|
|
if green > 255 then
|
|
green := 255;
|
|
if blue < 0 then
|
|
blue := 0
|
|
else
|
|
if blue > 255 then
|
|
blue := 255;
|
|
bmp.Canvas.Pixels[i1, i2] := blue shl 16 + green shl 8 + red;
|
|
end;
|
|
end;
|
|
|
|
procedure MakeTransparentBmp;
|
|
var bufp : TPACardinal;
|
|
buf : TPACardinal;
|
|
bufn : TPACardinal;
|
|
c1 : dword;
|
|
bmp1 : TBitmap;
|
|
i1, i2 : integer;
|
|
r, g, b, y : dword;
|
|
begin
|
|
bmp1 := TBitmap.Create;
|
|
bmp1.LoadFromFile('c:\desktop\org.bmp');
|
|
bmp1.PixelFormat := pf32bit;
|
|
for i1 := 0 to bmp1.Width - 1 do
|
|
for i2 := 0 to bmp1.Height - 1 do begin
|
|
buf := bmp1.Scanline[i2];
|
|
if i2 > 0 then
|
|
bufp := bmp1.Scanline[i2 - 1]
|
|
else
|
|
bufp := buf;
|
|
if i2 < bmp1.Height - 1 then
|
|
bufn := bmp1.Scanline[i2 + 1]
|
|
else
|
|
bufn := buf;
|
|
c1 := buf[i1];
|
|
if (c1 <> 0) and
|
|
( (bufp[i1] = $ffffff) or (bufn[i1] = $ffffff) or
|
|
((i1 > 0) and (bufp[i1 - 1] = $ffffff)) or ((i1 < bmp1.Width - 1) and (bufp[i1 + 1] = $ffffff)) or
|
|
((i1 > 0) and (buf [i1 - 1] = $ffffff)) or ((i1 < bmp1.Width - 1) and (buf [i1 + 1] = $ffffff)) or
|
|
((i1 > 0) and (bufn[i1 - 1] = $ffffff)) or ((i1 < bmp1.Width - 1) and (bufn[i1 + 1] = $ffffff)) ) then begin
|
|
if c1 <> $ffffff then begin
|
|
r := c1 and $ff;
|
|
g := (c1 shr 8) and $ff;
|
|
b := (c1 shr 16) and $ff;
|
|
y := $80;
|
|
r := (r + 1) div 2;
|
|
g := (g + 1) div 2;
|
|
b := (b + 1) div 2;
|
|
c1 := (y shl 24) or (b shl 16) or (g shl 8) or r;
|
|
end;
|
|
end else
|
|
c1 := $ff000000 or c1;
|
|
buf[i1] := c1;
|
|
end;
|
|
bmp1.SaveToFile('c:\desktop\transparent.bmp');
|
|
ExitProcess(0);
|
|
end;
|
|
|
|
(*
|
|
function SavePngFile(width, height, bitdepth: integer; alpha: boolean; pixels: pointer; const pngFile: AnsiString) : boolean;
|
|
|
|
function SwapDword(dw: dword) : dword;
|
|
begin
|
|
result := (dw shr 24) +
|
|
(dw shr 8) and $0000ff00 +
|
|
(dw shl 8) and $00ff0000 +
|
|
(dw shl 24);
|
|
end;
|
|
|
|
function SwapWord(w: word) : word;
|
|
begin
|
|
result := (w shr 8) + (w shl 8) and $ff00;
|
|
end;
|
|
|
|
function GetPngHeader : AnsiString;
|
|
begin
|
|
SetLength(result, 13);
|
|
TPACardinal(result)[0] := SwapDword(width);
|
|
TPACardinal(result)[1] := SwapDword(height);
|
|
TPAByte(result)[8] := bitdepth;
|
|
if alpha then
|
|
TPAByte(result)[9] := 6
|
|
else
|
|
TPAByte(result)[9] := 2;
|
|
end;
|
|
|
|
function CompressBitmap(buf: pointer; size: integer) : AnsiString;
|
|
|
|
function Adler32(buf: PByte; len: integer) : dword;
|
|
const Base = dword(65521); // largest prime smaller than 65536
|
|
NMAX = 3854; // Code with signed 32 bit integer
|
|
var c1, c2 : dword;
|
|
i1 : integer;
|
|
begin
|
|
c1 := 1;
|
|
c2 := 0;
|
|
while len > 0 do begin
|
|
if len < NMAX then
|
|
i1 := len
|
|
else i1 := NMAX;
|
|
dec(len, i1);
|
|
while i1 > 0 do begin
|
|
inc(c1, buf^);
|
|
inc(c2, c1);
|
|
inc(buf);
|
|
dec(i1);
|
|
end;
|
|
c1 := c1 mod Base;
|
|
c2 := c2 mod Base;
|
|
end;
|
|
result := (c2 shl 16) or c1;
|
|
end;
|
|
|
|
var i1 : integer;
|
|
pdw : ^dword;
|
|
begin
|
|
SetLength(result, size * 11 div 10 + 12);
|
|
i1 := Compress(buf, pointer(result), size, length(result));
|
|
if i1 > 0 then begin
|
|
SetLength(result, i1);
|
|
result := #$78#$01 + result + 'adlr';
|
|
pointer(pdw) := PAnsiChar(result) + length(result) - 4;
|
|
pdw^ := SwapDword(Adler32(buf, size));
|
|
end;
|
|
end;
|
|
|
|
procedure AddPngPart(var png: AnsiString; const name, data: AnsiString);
|
|
var pdw : ^dword;
|
|
crc : dword;
|
|
begin
|
|
png := png + 'len ' + name + data + 'crc ';
|
|
pointer(pdw) := PAnsiChar(png) + Length(png) - 4 - Length(data) - 8;
|
|
crc := not UpdateCrc32($ffffffff, pointer(NativeUInt(pdw) + 4)^, 4 + Length(data));
|
|
pdw^ := SwapDword(Length(data));
|
|
pointer(pdw) := PAnsiChar(png) + Length(png) - 4;
|
|
pdw^ := SwapDword(crc);
|
|
end;
|
|
|
|
var pngStr : AnsiString;
|
|
channels : integer;
|
|
size : integer;
|
|
buf : AnsiString;
|
|
src : TPWord;
|
|
dst : TPWord;
|
|
ix, iy, ic : integer;
|
|
fh : THandle;
|
|
c1 : dword;
|
|
begin
|
|
result := false;
|
|
if alpha then
|
|
channels := 4
|
|
else
|
|
channels := 3;
|
|
size := width * height * (bitdepth div 8) * channels + height;
|
|
SetLength(buf, size);
|
|
src := pixels;
|
|
dst := pointer(buf);
|
|
for iy := 0 to height - 1 do begin
|
|
TPByte(dst)^ := 0;
|
|
NativeUInt(dst) := NativeUInt(dst) + 1;
|
|
for ix := 0 to width - 1 do
|
|
for ic := 0 to channels - 1 do begin
|
|
dst^ := SwapWord(src^);
|
|
inc(src);
|
|
inc(dst);
|
|
end;
|
|
end;
|
|
pngStr := #$89#$50#$4e#$47#$0d#$0a#$1a#$0a;
|
|
AddPngPart(pngStr, 'IHDR', GetPngHeader);
|
|
AddPngPart(pngStr, 'IDAT', CompressBitmap(pointer(buf), size));
|
|
AddPngPart(pngStr, 'IEND', '');
|
|
fh := CreateFileA(PAnsiChar(pngFile), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0);
|
|
if fh <> INVALID_HANDLE_VALUE then begin
|
|
result := WriteFile(fh, pointer(pngStr)^, Length(pngStr), c1, nil) and (c1 = dword(Length(pngStr)));
|
|
CloseHandle(fh);
|
|
end;
|
|
end;
|
|
*)
|
|
|
|
end.
|