now works woo

python interface plus test and benchmark to go

update c++ too I guess

oh docs as well sigh
This commit is contained in:
John Cupitt 2015-11-07 18:47:02 +00:00
parent 3ed0904fab
commit 9cb2674a77
6 changed files with 276 additions and 29 deletions

View File

@ -6,6 +6,7 @@
- old code still there as vips_shrink2() for testing
- only allow [] for filename options
- add memory.h to Python API .. makes tracked highwater visible
- added bandjoin_const to add constant bands to an image
7/5/15 started 8.1.1
- oop, vips-8.0 wrapper script should be vips-8.1, thanks Danilo

6
TODO
View File

@ -1,6 +1,8 @@
- started bandjoinconst
- pyvips should use bandjoin_const when possible
see also unaryconst.c
benchmark, maybe not worthwhile
- test suite is broken, float->int mask I guess
- looks like we have a race in tiled threadcache? see

View File

@ -24,6 +24,8 @@
* - sizealike inputs
* 27/10/11
* - rewrite as a class
* 7/11/15
* - added bandjoin_const
*/
/*
@ -278,5 +280,197 @@ typedef struct _VipsBandjoinConst {
typedef VipsBandaryClass VipsBandjoinConstClass;
//G_DEFINE_TYPE( VipsBandjoinConst, vips_bandjoin_const, VIPS_TYPE_BANDARY );
G_DEFINE_TYPE( VipsBandjoinConst, vips_bandjoin_const, VIPS_TYPE_BANDARY );
static void
vips_bandjoin_const_finalize( GObject *object )
{
VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) object;
VIPS_FREE( bandjoin->c_ready );
G_OBJECT_CLASS( vips_bandjoin_const_parent_class )->finalize( object );
}
static void
vips_bandjoin_const_buffer( VipsBandary *bandary,
VipsPel *q, VipsPel **p, int width )
{
VipsConversion *conversion = (VipsConversion *) bandary;
VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) bandary;
VipsImage *in = bandary->ready[0];
/* Output pel size.
*/
const int ops = VIPS_IMAGE_SIZEOF_PEL( conversion->out );
/* Input pel size.
*/
const int ips = VIPS_IMAGE_SIZEOF_PEL( in );
/* Extra bands size.
*/
const int ebs = ops - ips;
VipsPel * restrict p1;
VipsPel * restrict q1;
int x, z;
q1 = q;
p1 = p[0];
for( x = 0; x < width; x++ ) {
for( z = 0; z < ips; z++ )
q1[z] = p1[z];
p1 += ips;
q1 += ips;
for( z = 0; z < ebs; z++ )
q1[z] = bandjoin->c_ready[z];
q1 += ebs;
}
}
static int
vips_bandjoin_const_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsBandary *bandary = (VipsBandary *) object;
VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) object;
if( bandjoin->c &&
bandjoin->in ) {
double *c;
int n;
c = vips_array_double_get( bandjoin->c, &n );
if( n == 0 )
return( vips_bandary_copy( bandary ) );
else
bandary->out_bands = bandjoin->in->Bands + n;
bandary->n = 1;
bandary->in = &bandjoin->in;
if( !(bandjoin->c_ready = vips__vector_to_pels( class->nickname,
n, bandjoin->in->BandFmt, bandjoin->in->Coding,
c, NULL, n )) )
return( -1 );
}
if( VIPS_OBJECT_CLASS( vips_bandjoin_const_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static void
vips_bandjoin_const_class_init( VipsBandjoinConstClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS( class );
VIPS_DEBUG_MSG( "vips_bandjoin_const_class_init\n" );
gobject_class->finalize = vips_bandjoin_const_finalize;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
vobject_class->nickname = "bandjoin_const";
vobject_class->description = _( "append a constant band to an image" );
vobject_class->build = vips_bandjoin_const_build;
bandary_class->process_line = vips_bandjoin_const_buffer;
VIPS_ARG_IMAGE( class, "in", 0,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsBandjoinConst, in ) );
VIPS_ARG_BOXED( class, "c", 12,
_( "Constants" ),
_( "Array of constants to add" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsBandjoinConst, c ),
VIPS_TYPE_ARRAY_DOUBLE );
}
static void
vips_bandjoin_const_init( VipsBandjoinConst *bandjoin )
{
/* Init our instance fields.
*/
}
static int
vips_bandjoin_constv( VipsImage *in, VipsImage **out,
double *c, int n, va_list ap )
{
VipsArrayDouble *array;
int result;
array = vips_array_double_new( c, n );
result = vips_call_split( "bandjoin_const", ap, in, out, array );
vips_area_unref( VIPS_AREA( array ) );
return( result );
}
/**
* vips_bandjoin_const:
* @in: (array length=n) (transfer none): array of input images
* @out: output image
* @c: (array length=n): array of constants to append
* @n: number of constants
* @...: %NULL-terminated list of optional named arguments
*
* Append a set of constant bands to an image.
*
* See also: vips_bandjoin().
*
* Returns: 0 on success, -1 on error
*/
int
vips_bandjoin_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
{
va_list ap;
int result;
va_start( ap, n );
result = vips_bandjoin_constv( in, out, c, n, ap );
va_end( ap );
return( result );
}
/**
* vips_bandjoin_const1:
* @in: input image
* @out: output image
* @c: constant to append
* @...: %NULL-terminated list of optional named arguments
*
* Append a single constant band to an image.
*
* Returns: 0 on success, -1 on error
*/
int
vips_bandjoin_const1( VipsImage *in, VipsImage **out, double c, ... )
{
va_list ap;
int result;
va_start( ap, c );
result = vips_bandjoin_constv( in, out, &c, 1, ap );
va_end( ap );
return( result );
}

View File

@ -229,6 +229,7 @@ vips_conversion_operation_init( void )
extern GType vips_replicate_get_type( void );
extern GType vips_cast_get_type( void );
extern GType vips_bandjoin_get_type( void );
extern GType vips_bandjoin_const_get_type( void );
extern GType vips_bandrank_get_type( void );
extern GType vips_black_get_type( void );
extern GType vips_rot_get_type( void );
@ -273,6 +274,7 @@ vips_conversion_operation_init( void )
vips_replicate_get_type();
vips_cast_get_type();
vips_bandjoin_get_type();
vips_bandjoin_const_get_type();
vips_bandrank_get_type();
vips_black_get_type();
vips_rot_get_type();

View File

@ -208,65 +208,79 @@ vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
return( 0 );
}
/* Calculate a pixel for an image from a vec of double. Valid while im is
* valid. imag can be NULL, meaning all zero for the imaginary component.
/* Make a pair of vector constants into a set of formatted pixels. bands can
* be 3 while n is 1, meaning expand the constant to the number of bands.
* imag can be NULL, meaning all zero for the imaginary component.
*/
VipsPel *
vips__vector_to_ink( const char *domain,
VipsImage *im, double *real, double *imag, int n )
vips__vector_to_pels( const char *domain,
int bands, VipsBandFormat format, VipsCoding coding,
double *real, double *imag, int n )
{
/* Run our pipeline relative to this.
*/
VipsImage *context = vips_image_new();
VipsImage **t = (VipsImage **)
vips_object_local_array( VIPS_OBJECT( context ), 6 );
vips_object_local_array( VIPS_OBJECT( context ), 8 );
VipsBandFormat format;
int bands;
VipsImage *in;
double *ones;
VipsPel *result;
int i;
#ifdef VIPS_DEBUG
printf( "vips__vector_to_ink: starting\n" );
printf( "vips__vector_to_pels: starting\n" );
#endif /*VIPS_DEBUG*/
vips_image_decode_predict( im, &bands, &format );
ones = VIPS_ARRAY( im, n, double );
ones = VIPS_ARRAY( context, n, double );
for( i = 0; i < n; i++ )
ones[i] = 1.0;
/* Cast vec to match the decoded image.
/* Make the real and imaginary parts.
*/
if( vips_black( &t[1], 1, 1, "bands", bands, NULL ) ||
vips_linear( t[1], &t[2], ones, real, n, NULL ) ||
vips_cast( t[2], &t[3], format, NULL ) ) {
if( vips_black( &t[0], 1, 1, "bands", bands, NULL ) ||
vips_linear( t[0], &t[1], ones, real, n, NULL ) ) {
g_object_unref( context );
return( NULL );
}
in = t[1];
if( imag ) {
if( vips_black( &t[2], 1, 1, "bands", bands, NULL ) ||
vips_linear( t[2], &t[3], ones, imag, n, NULL ) ||
vips_complexform( in, t[3], &t[4], NULL ) ) {
g_object_unref( context );
return( NULL );
}
in = t[4];
}
/* And now recode the vec to match the original im.
/* Cast to the output type and coding.
*/
if( vips_image_encode( t[3], &t[4], im->Coding ) ||
!(t[5] = vips_image_new_memory()) ||
vips_image_write( t[4], t[5] ) ) {
if( vips_cast( in, &t[5], format, NULL ) ||
vips_image_encode( t[5], &t[6], coding ) ) {
g_object_unref( context );
return( NULL );
}
in = t[6];
/* Write to memory, copy to output buffer.
*/
if( !(t[7] = vips_image_new_memory()) ||
vips_image_write( in, t[7] ) ) {
g_object_unref( context );
return( NULL );
}
in = t[7];
if( !(result =
VIPS_ARRAY( im, VIPS_IMAGE_SIZEOF_PEL( t[5] ), VipsPel )) ) {
VIPS_ARRAY( NULL, VIPS_IMAGE_SIZEOF_PEL( in ), VipsPel )) ) {
g_object_unref( context );
return( NULL );
}
g_assert( VIPS_IMAGE_SIZEOF_PEL( t[5] ) ==
VIPS_IMAGE_SIZEOF_PEL( im ) );
memcpy( result, t[5]->data, VIPS_IMAGE_SIZEOF_PEL( im ) );
g_object_unref( context );
memcpy( result, in->data, VIPS_IMAGE_SIZEOF_PEL( in ) );
#ifdef VIPS_DEBUG
{
@ -278,12 +292,43 @@ vips__vector_to_ink( const char *domain,
printf( "(%g, %g) ", real[i], imag ? imag[i] : 0 );
printf( "\n" );
printf( "\tink = " );
for( i = 0; i < VIPS_IMAGE_SIZEOF_PEL( im ); i++ )
for( i = 0; i < VIPS_IMAGE_SIZEOF_PEL( in ); i++ )
printf( "%d ", result[i] );
printf( "\n" );
}
#endif /*VIPS_DEBUG*/
g_object_unref( context );
return( result );
}
static void
vips__vector_to_ink_cb( VipsObject *object, char *buf )
{
g_free( buf );
}
/* Calculate a pixel for an image from a vec of double. Valid while im is
* valid.
*/
VipsPel *
vips__vector_to_ink( const char *domain,
VipsImage *im, double *real, double *imag, int n )
{
int bands;
VipsBandFormat format;
VipsPel *result;
vips_image_decode_predict( im, &bands, &format );
if( !(result = vips__vector_to_pels( domain,
bands, format, im->Coding, real, imag, n )) )
return( NULL );
g_signal_connect( im, "postclose",
G_CALLBACK( vips__vector_to_ink_cb ), result );
return( result );
}

View File

@ -171,6 +171,9 @@ int vips__bandalike( const char *domain,
/* draw
*/
VipsPel *vips__vector_to_pels( const char *domain,
int bands, VipsBandFormat format, VipsCoding coding,
double *real, double *imag, int n );
VipsPel *vips__vector_to_ink( const char *domain,
VipsImage *im, double *real, double *imag, int n );
double *vips__ink_to_vector( const char *domain,