new bilinear

This commit is contained in:
John Cupitt 2011-01-11 14:48:45 +00:00
parent 213cb019de
commit ae31832180
3 changed files with 3 additions and 218 deletions

View File

@ -7,6 +7,7 @@
- updated README - updated README
- don't use tables for bilinear on float data for a small speedup (thanks - don't use tables for bilinear on float data for a small speedup (thanks
Nicolas Robidoux) Nicolas Robidoux)
- no tables for uchar either, about a 15% speedup (thank Nicolas)
30/11/10 started 7.24.0 30/11/10 started 7.24.0
- bump for new stable - bump for new stable

20
TODO
View File

@ -1,23 +1,3 @@
- bilinear tweaks need sorting out
time vips im_affinei wtc.v wtc2.v bilinear 0.97 0 0 0.97 0 0 0 0 10000 10000
fastest of 4 runs, user time
7.24 - 4.0s
j-monday - 3.5s
n-20:59 - 4.0s
n-21:14 - 3.9s
n-22:20 - 4.1s
n-00:06 - 3.8s
n-14:26 - 4.1s
- fits save
- lazy fits load
- im_conv()/im_morph() could have more than 10 programs? try 20 and see if we - im_conv()/im_morph() could have more than 10 programs? try 20 and see if we
still have a speedup still have a speedup

View File

@ -326,46 +326,14 @@ typedef VipsInterpolateClass VipsInterpolateBilinearClass;
G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear, G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear,
VIPS_TYPE_INTERPOLATE ); VIPS_TYPE_INTERPOLATE );
/* Precalculated interpolation matricies, only for int types.
* We go to scale + 1 so
* we can round-to-nearest safely.
*/
static int vips_bilinear_matrixi
[VIPS_TRANSFORM_SCALE + 1][VIPS_TRANSFORM_SCALE + 1][4];
/* in this class, name vars in the 2x2 grid as eg. /* in this class, name vars in the 2x2 grid as eg.
* p1 p2 * p1 p2
* p3 p4 * p3 p4
*/ */
/* Interpolate a section ... int8/16 types, lookup tables for interpolation /* Fixed-point arithmetic, no tables.
* factors, fixed-point arithmetic.
*/ */
#define BILINEAR_INT( TYPE ) { \ #define BILINEAR_INT( TYPE ) { \
TYPE *tq = (TYPE *) out; \
\
const int six = sx & (VIPS_TRANSFORM_SCALE * 2 - 1); \
const int siy = sy & (VIPS_TRANSFORM_SCALE * 2 - 1); \
\
const int tx = (six + 1) >> 1; \
const int ty = (siy + 1) >> 1; \
\
const int c1 = vips_bilinear_matrixi[tx][ty][0]; \
const int c2 = vips_bilinear_matrixi[tx][ty][1]; \
const int c3 = vips_bilinear_matrixi[tx][ty][2]; \
const int c4 = vips_bilinear_matrixi[tx][ty][3]; \
\
const TYPE *tp1 = (TYPE *) p1; \
const TYPE *tp2 = (TYPE *) p2; \
const TYPE *tp3 = (TYPE *) p3; \
const TYPE *tp4 = (TYPE *) p4; \
\
for( z = 0; z < b; z++ ) \
tq[z] = (c1 * tp1[z] + c2 * tp2[z] + \
c3 * tp3[z] + c4 * tp4[z]) >> VIPS_INTERPOLATE_SHIFT; \
}
#define BILINEAR_INT2( TYPE ) { \
TYPE *tq = (TYPE *) out; \ TYPE *tq = (TYPE *) out; \
\ \
const int X = (x - ix) * 128; \ const int X = (x - ix) * 128; \
@ -384,118 +352,6 @@ static int vips_bilinear_matrixi
} \ } \
} }
/* n-20:59
*/
#define BILINEAR_INT3( TYPE ) { \
TYPE *tq = (TYPE *) out; \
\
const int X = (x - ix) * 128; \
const int Y = (y - iy) * 128; \
\
const TYPE *tp1 = (TYPE *) p1; \
const TYPE *tp2 = (TYPE *) p2; \
const TYPE *tp3 = (TYPE *) p3; \
const TYPE *tp4 = (TYPE *) p4; \
\
for( z = 0; z < b; z++ ) { \
const int d = tp2[z] - tp1[z]; \
\
tq[z] = ( ( ( ( ( ( tp4[z] - tp3[z] - d ) * X ) >> 7 ) + tp3[z] - tp1[z]) * Y + d * X) >> 7) + tp1[z]; \
} \
}
/* n-21:14
*/
#define BILINEAR_INT4( TYPE ) { \
TYPE *tq = (TYPE *) out; \
\
const int X = (x - ix) * 128; \
const int Y = (y - iy) * 128; \
\
const TYPE *tp1 = (TYPE *) p1; \
const TYPE *tp2 = (TYPE *) p2; \
const TYPE *tp3 = (TYPE *) p3; \
const TYPE *tp4 = (TYPE *) p4; \
\
for( z = 0; z < b; z++ ) { \
const int d21 = tp2[z] - tp1[z]; \
const int d31 = tp3[z] - tp1[z]; \
const int d34 = tp3[z] - tp4[z]; \
\
tq[z] = ( ( d21 * X + ( d31 - ( ( (d21+d34) * X ) >> 7)) * Y) >> 7) + tp1[z]; \
} \
}
/* n-22:20
*/
#define BILINEAR_INT5( TYPE ) { \
TYPE *tq = (TYPE *) out; \
\
const int X = (x - ix) * 128; \
const int Y = (y - iy) * 128; \
\
const TYPE *tp1 = (TYPE *) p1; \
const TYPE *tp2 = (TYPE *) p2; \
const TYPE *tp3 = (TYPE *) p3; \
const TYPE *tp4 = (TYPE *) p4; \
\
const int X128 = X * 128; \
\
for( z = 0; z < b; z++ ) { \
const int d21 = tp2[z] - tp1[z]; \
const int d31 = tp3[z] - tp1[z]; \
const int d34 = tp3[z] - tp4[z]; \
\
tq[z] = ( ( d21 * X128 + ( d31 * 128 - ( ( (d21+d34) * X ))) * Y) >> 14) + tp1[z]; \
} \
}
/* n-00:06
*/
#define BILINEAR_INT6( TYPE ) { \
TYPE *tq = (TYPE *) out; \
\
const int X = (x - ix) * 128; \
const int Y = (y - iy) * 128; \
\
const TYPE *tp1 = (TYPE *) p1; \
const TYPE *tp2 = (TYPE *) p2; \
const TYPE *tp3 = (TYPE *) p3; \
const TYPE *tp4 = (TYPE *) p4; \
\
const int X128 = X * 128; \
\
for( z = 0; z < b; z++ ) { \
const int d21 = tp2[z] - tp1[z]; \
const int d31 = tp3[z] - tp1[z]; \
const int d34 = tp3[z] - tp4[z]; \
\
tq[z] = ( tp1[z] << 14 + d21 * X128 + ( d31 * 128 - ( ( (d21+d34) * X ))) * Y) >> 14; \
} \
}
/* n-14:26
*/
#define BILINEAR_INT7( TYPE ) { \
TYPE *tq = (TYPE *) out; \
\
const int X = (x - ix) * 128; \
const int Y = (y - iy) * 128; \
\
const TYPE *tp1 = (TYPE *) p1; \
const TYPE *tp2 = (TYPE *) p2; \
const TYPE *tp3 = (TYPE *) p3; \
const TYPE *tp4 = (TYPE *) p4; \
\
for( z = 0; z < b; z++ ) { \
const int d21 = tp2[z] - tp1[z]; \
const int d31 = tp3[z] - tp1[z]; \
const int d34 = tp3[z] - tp4[z]; \
\
tq[z] = tp1[z] + ( ( ( ( d31 << 7 ) - ( ( (d21+d34) * X ))) * Y + ( d21 * ( X << 7 ) )) >> 14); \
} \
}
/* Interpolate a pel ... int32 and float types, no tables, float /* Interpolate a pel ... int32 and float types, no tables, float
* arithmetic. * arithmetic.
*/ */
@ -551,26 +407,6 @@ vips_interpolate_bilinear_interpolate( VipsInterpolate *interpolate,
const int ls = IM_REGION_LSKIP( in ); const int ls = IM_REGION_LSKIP( in );
const int b = in->im->Bands; const int b = in->im->Bands;
/* We want ((int)x), but the tables versions needs to find a mask
* index quickly from the residual. Calculate both.
*/
/* Find the mask index. We round-to-nearest, so we need to generate
* indexes in 0 to VIPS_TRANSFORM_SCALE, 2^n + 1 values. We multiply
* by 2 more than we need to, add one, mask, then shift down again to
* get the extra range.
const int sx = x * VIPS_TRANSFORM_SCALE * 2;
const int sy = y * VIPS_TRANSFORM_SCALE * 2;
*/
/* We want ((int)x) ... avoid repeating this double -> int conversion
* by just shifting sx down.
const int ix = sx >> (VIPS_TRANSFORM_SHIFT + 1);
const int iy = sy >> (VIPS_TRANSFORM_SHIFT + 1);
*/
/*
*/
const int ix = (int) x; const int ix = (int) x;
const int iy = (int) y; const int iy = (int) y;
@ -582,7 +418,7 @@ vips_interpolate_bilinear_interpolate( VipsInterpolate *interpolate,
int z; int z;
SWITCH_INTERPOLATE( in->im->BandFmt, SWITCH_INTERPOLATE( in->im->BandFmt,
BILINEAR_INT2, BILINEAR_FLOAT ); BILINEAR_INT, BILINEAR_FLOAT );
} }
static void static void
@ -591,44 +427,12 @@ vips_interpolate_bilinear_class_init( VipsInterpolateBilinearClass *class )
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class ); VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
VipsInterpolateClass *interpolate_class = VipsInterpolateClass *interpolate_class =
(VipsInterpolateClass *) class; (VipsInterpolateClass *) class;
int x, y;
object_class->nickname = "bilinear"; object_class->nickname = "bilinear";
object_class->description = _( "Bilinear interpolation" ); object_class->description = _( "Bilinear interpolation" );
interpolate_class->interpolate = vips_interpolate_bilinear_interpolate; interpolate_class->interpolate = vips_interpolate_bilinear_interpolate;
interpolate_class->window_size = 2; interpolate_class->window_size = 2;
/* Calculate the interpolation matricies.
*/
for( x = 0; x < VIPS_TRANSFORM_SCALE + 1; x++ )
for( y = 0; y < VIPS_TRANSFORM_SCALE + 1; y++ ) {
double X, Y, Xd, Yd;
double c1, c2, c3, c4;
/* Interpolation errors.
*/
X = (double) x / VIPS_TRANSFORM_SCALE;
Y = (double) y / VIPS_TRANSFORM_SCALE;
Xd = 1.0 - X;
Yd = 1.0 - Y;
/* Weights.
*/
c1 = Xd * Yd;
c2 = X * Yd;
c3 = Xd * Y;
c4 = X * Y;
vips_bilinear_matrixi[x][y][0] =
c1 * VIPS_INTERPOLATE_SCALE;
vips_bilinear_matrixi[x][y][1] =
c2 * VIPS_INTERPOLATE_SCALE;
vips_bilinear_matrixi[x][y][2] =
c3 * VIPS_INTERPOLATE_SCALE;
vips_bilinear_matrixi[x][y][3] =
c4 * VIPS_INTERPOLATE_SCALE;
}
} }
static void static void