Log in

View Full Version : Formulas in Avisynths resizers?


redfordxx
11th December 2006, 11:19
Pls, can anybody explain, which formulas are used in resizers?
I am interested in all:
Bilinear, Bicubic, Lanczos, Spline.
(also with these b and c params incorporated)
The only concern is special case of double upsizing.
Tnx

IanB
11th December 2006, 13:09
From ...\avisynth\src\filters\resample_functions.cpp (http://avisynth2.cvs.sourceforge.net/avisynth2/avisynth/src/filters/resample_functions.cpp?revision=1.12&view=markup)/***************************
***** Point filter *****
**************************/

double PointFilter::f(double x) {
return 1.0;
}

/***************************
***** Triangle filter (BiLinear) *****
**************************/

double TriangleFilter::f(double x) {
x = fabs(x);
return (x<1.0) ? 1.0-x : 0.0;
}

/*********************************
*** Mitchell-Netravali filter (BiCubic) ***
*********************************/

MitchellNetravaliFilter::MitchellNetravaliFilter (double b=1./3., double c=1./3.) {
p0 = ( 6. - 2.*b ) / 6.;
p2 = ( -18. + 12.*b + 6.*c ) / 6.;
p3 = ( 12. - 9.*b - 6.*c ) / 6.;
q0 = ( 8.*b + 24.*c ) / 6.;
q1 = ( - 12.*b - 48.*c ) / 6.;
q2 = ( 6.*b + 30.*c ) / 6.;
q3 = ( - b - 6.*c ) / 6.;
}

double MitchellNetravaliFilter::f (double x) {
x = fabs(x);
return (x<1) ? (p0+x*x*(p2+x*p3)) : (x<2) ? (q0+x*(q1+x*(q2+x*q3))) : 0.0;
}

/***********************
*** Lanczos3 filter ***
***********************/
LanczosFilter::LanczosFilter(int t = 3) {
taps = (double)(max( 1,min(100,t)));
}

double LanczosFilter::sinc(double value) {
if (value != 0.0) {
value *= M_PI;
return sin(value) / value;
} else {
return 1.0;
}
}

double LanczosFilter::f(double value) {
value = fabs(value);

if (value < taps) {
return (sinc(value) * sinc(value / taps));
} else {
return 0.0;
}
}


/***********************
*** Spline16 filter ***
***********************/

double Spline16Filter::f(double value) {
value = fabs(value);

if (value < 1.0) {
return ( ( value - 9.0/5.0 ) * value - 1.0/5.0 ) * value + 1.0;
} else if (value < 2.0) {
return ( ( -1.0/3.0 * (value-1.0) + 4.0/5.0 ) * (value-1.0) - 7.0/15.0 ) * (value-1.0);
}
return 0.0;
}

/***********************
*** Spline36 filter ***
***********************/

double Spline36Filter::f(double value) {
value = fabs(value);

if (value < 1.0) {
return ( ( 13.0/11.0 * value - 453.0/ 209.0 ) * value - 3.0/ 209.0 ) * value + 1.0;
} else if (value < 2.0) {
return ( ( - 6.0/11.0 * (value-1.0) + 270.0/ 209.0 ) * (value-1.0) - 156.0/ 209.0 ) *(value-1.0);
} else if (value < 3.0) {
return ( ( 1.0/11.0 * (value-2.0) - 45.0/ 209.0 ) * (value-2.0) + 26.0/ 209.0 ) *(value-2.0);
}
return 0.0;
}

/***********************
*** Gaussian filter ***
***********************/

GaussianFilter::GaussianFilter(double p = 30.0) {
param = min(100.0,max(0.1,p));
}

double GaussianFilter::f(double value) {
value = fabs(value);
double p = param*0.1;
return pow(2.0, - p*value*value);
}

redfordxx
11th December 2006, 14:21
Sorry, I tried, was unable to extract the info I need.:(
Is it possible to write it like (example):Lanczos(2*x)= (-1*p(2*x-2) + 4*p(2*x-1) + 7*p(2*x) - 2*p(2*x+1))/10
Lanczos(2*x+1)=(-2*p(2*x-1) + 7*p(2*x) + 4*p(2*x+1) - 1*p(2*x+2))/10Again - I am interested in doublesizing only.

wonkey_monkey
13th December 2006, 00:43
This page may help:

http://www.path.unimelb.edu.au/~dersch/interpolator/interpolator.html

(The "weight" formulae it gives are for one dimension only - that confused me for a while)

David

redfordxx
13th December 2006, 11:04
Thanks,
BTW sinc256 looks wonderful.
(The "weight" formulae it gives are for one dimension only - that confused me for a while)
afaik Avisynth resizes onedimensionally in two passes.
I don't know whether any resizers work twodimensionally.

I assume thats why there are always problems with diagonal edges

Manao
13th December 2006, 11:26
I assume thats why there are always problems with diagonal edgesSince Avisynth's resizers are separable, making a two passes resizing or a single pass resize won't change the result ( except for rounding errors between the two passes, but those are quite small ).

wonkey_monkey
13th December 2006, 11:32
afaik Avisynth resizes onedimensionally in two passes.
I don't know whether any resizers work twodimensionally.

Mine does ;) (but it's a library I wrote in C for manipulating stills - I've no idea how to write plugins). My functions, at least, are quicker and (slightly) more accurate when operating in both dimensions at once, but I think whatever problems you see would be present in any case.

And yes, sinc256 is lovely (new versions of Panotools support sinc1024!), but IMO it's not really worth the time unless you're going to do multiple transformations separately. I use Spline16 in everything I do.

David

redfordxx
13th December 2006, 14:10
Mine does ;) (but it's a library I wrote in C for manipulating stills .
Can I have a look on it?
I think whatever problems you see would be present in any case.
There can be two problems I can see:
-"steps" on diagonal lines - one of my ideas to avoid is to aproximate (more pixels than function parameters, probably the closest neigbours equal with some SSD on distant pixels) with onedimensional function rotated the right direction on 2D. I am working on it, but I would probably end up with some multiplication instead of weighted average of pixels.
(there can be other ways of projection on one dimension, but this is I think the easiest one)
-"ringing" - maybe it can be checked somehow like allowing number of inflex points (I guess second derivation=0) between new pixel's neighbors:
If the the two left and two right neighbour pixels form convex shape -> allow no inflex point
If the the two left and two right neighbour pixels do not form convex shape -> allow one inflex point
But I don't know how to incorporate it into the formula.

G_M_C
13th December 2006, 16:08
Thanks,
BTW sinc256 looks wonderful.
[...]


No kidding :o

That would be a very usefull adition to the resizers in AviSynth. My guess is that i would be usefull because these days enlarging is getting more of an issue (HDTV's wanting higher resolutions).

redfordxx
13th December 2006, 16:23
Lets have colors like this: tipical diagonal edge.
0 1 4 9 16
1 0 1 4 9
4 1 0 1 4
9 4 1 0 1
16 9 4 1 0
this can be interpolated by g(x,y,alpha)=f(xa,ya)=poly2(xa)
[xa,ya] are new coordinates after alpha rotation of [x,y]
alpha=-45deg in this case...
I hope the diagonal edge would be nice in result.

Now. Approximating e.g. 4x4 area with some 1D poly3 or more or other function with at least 4 parameters + alpha where, fixing 2x2 center pixels to be equal and the rest with SSD, plus some "ringing protection", that could give maybe nice results.

redfordxx
13th December 2006, 16:49
No kidding :o

That would be a very usefull adition to the resizers in AviSynth. My guess is that i would be usefull because these days enlarging is getting more of an issue (HDTV's wanting higher resolutions).
I guess it will pretty be slow but ...
U can do in AviSynth double upsizing easily, you need
mt_convolution, Interleave, AssumeFieldBased, Weave
for vertical pass and
TurnLeft TurnRight for horizontal pass;-)

BTW: guess that in that formula...
probably 1/4==3.14....
took me some thinking to figure out, so save your time.

redfordxx
13th December 2006, 18:14
Thinking again, I am not so enthusiastic about sinc anymore. I
The reason it won so well is I guess beacuse
1)all rotating step were in float
2)it ended in same spot as it began
I would expect ringing almost everywhere when used in upsizing. And probably impossible to interpolate linearily growing color.

tritical
13th December 2006, 21:29
Lanczos is sinc interpolation (using a lanczos window)... sinc 256 is just sinc interpolation using 16x16 pixels. Since avisynth has a lanczos resize method with an adjustable number of taps, you can do sinc256 in avisynth using lanczosresize(taps=8).. or sinc1024 using lanczosresize(taps=16).

wonkey_monkey
13th December 2006, 23:51
That would be a very usefull adition to the resizers in AviSynth.

For a single transformation, there's little advantage to using sinc it's s-l-o-w (Didee might like it ;) )

Thinking again, I am not so enthusiastic about sinc anymore. I
The reason it won so well is I guess beacuse
1)all rotating step were in float

I'm not sure what you mean... the pixels values weren't stored as floats between rotations.

2)it ended in same spot as it began

But it's been through 36 individual rotations since then - it hasn't just been rotated through 180 degrees. I've repeated the procedure on that page and it the quality steadily decreases very slowly until you reach the end.

I would expect ringing almost everywhere when used in upsizing. And probably impossible to interpolate linearily growing color.

Not sure what you mean about growing color, but yes, you do get a lot of ringing when you start scaling up too much. But as the page says, sinc is the theoretical optimum of resampling.

Here's one function from my library which might help - sorry it's not commented (or better written!):

int get_pixel(struct image *input, float x,float y, int *rp,int *gp,int *bp, int s) {
int l;
int ix,iy;
int qx,qy;
float r,g,b;
float weight;
float d;
float dx,dy;

if (xweights==0 && yweights==0) {
xweights=calloc(5, sizeof(float))+2*sizeof(float);
yweights=calloc(5, sizeof(float))+2*sizeof(float);
}

// quick:
if (s==1) {
qx=MINMAX(0,x,input->w-1); qy=MINMAX(0,y,input->h-1);
*rp=0; *gp=0; *bp=0;
if (qx>=0 && qx<input->w && qy>=0 && qy<input->h) {
*rp=input->bitmap[qx][qy].r;
*gp=input->bitmap[qx][qy].g;
*bp=input->bitmap[qx][qy].b;
}
return(0);
}

// x=MINMAX(0.5,x,input->w-0.5); y=MINMAX(0.5,y,input->h-0.5);

dx=(x-(floor(x)+0.5));
dy=(y-(floor(y)+0.5));

for (l=-2; l<=2; l++) {
d=fabs(dx-l);
if (d<1) xweights[l]=((d-9.0/5.0)*d-1.0/5.0)*d+1.0;
if (d>=1 && d<2) xweights[l]=((-1.0/3.0*(d-1)+4.0/5.0)*(d-1)-7.0/15.0)*(d-1);
if (d>=2) xweights[l]=0;
d=fabs(dy-l);
if (d<1) yweights[l]=((d-9.0/5.0)*d-1.0/5.0)*d+1.0;
if (d>=1 && d<2) yweights[l]=((-1.0/3.0*(d-1)+4.0/5.0)*(d-1)-7.0/15.0)*(d-1);
if (d>=2) yweights[l]=0;
}

r=0; g=0; b=0;
for (ix=-2; ix<=2; ix++) {
qx=floor(x)+ix;
qx=MINMAX(0,qx,input->w-1);
if (xweights[ix]==0) continue;
for (iy=-2; iy<=2; iy++) {
if (yweights[iy]==0) continue;
qy=floor(y)+iy;
qy=MINMAX(0,qy,input->h-1);
if (qx>=0 && qx<input->w && qy>=0 && qy<input->h) {
weight=xweights[ix]*yweights[iy];

r+=weight*input->bitmap[qx][qy].r;
g+=weight*input->bitmap[qx][qy].g;
b+=weight*input->bitmap[qx][qy].b;
}
}
}

*rp=MINMAX(0,r,255)+0.5;
*gp=MINMAX(0,g,255)+0.5;
*bp=MINMAX(0,b,255)+0.5;

// free(xweights-2*sizeof(float));
// free(yweights-2*sizeof(float));
}


Given an image and a (float) point, it will return the interpolated colour at that point. Note that 0.5,0.5 is the exact center of the pixel at (0,0) - all other weights go to 0 and the central weight goes to 1 at these points, so it returns that pixel's colour.

David

foxyshadis
14th December 2006, 00:39
sinc is ideal only if the nyquist frequency is beyond the threshold of detection. If the source has detectable pixels (and let's face it, computer screens are so low resolution that you'd have to double screen dpi to get there, to say nothing of upsampling 480p to monitor size) you will get increasingly ugly artifacts. That's because the brickwall process pushes all the artifacting closer up to the nyquist area; if it's visible you get bad aliasing, fringing, and ringing. Higher-order sinc filters are only useful for audio, or very high resolution video.

It also doesn't deal with edges (http://foxyshadis.slightlydark.com/random/grid-lanczos80000.png) or high-frequency impulses (http://foxyshadis.slightlydark.com/random/grid-lanczos8high0000.png) particularly well. They're extreme cases but that's where "ideal" encounters "pathological", so where you have to watch out.

redfordxx
14th December 2006, 01:30
nyquist
I have read lot of posts from you and almost in every post having more than two sentences is a word I dont understand;)

tritical
14th December 2006, 02:24
http://en.wikipedia.org/wiki/Nyquist_frequency

http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem

Like foxyshadis said, sinc is only ideal for reconstruction of a bandlimited signal that was sampled at a frequency twice that of the highest frequency... and that is only for the true sinc function, not a truncated version.

MfA
14th December 2006, 03:48
A "correctly" sampled image would look like crap anyway ... the Nyquist-Shanning sampling theorem is largely irrelevant to image processing (unless you are doing stuff like deblurring). Truncated sinc based filters don't look good because they are theoretically sound, they look good because the ringing introduces a bit of sharpening which we like.