From 0660bd1400a03493c5b3beabb7d3c2e3654d42dd Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 18 Aug 2009 15:24:56 +0000 Subject: [PATCH] more stuff --- ChangeLog | 4 +- libvips/arithmetic/arith_dispatch.c | 14 +- libvips/arithmetic/im_add.c | 8 +- libvips/arithmetic/im_avg.c | 65 ++++---- libvips/arithmetic/im_bandmean.c | 65 ++++---- libvips/arithmetic/im_measure.c | 56 ++++--- libvips/arithmetic/im_multiply.c | 242 ++++++++++++++-------------- libvips/arithmetic/im_subtract.c | 9 +- 8 files changed, 242 insertions(+), 221 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9ae3b73a..cb1d52d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,13 +21,15 @@ - add and use im_check_uncoded() and friends - matlab load handles column-major and plane-separated images (thanks Mikhail) - JPEG save allows "none" for profile, meaning don't attach a profile +- saner, simpler, faster typecasting for im_add(), im_subtract() +- im_measure() allows sel == NULL, meaning all patches 25/3/09 started 7.18.0 - revised version numbers - updated vipsmanual - revised manpages - removed name and "changed" from vipsobject since we don't use them yet -- explicitly link with stdc++ for nohalo etc stuff +- explicitly link with stdc++ for nohalo etc. stuff - wrap im_gauss_imask_sep in C++/Python 6/3/09 started 7.17.3 diff --git a/libvips/arithmetic/arith_dispatch.c b/libvips/arithmetic/arith_dispatch.c index 57e42b63..0c2fb31f 100644 --- a/libvips/arithmetic/arith_dispatch.c +++ b/libvips/arithmetic/arith_dispatch.c @@ -1127,9 +1127,7 @@ static int measure_vec( im_object *argv ) { IMAGE_BOX box; - int h, v, i; - int *sel; - int nsel; + int h, v; im_mask_object *mo = argv[1]; box.xstart = *((int *) argv[2]); @@ -1141,18 +1139,10 @@ measure_vec( im_object *argv ) h = *((int *) argv[6]); v = *((int *) argv[7]); - nsel = h * v; - if( !(sel = IM_ARRAY( NULL, nsel, int )) ) - return( -1 ); - for( i = 0; i < nsel; i++ ) - sel[i] = i + 1; - if( !(mo->mask = - im_measure( argv[0], &box, h, v, sel, nsel, mo->name )) ) { - im_free( sel ); + im_measure( argv[0], &box, h, v, NULL, 0, mo->name )) ) { return( -1 ); } - im_free( sel ); return( 0 ); } diff --git a/libvips/arithmetic/im_add.c b/libvips/arithmetic/im_add.c index 73f42765..c6afe6bf 100644 --- a/libvips/arithmetic/im_add.c +++ b/libvips/arithmetic/im_add.c @@ -104,6 +104,7 @@ add_buffer( PEL **in, PEL *out, int width, IMAGE *im ) case IM_BANDFMT_INT: LOOP( signed int, signed int ); break; case IM_BANDFMT_FLOAT: + case IM_BANDFMT_COMPLEX: #ifdef HAVE_LIBOIL oil_add_f32( (float *) out, (float *) in[0], (float *) in[1], sz ); @@ -112,9 +113,10 @@ add_buffer( PEL **in, PEL *out, int width, IMAGE *im ) #endif /*HAVE_LIBOIL*/ break; - case IM_BANDFMT_DOUBLE: LOOP( double, double ); break; - case IM_BANDFMT_COMPLEX:LOOP( float, float ); break; - case IM_BANDFMT_DPCOMPLEX:LOOP( double, double ); break; + case IM_BANDFMT_DOUBLE: + case IM_BANDFMT_DPCOMPLEX: + LOOP( double, double ); + break; default: assert( 0 ); diff --git a/libvips/arithmetic/im_avg.c b/libvips/arithmetic/im_avg.c index 9ba3f8f8..04629ab6 100644 --- a/libvips/arithmetic/im_avg.c +++ b/libvips/arithmetic/im_avg.c @@ -1,12 +1,4 @@ -/* @(#) Find the average of an image. Takes any non-complex image format, - * @(#) returns a double. Finds the average of all bands. - * @(#) - * @(#) int - * @(#) im_avg( im, out ) - * @(#) IMAGE *im; - * @(#) double *out; - * @(#) - * @(#) Returns 0 on success and -1 on error. +/* im_avg.c * * Copyright: 1990, J. Cupitt * @@ -29,6 +21,8 @@ * - use 64 bit arithmetic * 8/12/06 * - add liboil support + * 18/8/09 + * - gtkdoc, minor reformatting */ /* @@ -123,27 +117,27 @@ scan_fn( REGION *reg, void *seq, void *a, void *b ) /* Sum pels in this section. */ -#define loop(TYPE) \ - { TYPE *p;\ - \ - for( y = to; y < bo; y++ ) { \ - p = (TYPE *) IM_REGION_ADDR( reg, le, y ); \ - \ - for( x = 0; x < sz; x++ ) \ - sum += *p++;\ - }\ - } +#define LOOP( TYPE ) { \ + TYPE *p; \ + \ + for( y = to; y < bo; y++ ) { \ + p = (TYPE *) IM_REGION_ADDR( reg, le, y ); \ + \ + for( x = 0; x < sz; x++ ) \ + sum += *p++; \ + } \ +} /* Now generate code for all types. */ switch( im->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; - case IM_BANDFMT_UINT: loop(unsigned int); break; - case IM_BANDFMT_INT: loop(signed int); break; - case IM_BANDFMT_FLOAT: loop(float); break; + 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; + case IM_BANDFMT_UINT: LOOP( unsigned int ); break; + case IM_BANDFMT_INT: LOOP( signed int ); break; + case IM_BANDFMT_FLOAT: LOOP( float ); break; case IM_BANDFMT_DOUBLE: #ifdef HAVE_LIBOIL @@ -156,7 +150,7 @@ scan_fn( REGION *reg, void *seq, void *a, void *b ) sum += t; } #else /*!HAVE_LIBOIL*/ - loop(double); + LOOP( double ); #endif /*HAVE_LIBOIL*/ break; @@ -171,11 +165,24 @@ scan_fn( REGION *reg, void *seq, void *a, void *b ) return( 0 ); } -/* Find the average of an image. +/** + * im_avg: + * @in: input #IMAGE + * @out: output pixel average + * + * This operation finds the average value in an image. It operates on all + * bands of the input image: use im_stats() if you need to calculate an + * average for each band. + * + * Non-complex images only. + * + * See also: im_stats(), im_bandmean(), im_deviate(), im_rank() + * + * Returns: 0 on success, -1 on error */ int im_avg( IMAGE *in, double *out ) -{ +{ double sum = 0.0; gint64 vals, pels; diff --git a/libvips/arithmetic/im_bandmean.c b/libvips/arithmetic/im_bandmean.c index dedaae8a..d187812a 100644 --- a/libvips/arithmetic/im_bandmean.c +++ b/libvips/arithmetic/im_bandmean.c @@ -1,15 +1,12 @@ -/* @(#) Average the bands in an image. - * @(#) - * @(#) int - * @(#) im_bandmean(in, out) - * @(#) IMAGE *in, *out; - * @(#) - * @(#) Returns 0 on success and -1 on error +/* im_bandmean.c * * Author: Simon Goodall * Written on: 17/7/07 * 17/7/07 JC * - hacked about a bit + * 18/8/09 + * - gtkdoc + * - get rid of the complex case, just double the width */ /* @@ -58,13 +55,13 @@ TYPE *p1 = (TYPE *) p; \ TYPE *q1 = (TYPE *) q; \ \ - for( i = 0; i < n; i++ ) { \ + for( i = 0; i < sz; i++ ) { \ STYPE sum; \ \ sum = 0; \ for( j = 0; j < b; j++ ) \ sum += p1[j]; \ - *q1++ = sum > 0 ? (sum + b / 2) / b : (sum - b / 2) / b; \ + q1[i] = sum > 0 ? (sum + b / 2) / b : (sum - b / 2) / b; \ p1 += b; \ } \ } @@ -75,45 +72,27 @@ TYPE *p1 = (TYPE *) p; \ TYPE *q1 = (TYPE *) q; \ \ - for( i = 0; i < n; i++ ) { \ + for( i = 0; i < sz; i++ ) { \ TYPE sum; \ \ sum = 0; \ for( j = 0; j < b; j++ ) \ sum += p1[j]; \ - *q1++ = sum / b; \ + q1[i] = sum / b; \ p1 += b; \ } \ } -/* Complex loop. Mean reals and imaginaries separately. - */ -#define CLOOP( TYPE ) { \ - TYPE *p1 = (TYPE *) p; \ - TYPE *q1 = (TYPE *) q; \ - \ - for( i = 0; i < n * 2; i += 2 ) { \ - TYPE sum; \ - \ - sum = 0; \ - for( j = 0; j < b; j++ ) \ - sum += p1[j * 2]; \ - q1[0] = sum / b; \ - sum = 0; \ - for( j = 0; j < b; j++ ) \ - sum += p1[j * 2 + 1]; \ - q1[1] = sum / b; \ - p1 += b; \ - q1 += 2; \ - } \ -} - static void bandmean_buffer( PEL *p, PEL *q, int n, IMAGE *in ) { - int i, j; + /* Complex just doubles the size. + */ + const int sz = n * (im_iscomplex( in ) ? 2 : 1); const int b = in->Bands; + int i, j; + switch( in->BandFmt ) { case IM_BANDFMT_CHAR: ILOOP( signed char, int ); break; case IM_BANDFMT_UCHAR: ILOOP( unsigned char, unsigned int ); break; @@ -123,14 +102,28 @@ bandmean_buffer( PEL *p, PEL *q, int n, IMAGE *in ) case IM_BANDFMT_UINT: ILOOP( unsigned int, unsigned int ); break; case IM_BANDFMT_FLOAT: FLOOP( float ); break; case IM_BANDFMT_DOUBLE: FLOOP( double ); break; - case IM_BANDFMT_COMPLEX: CLOOP( float ); break; - case IM_BANDFMT_DPCOMPLEX: CLOOP( double ); break; + case IM_BANDFMT_COMPLEX:FLOOP( float ); break; + case IM_BANDFMT_DPCOMPLEX:FLOOP( double ); break; default: assert( 0 ); } } +/** + * im_bandmean: + * @in: input #IMAGE + * @out: output #IMAGE + * + * im_bandmean() writes a one-band image where each pixel is the average of + * the bands for that pixel in the input image. The output band format is + * the same as the input band format. Integer types use round-to-nearest + * averaging. + * + * See also: im_add(), im_avg(), im_recomb() + * + * Returns: 0 on success, -1 on error + */ int im_bandmean( IMAGE *in, IMAGE *out ) { diff --git a/libvips/arithmetic/im_measure.c b/libvips/arithmetic/im_measure.c index a024c89e..b41a161e 100644 --- a/libvips/arithmetic/im_measure.c +++ b/libvips/arithmetic/im_measure.c @@ -152,25 +152,38 @@ measure_patches( IMAGE *im, double *coeff, IMAGE_BOX *box, * @name: name to give to returned @DOUBLEMASK * * Analyse a grid of colour patches, producing a #DOUBLEMASK of patch averages. - * 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. + * 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 | - * +---+---+---+---+ + * + * + * + * + * 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. * - * Returns: #DOUBLEMASK with a row for each selected patch, a column for each - * image band. - * - * Related: im_avg(), im_deviate(), im_stats(). + * See also: im_avg(), im_deviate(), im_stats(). + * + * Returns: #DOUBLEMASK of measurements. */ DOUBLEMASK * im_measure( IMAGE *im, IMAGE_BOX *box, int h, int v, @@ -197,13 +210,20 @@ im_measure( IMAGE *im, IMAGE_BOX *box, int h, int v, return( mask ); } - if( im->Coding != IM_CODING_NONE ) { - im_error( "im_measure", "%s", _( "not uncoded" ) ); - return( NULL ); - } - if( im_iscomplex( im ) ) { - im_error( "im_measure", "%s", _( "bad input type" ) ); + if( im_check_uncoded( "im_measure", im ) || + im_check_noncomplex( "im_measure", im ) ) return( NULL ); + + /* Default to all patches if sel == NULL. + */ + if( sel == NULL ) { + int i; + + nsel = h * v; + if( !(sel = IM_ARRAY( im, nsel, int )) ) + return( NULL ); + for( i = 0; i < nsel; i++ ) + sel[i] = i + 1; } /* What size mask do we need? diff --git a/libvips/arithmetic/im_multiply.c b/libvips/arithmetic/im_multiply.c index 7e2488cf..1b94eaef 100644 --- a/libvips/arithmetic/im_multiply.c +++ b/libvips/arithmetic/im_multiply.c @@ -29,6 +29,10 @@ * - updated for 1 band $op n band image -> n band image case * 8/12/06 * - add liboil support + * 18/8/08 + * - revise upcasting system + * - add gtkdoc comments + * - remove separate complex case, just double size */ /* @@ -78,77 +82,49 @@ #include #endif /*WITH_DMALLOC*/ -/* Swap two IMAGE pointers. - */ -#define SWAP(A,B) { \ - IMAGE *t; \ - t = (A); (A) = (B); (B) = t; \ -} - -/* Complex multiply. - */ -#define cloop(TYPE) \ -{\ - TYPE *p1 = (TYPE *) in[0];\ - TYPE *p2 = (TYPE *) in[1];\ - TYPE *q = (TYPE *) out;\ +#define LOOP( IN, OUT ) { \ + IN *p1 = (IN *) in[0]; \ + IN *p2 = (IN *) in[1]; \ + OUT *q = (OUT *) out; \ \ - for( x = 0; x < sz; x++ ) {\ - double x1 = p1[0];\ - double y1 = p1[1];\ - double x2 = p2[0];\ - double y2 = p2[1];\ - \ - p1 += 2;\ - p2 += 2;\ - \ - q[0] = x1 * x2 - y1 * y2;\ - q[1] = x1 * y2 + x2 * y1;\ - \ - q += 2;\ - }\ -} - -/* Real multiply. - */ -#define rloop(TYPE) \ -{\ - TYPE *p1 = (TYPE *) in[0];\ - TYPE *p2 = (TYPE *) in[1];\ - TYPE *q = (TYPE *) out;\ - \ - for( x = 0; x < sz; x++ )\ - q[x] = p1[x] * p2[x];\ + for( x = 0; x < sz; x++ ) \ + q[x] = p1[x] * p2[x]; \ } static void multiply_buffer( PEL **in, PEL *out, int width, IMAGE *im ) { - int x; - int sz = width * im->Bands; + /* Complex just doubles the size. + */ + const int sz = width * im->Bands * (im_iscomplex( im ) ? 2 : 1); - /* Multiply all input types. + int x; + + /* Multiply all input types. Keep types here in sync with + * bandfmt_multiply[] below. */ switch( im->BandFmt ) { - case IM_BANDFMT_CHAR: rloop( signed char ); break; - case IM_BANDFMT_UCHAR: rloop( unsigned char ); break; - case IM_BANDFMT_SHORT: rloop( signed short ); break; - case IM_BANDFMT_USHORT: rloop( unsigned short ); break; - case IM_BANDFMT_INT: rloop( signed int ); break; - case IM_BANDFMT_UINT: rloop( unsigned int ); break; + case IM_BANDFMT_CHAR: LOOP( signed char, signed short ); break; + case IM_BANDFMT_UCHAR: LOOP( unsigned char, unsigned short ); break; + case IM_BANDFMT_SHORT: LOOP( signed short, signed int ); break; + case IM_BANDFMT_USHORT: LOOP( unsigned short, unsigned int ); break; + case IM_BANDFMT_INT: LOOP( signed int, signed int ); break; + case IM_BANDFMT_UINT: LOOP( unsigned int, unsigned int ); break; case IM_BANDFMT_FLOAT: + case IM_BANDFMT_COMPLEX: #ifdef HAVE_LIBOIL oil_multiply_f32( (float *) out, (float *) in[0], (float *) in[1], sz ); #else /*!HAVE_LIBOIL*/ - rloop( float ); + LOOP( float, float ); #endif /*HAVE_LIBOIL*/ break; - case IM_BANDFMT_DOUBLE: rloop( double ); break; - case IM_BANDFMT_COMPLEX: cloop( float ); break; - case IM_BANDFMT_DPCOMPLEX: cloop( double ); break; + case IM_BANDFMT_DOUBLE: + case IM_BANDFMT_DPCOMPLEX: + LOOP( double, double ); + break; default: assert( 0 ); @@ -164,45 +140,108 @@ multiply_buffer( PEL **in, PEL *out, int width, IMAGE *im ) #define UI IM_BANDFMT_UINT #define I IM_BANDFMT_INT #define F IM_BANDFMT_FLOAT -#define M IM_BANDFMT_COMPLEX +#define X IM_BANDFMT_COMPLEX #define D IM_BANDFMT_DOUBLE -#define DM IM_BANDFMT_DPCOMPLEX +#define DX IM_BANDFMT_DPCOMPLEX -/* Type conversions for two integer inputs. Rules for float and complex - * encoded with ifs. We are sign and value preserving. +/* Type promotion for multiplication. Sign and value preserving. Make sure + * these match the case statement in multiply_buffer() above. */ -static int iformat[6][6] = { - /* UC C US S UI I */ -/* UC */ { US, S, UI, I, UI, I }, -/* C */ { S, S, I, I, I, I }, -/* US */ { UI, I, UI, I, UI, I }, -/* S */ { I, I, I, I, I, I }, -/* UI */ { UI, I, UI, I, UI, I }, -/* I */ { I, I, I, I, I, I } +static int bandfmt_multiply[10] = { +/* UC C US S UI I F X D DX */ + US, S, UI, I, UI, I, F, X, D, DX }; +/** + * im_multiply: + * @in1: input #IMAGE 1 + * @in2: input #IMAGE 2 + * @out: output #IMAGE + * + * This operation calculates @in1 * @in2 and writes the result to @out. + * The images must be the same size. They may have any format. + * + * If the number of bands differs, one of the images + * must have one band. In this case, an n-band image is formed from the + * one-band image by joining n copies of the one-band image together, and then + * the two n-band images are operated upon. + * + * The two input images are cast up to the smallest common type (see table + * Smallest common format in + * arithmetic), then the + * following table is used to determine the output type: + * + * + * im_add() type promotion + * + * + * + * input type + * output type + * + * + * + * + * uchar + * ushort + * + * + * char + * short + * + * + * ushort + * uint + * + * + * short + * int + * + * + * uint + * uint + * + * + * int + * int + * + * + * float + * float + * + * + * double + * double + * + * + * complex + * complex + * + * + * double complex + * double complex + * + * + * + *
+ * + * In other words, the output type is just large enough to hold the whole + * range of possible values. + * + * See also: im_divide(), im_lintra(). + * + * Returns: 0 on success, -1 on error + */ int im_multiply( IMAGE *in1, IMAGE *in2, IMAGE *out ) { - /* Basic checks. - */ - if( im_piocheck( in1, out ) || im_pincheck( in2 ) ) + if( im_piocheck( in1, out ) || + im_pincheck( in2 ) || + im_check_bands_1orn( "im_multiply", in1, in2 ) || + im_check_uncoded( "im_multiply", in1 ) || + im_check_uncoded( "im_multiply", in2 ) ) return( -1 ); - if( in1->Xsize != in2->Xsize || in1->Ysize != in2->Ysize ) { - im_error( "im_multiply", "%s", _( "not same size" ) ); - return( -1 ); - } - if( in1->Bands != in2->Bands && - (in1->Bands != 1 && in2->Bands != 1) ) { - im_error( "im_multiply", - "%s", _( "not same number of bands" ) ); - return( -1 ); - } - if( in1->Coding != IM_CODING_NONE || in2->Coding != IM_CODING_NONE ) { - im_error( "im_multiply", "%s", _( "not uncoded" ) ); - return( -1 ); - } if( im_cp_descv( out, in1, in2, NULL ) ) return( -1 ); @@ -210,45 +249,10 @@ im_multiply( IMAGE *in1, IMAGE *in2, IMAGE *out ) */ out->Bands = IM_MAX( in1->Bands, in2->Bands ); - /* Swap arguments to get the largest on the left. - */ - if( in1->Bbits < in2->Bbits ) - SWAP( in1, in2 ); - /* What output type will we write? int, float or complex. */ - if( im_iscomplex( in1 ) || im_iscomplex( in2 ) ) { - /* Make sure we have complex on the left. - */ - if( !im_iscomplex( in1 ) ) - SWAP( in1, in2 ); - - /* What kind of complex? - */ - if( in1->BandFmt == IM_BANDFMT_DPCOMPLEX ) - /* Output will be DPCOMPLEX. - */ - out->BandFmt = IM_BANDFMT_DPCOMPLEX; - else - out->BandFmt = IM_BANDFMT_COMPLEX; - } - else if( im_isfloat( in1 ) || im_isfloat( in2 ) ) { - /* Make sure we have float on the left. - */ - if( !im_isfloat( in1 ) ) - SWAP( in1, in2 ); - - /* What kind of float? - */ - if( in1->BandFmt == IM_BANDFMT_DOUBLE ) - out->BandFmt = IM_BANDFMT_DOUBLE; - else - out->BandFmt = IM_BANDFMT_FLOAT; - } - else - /* Must be int+int = int. - */ - out->BandFmt = iformat[in2->BandFmt][in1->BandFmt]; + out->BandFmt = bandfmt_multiply[im__format_common( in1, in2 )]; + out->Bbits = im_bits_of_fmt( out->BandFmt ); /* And process! */ diff --git a/libvips/arithmetic/im_subtract.c b/libvips/arithmetic/im_subtract.c index 24865141..983c34e8 100644 --- a/libvips/arithmetic/im_subtract.c +++ b/libvips/arithmetic/im_subtract.c @@ -113,7 +113,9 @@ subtract_buffer( PEL **in, PEL *out, int width, IMAGE *im ) case IM_BANDFMT_USHORT: LOOP( unsigned short, signed int ); break; case IM_BANDFMT_INT: LOOP( signed int, signed int ); break; case IM_BANDFMT_UINT: LOOP( unsigned int, signed int ); break; + case IM_BANDFMT_FLOAT: + case IM_BANDFMT_COMPLEX: #ifdef HAVE_LIBOIL oil_subtract_f32( (float *) out, (float *) in[0], (float *) in[1], sz ); @@ -122,9 +124,10 @@ subtract_buffer( PEL **in, PEL *out, int width, IMAGE *im ) #endif /*HAVE_LIBOIL*/ break; - case IM_BANDFMT_DOUBLE: LOOP( double, double ); break; - case IM_BANDFMT_COMPLEX:LOOP( float, float ); break; - case IM_BANDFMT_DPCOMPLEX:LOOP( double, double ); break; + case IM_BANDFMT_DOUBLE: + case IM_BANDFMT_DPCOMPLEX: + LOOP( double, double ); + break; default: assert( 0 );