diff --git a/TODO b/TODO index 84b05cc0..ab635c40 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,6 @@ -- finish adding maxpos stuff to im_stats +- avg/dev etc. should uncode images? eg. labq2lab etc. + + test new measure diff --git a/libvips/arithmetic/Makefile.am b/libvips/arithmetic/Makefile.am index cfe3afa2..2b5d00c7 100644 --- a/libvips/arithmetic/Makefile.am +++ b/libvips/arithmetic/Makefile.am @@ -11,7 +11,7 @@ libarithmetic_la_SOURCES = \ im_linreg.c \ im_maxpos_avg.c \ im_maxpos_vec.c \ - im_measure.c \ + measure.c \ multiply.c \ im_point_bilinear.c \ im_remainder.c \ diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index 56d1945b..08c029f3 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -515,6 +515,7 @@ vips_arithmetic_operation_init( void ) extern GType vips_abs_get_type( void ); extern GType vips_sign_get_type( void ); extern GType vips_stats_get_type( void ); + extern GType vips_measure_get_type( void ); vips_add_get_type(); vips_subtract_get_type(); @@ -530,5 +531,6 @@ vips_arithmetic_operation_init( void ) vips_abs_get_type(); vips_sign_get_type(); vips_stats_get_type(); + vips_measure_get_type(); } diff --git a/libvips/arithmetic/measure.c b/libvips/arithmetic/measure.c index 88490000..1b25f641 100644 --- a/libvips/arithmetic/measure.c +++ b/libvips/arithmetic/measure.c @@ -113,104 +113,80 @@ vips_measure_build( VipsObject *object ) { VipsMeasure *measure = (VipsMeasure *) object; - if( measure->in && - vips_argument_get_assigned( object, "h" ) && - vips_argument_get_assigned( object, "v" ) ) { - int bands = vips_image_get_bands( measure->in ); - - if( vips_check_noncomplex( "VipsMeasure", measure->in ) ) - return( -1 ); - - g_object_set( object, - "out", vips_image_new_array( bands, - measure->h * measure->v ), - NULL ); - } + int bands; + double pw; + double ph; + int j, i; + int w, h; + int b; if( VIPS_OBJECT_CLASS( vips_measure_parent_class )->build( object ) ) return( -1 ); - need labq2lab on labq images + bands = vips_image_get_bands( measure->in ); - or maybe stats/avg/dev should do this? + g_object_set( object, + "out", vips_image_new_array( bands, measure->h * measure->v ), + NULL ); - they could handle rad etc as well ... add it to statistics.c - - need to keep the whole of im_measure() in deprecated, we've removed - the 'measure these patch numbers' feature - - maybe remove the noncomplex check? - - parent->build() only checks that inputs have been set, I think, we - don't actually need to set out before calling it - - where else do we set out before build? verify + /* left/top/width/height default to the size of the image. + */ + if( !vips_argument_get_assigned( object, "width" ) ) + g_object_set( object, + "width", vips_image_get_width( measure->in ), + NULL ); + if( !vips_argument_get_assigned( object, "height" ) ) + g_object_set( object, + "height", vips_image_get_height( measure->in ), + NULL ); /* How large are the patches we are to measure? */ - double pw = (double) width / (double) u; - double ph = (double) height / (double) v; + pw = (double) measure->width / measure->h; + ph = (double) measure->height / measure->v; - /* Set up sub to be the size we need for a patch. + /* The size of a patch. */ w = (pw + 1) / 2; h = (ph + 1) / 2; - /* Loop through sel, picking out areas to measure. - */ - for( j = 0, patch = 0; patch < nsel; patch++ ) { - /* Sanity check. Is the patch number sensible? - */ - if( sel[patch] <= 0 || sel[patch] > u * v ) { - im_error( "im_measure", - _( "patch %d is out of range" ), - sel[patch] ); - return( 1 ); - } + for( j = 0; j < measure->v; j++ ) { + for( i = 0; i < measure->h; i++ ) { + int x = measure->left + i * pw + (pw + 2) / 4; + int y = measure->top + j * ph + (ph + 2) / 4; - /* Patch coordinates. - */ - m = (sel[patch] - 1) % u; - n = (sel[patch] - 1) / u; + double avg, dev; - /* Move sub to correct position. - */ - x = left + m * pw + (pw + 2) / 4; - y = top + n * ph + (ph + 2) / 4; + for( b = 0; b < bands; b++ ) { + VipsImage **t = (VipsImage **) + vips_object_local_array( object, 2 ); - /* Loop through bands. - */ - for( i = 0; i < im->Bands; i++, j++ ) { - /* Make temp buffer to extract to. - */ - if( !(tmp = im_open( "patch", "t" )) ) - return( -1 ); - - /* Extract and measure. - */ - if( im_extract_areabands( im, tmp, x, y, w, h, i, 1 ) || - im_avg( tmp, &avg ) || - im_deviate( tmp, &dev ) ) { - im_close( tmp ); - return( -1 ); + /* Extract and measure. + */ + if( vips_extract_area( measure->in, &t[0], + x, y, w, h, NULL ) || + vips_extract_band( t[0], &t[1], + b, NULL ) || + vips_avg( t[1], &avg, NULL ) || + vips_deviate( t[1], &dev, NULL ) ) + return( -1 ); + + /* Is the deviation large compared with the + * average? This could be a clue that our + * parameters have caused us to miss the + * patch. Look out for averages <0, or + * averages near zero (can get these if use + * measure on IM_TYPE_LAB images). + */ + if( dev * 5 > fabs( avg ) && fabs( avg ) > 3 ) + im_warn( "im_measure", + _( "patch %d x %d, band %d: " + "avg = %g, sdev = %g" ), + i, j, avg, dev ); + + *ARY( measure->out, b, x + y * measure->h ) = + avg; } - im_close( tmp ); - - /* Is the deviation large compared with the average? - * This could be a clue that our parameters have - * caused us to miss the patch. Look out for averages - * <0, or averages near zero (can get these if use - * im_measure() on IM_TYPE_LAB images). - */ - if( dev * 5 > fabs( avg ) && fabs( avg ) > 3 ) - im_warn( "im_measure", - _( "patch %d, band %d: " - "avg = %g, sdev = %g" ), - patch, i, avg, dev ); - - /* Save results. - */ - coeff[j] = avg; } } @@ -240,7 +216,7 @@ vips_measure_class_init( VipsMeasureClass *class ) _( "in" ), _( "Image to measure" ), VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsJoin, in1 ) ); + G_STRUCT_OFFSET( VipsMeasure, in ) ); VIPS_ARG_IMAGE( class, "out", 2, _( "Output" ), diff --git a/libvips/deprecated/Makefile.am b/libvips/deprecated/Makefile.am index c741e360..57fd5482 100644 --- a/libvips/deprecated/Makefile.am +++ b/libvips/deprecated/Makefile.am @@ -17,6 +17,7 @@ libdeprecated_la_SOURCES = \ im_printlines.c \ im_convsub.c \ im_line.c \ + im_measure.c \ im_resize_linear.c \ im_debugim.c \ im_gfadd.c \ diff --git a/libvips/arithmetic/im_measure.c b/libvips/deprecated/im_measure.c similarity index 75% rename from libvips/arithmetic/im_measure.c rename to libvips/deprecated/im_measure.c index 6f76f544..191d7f25 100644 --- a/libvips/arithmetic/im_measure.c +++ b/libvips/deprecated/im_measure.c @@ -19,6 +19,9 @@ * - remove deprecated im_extract() * 30/11/09 * - changes for im_extract() broke averaging + * 9/11/11 + * - moved to deprecated, the new VipsMeasure does not have the + * select-patches thing, so we have to keep this around */ /* @@ -142,55 +145,8 @@ measure_patches( IMAGE *im, double *coeff, return( 0 ); } -/** - * im_measure_area: - * @im: image to measure - * @left: area of image containing chart - * @top: area of image containing chart - * @width: area of image containing chart - * @height: area of image containing chart - * @h: patches across chart - * @v: patches down chart - * @sel: array of patch numbers to measure (numbered from 1 in row-major order) - * @nsel: length of patch number array - * @name: name to give to returned @DOUBLEMASK - * - * Analyse a grid of colour patches, producing a #DOUBLEMASK of patch averages. - * The mask has a row for each measured patch, and a column for each image - * band. The operations issues a warning if any patch has a deviation more - * than 20% of - * the mean. Only the central 50% of each patch is averaged. If @sel is %NULL - * then all patches are measured. - * - * Example: 6 band image of 4x2 block of colour patches. - * - * - * - * - * 1 - * 2 - * 3 - * 4 - * - * - * 5 - * 6 - * 7 - * 8 - * - * - * - * - * Then call im_measure( im, box, 4, 2, { 2, 4 }, 2, "fred" ) makes a mask - * "fred" which has 6 columns, two rows. The first row contains the averages - * for patch 2, the second for patch 4. - * - * See also: im_avg(), im_deviate(), im_stats(). - * - * Returns: #DOUBLEMASK of measurements. - */ -DOUBLEMASK * -im_measure_area( IMAGE *im, +static DOUBLEMASK * +internal_im_measure_area( IMAGE *im, int left, int top, int width, int height, int u, int v, int *sel, int nsel, const char *name ) @@ -249,3 +205,33 @@ im_measure_area( IMAGE *im, return( mask ); } + +DOUBLEMASK * +im_measure_area( IMAGE *im, + int left, int top, int width, int height, + int u, int v, + int *sel, int nsel, const char *name ) +{ + if( sel ) + return( internal_im_measure_area( im, + left, top, width, height, u, v, sel, nsel, name ) ); + else { + DOUBLEMASK *msk; + VipsImage *t; + + if( vips_measure( im, &t, u, v, + "left", left, + "top", top, + "width", width, + "height", height, + NULL ) ) + return( NULL ); + if( !(msk = im_vips2mask( t, name )) ) { + g_object_unref( t ); + return( NULL ); + } + g_object_unref( t ); + + return( msk ); + } +} diff --git a/libvips/include/vips/arithmetic.h b/libvips/include/vips/arithmetic.h index a91c27b9..2585e915 100644 --- a/libvips/include/vips/arithmetic.h +++ b/libvips/include/vips/arithmetic.h @@ -98,14 +98,12 @@ int vips_sign( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); int vips_stats( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); +int vips_measure( VipsImage *in, VipsImage **out, int h, int v, ... ) + __attribute__((sentinel)); -DOUBLEMASK *im_measure_area( VipsImage *im, - int left, int top, int width, int height, - int h, int v, - int *sel, int nsel, const char *name ); int im_maxpos_avg( VipsImage *im, double *xpos, double *ypos, double *out ); int im_maxpos_vec( VipsImage *im, int *xpos, int *ypos, double *maxima, int n ); int im_minpos_vec( VipsImage *im, int *xpos, int *ypos, double *minima, int n ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index d0a6ead2..ba1e8c94 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -536,6 +536,10 @@ int im_lintra_vec( int n, double *a, VipsImage *in, double *b, VipsImage *out ); int im_abs( VipsImage *in, VipsImage *out ); int im_sign( VipsImage *in, VipsImage *out ); DOUBLEMASK *im_stats( VipsImage *in ); +DOUBLEMASK *im_measure_area( VipsImage *im, + int left, int top, int width, int height, + int h, int v, + int *sel, int nsel, const char *name ); int im_sintra( VipsImage *in, VipsImage *out ); int im_costra( VipsImage *in, VipsImage *out ); diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c index 08daeb4c..644a1bff 100644 --- a/libvips/iofuncs/operation.c +++ b/libvips/iofuncs/operation.c @@ -859,7 +859,8 @@ vips_call_argv_unref_output( VipsObject *object, void *a, void *b ) { if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) && - G_IS_PARAM_SPEC_OBJECT( pspec ) ) { + G_IS_PARAM_SPEC_OBJECT( pspec ) && + argument_instance->assigned ) { GObject *value; g_object_get( object,