From 5540fa97f4952d9bba1bd675a40e4fdd574b4ead Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 28 Jun 2020 12:14:13 +0100 Subject: [PATCH] small cleanups for disable deprecated - move matrixinvert to mosaicing, fix a leak - add note to changelog - small fixes see https://github.com/libvips/libvips/pull/1593 --- ChangeLog | 2 + libvips/Makefile.am | 3 +- libvips/create/Makefile.am | 1 - libvips/include/vips/create.h | 3 - libvips/include/vips/mosaicing.h | 3 + libvips/morphology/morph.c | 8 +- libvips/mosaicing/Makefile.am | 1 + libvips/mosaicing/global_balance.c | 14 +- libvips/{create => mosaicing}/matrixinvert.c | 282 ++++++++++--------- libvips/resample/transform.c | 5 +- 10 files changed, 163 insertions(+), 159 deletions(-) rename libvips/{create => mosaicing}/matrixinvert.c (68%) diff --git a/ChangeLog b/ChangeLog index bee86b68..fb5b0b2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -37,6 +37,8 @@ - pngsave @bitdepth parameter lets you write 1, 2 and 4 bit PNGs - ppmsave also uses "bitdepth" now, for consistency - reduce operation cache max to 100 +- rework the final bits of vips7 for vips8 [kleisauke] +- --disable-deprecated now works [kleisauke] 24/4/20 started 8.9.3 - better iiif tile naming [IllyaMoskvin] diff --git a/libvips/Makefile.am b/libvips/Makefile.am index dd8106ca..6288cf33 100644 --- a/libvips/Makefile.am +++ b/libvips/Makefile.am @@ -24,8 +24,7 @@ SUBDIRS = \ iofuncs \ morphology \ mosaicing \ - create \ - . + create lib_LTLIBRARIES = libvips.la diff --git a/libvips/create/Makefile.am b/libvips/create/Makefile.am index 9b2cbd5a..8b5c11e4 100644 --- a/libvips/create/Makefile.am +++ b/libvips/create/Makefile.am @@ -25,7 +25,6 @@ libcreate_la_SOURCES = \ mask_gaussian_ring.c \ mask_gaussian_band.c \ mask_fractal.c \ - matrixinvert.c \ fractsurf.c \ eye.c \ grey.c \ diff --git a/libvips/include/vips/create.h b/libvips/include/vips/create.h index d809dba3..f04752d4 100644 --- a/libvips/include/vips/create.h +++ b/libvips/include/vips/create.h @@ -110,9 +110,6 @@ int vips_mask_fractal( VipsImage **out, int width, int height, double fractal_dimension, ... ) __attribute__((sentinel)); -int vips_matrixinvert( VipsImage *m, VipsImage **out, ... ) - __attribute__((sentinel)); - int vips_fractsurf( VipsImage **out, int width, int height, double fractal_dimension, ... ) __attribute__((sentinel)); diff --git a/libvips/include/vips/mosaicing.h b/libvips/include/vips/mosaicing.h index a598e7e4..4a18068c 100644 --- a/libvips/include/vips/mosaicing.h +++ b/libvips/include/vips/mosaicing.h @@ -92,6 +92,9 @@ int vips_remosaic( VipsImage *in, VipsImage **out, const char *old_str, const char *new_str, ... ) __attribute__((sentinel)); +int vips_matrixinvert( VipsImage *m, VipsImage **out, ... ) + __attribute__((sentinel)); + #ifdef __cplusplus } diff --git a/libvips/morphology/morph.c b/libvips/morphology/morph.c index adca5876..7f7ffc48 100644 --- a/libvips/morphology/morph.c +++ b/libvips/morphology/morph.c @@ -192,7 +192,6 @@ vips_morph_start( VipsImage *out, void *a, void *b ) { VipsImage *in = (VipsImage *) a; VipsMorph *morph = (VipsMorph *) b; - VipsImage *M = morph->M; VipsMorphSequence *seq; @@ -227,8 +226,10 @@ vips_morph_start( VipsImage *out, void *a, void *b ) /* Vector mode. */ if( morph->n_pass ) { - seq->t1 = VIPS_ARRAY( NULL, VIPS_IMAGE_N_ELEMENTS( in ), VipsPel ); - seq->t2 = VIPS_ARRAY( NULL, VIPS_IMAGE_N_ELEMENTS( in ), VipsPel ); + seq->t1 = VIPS_ARRAY( NULL, + VIPS_IMAGE_N_ELEMENTS( in ), VipsPel ); + seq->t2 = VIPS_ARRAY( NULL, + VIPS_IMAGE_N_ELEMENTS( in ), VipsPel ); if( !seq->t1 || !seq->t2 ) { @@ -628,7 +629,6 @@ vips_morph_gen_vector( VipsRegion *or, VipsMorphSequence *seq = (VipsMorphSequence *) vseq; VipsMorph *morph = (VipsMorph *) b; VipsImage *M = morph->M; - VipsImage *in = (VipsImage *) a; VipsRegion *ir = seq->ir; VipsRect *r = &or->valid; int sz = VIPS_REGION_N_ELEMENTS( or ); diff --git a/libvips/mosaicing/Makefile.am b/libvips/mosaicing/Makefile.am index 35f23916..d7da3b87 100644 --- a/libvips/mosaicing/Makefile.am +++ b/libvips/mosaicing/Makefile.am @@ -6,6 +6,7 @@ libmosaicing_la_SOURCES = \ mosaic.c \ match.c \ mosaic1.c \ + matrixinvert.c \ global_balance.c \ im_avgdxdy.c \ im_chkpair.c \ diff --git a/libvips/mosaicing/global_balance.c b/libvips/mosaicing/global_balance.c index b63a3cb0..190db7e2 100644 --- a/libvips/mosaicing/global_balance.c +++ b/libvips/mosaicing/global_balance.c @@ -1483,7 +1483,7 @@ vips__build_mosaic( SymbolTable *st, VipsImage *out, transform_fn tfn, void *a ) } static int -vips__transposematrix( VipsImage *in, VipsImage **out ) +vips__matrixtranspose( VipsImage *in, VipsImage **out ) { int yc, xc; @@ -1502,7 +1502,7 @@ vips__transposematrix( VipsImage *in, VipsImage **out ) } static int -vips__multiplymatrix( VipsImage *in1, VipsImage *in2, VipsImage **out ) +vips__matrixmultiply( VipsImage *in1, VipsImage *in2, VipsImage **out ) { int xc, yc, col; double sum; @@ -1512,7 +1512,7 @@ vips__multiplymatrix( VipsImage *in1, VipsImage *in2, VipsImage **out ) /* Check matrix sizes. */ if( in1->Xsize != in2->Ysize ) { - vips_error( "vips__multiplymatrix", "%s", _( "bad sizes" ) ); + vips_error( "vips__matrixmultiply", "%s", _( "bad sizes" ) ); return( -1 ); } @@ -1577,11 +1577,11 @@ find_factors( SymbolTable *st, double gamma ) /* Calculate LMS. */ - if( vips__transposematrix( t[1], &t[2] ) || - vips__multiplymatrix( t[2], t[1], &t[3] ) || + if( vips__matrixtranspose( t[1], &t[2] ) || + vips__matrixmultiply( t[2], t[1], &t[3] ) || vips_matrixinvert( t[3], &t[4], NULL ) || - vips__multiplymatrix( t[4], t[2], &t[5] ) || - vips__multiplymatrix( t[5], t[0], &t[6] ) ) + vips__matrixmultiply( t[4], t[2], &t[5] ) || + vips__matrixmultiply( t[5], t[0], &t[6] ) ) return( -1 ); /* Make array of correction factors. diff --git a/libvips/create/matrixinvert.c b/libvips/mosaicing/matrixinvert.c similarity index 68% rename from libvips/create/matrixinvert.c rename to libvips/mosaicing/matrixinvert.c index 434af9d8..04e2d37b 100644 --- a/libvips/create/matrixinvert.c +++ b/libvips/mosaicing/matrixinvert.c @@ -46,16 +46,13 @@ #include -#include "pcreate.h" - /* Our state. */ typedef struct _VipsMatrixinvert { - VipsCreate parent_instance; + VipsOperation parent_instance; - /* Input image. - */ VipsImage *in; + VipsImage *out; /* .. and cast to a matrix. */ @@ -66,9 +63,9 @@ typedef struct _VipsMatrixinvert { VipsImage *lu; } VipsMatrixinvert; -typedef VipsCreateClass VipsMatrixinvertClass; +typedef VipsOperationClass VipsMatrixinvertClass; -G_DEFINE_TYPE( VipsMatrixinvert, vips_matrixinvert, VIPS_TYPE_CREATE ); +G_DEFINE_TYPE( VipsMatrixinvert, vips_matrixinvert, VIPS_TYPE_OPERATION ); static void vips_matrixinvert_dispose( GObject *gobject ) @@ -83,11 +80,11 @@ vips_matrixinvert_dispose( GObject *gobject ) /* DBL_MIN is smallest *normalized* double precision float */ -#define TOO_SMALL 2.0 * DBL_MIN +#define TOO_SMALL (2.0 * DBL_MIN) /* Save a bit of typing. */ -#define ME( m, i, j ) *VIPS_MATRIX( (m), (i), (j) ) +#define ME( m, i, j ) (*VIPS_MATRIX( (m), (i), (j) )) /** * lu_decomp: @@ -268,149 +265,132 @@ lu_solve( VipsImage *lu, double *vec ) } static int -vips_matrixinvert_direct( VipsImage *mat, VipsImage **out ) { - switch( mat->Xsize ) { - case 1: { - double det = ME( mat, 0, 0 ); - - if( fabs( det ) < TOO_SMALL ) { - /* divisor is near zero */ - vips_error( "matrixinvert", - "%s", _( "singular or near-singular matrix" ) ); - return( -1 ); - } - - ME( *out, 0, 0 ) = 1.0 / det; - - return( 0 ); - } - case 2: { - double det = ME( mat, 0, 0 ) * ME( mat, 1, 1 ) - - ME( mat, 0, 1 ) * ME( mat, 1, 0 ); - - if( fabs( det ) < TOO_SMALL ) { - /* divisor is near zero */ - vips_error( "matrixinvert", - "%s", _( "singular or near-singular matrix" ) ); - return( -1 ); - } - - double tmp = 1.0 / det; - - ME( *out, 0, 0 ) = tmp * ME( mat, 1, 1 ); - ME( *out, 0, 1 ) = -tmp * ME( mat, 0, 1 ); - ME( *out, 1, 0 ) = -tmp * ME( mat, 1, 0 ); - ME( *out, 1, 1 ) = tmp * ME( mat, 0, 0 ); - - return( 0 ); - } - case 3: { - double det = ME( mat, 0, 0 ) * ( ME( mat, 1, 1 ) * - ME( mat, 2, 2 ) - ME( mat, 1, 2 ) * ME( mat, 2, 1 ) ); - det -= ME( mat, 0, 1 ) * ( ME( mat, 1, 0 ) * - ME( mat, 2, 2 ) - ME( mat, 1, 2 ) * ME( mat, 2, 0) ); - det += ME( mat, 0, 2) * ( ME( mat, 1, 0 ) * - ME( mat, 2, 1 ) - ME( mat, 1, 1 ) * ME( mat, 2, 0 ) ); - - if( fabs( det ) < TOO_SMALL ) { - /* divisor is near zero */ - vips_error( "matrixinvert", - "%s", _( "singular or near-singular matrix" ) ); - return( -1 ); - } - - double tmp = 1.0 / det; - - ME( *out, 0, 0 ) = tmp * ( ME( mat, 1, 1 ) * ME( mat, 2, 2 ) - - ME( mat, 1, 2 ) * ME( mat, 2, 1 ) ); - ME( *out, 1, 0 ) = tmp * ( ME( mat, 1, 2 ) * ME( mat, 2, 0 ) - - ME( mat, 1, 0 ) * ME( mat, 2, 2 ) ); - ME( *out, 2, 0 ) = tmp * ( ME( mat, 1, 0 ) * ME( mat, 2, 1 ) - - ME( mat, 1, 1 ) * ME( mat, 2, 0 ) ); - - ME( *out, 0, 1 ) = tmp * ( ME( mat, 0, 2 ) * ME( mat, 2, 1 ) - - ME( mat, 0, 1 ) * ME( mat, 2, 2 ) ); - ME( *out, 1, 1 ) = tmp * ( ME( mat, 0, 0 ) * ME( mat, 2, 2 ) - - ME( mat, 0, 2 ) * ME( mat, 2, 0 ) ); - ME( *out, 2, 1 ) = tmp * ( ME( mat, 0, 1 ) * ME( mat, 2, 0 ) - - ME( mat, 0, 0 ) * ME( mat, 2, 1 ) ); - - ME( *out, 0, 2 ) = tmp * ( ME( mat, 0, 1 ) * ME( mat, 1, 2 ) - - ME( mat, 0, 2 ) * ME( mat, 1, 1 ) ); - ME( *out, 1, 2 ) = tmp * ( ME( mat, 0, 2 ) * ME( mat, 1, 0 ) - - ME( mat, 0, 0 ) * ME( mat, 1, 2 ) ); - ME( *out, 2, 2 ) = tmp * ( ME( mat, 0, 0 ) * ME( mat, 1, 1 ) - - ME( mat, 0, 1 ) * ME( mat, 1, 0 ) ); - - return( 0 ); - } - /* TODO(kleisauke): - * We sometimes use 4x4 matrices, could we also make a - * direct version for those? For e.g.: - * https://stackoverflow.com/a/1148405/10952119 */ - default: - return( -1 ); - } -} - -static int -vips_matrixinvert_build_init( VipsMatrixinvert *matrix ) +vips_matrixinvert_solve( VipsMatrixinvert *matrix ) { - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( matrix ); + VipsImage *out = matrix->out; - int x, y; - - if( !matrix->mat || - matrix->mat->Xsize != matrix->mat->Ysize ) { - vips_error( class->nickname, "%s", _( "non-square matrix" ) ); - return( -1 ); - } - - /* No need to LU decompose the matrix for < 4x4 matrices - */ - if( matrix->mat->Xsize < 4 ) - return( 0 ); + int i, j; + double *vec; if( !(matrix->lu = lu_decomp( matrix->mat ) ) ) return( -1 ); - return( 0 ); -} - -static int -vips_matrixinvert_build_create( VipsMatrixinvert *matrix, VipsImage **out ) -{ - int i, j; - double *vec; - - *out = vips_image_new_matrix( matrix->mat->Xsize, matrix->mat->Ysize ); - - /* Direct path for < 4x4 matrices - */ - if( matrix->mat->Xsize < 4 ) - return( vips_matrixinvert_direct( matrix->mat, out ) ); - - vec = VIPS_ARRAY( NULL, matrix->lu->Xsize, double ); - - if( !vec ) + if( !(vec = VIPS_ARRAY( matrix, matrix->lu->Xsize, double )) ) return( -1 ); for( j = 0; j < matrix->lu->Xsize; ++j ) { - for( i = 0; i < matrix->lu->Xsize; ++i ) vec[i] = 0.0; vec[j] = 1.0; - if ( lu_solve( matrix->lu, vec ) ) { - g_free( vec ); + if( lu_solve( matrix->lu, vec ) ) + return( -1 ); + + for( i = 0; i < matrix->lu->Xsize; ++i ) + ME( out, i, j ) = vec[i]; + } + + return( 0 ); +} + +static int +vips_matrixinvert_direct( VipsMatrixinvert *matrix ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( matrix ); + VipsImage *in = matrix->mat; + VipsImage *out = matrix->out; + + switch( matrix->mat->Xsize ) { + case 1: +{ + double det = ME( in, 0, 0 ); + + if( fabs( det ) < TOO_SMALL ) { + /* divisor is near zero */ + vips_error( class->nickname, + "%s", _( "singular or near-singular matrix" ) ); return( -1 ); } - for( i = 0; i < matrix->lu->Xsize; ++i ) - ME( *out, i, j ) = vec[i]; + ME( out, 0, 0 ) = 1.0 / det; +} + break; + + case 2: +{ + double det = ME( in, 0, 0 ) * ME( in, 1, 1 ) - + ME( in, 0, 1 ) * ME( in, 1, 0 ); + + double tmp; + + if( fabs( det ) < TOO_SMALL ) { + /* divisor is near zero */ + vips_error( class->nickname, + "%s", _( "singular or near-singular matrix" ) ); + return( -1 ); + } + + tmp = 1.0 / det; + ME( out, 0, 0 ) = tmp * ME( in, 1, 1 ); + ME( out, 0, 1 ) = -tmp * ME( in, 0, 1 ); + ME( out, 1, 0 ) = -tmp * ME( in, 1, 0 ); + ME( out, 1, 1 ) = tmp * ME( in, 0, 0 ); +} + break; + + case 3: +{ + double det; + double tmp; + + det = ME( in, 0, 0 ) * ( ME( in, 1, 1 ) * + ME( in, 2, 2 ) - ME( in, 1, 2 ) * ME( in, 2, 1 ) ); + det -= ME( in, 0, 1 ) * ( ME( in, 1, 0 ) * + ME( in, 2, 2 ) - ME( in, 1, 2 ) * ME( in, 2, 0) ); + det += ME( in, 0, 2) * ( ME( in, 1, 0 ) * + ME( in, 2, 1 ) - ME( in, 1, 1 ) * ME( in, 2, 0 ) ); + + if( fabs( det ) < TOO_SMALL ) { + /* divisor is near zero */ + vips_error( class->nickname, + "%s", _( "singular or near-singular matrix" ) ); + return( -1 ); + } + + tmp = 1.0 / det; + + ME( out, 0, 0 ) = tmp * ( ME( in, 1, 1 ) * ME( in, 2, 2 ) - + ME( in, 1, 2 ) * ME( in, 2, 1 ) ); + ME( out, 1, 0 ) = tmp * ( ME( in, 1, 2 ) * ME( in, 2, 0 ) - + ME( in, 1, 0 ) * ME( in, 2, 2 ) ); + ME( out, 2, 0 ) = tmp * ( ME( in, 1, 0 ) * ME( in, 2, 1 ) - + ME( in, 1, 1 ) * ME( in, 2, 0 ) ); + + ME( out, 0, 1 ) = tmp * ( ME( in, 0, 2 ) * ME( in, 2, 1 ) - + ME( in, 0, 1 ) * ME( in, 2, 2 ) ); + ME( out, 1, 1 ) = tmp * ( ME( in, 0, 0 ) * ME( in, 2, 2 ) - + ME( in, 0, 2 ) * ME( in, 2, 0 ) ); + ME( out, 2, 1 ) = tmp * ( ME( in, 0, 1 ) * ME( in, 2, 0 ) - + ME( in, 0, 0 ) * ME( in, 2, 1 ) ); + + ME( out, 0, 2 ) = tmp * ( ME( in, 0, 1 ) * ME( in, 1, 2 ) - + ME( in, 0, 2 ) * ME( in, 1, 1 ) ); + ME( out, 1, 2 ) = tmp * ( ME( in, 0, 2 ) * ME( in, 1, 0 ) - + ME( in, 0, 0 ) * ME( in, 1, 2 ) ); + ME( out, 2, 2 ) = tmp * ( ME( in, 0, 0 ) * ME( in, 1, 1 ) - + ME( in, 0, 1 ) * ME( in, 1, 0 ) ); +} + break; + + /* TODO(kleisauke): + * We sometimes use 4x4 matrices, could we also make a + * direct version for those? For e.g.: + * https://stackoverflow.com/a/1148405/10952119 */ + default: + g_assert( 0 ); + return( -1 ); } - g_free( vec ); return( 0 ); } @@ -419,19 +399,35 @@ static int vips_matrixinvert_build( VipsObject *object ) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); - VipsCreate *create = VIPS_CREATE( object ); VipsMatrixinvert *matrix = (VipsMatrixinvert *) object; - VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 ); - if( VIPS_OBJECT_CLASS( vips_matrixinvert_parent_class )->build( object ) ) + if( VIPS_OBJECT_CLASS( vips_matrixinvert_parent_class )-> + build( object ) ) return( -1 ); if( vips_check_matrix( class->nickname, matrix->in, &matrix->mat ) ) return( -1 ); - if( vips_matrixinvert_build_init( matrix ) || - vips_matrixinvert_build_create( matrix, &create->out ) ) + if( matrix->mat->Xsize != matrix->mat->Ysize ) { + vips_error( class->nickname, "%s", _( "non-square matrix" ) ); return( -1 ); + } + + g_object_set( matrix, + "out", vips_image_new_matrix( matrix->mat->Xsize, + matrix->mat->Ysize ), + NULL ); + + /* Direct path for < 4x4 matrices + */ + if( matrix->mat->Xsize >= 4 ) { + if( vips_matrixinvert_solve( matrix ) ) + return( -1 ); + } + else { + if( vips_matrixinvert_direct( matrix ) ) + return( -1 ); + } return( 0 ); } @@ -455,6 +451,12 @@ vips_matrixinvert_class_init( VipsMatrixinvertClass *class ) _( "An square matrix" ), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsMatrixinvert, in ) ); + + VIPS_ARG_IMAGE( class, "out", 1, + _( "Output" ), + _( "Output matrix" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsMatrixinvert, out ) ); } static void @@ -465,7 +467,7 @@ vips_matrixinvert_init( VipsMatrixinvert *matrix ) /** * vips_matrixinvert: (method) * @m: matrix to invert - * @out: (out): output image + * @out: (out): output matrix * @...: %NULL-terminated list of optional named arguments * * This operation calculates the inverse of the matrix represented in @m. diff --git a/libvips/resample/transform.c b/libvips/resample/transform.c index aaad7c34..59ca9715 100644 --- a/libvips/resample/transform.c +++ b/libvips/resample/transform.c @@ -43,8 +43,9 @@ #include #include -/* DBL_MIN is smallest *normalized* double precision float */ -#define TOO_SMALL 2.0 * DBL_MIN +/* DBL_MIN is smallest *normalized* double precision float + */ +#define TOO_SMALL (2.0 * DBL_MIN) /* Calculate the inverse transformation. */