add signed int bicubic path

better rounding for 8- and 16-bit signed int bicubic
This commit is contained in:
John Cupitt 2014-08-07 10:13:08 +01:00
parent 2e3baa1bef
commit 2b086cfe6e
3 changed files with 158 additions and 39 deletions

2
TODO
View File

@ -1,5 +1,3 @@
- bicubic needs a signed int lut path with rounding in the other direction
for negatives
- vips_object_unref_outputs() needs docs ... bindings will need it

View File

@ -104,9 +104,10 @@ G_DEFINE_TYPE( VipsInterpolateBicubic, vips_interpolate_bicubic,
/* Fixed-point version, for 8 and 16-bit types.
*/
template <typename T, int min_value, int max_value>
template <typename T, int max_value>
static void inline
bicubic_int_tab( void *pout, const VipsPel *pin,
bicubic_unsigned_int_tab( void *pout, const VipsPel *pin,
const int bands, const int lskip,
const int *cx, const int *cy )
{
@ -152,7 +153,73 @@ bicubic_int_tab( void *pout, const VipsPel *pin,
const T qua_thr = in[l3_plus_b2];
const T qua_fou = in[l3_plus_b3];
int bicubic = bicubic_int<T>(
int bicubic = bicubic_unsigned_int<T>(
uno_one, uno_two, uno_thr, uno_fou,
dos_one, dos_two, dos_thr, dos_fou,
tre_one, tre_two, tre_thr, tre_fou,
qua_one, qua_two, qua_thr, qua_fou,
cx, cy );
if( bicubic < 0 )
bicubic = 0;
else if( bicubic > max_value )
bicubic = max_value;
out[z] = bicubic;
in += 1;
}
}
template <typename T, int min_value, int max_value>
static void inline
bicubic_signed_int_tab( void *pout, const VipsPel *pin,
const int bands, const int lskip,
const int *cx, const int *cy )
{
T* restrict out = (T *) pout;
const T* restrict in = (T *) pin;
const int b1 = bands;
const int b2 = b1 + b1;
const int b3 = b1 + b2;
const int l1 = lskip / sizeof( T );
const int l2 = l1 + l1;
const int l3 = l1 + l2;
const int l1_plus_b1 = l1 + b1;
const int l1_plus_b2 = l1 + b2;
const int l1_plus_b3 = l1 + b3;
const int l2_plus_b1 = l2 + b1;
const int l2_plus_b2 = l2 + b2;
const int l2_plus_b3 = l2 + b3;
const int l3_plus_b1 = l3 + b1;
const int l3_plus_b2 = l3 + b2;
const int l3_plus_b3 = l3 + b3;
for( int z = 0; z < bands; z++ ) {
const T uno_one = in[0];
const T uno_two = in[b1];
const T uno_thr = in[b2];
const T uno_fou = in[b3];
const T dos_one = in[l1];
const T dos_two = in[l1_plus_b1];
const T dos_thr = in[l1_plus_b2];
const T dos_fou = in[l1_plus_b3];
const T tre_one = in[l2];
const T tre_two = in[l2_plus_b1];
const T tre_thr = in[l2_plus_b2];
const T tre_fou = in[l2_plus_b3];
const T qua_one = in[l3];
const T qua_two = in[l3_plus_b1];
const T qua_thr = in[l3_plus_b2];
const T qua_fou = in[l3_plus_b3];
int bicubic = bicubic_signed_int<T>(
uno_one, uno_two, uno_thr, uno_fou,
dos_one, dos_two, dos_thr, dos_fou,
tre_one, tre_two, tre_thr, tre_fou,
@ -350,7 +417,7 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
switch( in->im->BandFmt ) {
case VIPS_FORMAT_UCHAR:
bicubic_int_tab<unsigned char, 0, UCHAR_MAX>(
bicubic_unsigned_int_tab<unsigned char, UCHAR_MAX>(
out, p, bands, lskip,
cxi, cyi );
@ -371,19 +438,19 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
break;
case VIPS_FORMAT_CHAR:
bicubic_int_tab<signed char, SCHAR_MIN, SCHAR_MAX>(
bicubic_signed_int_tab<signed char, SCHAR_MIN, SCHAR_MAX>(
out, p, bands, lskip,
cxi, cyi );
break;
case VIPS_FORMAT_USHORT:
bicubic_int_tab<unsigned short, 0, USHRT_MAX>(
bicubic_unsigned_int_tab<unsigned short, USHRT_MAX>(
out, p, bands, lskip,
cxi, cyi );
break;
case VIPS_FORMAT_SHORT:
bicubic_int_tab<signed short, SHRT_MIN, SHRT_MAX>(
bicubic_signed_int_tab<signed short, SHRT_MIN, SHRT_MAX>(
out, p, bands, lskip,
cxi, cyi );
break;

View File

@ -169,49 +169,103 @@ bilinear_nosign(
* Bicubic (Catmull-Rom) interpolation templates:
*/
static int inline
unsigned_fixed_round( int v )
{
const int round_by = VIPS_INTERPOLATE_SCALE >> 1;
return( (v + round_by) >> VIPS_INTERPOLATE_SHIFT );
}
/* Fixed-point integer bicubic, used for 8 and 16-bit types.
*/
template <typename T> static int inline
bicubic_int(
bicubic_unsigned_int(
const T uno_one, const T uno_two, const T uno_thr, const T uno_fou,
const T dos_one, const T dos_two, const T dos_thr, const T dos_fou,
const T tre_one, const T tre_two, const T tre_thr, const T tre_fou,
const T qua_one, const T qua_two, const T qua_thr, const T qua_fou,
const int* restrict cx, const int* restrict cy )
{
const int r0 =
(cx[0] * uno_one +
cx[1] * uno_two +
cx[2] * uno_thr +
cx[3] * uno_fou +
(VIPS_INTERPOLATE_SCALE >> 1)) >> VIPS_INTERPOLATE_SHIFT;
const int r0 = unsigned_fixed_round(
cx[0] * uno_one +
cx[1] * uno_two +
cx[2] * uno_thr +
cx[3] * uno_fou );
const int r1 =
(cx[0] * dos_one +
cx[1] * dos_two +
cx[2] * dos_thr +
cx[3] * dos_fou +
(VIPS_INTERPOLATE_SCALE >> 1)) >> VIPS_INTERPOLATE_SHIFT;
const int r1 = unsigned_fixed_round(
cx[0] * dos_one +
cx[1] * dos_two +
cx[2] * dos_thr +
cx[3] * dos_fou );
const int r2 =
(cx[0] * tre_one +
cx[1] * tre_two +
cx[2] * tre_thr +
cx[3] * tre_fou +
(VIPS_INTERPOLATE_SCALE >> 1)) >> VIPS_INTERPOLATE_SHIFT;
const int r2 = unsigned_fixed_round(
cx[0] * tre_one +
cx[1] * tre_two +
cx[2] * tre_thr +
cx[3] * tre_fou );
const int r3 =
(cx[0] * qua_one +
cx[1] * qua_two +
cx[2] * qua_thr +
cx[3] * qua_fou +
(VIPS_INTERPOLATE_SCALE >> 1)) >> VIPS_INTERPOLATE_SHIFT;
const int r3 = unsigned_fixed_round(
cx[0] * qua_one +
cx[1] * qua_two +
cx[2] * qua_thr +
cx[3] * qua_fou );
return( (cy[0] * r0 +
cy[1] * r1 +
cy[2] * r2 +
cy[3] * r3 +
(VIPS_INTERPOLATE_SCALE >> 1)) >> VIPS_INTERPOLATE_SHIFT );
return( unsigned_fixed_round(
cy[0] * r0 +
cy[1] * r1 +
cy[2] * r2 +
cy[3] * r3 ) );
}
static int inline
signed_fixed_round( int v )
{
const int sign_of_v = 2 * (v > 0) - 1;
const int round_by = sign_of_v * (VIPS_INTERPOLATE_SCALE >> 1);
return( (v + round_by) >> VIPS_INTERPOLATE_SHIFT );
}
/* Fixed-point integer bicubic, used for 8 and 16-bit types.
*/
template <typename T> static int inline
bicubic_signed_int(
const T uno_one, const T uno_two, const T uno_thr, const T uno_fou,
const T dos_one, const T dos_two, const T dos_thr, const T dos_fou,
const T tre_one, const T tre_two, const T tre_thr, const T tre_fou,
const T qua_one, const T qua_two, const T qua_thr, const T qua_fou,
const int* restrict cx, const int* restrict cy )
{
const int r0 = signed_fixed_round(
cx[0] * uno_one +
cx[1] * uno_two +
cx[2] * uno_thr +
cx[3] * uno_fou );
const int r1 = signed_fixed_round(
cx[0] * dos_one +
cx[1] * dos_two +
cx[2] * dos_thr +
cx[3] * dos_fou );
const int r2 = signed_fixed_round(
cx[0] * tre_one +
cx[1] * tre_two +
cx[2] * tre_thr +
cx[3] * tre_fou );
const int r3 = signed_fixed_round(
cx[0] * qua_one +
cx[1] * qua_two +
cx[2] * qua_thr +
cx[3] * qua_fou );
return( signed_fixed_round(
cy[0] * r0 +
cy[1] * r1 +
cy[2] * r2 +
cy[3] * r3 ) );
}
/* Floating-point bicubic, used for int/float/double types.