add --uchar option to vips_linear()
This commit is contained in:
parent
a181ef1f2c
commit
e489d2e099
@ -35,6 +35,7 @@
|
|||||||
- redone im_fwfft(), im_invfft(), im_freqflt(), im_disp_ps(), im_fractsurf(),
|
- redone im_fwfft(), im_invfft(), im_freqflt(), im_disp_ps(), im_fractsurf(),
|
||||||
im_phasecor() as classes
|
im_phasecor() as classes
|
||||||
- vips_colourspace() allows B_W, GREY16, RGB16 as source / target
|
- vips_colourspace() allows B_W, GREY16, RGB16 as source / target
|
||||||
|
- vips_linear() has a uchar output mode
|
||||||
|
|
||||||
9/1/14 started 7.36.6
|
9/1/14 started 7.36.6
|
||||||
- fix some clang compiler warnings
|
- fix some clang compiler warnings
|
||||||
|
6
TODO
6
TODO
@ -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
|
- do restrict on some more packages, we've just done arithmetic so far
|
||||||
|
|
||||||
also resample, colour, some of conversion, create,
|
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?
|
- maybe avg?
|
||||||
|
|
||||||
but avg doesn't subclass arithmetic, so we can't
|
but avg doesn't subclass arithmetic, so we can't
|
||||||
|
@ -554,8 +554,11 @@ vips_arithmetic_build( VipsObject *object )
|
|||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
arithmetic->out->Bands = arithmetic->ready[0]->Bands;
|
arithmetic->out->Bands = arithmetic->ready[0]->Bands;
|
||||||
arithmetic->out->BandFmt =
|
if( arithmetic->format != VIPS_FORMAT_NOTSET )
|
||||||
aclass->format_table[arithmetic->ready[0]->BandFmt];
|
arithmetic->out->BandFmt = arithmetic->format;
|
||||||
|
else
|
||||||
|
arithmetic->out->BandFmt =
|
||||||
|
aclass->format_table[arithmetic->ready[0]->BandFmt];
|
||||||
|
|
||||||
if( vips_image_generate( arithmetic->out,
|
if( vips_image_generate( arithmetic->out,
|
||||||
vips_start_many, vips_arithmetic_gen, vips_stop_many,
|
vips_start_many, vips_arithmetic_gen, vips_stop_many,
|
||||||
@ -592,6 +595,7 @@ static void
|
|||||||
vips_arithmetic_init( VipsArithmetic *arithmetic )
|
vips_arithmetic_init( VipsArithmetic *arithmetic )
|
||||||
{
|
{
|
||||||
arithmetic->base_bands = 1;
|
arithmetic->base_bands = 1;
|
||||||
|
arithmetic->format = VIPS_FORMAT_NOTSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -42,6 +42,8 @@
|
|||||||
* - 1ary is back, faster with gcc 4.8
|
* - 1ary is back, faster with gcc 4.8
|
||||||
* 3/12/13
|
* 3/12/13
|
||||||
* - try an ORC path with the band loop unrolled
|
* - 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 *a;
|
||||||
VipsArea *b;
|
VipsArea *b;
|
||||||
|
|
||||||
|
/* uchar output.
|
||||||
|
*/
|
||||||
|
gboolean uchar;
|
||||||
|
|
||||||
/* Our constants expanded to match arith->ready in size.
|
/* Our constants expanded to match arith->ready in size.
|
||||||
*/
|
*/
|
||||||
int n;
|
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 ) )
|
if( VIPS_OBJECT_CLASS( vips_linear_parent_class )->build( object ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -198,7 +207,6 @@ vips_linear_build( VipsObject *object )
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Complex input, complex output.
|
/* Complex input, complex output.
|
||||||
*/
|
*/
|
||||||
#define LOOPCMPLXN( IN, OUT ) { \
|
#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.
|
/* Lintra a buffer, n set of scale/offset.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
@ -228,21 +291,59 @@ vips_linear_buffer( VipsArithmetic *arithmetic,
|
|||||||
|
|
||||||
int i, x, k;
|
int i, x, k;
|
||||||
|
|
||||||
switch( vips_image_get_format( im ) ) {
|
if( linear->uchar )
|
||||||
case VIPS_FORMAT_UCHAR: LOOP( unsigned char, float ); break;
|
switch( vips_image_get_format( im ) ) {
|
||||||
case VIPS_FORMAT_CHAR: LOOP( signed char, float ); break;
|
case VIPS_FORMAT_UCHAR:
|
||||||
case VIPS_FORMAT_USHORT: LOOP( unsigned short, float ); break;
|
LOOPuc( unsigned char ); break;
|
||||||
case VIPS_FORMAT_SHORT: LOOP( signed short, float ); break;
|
case VIPS_FORMAT_CHAR:
|
||||||
case VIPS_FORMAT_UINT: LOOP( unsigned int, float ); break;
|
LOOPuc( signed char ); break;
|
||||||
case VIPS_FORMAT_INT: LOOP( signed int, float ); break;
|
case VIPS_FORMAT_USHORT:
|
||||||
case VIPS_FORMAT_FLOAT: LOOP( float, float ); break;
|
LOOPuc( unsigned short ); break;
|
||||||
case VIPS_FORMAT_DOUBLE: LOOP( double, double ); break;
|
case VIPS_FORMAT_SHORT:
|
||||||
case VIPS_FORMAT_COMPLEX: LOOPCMPLXN( float, float ); break;
|
LOOPuc( signed short ); break;
|
||||||
case VIPS_FORMAT_DPCOMPLEX: LOOPCMPLXN( double, double ); 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.
|
/* Save a bit of typing.
|
||||||
@ -296,6 +397,14 @@ vips_linear_class_init( VipsLinearClass *class )
|
|||||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsLinear, b ),
|
G_STRUCT_OFFSET( VipsLinear, b ),
|
||||||
VIPS_TYPE_ARRAY_DOUBLE );
|
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
|
static void
|
||||||
@ -331,9 +440,14 @@ vips_linearv( VipsImage *in, VipsImage **out,
|
|||||||
* @n: length of constant arrays
|
* @n: length of constant arrays
|
||||||
* @...: %NULL-terminated list of optional named arguments
|
* @...: %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
|
* 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
|
* is float for integer input, double for double input, complex for
|
||||||
* complex input and double complex for double complex input.
|
* 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
|
* 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
|
* 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
|
* @b: constant for addition
|
||||||
* @...: %NULL-terminated list of optional named arguments
|
* @...: %NULL-terminated list of optional named arguments
|
||||||
*
|
*
|
||||||
|
* Optional arguments:
|
||||||
|
*
|
||||||
|
* @uchar: output uchar pixels
|
||||||
|
*
|
||||||
* Run vips_linear() with a single constant.
|
* Run vips_linear() with a single constant.
|
||||||
*
|
*
|
||||||
* See also: vips_linear().
|
* See also: vips_linear().
|
||||||
|
@ -77,6 +77,10 @@ typedef struct _VipsArithmetic {
|
|||||||
/* The input images, ready for the operation.
|
/* The input images, ready for the operation.
|
||||||
*/
|
*/
|
||||||
VipsImage **ready;
|
VipsImage **ready;
|
||||||
|
|
||||||
|
/* Set this to override class->format_table.
|
||||||
|
*/
|
||||||
|
VipsBandFormat format;
|
||||||
} VipsArithmetic;
|
} VipsArithmetic;
|
||||||
|
|
||||||
typedef struct _VipsArithmeticClass {
|
typedef struct _VipsArithmeticClass {
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
* 30/5/13
|
* 30/5/13
|
||||||
* - redo as a class
|
* - redo as a class
|
||||||
* - add log scale and exponent as an option
|
* - 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 ) ||
|
if( vips_pow_const1( scale->in, &t[2], scale->exp, NULL ) ||
|
||||||
vips_linear1( t[2], &t[3], 1.0, 1.0, NULL ) ||
|
vips_linear1( t[2], &t[3], 1.0, 1.0, NULL ) ||
|
||||||
vips_log10( t[3], &t[4], NULL ) ||
|
vips_log10( t[3], &t[4], NULL ) ||
|
||||||
vips_linear1( t[4], &t[5], f, 0.0, NULL ) ||
|
vips_linear1( t[4], &t[5], f, 0.0,
|
||||||
vips_cast( t[5], &t[6], VIPS_FORMAT_UCHAR, NULL ) ||
|
"uchar", TRUE,
|
||||||
vips_image_write( t[6], conversion->out ) )
|
NULL ) ||
|
||||||
|
vips_image_write( t[5], conversion->out ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
double f = 255.0 / (mx - mn);
|
double f = 255.0 / (mx - mn);
|
||||||
double a = -(mn * f);
|
double a = -(mn * f);
|
||||||
|
|
||||||
if( vips_linear1( scale->in, &t[2], f, a, NULL ) ||
|
if( vips_linear1( scale->in, &t[2], f, a,
|
||||||
vips_cast( t[2], &t[3], VIPS_FORMAT_UCHAR, NULL ) ||
|
"uchar", TRUE,
|
||||||
vips_image_write( t[3], conversion->out ) )
|
NULL ) ||
|
||||||
|
vips_image_write( t[2], conversion->out ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,15 +115,16 @@ vips_point_build( VipsObject *object )
|
|||||||
float range = max - min;
|
float range = max - min;
|
||||||
|
|
||||||
if( vips_linear1( in, &t[2],
|
if( vips_linear1( in, &t[2],
|
||||||
255.0 / range, -min * 255.0 / range, NULL ) ||
|
255.0 / range, -min * 255.0 / range,
|
||||||
vips_cast( t[2], &t[3], VIPS_FORMAT_UCHAR, NULL ) )
|
"uchar", TRUE,
|
||||||
|
NULL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
in = t[3];
|
in = t[2];
|
||||||
|
|
||||||
/* uchar mode always does B_W. We don't want FOURIER or
|
/* uchar mode always does B_W. We don't want FOURIER or
|
||||||
* whatever in this case.
|
* whatever in this case.
|
||||||
*/
|
*/
|
||||||
t[3]->Type = VIPS_INTERPRETATION_B_W;
|
in->Type = VIPS_INTERPRETATION_B_W;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( vips_image_write( in, create->out ) )
|
if( vips_image_write( in, create->out ) )
|
||||||
|
Loading…
Reference in New Issue
Block a user