From 2932f383bc05517baa57b59cd500bc24bbb18e4c Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 3 Feb 2010 16:24:05 +0000 Subject: [PATCH] convolution docs --- doc/reference/libvips-docs.sgml.in | 2 +- libvips/conversion/im_gaussnoise.c | 4 +- libvips/conversion/im_system_image.c | 9 ++ libvips/convolution/im_addgnoise.c | 56 ++++----- libvips/convolution/im_compass.c | 69 +++++++---- libvips/convolution/im_contrast_surface.c | 55 ++++----- libvips/convolution/im_conv.c | 66 +++++------ libvips/convolution/im_conv_f.c | 43 ++++--- libvips/convolution/im_convsep.c | 59 +++++---- libvips/convolution/im_convsep_f.c | 65 +++++----- libvips/convolution/im_fastcor.c | 65 +++++----- libvips/convolution/im_gradcor.c | 138 ++++++++++++++-------- libvips/convolution/im_sharpen.c | 89 ++++++++++++-- libvips/convolution/im_spcor.c | 76 ++++++------ libvips/include/vips/check.h | 2 + libvips/iofuncs/check.c | 54 +++++++++ 16 files changed, 525 insertions(+), 327 deletions(-) diff --git a/doc/reference/libvips-docs.sgml.in b/doc/reference/libvips-docs.sgml.in index a0ff1f2f..b771a7e2 100644 --- a/doc/reference/libvips-docs.sgml.in +++ b/doc/reference/libvips-docs.sgml.in @@ -37,11 +37,11 @@ + VIPS operation API by section (no gtkdoc comments yet) - diff --git a/libvips/conversion/im_gaussnoise.c b/libvips/conversion/im_gaussnoise.c index 49754624..a94a2b36 100644 --- a/libvips/conversion/im_gaussnoise.c +++ b/libvips/conversion/im_gaussnoise.c @@ -105,7 +105,7 @@ gnoise_gen( REGION *or, void *seq, void *a, void *b ) /** * im_gaussnoise: - * @out: output #IMAGE + * @out: output image * @x: output width * @y: output height * @mean: average value in output @@ -115,7 +115,7 @@ gnoise_gen( REGION *or, void *seq, void *a, void *b ) * distribution. The noise distribution is created by averaging 12 random * numbers with the appropriate weights. * - * See also: im_make_xy(), im_text(), im_black(). + * See also: im_addgnoise(), im_make_xy(), im_text(), im_black(). * * Returns: 0 on success, -1 on error */ diff --git a/libvips/conversion/im_system_image.c b/libvips/conversion/im_system_image.c index 8121faa1..958897e8 100644 --- a/libvips/conversion/im_system_image.c +++ b/libvips/conversion/im_system_image.c @@ -113,6 +113,15 @@ system_image( IMAGE *im, * * In all cases, @log must be freed with im_free(). * + * For example, this call will run the ImageMagick convert program on an + * image, using JPEG files to pass images into and out of the convert command. + * + * |[ + * im_system_image( in, out, + * "%s.jpg", "%s.jpg", "convert %s -swirl 45 %s", + * &log ) + * ]| + * * See also: im_system(). * * Returns: an image on success, NULL on error diff --git a/libvips/convolution/im_addgnoise.c b/libvips/convolution/im_addgnoise.c index 87de342a..7ab0beed 100644 --- a/libvips/convolution/im_addgnoise.c +++ b/libvips/convolution/im_addgnoise.c @@ -1,15 +1,4 @@ -/* @(#) Add gaussian noise with mean 0 and variance sigma to image - * @(#) The noise is generated by averaging 12 random numbers - * @(#) page 78 PIETGEN 1989 n = 12 - * @(#) Input image is any, output is float - * @(#) If running on SYSTEM V CONSTANT should be replaced by 2**15 - 1 - * @(#) Usage - * @(#) - * @(#) int im_addgnoise(imin, imout, sigma) - * @(#) IMAGE *imin, *imout; - * @(#) double sigma; - * @(#) Returns 0 on success and -1 on error - * @(#) +/* im_addgnoise * * Copyright 1990, N. Dessipris. * @@ -26,6 +15,9 @@ * 2008-01-28 tcv: * - now works (was broken) * - no limit on bands + * 4/2/10 + * - no need to bandup here now, im_add() does that + * - gtkdoc */ /* @@ -66,25 +58,29 @@ #include #endif /*WITH_DMALLOC*/ +/** + * im_addgnoise: + * @in: input image + * @out: output image + * @sigma: standard deviation of noise + * + * Add gaussian noise with mean 0 and variance sigma to @in. + * The noise is generated by averaging 12 random numbers, + * see page 78, PIETGEN, 1989. + * + * See also: im_gaussnoise(). + * + * Returns: 0 on success, -1 on error + */ int -im_addgnoise( IMAGE *in, IMAGE *out, double sigma ){ -#define FUNCTION_NAME "im_addgnoise" +im_addgnoise( IMAGE *in, IMAGE *out, double sigma ) +{ + IMAGE *t; - if( im_piocheck( in, out )) - return -1; - { - int i; - IMAGE **temps= IM_ARRAY( out, in-> Bands, IMAGE* ); - IMAGE *joined_temps= im_open_local( out, FUNCTION_NAME ": joined_temps", "p" ); + if( !(t = im_open_local( out, "im_addgnoise", "p" )) || + im_gaussnoise( t, in->Xsize, in->Ysize, 0, sigma ) || + im_add( in, t, out ) ) + return( -1 ); - if( ! temps || ! joined_temps || im_open_local_array( out, temps, in-> Bands, FUNCTION_NAME ": temps", "p" )) - return -1; - - for( i= 0; i < in-> Bands; ++i ) - if( im_gaussnoise( temps[i], in-> Xsize, in-> Ysize, 0.0, sigma )) - return -1; - - return im_gbandjoin( temps, joined_temps, in-> Bands ) || im_add( in, joined_temps, out ); - } -#undef FUNCTION_NAME + return( 0 ); } diff --git a/libvips/convolution/im_compass.c b/libvips/convolution/im_compass.c index 7b357da7..8f24f811 100644 --- a/libvips/convolution/im_compass.c +++ b/libvips/convolution/im_compass.c @@ -1,28 +1,12 @@ -/* @(#) im_complass: Optimised convolution for line detection - * @(#) Uses the entered mask and 7 rotated versions of it (each by 45 degrees) - * @(#) - * @(#) Usage - * @(#) int im_compass( in, out, m ) - * @(#) IMAGE *in, *out; - * @(#) INTMASK *m; - * @(#) - * @(#) Returns 0 on sucess and -1 on error - * @(#) - * @(#) Returns an int pointer to valid offsets for rotating a square mask - * @(#) of odd size by 45 degrees. - * @(#) - * @(#) Usage - * @(#) int *im_offsets45( size ) - * @(#) int size; - * @(#) - * @(#) Returns an int pointer to valid offsets on sucess and -1 on error - * @(#) +/* im_compass * * Author: N. Dessipris (Copyright, N. Dessipris 1991) * Written on: 08/05/1991 * Modified on: * 11/3/01 JC * - rewritten, calling im_conv() and im_maxvalue() + * 3/2/10 + * - gtkdoc */ /* @@ -67,6 +51,20 @@ #include #endif /*WITH_DMALLOC*/ +/** + * im_compass: + * @in: input image + * @out: output image + * @mask: convolution mask + * + * @in is convolved 8 times with @mask, each time @mask is rotated by 45 + * degrees. Each output pixel is the largest absolute value of the 8 + * convolutions. + * + * See also: im_lindetect(), im_gradient(), im_conv(). + * + * Returns: 0 on success, -1 on error + */ int im_compass( IMAGE *in, IMAGE *out, INTMASK *mask ) { @@ -94,6 +92,20 @@ im_compass( IMAGE *in, IMAGE *out, INTMASK *mask ) return( im_maxvalue( absed, out, 8 ) ); } +/** + * im_lindetect: + * @in: input image + * @out: output image + * @mask: convolution mask + * + * @in is convolved four times with @mask, each time @mask is rotated by 45 + * degrees. Each output pixel is the largest absolute value of the four + * convolutions. + * + * See also: im_compass(), im_gradient(), im_conv(). + * + * Returns: 0 on success, -1 on error + */ int im_lindetect( IMAGE *in, IMAGE *out, INTMASK *mask ) { @@ -121,15 +133,26 @@ im_lindetect( IMAGE *in, IMAGE *out, INTMASK *mask ) return( im_maxvalue( absed, out, 4 ) ); } -#define GTEMPS (4) - +/** + * im_gradient: + * @in: input image + * @out: output image + * @mask: convolution mask + * + * @in is convolved with @mask and with @mask after a 90 degree rotation. The + * result is the sum of the absolute value of the two convolutions. + * + * See also: im_lindetect(), im_gradient(), im_conv(). + * + * Returns: 0 on success, -1 on error + */ int im_gradient( IMAGE *in, IMAGE *out, INTMASK *mask ) { - IMAGE *t[GTEMPS]; + IMAGE *t[4]; INTMASK *rmask; - if( im_open_local_array( out, t, GTEMPS, "im_gradient", "p" ) ) + if( im_open_local_array( out, t, 4, "im_gradient", "p" ) ) return( -1 ); if( !(rmask = (INTMASK *) im_local( out, diff --git a/libvips/convolution/im_contrast_surface.c b/libvips/convolution/im_contrast_surface.c index 17515d6d..9731ed0f 100644 --- a/libvips/convolution/im_contrast_surface.c +++ b/libvips/convolution/im_contrast_surface.c @@ -1,27 +1,4 @@ -/* @(#) Generate an image where the value of each pixel represents the - * @(#) contrast within a window of half_win_size from the corresponsing - * @(#) point in the input image. Sub-sample by a factor of spacing. - * @(#) - * @(#) Pixels beyond the edges of the image are considered to be have the - * @(#) value zero (black). - * @(#) - * @(#) Input must be single-band uncoded uchar, WIO or PIO. - * @(#) - * @(#) Output is single-band uncoded uint, WIO or PIO. - * @(#) - * @(#) int - * @(#) im_contrast_surface( - * @(#) IMAGE *in, - * @(#) IMAGE *out, - * @(#) int half_win_size, - * @(#) int spacing - * @(#) ); - * @(#) - * @(#) Returns either 0 (success) or -1 (fail) - * @(#) - * @(#) Also: im_contrast_surface_raw(). As above, but pixels within - * @(#) half_win_size of the edge are not calculated, and output is smaller - * @(#) accordingly. +/* im_contrast_surface * * Copyright: 2006, The Nottingham Trent University * @@ -29,6 +6,9 @@ * (based on algorithm by Nicos Dessipris & John Cupitt) * * Written on: 2006-03-13 + * 3/2/10 + * - gtkdoc + * - small cleanups */ /* @@ -111,6 +91,21 @@ static unsigned int calc_cont (REGION * reg, int win_size_less_one, /** EXPORTED FUNCTIONS **/ +/** + * im_contrast_surface: + * @in: input image + * @out: output image + * @half_win_size: window radius + * @spacing: subsample output by this + * + * Generate an image where the value of each pixel represents the + * contrast within a window of half_win_size from the corresponsing + * point in the input image. Sub-sample by a factor of spacing. + * + * See also: im_spcor(), im_gradcor(). + * + * Returns: 0 on success, -1 on error. + */ int im_contrast_surface (IMAGE * in, IMAGE * out, int half_win_size, int spacing) { @@ -138,16 +133,12 @@ im_contrast_surface_raw (IMAGE * in, IMAGE * out, int half_win_size, cont_surf_params_t *params; - if (im_piocheck (in, out)) + if (im_piocheck (in, out) || + im_check_uncoded (FUNCTION_NAME, in) || + im_check_mono (FUNCTION_NAME, in) || + im_check_format (FUNCTION_NAME, in, IM_BANDFMT_UCHAR)) return -1; - if (IM_CODING_NONE != in->Coding || IM_BANDFMT_UCHAR != in->BandFmt - || 1 != in->Bands) - { - im_error (FUNCTION_NAME, "%s", _("one band uncoded uchar only")); - return -1; - } - if (half_win_size < 1 || spacing < 1) { im_error (FUNCTION_NAME, "%s", _("bad parameters")); diff --git a/libvips/convolution/im_conv.c b/libvips/convolution/im_conv.c index dc0c9ada..069854ca 100644 --- a/libvips/convolution/im_conv.c +++ b/libvips/convolution/im_conv.c @@ -1,27 +1,4 @@ -/* @(#) Convolve an image with an INTMASK. Image can have any number of bands, - * @(#) any non-complex type. Size and type of output image matches type of - * @(#) input image. - * @(#) - * @(#) int - * @(#) im_conv( in, out, mask ) - * @(#) IMAGE *in, *out; - * @(#) INTMASK *mask; - * @(#) - * @(#) Also: im_conv_raw(). As above, but does not add a black border. - * @(#) - * @(#) Returns either 0 (success) or -1 (fail) - * @(#) - * @(#) Old code, kept for use of other old code in this package: - * @(#) - * @(#) Creates int luts for all non zero elm of the original mask; - * @(#) which is kept in buffer of length buffersize - * @(#) cnt is needed for freeing luts. Called by the above. - * @(#) - * @(#) int im__create_int_luts( buffer, buffersize, orig_luts, luts, cnt ) - * @(#) int *buffer, buffersize; - * @(#) int **orig_luts, **luts, *cnt; - * @(#) - * @(#) Returns either 0 (sucess) or -1 (fail) +/* im_conv * * Copyright: 1990, N. Dessipris. * @@ -71,6 +48,9 @@ * - only check for non-zero elements once * - add mask-all-zero check * - cleanups + * 3/2/10 + * - gtkdoc + * - more cleanups */ /* @@ -285,7 +265,7 @@ conv_start( IMAGE *out, void *a, void *b ) i += 1; \ } -/* INT and FLOAT inner loops. +/* INT inner loops. */ #define CONV_INT( TYPE, IM_CLIP ) { \ TYPE ** restrict p = (TYPE **) seq->pts; \ @@ -307,6 +287,8 @@ conv_start( IMAGE *out, void *a, void *b ) } \ } +/* FLOAT inner loops. + */ #define CONV_FLOAT( TYPE ) { \ TYPE ** restrict p = (TYPE **) seq->pts; \ TYPE * restrict q = (TYPE *) IM_REGION_ADDR( or, le, y ); \ @@ -434,14 +416,9 @@ im_conv_raw( IMAGE *in, IMAGE *out, INTMASK *mask ) */ if( im_piocheck( in, out ) || im_check_uncoded( "im_conv", in ) || - im_check_noncomplex( "im_conv", in ) ) + im_check_noncomplex( "im_conv", in ) || + im_check_imask( "im_conv", mask ) ) return( -1 ); - if( !mask || mask->xsize > 1000 || mask->ysize > 1000 || - mask->xsize <= 0 || mask->ysize <= 0 || !mask->coeff || - mask->scale == 0 ) { - im_error( "im_conv", "%s", _( "nonsense mask parameters" ) ); - return( -1 ); - } if( !(conv = conv_new( in, out, mask )) ) return( -1 ); @@ -460,10 +437,8 @@ im_conv_raw( IMAGE *in, IMAGE *out, INTMASK *mask ) /* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause * too many recalculations on overlaps. */ - if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) ) - return( -1 ); - - if( im_generate( out, conv_start, conv_gen, conv_stop, in, conv ) ) + if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) || + im_generate( out, conv_start, conv_gen, conv_stop, in, conv ) ) return( -1 ); out->Xoffset = -mask->xsize / 2; @@ -472,7 +447,24 @@ im_conv_raw( IMAGE *in, IMAGE *out, INTMASK *mask ) return( 0 ); } -/* The above, with a border to make out the same size as in. +/** + * im_conv: + * @in: input image + * @out: output image + * @mask: convolution mask + * + * Convolve @in with @mask using integer arithmetic. The output image + * always has the same #VipsBandFmt as the input image. Non-complex images + * only. + * + * Each output pixel is + * calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale + * and offset are part of @mask. For integer @in, the division by scale + * includes round-to-nearest. + * + * See also: im_conv_f(), im_convsep(), im_create_imaskv(). + * + * Returns: 0 on success, -1 on error */ int im_conv( IMAGE *in, IMAGE *out, INTMASK *mask ) diff --git a/libvips/convolution/im_conv_f.c b/libvips/convolution/im_conv_f.c index b312550e..edb58a5a 100644 --- a/libvips/convolution/im_conv_f.c +++ b/libvips/convolution/im_conv_f.c @@ -1,14 +1,4 @@ -/* @(#) Convolve an image with a DOUBLEMASK. Image can have any number of bands, - * @(#) any non-complex type. Output is IM_BANDFMT_FLOAT for all non-complex inputs - * @(#) except IM_BANDFMT_DOUBLE, which gives IM_BANDFMT_DOUBLE. - * @(#) - * @(#) int - * @(#) im_conv_f( in, out, mask ) - * @(#) IMAGE *in, *out; - * @(#) DOUBLEMASK *mask; - * @(#) - * @(#) Returns either 0 (success) or -1 (fail) - * @(#) +/* im_conv_f * * Copyright: 1990, N. Dessipris. * @@ -43,6 +33,9 @@ * 13/11/09 * - rename as im_conv_f() to make it easier to vips.c to make the * overloaded version + * 3/2/10 + * - gtkdoc + * - more cleanups */ /* @@ -320,14 +313,9 @@ im_conv_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask ) */ if( im_piocheck( in, out ) || im_check_uncoded( "im_conv", in ) || - im_check_noncomplex( "im_conv", in ) ) + im_check_noncomplex( "im_conv", in ) || + im_check_dmask( "im_conv", mask ) ) return( -1 ); - if( !mask || mask->xsize > 1000 || mask->ysize > 1000 || - mask->xsize <= 0 || mask->ysize <= 0 || !mask->coeff || - mask->scale == 0 ) { - im_error( "im_conv", "%s", _( "nonsense mask parameters" ) ); - return( -1 ); - } if( !(conv = conv_new( in, out, mask )) ) return( -1 ); @@ -360,7 +348,24 @@ im_conv_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask ) return( 0 ); } -/* The above, with a border to make out the same size as in. +/** + * im_conv_f: + * @in: input image + * @out: output image + * @mask: convolution mask + * + * Convolve @in with @mask using floating-point arithmetic. The output image + * is always %IM_BANDFMT_FLOAT unless @in is %IM_BANDFMT_DOUBLE, in which case + * @out is also %IM_BANDFMT_DOUBLE. Non-complex images + * only. + * + * Each output pixel is + * calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale + * and offset are part of @mask. + * + * See also: im_conv(), im_convsep_f(), im_create_dmaskv(). + * + * Returns: 0 on success, -1 on error */ int im_conv_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask ) diff --git a/libvips/convolution/im_convsep.c b/libvips/convolution/im_convsep.c index 19380219..8adc52b2 100644 --- a/libvips/convolution/im_convsep.c +++ b/libvips/convolution/im_convsep.c @@ -1,15 +1,4 @@ -/* @(#) Convolve an image with a seperable (1xN, or Nx1) INTMASK. Image can - * @(#) have any number of bands, any non-complex type. Size and type of - * @(#) output image matches type of input image. - * @(#) - * @(#) int - * @(#) im_convsep( in, out, mask ) - * @(#) IMAGE *in, *out; - * @(#) INTMASK *mask; - * @(#) - * @(#) Also: im_convsep_raw(). As above, but does not add a black border. - * @(#) - * @(#) Returns either 0 (success) or -1 (fail) +/* im_convsep * * Copyright: 1990, N. Dessipris. * @@ -29,6 +18,9 @@ * overflow on intermediates * 12/5/08 * - int rounding was +1 too much, argh + * 3/2/10 + * - gtkdoc + * - more cleanups */ /* @@ -379,24 +371,16 @@ im_convsep_raw( IMAGE *in, IMAGE *out, INTMASK *mask ) /* Check parameters. */ - if( !in || in->Coding != IM_CODING_NONE || - vips_bandfmt_iscomplex( in->BandFmt ) ) { - im_error( "im_convsep", "%s", _( "non-complex uncoded only" ) ); + if( im_piocheck( in, out ) || + im_check_uncoded( "im_convsep", in ) || + im_check_noncomplex( "im_convsep", in ) || + im_check_imask( "im_convsep", mask ) ) return( -1 ); - } - if( !mask || mask->xsize > 1000 || mask->ysize > 1000 || - mask->xsize <= 0 || mask->ysize <= 0 || !mask->coeff || - mask->scale == 0 ) { - im_error( "im_convsep", "%s", _( "nonsense mask parameters" ) ); - return( -1 ); - } if( mask->xsize != 1 && mask->ysize != 1 ) { im_error( "im_convsep", "%s", _( "expect 1xN or Nx1 input mask" ) ); return( -1 ); } - if( im_piocheck( in, out ) ) - return( -1 ); if( !(conv = conv_new( in, out, mask )) ) return( -1 ); @@ -424,7 +408,32 @@ im_convsep_raw( IMAGE *in, IMAGE *out, INTMASK *mask ) return( 0 ); } -/* The above, with a border to make out the same size as in. + +/** + * im_convsep: + * @in: input image + * @out: output image + * @mask: convolution mask + * + * Perform a separable convolution of @in with @mask using integer arithmetic. + * + * The mask must be 1xn or nx1 elements. + * The output image + * always has the same #VipsBandFmt as the input image. Non-complex images + * only. + * + * The image is convolved twice: once with @mask and then again with @mask + * rotated by 90 degrees. This is much faster for certain types of mask + * (gaussian blur, for example) than doing a full 2D convolution. + * + * Each output pixel is + * calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale + * and offset are part of @mask. For integer @in, the division by scale + * includes round-to-nearest. + * + * See also: im_convsep_f(), im_conv(), im_create_imaskv(). + * + * Returns: 0 on success, -1 on error */ int im_convsep( IMAGE *in, IMAGE *out, INTMASK *mask ) diff --git a/libvips/convolution/im_convsep_f.c b/libvips/convolution/im_convsep_f.c index 65346373..0f752f11 100644 --- a/libvips/convolution/im_convsep_f.c +++ b/libvips/convolution/im_convsep_f.c @@ -1,14 +1,4 @@ -/* @(#) Convolve an image with a DOUBLEMASK. Image can have any number of bands, - * @(#) any non-complex type. Output is IM_BANDFMT_FLOAT for all non-complex inputs - * @(#) except IM_BANDFMT_DOUBLE, which gives IM_BANDFMT_DOUBLE. - * @(#) Separable mask of sizes 1xN or Nx1 - * @(#) - * @(#) int im_convsep_f( in, out, mask ) - * @(#) IMAGE *in, *out; - * @(#) DOUBLEMASK *mask; details in mask.h - * @(#) - * @(#) Returns either 0 (sucess) or -1 (fail) - * @(#) Picture can have any number of channels (max 64). +/* im_convsep_f * * Copyright: 1990, N. Dessipris. * @@ -21,6 +11,9 @@ * - now uses im_embed() with edge stretching on the input, not * the output * - sets Xoffset / Yoffset + * 3/2/10 + * - gtkdoc + * - more cleanups */ /* @@ -81,10 +74,7 @@ typedef struct { static int conv_destroy( Conv *conv ) { - if( conv->mask ) { - (void) im_free_dmask( conv->mask ); - conv->mask = NULL; - } + IM_FREEF( im_free_dmask, conv->mask ); return( 0 ); } @@ -285,26 +275,16 @@ im_convsep_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask ) /* Check parameters. */ - if( !in || - in->Coding != IM_CODING_NONE || - vips_bandfmt_iscomplex( in->BandFmt ) ) { - im_error( "im_convsep_f", - "%s", _( "non-complex uncoded only" ) ); + if( im_piocheck( in, out ) || + im_check_uncoded( "im_convsep_f", in ) || + im_check_noncomplex( "im_convsep_f", in ) || + im_check_dmask( "im_convsep_f", mask ) ) return( -1 ); - } - if( !mask || mask->xsize > 1000 || mask->ysize > 1000 || - mask->xsize <= 0 || mask->ysize <= 0 || !mask->coeff || - mask->scale == 0 ) { - im_error( "im_convsep_f", "%s", _( "bad mask parameters" ) ); - return( -1 ); - } if( mask->xsize != 1 && mask->ysize != 1 ) { im_error( "im_convsep_f", "%s", _( "expect 1xN or Nx1 input mask" ) ); return( -1 ); } - if( im_piocheck( in, out ) ) - return( -1 ); if( !(conv = conv_new( in, out, mask )) ) return( -1 ); @@ -335,7 +315,32 @@ im_convsep_f_raw( IMAGE *in, IMAGE *out, DOUBLEMASK *mask ) return( 0 ); } -/* The above, with a border to make out the same size as in. +/** + * im_convsep_f: + * @in: input image + * @out: output image + * @mask: convolution mask + * + * Perform a separable convolution of @in with @mask using floating-point + * arithmetic. + * + * The mask must be 1xn or nx1 elements. + * The output image + * is always %IM_BANDFMT_FLOAT unless @in is %IM_BANDFMT_DOUBLE, in which case + * @out is also %IM_BANDFMT_DOUBLE. Non-complex images + * only. + * + * The image is convolved twice: once with @mask and then again with @mask + * rotated by 90 degrees. This is much faster for certain types of mask + * (gaussian blur, for example) than doing a full 2D convolution. + * + * Each output pixel is + * calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale + * and offset are part of @mask. + * + * See also: im_convsep(), im_conv(), im_create_dmaskv(). + * + * Returns: 0 on success, -1 on error */ int im_convsep_f( IMAGE *in, IMAGE *out, DOUBLEMASK *mask ) diff --git a/libvips/convolution/im_fastcor.c b/libvips/convolution/im_fastcor.c index 0901eedd..ceef5803 100644 --- a/libvips/convolution/im_fastcor.c +++ b/libvips/convolution/im_fastcor.c @@ -1,19 +1,4 @@ -/* @(#) Functions which calculates spatial correlation between two images. - * @(#) by taking absolute differences pixel by pixel without calculating - * @(#) the correlation coefficient. - * @(#) - * @(#) The function works as follows: - * @(#) - * @(#) int im_fastcor( im, ref, out ) - * @(#) IMAGE *im, *ref, *out; - * @(#) - * @(#) ref must be smaller than in. The correlation is - * @(#) calculated by overlaping im on the top left corner of ref - * @(#) and moving it all over ref calculating the correlation coefficient - * @(#) at each point. The resultant coefficients are written as unsigned int - * @(#) numbers in out which has the size of im. - * @(#) - * @(#) Returns 0 on sucess and -1 on error. +/* im_fastcor * * Copyright: 1990, N. Dessipris. * @@ -34,6 +19,9 @@ * - use im_embed() with edge stretching on the input, not the output * - calculate sum of squares of differences, rather than abs of * difference + * 3/2/10 + * - gtkdoc + * - cleanups */ /* @@ -142,7 +130,8 @@ im_fastcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out ) { /* PIO between in and out; WIO from ref. */ - if( im_piocheck( in, out ) || im_incheck( ref ) ) + if( im_piocheck( in, out ) || + im_incheck( ref ) ) return( -1 ); /* Check sizes. @@ -154,14 +143,13 @@ im_fastcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out ) /* Check types. */ - if( in->Coding != IM_CODING_NONE || in->Bands != 1 || - in->BandFmt != IM_BANDFMT_UCHAR || - ref->Coding != IM_CODING_NONE || ref->Bands != 1 || - ref->BandFmt != IM_BANDFMT_UCHAR ) { - im_error( "im_fastcor_raw", "%s", - _( "input not uncoded 1 band uchar" ) ); + if( im_check_uncoded( "im_fastcor", in ) || + im_check_format( "im_fastcor", in, IM_BANDFMT_UCHAR ) || + im_check_mono( "im_fastcor", in ) || + im_check_uncoded( "im_fastcor", ref ) || + im_check_format( "im_fastcor", ref, IM_BANDFMT_UCHAR ) || + im_check_mono( "im_fastcor", ref ) ) return( -1 ); - } /* Prepare the output image. */ @@ -171,16 +159,12 @@ im_fastcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out ) out->Xsize = in->Xsize - ref->Xsize + 1; out->Ysize = in->Ysize - ref->Ysize + 1; - /* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause + /* FATSTRIP is good for us, as THINSTRIP will cause * too many recalculations on overlaps. */ - if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) ) - return( -1 ); - - /* Write the correlation. - */ - if( im_generate( out, - im_start_one, fastcor_gen, im_stop_one, in, ref ) ) + if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) || + im_generate( out, + im_start_one, fastcor_gen, im_stop_one, in, ref ) ) return( -1 ); out->Xoffset = -ref->Xsize / 2; @@ -189,7 +173,22 @@ im_fastcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out ) return( 0 ); } -/* The above, with a border to make out the same size as in. +/** + * im_fastcor: + * @in: input image + * @ref: reference image + * @out: output image + * + * Calculate a fast correlation surface. + * + * @ref is placed at every position in @in and the sum of squares of + * differences calculated. One-band, 8-bit unsigned images only. The output + * image is always %IM_BANDFMT_UINT. @ref must be smaller than @in. The output + * image is the same size as the input. + * + * See also: im_spcor(). + * + * Returns: 0 on success, -1 on error */ int im_fastcor( IMAGE *in, IMAGE *ref, IMAGE *out ) diff --git a/libvips/convolution/im_gradcor.c b/libvips/convolution/im_gradcor.c index 93abe22a..87731cd3 100644 --- a/libvips/convolution/im_gradcor.c +++ b/libvips/convolution/im_gradcor.c @@ -1,23 +1,12 @@ -/* @(#) Like im_spcor(), but with a new metric. - * @(#) - * @(#) takes the gradient images of the two images, and takes the dot-product - * @(#) correlation of the two vector images. - * @(#) - * @(#) (vector images are never really used, the two components are - * @(#) calculated separately) - * @(#) - * @(#) The vector expression of this method is my (tcv) own creation. It is - * @(#) equivalent to the complex-number method of: - * @(#) - * @(#) ARGYRIOU, V. et al. 2003. Estimation of sub-pixel motion using - * @(#) gradient cross correlation. Electronics Letters, 39 (13). - * @(#) - * @(#) It's suitability for sub-pixel alignment is not (yet) tested. +/* im_gradcor * * Copyright: 2007 Nottingham Trent University * * Author: Tom Vajzovic * Written on: 2007-06-07 + * 3/2/10 + * - gtkdoc + * - cleanups */ /* @@ -112,19 +101,14 @@ int im_gradcor_raw( IMAGE *large, IMAGE *small, IMAGE *out ){ if( im_piocheck( large, out ) || im_pincheck( small ) ) return -1; - if( ! vips_bandfmt_isint( large->BandFmt ) || - ! vips_bandfmt_isint( small->BandFmt ) ){ - im_error( FUNCTION_NAME, "image does not have integer band format" ); - return -1; - } - if( large-> Coding || small-> Coding ){ - im_error( FUNCTION_NAME, "image is not uncoded" ); - return -1; - } - if( 1 != large-> Bands || 1 != small-> Bands ){ - im_error( FUNCTION_NAME, "image is multi-band" ); - return -1; - } + if( im_check_uncoded( "im_gradcor", large ) || + im_check_mono( "im_gradcor", large ) || + im_check_uncoded( "im_gradcor", small ) || + im_check_mono( "im_gradcor", small ) || + im_check_format_same( "im_gradcor", large, small ) || + im_check_int( "im_gradcor", large ) ) + return( -1 ); + if( large-> Xsize < small-> Xsize || large-> Ysize < small-> Ysize ){ im_error( FUNCTION_NAME, "second image must be smaller than first" ); return -1; @@ -152,6 +136,32 @@ int im_gradcor_raw( IMAGE *large, IMAGE *small, IMAGE *out ){ #undef FUNCTION_NAME } +/** + * im_gradcor: + * @in: input image + * @ref: reference image + * @out: output image + * + * Calculate a correlation surface. + * + * @ref is placed at every position in @in and a correlation coefficient + * calculated. One-band, integer images only. @in and @ref must have the + * same #VipsBandFmt. The output + * image is always %IM_BANDFMT_FLOAT. @ref must be smaller than @in. The output + * image is the same size as the input. + * + * The method takes the gradient images of the two images then takes the + * dot-product correlation of the two vector images. + * The vector expression of this method is my (tcv) own creation. It is + * equivalent to the complex-number method of: + * + * ARGYRIOU, V. et al. 2003. Estimation of sub-pixel motion using + * gradient cross correlation. Electronics Letters, 39 (13). + * + * See also: im_spcor(). + * + * Returns: 0 on success, -1 on error + */ int im_gradcor( IMAGE *in, IMAGE *ref, IMAGE *out ) { @@ -173,24 +183,35 @@ im_gradcor( IMAGE *in, IMAGE *ref, IMAGE *out ) #undef FUNCTION_NAME } +/** + * im_grad_x: + * @in: input image + * @out: output image + * + * Find horizontal differences between adjacent pixels. + * + * Generates an image where the value of each pixel is the difference between + * it and the pixel to its right. The output has the same height as the input + * and one pixel less width. One-band integer formats only. The result is + * always %IM_BANDFMT_INT. + * + * This operation is much faster than (though equivalent to) im_conv() with the + * mask [[-1, 1]]. + * + * See also: im_grad_y(), im_conv(). + * + * Returns: 0 on success, -1 on error + */ int im_grad_x( IMAGE *in, IMAGE *out ){ #define FUNCTION_NAME "im_grad_x" if( im_piocheck( in, out ) ) return -1; - if( ! vips_bandfmt_isint( in->BandFmt ) ){ - im_error( FUNCTION_NAME, "image does not have integer band format" ); - return -1; - } - if( in-> Coding ){ - im_error( FUNCTION_NAME, "image is not uncoded" ); - return -1; - } - if( 1 != in-> Bands ){ - im_error( FUNCTION_NAME, "image is multi-band" ); - return -1; - } + if( im_check_uncoded( "im_grad_x", in ) || + im_check_mono( "im_grad_x", in ) || + im_check_int( "im_grad_x", in ) ) + return( -1 ); if( im_cp_desc( out, in ) ) return -1; @@ -238,24 +259,37 @@ int im_grad_x( IMAGE *in, IMAGE *out ){ #undef FUNCTION_NAME } + +/** + * im_grad_y: + * @in: input image + * @out: output image + * + * Find vertical differences between adjacent pixels. + * + * Generates an image where the value of each pixel is the difference between + * it and the pixel below it. The output has the same width as the input + * and one pixel less height. One-band integer formats only. The result is + * always %IM_BANDFMT_INT. + * + * This operation is much faster than (though equivalent to) im_conv() with the + * mask [[-1], [1]]. + * + * See also: im_grad_x(), im_conv(). + * + * Returns: 0 on success, -1 on error + */ int im_grad_y( IMAGE *in, IMAGE *out ){ #define FUNCTION_NAME "im_grad_y" if( im_piocheck( in, out ) ) return -1; - if( ! vips_bandfmt_isint( in->BandFmt ) ){ - im_error( FUNCTION_NAME, "image does not have integer band format" ); - return -1; - } - if( in-> Coding ){ - im_error( FUNCTION_NAME, "image is not uncoded" ); - return -1; - } - if( 1 != in-> Bands ){ - im_error( FUNCTION_NAME, "image is multi-band" ); - return -1; - } + if( im_check_uncoded( "im_grad_y", in ) || + im_check_mono( "im_grad_y", in ) || + im_check_int( "im_grad_y", in ) ) + return( -1 ); + if( im_cp_desc( out, in ) ) return -1; diff --git a/libvips/convolution/im_sharpen.c b/libvips/convolution/im_sharpen.c index bc7d24eb..7a1f1350 100644 --- a/libvips/convolution/im_sharpen.c +++ b/libvips/convolution/im_sharpen.c @@ -36,6 +36,9 @@ * - ~15% speed up in total * 29/11/06 * - convolve first to help region sharing + * 3/2/10 + * - gtkdoc + * - cleanups */ /* @@ -212,6 +215,73 @@ sharpen_mask_new( int radius ) return( line ); } +/** + * im_sharpen: + * @in: input image + * @out: output image + * @mask_size: how large a mask to use + * @x1: flat/jaggy threshold + * @y2: maximum amount of brightening + * @y3: maximum amount of darkening + * @m1: slope for flat areas + * @m2: slope for jaggy areas + * + * Selectively sharpen the L channel of a LAB image. Works for %IM_CODING_LABQ + * and LABS images. + * + * The operation performs a gaussian blur of size @mask_size and subtracts + * from @in to + * generate a high-frequency signal. This signal is passed through a lookup + * table formed from the five parameters and added back to @in. + * + * The lookup table is formed like this: + * + * |[ + ^ + y2 |- - - - - ----------- + | / + | / slope m2 + | .../ + -x1 | ... | + -------------------...----------------------> + | ... | x1 + |... slope m1 + / | + / m2 | + / | + / | + / | + / | + ______/ _ _ _ _ _ _ | -y3 + | + * ]| + * + * For printing, we recommend the following settings: + * + * |[ + mask_size == 7 + x1 == 1.5 + y2 == 20 (don't brighten by more than 20 L*) + y3 == 50 (can darken by up to 50 L*) + + m1 == 1 (some sharpening in flat areas) + m2 == 2 (more sharpening in jaggy areas) + * ]| + * + * If you want more or less sharpening, we suggest you just change the m1 + * and m2 parameters. + * + * The @mask_size parameter changes the width of the fringe and can be + * adjusted according to the output printing resolution. As an approximate + * guideline, use 3 for 4 pixels/mm (CRT display resolution), 5 for 8 + * pixels/mm, 7 for 12 pixels/mm and 9 for 16 pixels/mm (300 dpi == 12 + * pixels/mm). These figures refer to the image raster, not the half-tone + * resolution. + * + * See also: im_conv(). + * + * Returns: 0 on success, -1 on error. + */ int im_sharpen( IMAGE *in, IMAGE *out, int mask_size, @@ -243,20 +313,19 @@ im_sharpen( IMAGE *in, IMAGE *out, /* Check IMAGE parameters */ - if( in->Coding != IM_CODING_NONE || - in->Bands != 3 || - in->BandFmt != IM_BANDFMT_SHORT ) { - im_error( "im_sharpen", "%s", _( "input not 3-band short" ) ); - return( -1 ); - } - - if( im_piocheck( in, out ) ) + if( im_piocheck( in, out ) || + im_check_uncoded( "im_sharpen", in ) || + im_check_bands( "im_gradcor", in, 3 ) || + im_check_format( "im_gradcor", in, IM_BANDFMT_SHORT ) ) return( -1 ); /* Check number range. */ - if( x1 < 0 || x2 < 0 || x1 > 99 || x2 > 99 || x1 > x2 || - x3 < 0 || x3 > 99 || x1 > x3 ) { + if( x1 < 0 || x1 > 99 || + x2 < 0 || x2 > 99 || + x1 > x2 || + x3 < 0 || x3 > 99 || + x1 > x3 ) { im_error( "im_sharpen", "%s", _( "parameters out of range" ) ); return( -1 ); } diff --git a/libvips/convolution/im_spcor.c b/libvips/convolution/im_spcor.c index d0b6c946..252bc458 100644 --- a/libvips/convolution/im_spcor.c +++ b/libvips/convolution/im_spcor.c @@ -1,21 +1,4 @@ -/* @(#) Functions which calculates the correlation coefficient between two - * @(#) images. - * @(#) - * @(#) int im_spcor( IMAGE *in, IMAGE *ref, IMAGE *out ) - * @(#) - * @(#) We calculate: - * @(#) - * @(#) sumij (ref(i,j)-mean(ref))(inkl(i,j)-mean(inkl)) - * @(#) c(k,l) = ------------------------------------------------ - * @(#) sqrt(sumij (ref(i,j)-mean(ref))^2) * - * @(#) sqrt(sumij (inkl(i,j)-mean(inkl))^2) - * @(#) - * @(#) where inkl is the area of in centred at position (k,l). - * @(#) - * @(#) Writes float to out. in and ref must be 1 band uchar, or 1 band - * @(#) ushort. - * @(#) - * @(#) Returns 0 on sucess and -1 on error. +/* im_spcor * * Copyright: 1990, N. Dessipris; 2006, 2007 Nottingham Trent University. * @@ -48,6 +31,9 @@ * - make im_spcor a wrapper selecting either im__spcor or im__spcor2 * 2008-09-09 JC * - roll back the windowed version for now, it has some tile edge effects + * 3/2/10 + * - gtkdoc + * - cleanups */ /* @@ -185,14 +171,11 @@ spcor_gen( REGION *or, void *vseq, void *a, void *b ) */ switch( ref->BandFmt ) { case IM_BANDFMT_UCHAR: LOOP(unsigned char); break; + case IM_BANDFMT_CHAR: LOOP(signed char); break; case IM_BANDFMT_USHORT: LOOP(unsigned short); break; case IM_BANDFMT_SHORT: LOOP(signed short); break; default: - error_exit( "im_spcor: internal error #7934" ); - - /* Keep gcc -Wall happy. - */ - return( -1 ); + g_assert( 0 ); } /* Now: calculate correlation coefficient! @@ -260,20 +243,17 @@ im_spcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out ) /* Check types. */ - if( in->Coding != IM_CODING_NONE || - in->Bands != 1 || - ref->Coding != IM_CODING_NONE || - ref->Bands != 1 || - in->BandFmt != ref->BandFmt ) { - im_error( "im_spcor_raw", - "%s", _( "input not uncoded 1 band" ) ); + if( im_check_uncoded( "im_spcor", in ) || + im_check_mono( "im_spcor", in ) || + im_check_uncoded( "im_spcor", ref ) || + im_check_mono( "im_spcor", ref ) || + im_check_format_same( "im_spcor", in, ref ) ) return( -1 ); - } if( in->BandFmt != IM_BANDFMT_UCHAR && in->BandFmt != IM_BANDFMT_CHAR && in->BandFmt != IM_BANDFMT_SHORT && in->BandFmt != IM_BANDFMT_USHORT ) { - im_error( "im_spcor_raw", + im_error( "im_spcor", "%s", _( "input not char/uchar/short/ushort" ) ); return( -1 ); } @@ -309,7 +289,37 @@ im_spcor_raw( IMAGE *in, IMAGE *ref, IMAGE *out ) return( 0 ); } -/* The above, with the input expanded to make out the same size as in. +/** + * im_spcor: + * @in: input image + * @ref: reference image + * @out: output image + * + * Calculate a correlation surface. + * + * @ref is placed at every position in @in and the correlation coefficient + * calculated. One-band, 8 or 16-bit images only. @in and @ref must have the + * same #VipsBandFmt. The output + * image is always %IM_BANDFMT_FLOAT. @ref must be smaller than @in. The output + * image is the same size as the input. + * + * The correlation coefficient is calculated as: + * + * |[ + * sumij (ref(i,j)-mean(ref))(inkl(i,j)-mean(inkl)) + * c(k,l) = ------------------------------------------------ + * sqrt(sumij (ref(i,j)-mean(ref))^2) * + * sqrt(sumij (inkl(i,j)-mean(inkl))^2) + * ]| + * + * where inkl is the area of @in centred at position (k,l). + * + * from Niblack "An Introduction to Digital Image Processing", + * Prentice/Hall, pp 138. + * + * See also: im_gradcor(), im_fastcor(). + * + * Returns: 0 on success, -1 on error */ int im_spcor( IMAGE *in, IMAGE *ref, IMAGE *out ) diff --git a/libvips/include/vips/check.h b/libvips/include/vips/check.h index 4a063ec8..7ae869af 100644 --- a/libvips/include/vips/check.h +++ b/libvips/include/vips/check.h @@ -59,6 +59,8 @@ int im_check_u8or16( const char *domain, IMAGE *im ); int im_check_format_same( const char *domain, IMAGE *im1, IMAGE *im2 ); int im_check_size_same( const char *domain, IMAGE *im1, IMAGE *im2 ); int im_check_vector( const char *domain, int n, IMAGE *im ); +int im_check_imask( const char *domain, INTMASK *mask ); +int im_check_dmask( const char *domain, DOUBLEMASK *mask ); gboolean vips_bandfmt_isint( VipsBandFmt fmt ); gboolean vips_bandfmt_isuint( VipsBandFmt fmt ); diff --git a/libvips/iofuncs/check.c b/libvips/iofuncs/check.c index 9b8eba8f..90313759 100644 --- a/libvips/iofuncs/check.c +++ b/libvips/iofuncs/check.c @@ -919,6 +919,60 @@ im_check_vector( const char *domain, int n, IMAGE *im ) return( 0 ); } +/** + * im_check_imask: + * @domain: the originating domain for the error message + * @mask: mask to check + * + * Sanity-check a mask parameter. + * + * See also: im_error(). + * + * Returns: 0 if OK, -1 otherwise. + */ +int +im_check_imask( const char *domain, INTMASK *mask ) +{ + if( !mask || + mask->xsize > 1000 || + mask->ysize > 1000 || + mask->xsize <= 0 || + mask->ysize <= 0 || + !mask->coeff ) { + im_error( "im_conv", "%s", _( "nonsense mask parameters" ) ); + return( -1 ); + } + + return( 0 ); +} + +/** + * im_check_dmask: + * @domain: the originating domain for the error message + * @mask: mask to check + * + * Sanity-check a mask parameter. + * + * See also: im_error(). + * + * Returns: 0 if OK, -1 otherwise. + */ +int +im_check_dmask( const char *domain, DOUBLEMASK *mask ) +{ + if( !mask || + mask->xsize > 1000 || + mask->ysize > 1000 || + mask->xsize <= 0 || + mask->ysize <= 0 || + !mask->coeff ) { + im_error( "im_conv", "%s", _( "nonsense mask parameters" ) ); + return( -1 ); + } + + return( 0 ); +} + /** * vips_bandfmt_isint: * @fmt: format to test