more accurate bilinear for int16 pixels

fixed-point interpolation could give small errors

see https://github.com/libvips/libvips/issues/1309

need a similar change for bicubic etc.
This commit is contained in:
John Cupitt 2019-05-13 18:32:48 +01:00
parent a02229245e
commit c9ba0915c1
1 changed files with 11 additions and 12 deletions

View File

@ -472,8 +472,8 @@ G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear,
z += 1; \ z += 1; \
} }
/* Interpolate a pel ... int32 and float types, no tables, float /* Interpolate a pel ... int16, int32 and float types, no tables, float
* arithmetic. Use float, not double, for coefficient calculation, or we can * arithmetic. Use double not float for coefficient calculation or we can
* get small over/undershoots. * get small over/undershoots.
*/ */
#define BILINEAR_FLOAT( TYPE ) { \ #define BILINEAR_FLOAT( TYPE ) { \
@ -498,15 +498,15 @@ G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear,
VIPS_UNROLL( b, BILINEAR_FLOAT_INNER ); \ VIPS_UNROLL( b, BILINEAR_FLOAT_INNER ); \
} }
/* Expand for band types. with a fixed-point interpolator and a float /* The fixed-point path is fine for uchar pixels, but it'll be inaccurate for
* interpolator. * shorts and larger.
*/ */
#define SWITCH_INTERPOLATE( FMT, INT, FLOAT ) { \ #define SWITCH_INTERPOLATE( FMT, INT, FLOAT ) { \
switch( (FMT) ) { \ switch( (FMT) ) { \
case VIPS_FORMAT_UCHAR: INT( unsigned char ); break; \ case VIPS_FORMAT_UCHAR: INT( unsigned char ); break; \
case VIPS_FORMAT_CHAR: INT( char ); break; \ case VIPS_FORMAT_CHAR: INT( char ); break; \
case VIPS_FORMAT_USHORT:INT( unsigned short ); break; \ case VIPS_FORMAT_USHORT:FLOAT( unsigned short ); break; \
case VIPS_FORMAT_SHORT: INT( short ); break; \ case VIPS_FORMAT_SHORT: FLOAT( short ); break; \
case VIPS_FORMAT_UINT: FLOAT( unsigned int ); break; \ case VIPS_FORMAT_UINT: FLOAT( unsigned int ); break; \
case VIPS_FORMAT_INT: FLOAT( int ); break; \ case VIPS_FORMAT_INT: FLOAT( int ); break; \
case VIPS_FORMAT_FLOAT: FLOAT( float ); break; \ case VIPS_FORMAT_FLOAT: FLOAT( float ); break; \
@ -544,8 +544,7 @@ vips_interpolate_bilinear_interpolate( VipsInterpolate *interpolate,
g_assert( (int) x + 1 < VIPS_RECT_RIGHT( &in->valid ) ); g_assert( (int) x + 1 < VIPS_RECT_RIGHT( &in->valid ) );
g_assert( (int) y + 1 < VIPS_RECT_BOTTOM( &in->valid ) ); g_assert( (int) y + 1 < VIPS_RECT_BOTTOM( &in->valid ) );
SWITCH_INTERPOLATE( in->im->BandFmt, SWITCH_INTERPOLATE( in->im->BandFmt, BILINEAR_INT, BILINEAR_FLOAT );
BILINEAR_INT, BILINEAR_FLOAT );
} }
static void static void