add --uchar option to vips_linear()

This commit is contained in:
John Cupitt 2014-01-14 19:31:19 +00:00
parent a181ef1f2c
commit e489d2e099
7 changed files with 162 additions and 34 deletions

View File

@ -35,6 +35,7 @@
- redone im_fwfft(), im_invfft(), im_freqflt(), im_disp_ps(), im_fractsurf(),
im_phasecor() as classes
- vips_colourspace() allows B_W, GREY16, RGB16 as source / target
- vips_linear() has a uchar output mode
9/1/14 started 7.36.6
- fix some clang compiler warnings

6
TODO
View File

@ -1,13 +1,9 @@
- now vips_linear() has uchar output, can we do something with orc?
- do restrict on some more packages, we've just done arithmetic so far
also resample, colour, some of conversion, create,
- orc is poor for float stuff ... if vips_linear() had a "preserve type"
option we could do something
maybe a "uchar ouput" option? this seems to be a very common case
- maybe avg?
but avg doesn't subclass arithmetic, so we can't

View File

@ -554,8 +554,11 @@ vips_arithmetic_build( VipsObject *object )
return( -1 );
arithmetic->out->Bands = arithmetic->ready[0]->Bands;
arithmetic->out->BandFmt =
aclass->format_table[arithmetic->ready[0]->BandFmt];
if( arithmetic->format != VIPS_FORMAT_NOTSET )
arithmetic->out->BandFmt = arithmetic->format;
else
arithmetic->out->BandFmt =
aclass->format_table[arithmetic->ready[0]->BandFmt];
if( vips_image_generate( arithmetic->out,
vips_start_many, vips_arithmetic_gen, vips_stop_many,
@ -592,6 +595,7 @@ static void
vips_arithmetic_init( VipsArithmetic *arithmetic )
{
arithmetic->base_bands = 1;
arithmetic->format = VIPS_FORMAT_NOTSET;
}
void

View File

@ -42,6 +42,8 @@
* - 1ary is back, faster with gcc 4.8
* 3/12/13
* - try an ORC path with the band loop unrolled
* 14/1/14
* - add uchar output option
*/
/*
@ -96,6 +98,10 @@ typedef struct _VipsLinear {
VipsArea *a;
VipsArea *b;
/* uchar output.
*/
gboolean uchar;
/* Our constants expanded to match arith->ready in size.
*/
int n;
@ -159,6 +165,9 @@ vips_linear_build( VipsObject *object )
}
}
if( linear->uchar )
arithmetic->format = VIPS_FORMAT_UCHAR;
if( VIPS_OBJECT_CLASS( vips_linear_parent_class )->build( object ) )
return( -1 );
@ -198,7 +207,6 @@ vips_linear_build( VipsObject *object )
} \
}
/* Complex input, complex output.
*/
#define LOOPCMPLXN( IN, OUT ) { \
@ -214,6 +222,61 @@ vips_linear_build( VipsObject *object )
} \
}
/* Non-complex input, any output, all bands of the constant equal, uchar
* output.
*/
#define LOOP1uc( IN ) { \
IN * restrict p = (IN *) in[0]; \
VipsPel * restrict q = (VipsPel *) out; \
float a1 = a[0]; \
float b1 = b[0]; \
int sz = width * nb; \
\
for( x = 0; x < sz; x++ ) { \
float t = a1 * p[x] + b1; \
\
q[x] = VIPS_CLIP( 0, t, 255 ); \
} \
}
/* Non-complex input, uchar output.
*/
#define LOOPNuc( IN ) { \
IN * restrict p = (IN *) in[0]; \
VipsPel * restrict q = (VipsPel *) out; \
\
for( i = 0, x = 0; x < width; x++ ) \
for( k = 0; k < nb; k++, i++ ) { \
double t = a[k] * p[i] + b[k]; \
\
q[i] = VIPS_CLIP( 0, t, 255 ); \
} \
}
#define LOOPuc( IN ) { \
if( linear->a->n == 1 && linear->b->n == 1 ) { \
LOOP1uc( IN ); \
} \
else { \
LOOPNuc( IN ); \
} \
}
/* Complex input, uchar output.
*/
#define LOOPCMPLXNuc( IN ) { \
IN * restrict p = (IN *) in[0]; \
VipsPel * restrict q = (VipsPel *) out; \
\
for( i = 0, x = 0; x < width; x++ ) \
for( k = 0; k < nb; k++, i++ ) { \
double t = a[k] * p[0] + b[k]; \
\
q[i] = VIPS_CLIP( 0, t, 255 ); \
p += 2; \
} \
}
/* Lintra a buffer, n set of scale/offset.
*/
static void
@ -228,21 +291,59 @@ vips_linear_buffer( VipsArithmetic *arithmetic,
int i, x, k;
switch( vips_image_get_format( im ) ) {
case VIPS_FORMAT_UCHAR: LOOP( unsigned char, float ); break;
case VIPS_FORMAT_CHAR: LOOP( signed char, float ); break;
case VIPS_FORMAT_USHORT: LOOP( unsigned short, float ); break;
case VIPS_FORMAT_SHORT: LOOP( signed short, float ); break;
case VIPS_FORMAT_UINT: LOOP( unsigned int, float ); break;
case VIPS_FORMAT_INT: LOOP( signed int, float ); break;
case VIPS_FORMAT_FLOAT: LOOP( float, float ); break;
case VIPS_FORMAT_DOUBLE: LOOP( double, double ); break;
case VIPS_FORMAT_COMPLEX: LOOPCMPLXN( float, float ); break;
case VIPS_FORMAT_DPCOMPLEX: LOOPCMPLXN( double, double ); break;
if( linear->uchar )
switch( vips_image_get_format( im ) ) {
case VIPS_FORMAT_UCHAR:
LOOPuc( unsigned char ); break;
case VIPS_FORMAT_CHAR:
LOOPuc( signed char ); break;
case VIPS_FORMAT_USHORT:
LOOPuc( unsigned short ); break;
case VIPS_FORMAT_SHORT:
LOOPuc( signed short ); break;
case VIPS_FORMAT_UINT:
LOOPuc( unsigned int ); break;
case VIPS_FORMAT_INT:
LOOPuc( signed int ); break;
case VIPS_FORMAT_FLOAT:
LOOPuc( float ); break;
case VIPS_FORMAT_DOUBLE:
LOOPuc( double ); break;
case VIPS_FORMAT_COMPLEX:
LOOPCMPLXNuc( float ); break;
case VIPS_FORMAT_DPCOMPLEX:
LOOPCMPLXNuc( double ); break;
default:
g_assert( 0 );
}
else
switch( vips_image_get_format( im ) ) {
case VIPS_FORMAT_UCHAR:
LOOP( unsigned char, float ); break;
case VIPS_FORMAT_CHAR:
LOOP( signed char, float ); break;
case VIPS_FORMAT_USHORT:
LOOP( unsigned short, float ); break;
case VIPS_FORMAT_SHORT:
LOOP( signed short, float ); break;
case VIPS_FORMAT_UINT:
LOOP( unsigned int, float ); break;
case VIPS_FORMAT_INT:
LOOP( signed int, float ); break;
case VIPS_FORMAT_FLOAT:
LOOP( float, float ); break;
case VIPS_FORMAT_DOUBLE:
LOOP( double, double ); break;
case VIPS_FORMAT_COMPLEX:
LOOPCMPLXN( float, float ); break;
case VIPS_FORMAT_DPCOMPLEX:
LOOPCMPLXN( double, double ); break;
default:
g_assert( 0 );
}
default:
g_assert( 0 );
}
}
/* Save a bit of typing.
@ -296,6 +397,14 @@ vips_linear_class_init( VipsLinearClass *class )
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsLinear, b ),
VIPS_TYPE_ARRAY_DOUBLE );
VIPS_ARG_BOOL( class, "uchar", 112,
_( "uchar" ),
_( "Output should be uchar" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsLinear, uchar ),
FALSE );
}
static void
@ -331,9 +440,14 @@ vips_linearv( VipsImage *in, VipsImage **out,
* @n: length of constant arrays
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @uchar: output uchar pixels
*
* Pass an image through a linear transform, ie. (@out = @in * @a + @b). Output
* is always float for integer input, double for double input, complex for
* complex input and double complex for double complex input.
* is float for integer input, double for double input, complex for
* complex input and double complex for double complex input. Set @uchar to
* output uchar pixels.
*
* If the arrays of constants have just one element, that constant is used for
* all image bands. If the arrays have more than one element and they have
@ -367,6 +481,10 @@ vips_linear( VipsImage *in, VipsImage **out, double *a, double *b, int n, ... )
* @b: constant for addition
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @uchar: output uchar pixels
*
* Run vips_linear() with a single constant.
*
* See also: vips_linear().

View File

@ -77,6 +77,10 @@ typedef struct _VipsArithmetic {
/* The input images, ready for the operation.
*/
VipsImage **ready;
/* Set this to override class->format_table.
*/
VipsBandFormat format;
} VipsArithmetic;
typedef struct _VipsArithmeticClass {

View File

@ -18,6 +18,8 @@
* 30/5/13
* - redo as a class
* - add log scale and exponent as an option
* 14/1/14
* - use linear uchar mode
*/
/*
@ -107,18 +109,20 @@ vips_scale_build( VipsObject *object )
if( vips_pow_const1( scale->in, &t[2], scale->exp, NULL ) ||
vips_linear1( t[2], &t[3], 1.0, 1.0, NULL ) ||
vips_log10( t[3], &t[4], NULL ) ||
vips_linear1( t[4], &t[5], f, 0.0, NULL ) ||
vips_cast( t[5], &t[6], VIPS_FORMAT_UCHAR, NULL ) ||
vips_image_write( t[6], conversion->out ) )
vips_linear1( t[4], &t[5], f, 0.0,
"uchar", TRUE,
NULL ) ||
vips_image_write( t[5], conversion->out ) )
return( -1 );
}
else {
double f = 255.0 / (mx - mn);
double a = -(mn * f);
if( vips_linear1( scale->in, &t[2], f, a, NULL ) ||
vips_cast( t[2], &t[3], VIPS_FORMAT_UCHAR, NULL ) ||
vips_image_write( t[3], conversion->out ) )
if( vips_linear1( scale->in, &t[2], f, a,
"uchar", TRUE,
NULL ) ||
vips_image_write( t[2], conversion->out ) )
return( -1 );
}

View File

@ -115,15 +115,16 @@ vips_point_build( VipsObject *object )
float range = max - min;
if( vips_linear1( in, &t[2],
255.0 / range, -min * 255.0 / range, NULL ) ||
vips_cast( t[2], &t[3], VIPS_FORMAT_UCHAR, NULL ) )
255.0 / range, -min * 255.0 / range,
"uchar", TRUE,
NULL ) )
return( -1 );
in = t[3];
in = t[2];
/* uchar mode always does B_W. We don't want FOURIER or
* whatever in this case.
*/
t[3]->Type = VIPS_INTERPRETATION_B_W;
in->Type = VIPS_INTERPRETATION_B_W;
}
if( vips_image_write( in, create->out ) )