From b3484e1c8ea60ce7bb684e47ad07c64556ecf99b Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 11 Nov 2013 14:57:55 +0000 Subject: [PATCH] rename vips_gammacorrect() as vips_gamma() and swap exp to 1 / exp also works for any format --- ChangeLog | 2 + libvips/conversion/gammacorrect.c | 106 +++++++++++++++++++----------- libvips/deprecated/vips7compat.c | 4 +- libvips/include/vips/conversion.h | 2 +- 4 files changed, 73 insertions(+), 41 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1f18dde8..b3ccf803 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,8 @@ - radiance load supports sequential read - rewritten radiance decode is much faster - add vips_crop(), a synonym for vips_extract_area() +- rename vips_gammacorrect() as vips_gamma(), now takes 1 / exp +- vips_gamma() works for any format 18/10/13 started 7.36.3 - fix compiler warnings in ubuntu 13.10 diff --git a/libvips/conversion/gammacorrect.c b/libvips/conversion/gammacorrect.c index bd7b5bed..93aa1e93 100644 --- a/libvips/conversion/gammacorrect.c +++ b/libvips/conversion/gammacorrect.c @@ -1,4 +1,4 @@ -/* Gamma-correct image with factor gammafactor. +/* Raise an image to a gamma factor * * Copyright: 1990, N. Dessipris. * @@ -11,6 +11,10 @@ * - 16 bit as well * 1/8/13 * - redone as a class + * 11/11/13 + * - any format + * - calculate pow(1/exp) rather than pow(exp) to be consistent with + * other packages */ /* @@ -49,50 +53,76 @@ #include "pconversion.h" -typedef struct _VipsGammacorrect { +typedef struct _VipsGamma { VipsConversion parent_instance; VipsImage *in; double exponent; -} VipsGammacorrect; +} VipsGamma; -typedef VipsConversionClass VipsGammacorrectClass; +typedef VipsConversionClass VipsGammaClass; -G_DEFINE_TYPE( VipsGammacorrect, vips_gammacorrect, VIPS_TYPE_CONVERSION ); +G_DEFINE_TYPE( VipsGamma, vips_gamma, VIPS_TYPE_CONVERSION ); + +/* For each input format, what we normalise the pow() about. + */ +static double vips_gamma_maxval[10] = { +/* UC */ UCHAR_MAX, +/* C */ SCHAR_MAX, +/* US */ USHRT_MAX, +/* S */ SHRT_MAX, +/* UI */ UINT_MAX, +/* I */ INT_MAX, +/* F */ 1.0, +/* X */ 1.0, +/* D */ 1.0, +/* DX */ 1.0 +}; static int -vips_gammacorrect_build( VipsObject *object ) +vips_gamma_build( VipsObject *object ) { - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsConversion *conversion = VIPS_CONVERSION( object ); - VipsGammacorrect *gammacorrect = (VipsGammacorrect *) object; + VipsGamma *gamma = (VipsGamma *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 5 ); - VipsImage *in = gammacorrect->in; + VipsImage *in = gamma->in; + double scale; - double mx1, mx2; - - if( VIPS_OBJECT_CLASS( vips_gammacorrect_parent_class )-> + if( VIPS_OBJECT_CLASS( vips_gamma_parent_class )-> build( object ) ) return( -1 ); - if( vips_check_u8or16( class->nickname, in ) || - vips_identity( &t[0], - "ushort", in->BandFmt == VIPS_FORMAT_USHORT, - NULL ) || - vips_pow_const1( t[0], &t[1], gammacorrect->exponent, NULL ) || - vips_max( t[0], &mx1, NULL ) || - vips_max( t[1], &mx2, NULL ) || - vips_linear1( t[1], &t[2], mx1 / mx2, 0, NULL ) || - vips_cast( t[2], &t[3], in->BandFmt, NULL ) || - vips_maplut( in, &t[4], t[3], NULL ) || - vips_image_write( t[4], conversion->out ) ) - return( -1 ); + scale = pow( vips_gamma_maxval[in->BandFmt], + gamma->exponent ) / + vips_gamma_maxval[in->BandFmt]; + + if( in->BandFmt == VIPS_FORMAT_UCHAR && + in->BandFmt == VIPS_FORMAT_USHORT ) { + if( vips_identity( &t[0], + "ushort", in->BandFmt == VIPS_FORMAT_USHORT, + NULL ) || + vips_pow_const1( t[0], &t[1], + 1.0 / gamma->exponent, NULL ) || + vips_linear1( t[1], &t[2], 1.0 / scale, 0, NULL ) || + vips_cast( t[2], &t[3], in->BandFmt, NULL ) || + vips_maplut( in, &t[4], t[3], NULL ) || + vips_image_write( t[4], conversion->out ) ) + return( -1 ); + } + else { + if( vips_pow_const1( in, &t[1], + 1.0 / gamma->exponent, NULL ) || + vips_linear1( t[1], &t[2], 1.0 / scale, 0, NULL ) || + vips_cast( t[2], &t[3], in->BandFmt, NULL ) || + vips_image_write( t[3], conversion->out ) ) + return( -1 ); + } return( 0 ); } static void -vips_gammacorrect_class_init( VipsGammacorrectClass *class ) +vips_gamma_class_init( VipsGammaClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); @@ -101,9 +131,9 @@ vips_gammacorrect_class_init( VipsGammacorrectClass *class ) gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; - vobject_class->nickname = "gammacorrect"; - vobject_class->description = _( "gammacorrect a pair of images" ); - vobject_class->build = vips_gammacorrect_build; + vobject_class->nickname = "gamma"; + vobject_class->description = _( "gamma an image" ); + vobject_class->build = vips_gamma_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL_UNBUFFERED; @@ -111,48 +141,48 @@ vips_gammacorrect_class_init( VipsGammacorrectClass *class ) _( "in" ), _( "Input image" ), VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsGammacorrect, in ) ); + G_STRUCT_OFFSET( VipsGamma, in ) ); VIPS_ARG_DOUBLE( class, "exponent", 0, _( "exponent" ), _( "Gamma factor" ), VIPS_ARGUMENT_OPTIONAL_INPUT, - G_STRUCT_OFFSET( VipsGammacorrect, exponent ), + G_STRUCT_OFFSET( VipsGamma, exponent ), 0.000001, 1000.0, 2.4 ); } static void -vips_gammacorrect_init( VipsGammacorrect *gammacorrect ) +vips_gamma_init( VipsGamma *gamma ) { - gammacorrect->exponent = 2.4; + gamma->exponent = 1.0 / 2.4; } /** - * vips_gammacorrect: + * vips_gamma: * @in: input image * @out: output image * @...: %NULL-terminated list of optional named arguments * * Optional arguments: * - * @exponent: gamma factor, default 2.4 + * @exponent: gamma, default 1.0 / 2.4 * - * Gamma-correct an 8- or 16-bit unsigned image with a lookup table. The - * output format is the same as the input format. + * Calculate @in ** (1 / @exponent), normalising to the maximum range of the + * input type. For float types use 1.0 as the maximum. * * See also: vips_identity(), vips_pow_const1(), vips_maplut() * * Returns: 0 on success, -1 on error */ int -vips_gammacorrect( VipsImage *in, VipsImage **out, ... ) +vips_gamma( VipsImage *in, VipsImage **out, ... ) { va_list ap; int result; va_start( ap, out ); - result = vips_call_split( "gammacorrect", ap, in, out ); + result = vips_call_split( "gamma", ap, in, out ); va_end( ap ); return( result ); diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index c60e76dc..af3367c6 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -4150,8 +4150,8 @@ im_gammacorrect( IMAGE *in, IMAGE *out, double exponent ) { VipsImage *x; - if( vips_gammacorrect( in, &x, - "exponent", exponent, + if( vips_gamma( in, &x, + "exponent", 1.0 / exponent, NULL ) ) return( -1 ); diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index 69dc903c..2d2f95b3 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -186,7 +186,7 @@ int vips_flatten( VipsImage *in, VipsImage **out, ... ) int vips_falsecolour( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); -int vips_gammacorrect( VipsImage *in, VipsImage **out, ... ) +int vips_gamma( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); int im_insertset( VipsImage *main, VipsImage *sub, VipsImage *out, int n, int *x, int *y );