| /* im_avg.c |
| * |
| * Copyright: 1990, J. Cupitt |
| * |
| * Author: J. Cupitt |
| * Written on: 02/08/1990 |
| * Modified on: |
| * 5/5/93 JC |
| * - now does partial images |
| * - less likely to overflow |
| * 1/7/93 JC |
| * - adapted for partial v2 |
| * - ANSI C |
| * 21/2/95 JC |
| * - modernised again |
| * 11/5/95 JC |
| * - oops! return( NULL ) in im_avg(), instead of return( -1 ) |
| * 20/6/95 JC |
| * - now returns double |
| * 13/1/05 |
| * - use 64 bit arithmetic |
| * 8/12/06 |
| * - add liboil support |
| * 18/8/09 |
| * - gtkdoc, minor reformatting |
| * 7/9/09 |
| * - rewrite for im__wrapiter() |
| * - add complex case (needed for im_max()) |
| * 8/9/09 |
| * - wrapscan stuff moved here |
| */ |
| |
| /* |
| |
| This file is part of VIPS. |
| |
| VIPS is free software; you can redistribute it and/or modify |
| it under the terms of the GNU Lesser General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
| */ |
| |
| /* |
| |
| These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk |
| |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif /*HAVE_CONFIG_H*/ |
| #include <vips/intl.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <math.h> |
| |
| #include <vips/vips.h> |
| #include <vips/internal.h> |
| |
| #ifdef HAVE_LIBOIL |
| #include <liboil/liboil.h> |
| #endif /*HAVE_LIBOIL*/ |
| |
| #ifdef WITH_DMALLOC |
| #include <dmalloc.h> |
| #endif /*WITH_DMALLOC*/ |
| |
| typedef struct _Wrapscan { |
| IMAGE *in; |
| im_start_fn start; |
| im__wrapscan_fn scan; |
| im_stop_fn stop; |
| void *a; |
| void *b; |
| } Wrapscan; |
| |
| static void * |
| wrapscan_start( VipsImage *in, void *a, void *b ) |
| { |
| Wrapscan *wrapscan = (Wrapscan *) a; |
| |
| return( wrapscan->start( in, wrapscan->a, wrapscan->b ) ); |
| } |
| |
| static int |
| wrapscan_stop( void *seq, void *a, void *b ) |
| { |
| Wrapscan *wrapscan = (Wrapscan *) a; |
| |
| return( wrapscan->stop( seq, wrapscan->a, wrapscan->b ) ); |
| } |
| |
| static int |
| wrapscan_scan( REGION *reg, void *seq, void *a, void *b ) |
| { |
| Wrapscan *wrapscan = (Wrapscan *) a; |
| Rect *r = ®->valid; |
| int lsk = IM_REGION_LSKIP( reg ); |
| |
| int y; |
| PEL *p; |
| |
| p = (PEL *) IM_REGION_ADDR( reg, r->left, r->top ); |
| for( y = 0; y < r->height; y++ ) { |
| if( wrapscan->scan( p, r->width, seq, |
| wrapscan->a, wrapscan->b ) ) |
| return( -1 ); |
| p += lsk; |
| } |
| |
| return( 0 ); |
| } |
| |
| /* Like vips_sink(), but the scan function works a line at a time, like |
| * im_wrap*(). Shared with im_min(), im_deviate() etc. |
| */ |
| int |
| im__wrapscan( VipsImage *in, |
| VipsStart start, im__wrapscan_fn scan, VipsStop stop, |
| void *a, void *b ) |
| { |
| Wrapscan wrapscan; |
| |
| wrapscan.in = in; |
| wrapscan.start = start; |
| wrapscan.scan = scan; |
| wrapscan.stop = stop; |
| wrapscan.a = a; |
| wrapscan.b = b; |
| |
| return( vips_sink( in, |
| wrapscan_start, wrapscan_scan, wrapscan_stop, |
| &wrapscan, NULL ) ); |
| } |
| |
| /* Start function: allocate space for a double in which we can accumulate the |
| * sum. |
| */ |
| static void * |
| avg_start( IMAGE *out, void *a, void *b ) |
| { |
| double *sum; |
| |
| if( !(sum = IM_NEW( NULL, double )) ) |
| return( NULL ); |
| *sum = 0.0; |
| |
| return( (void *) sum ); |
| } |
| |
| /* Stop function. Add this little sum to the main sum. |
| */ |
| static int |
| avg_stop( void *seq, void *a, void *b ) |
| { |
| double *sum = (double *) seq; |
| double *global_sum = (double *) b; |
| |
| *global_sum += *sum; |
| |
| im_free( seq ); |
| |
| return( 0 ); |
| } |
| |
| /* Sum pels in this section. |
| */ |
| #define LOOP( TYPE ) { \ |
| TYPE *p = (TYPE *) in; \ |
| \ |
| for( x = 0; x < sz; x++ ) \ |
| m += p[x]; \ |
| } |
| |
| #define CLOOP( TYPE ) { \ |
| TYPE *p = (TYPE *) in; \ |
| \ |
| for( x = 0; x < sz; x++ ) { \ |
| double mod, re, im; \ |
| \ |
| re = p[0]; \ |
| im = p[1]; \ |
| p += 2; \ |
| mod = re * re + im * im; \ |
| \ |
| m += mod; \ |
| } \ |
| } |
| |
| /* Loop over region, accumulating a sum in *tmp. |
| */ |
| static int |
| avg_scan( void *in, int n, void *seq, void *a, void *b ) |
| { |
| const IMAGE *im = (IMAGE *) a; |
| const int sz = n * im->Bands; |
| |
| double *sum = (double *) seq; |
| |
| int x; |
| double m; |
| |
| m = *sum; |
| |
| /* 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_DOUBLE: |
| #ifdef HAVE_LIBOIL |
| { |
| double *p = (double *) in; |
| double t; |
| |
| oil_sum_f64( &t, p, sizeof( double ), sz ); |
| |
| m += t; |
| } |
| #else /*!HAVE_LIBOIL*/ |
| LOOP( double ); |
| #endif /*HAVE_LIBOIL*/ |
| break; |
| |
| case IM_BANDFMT_COMPLEX: CLOOP( float ); break; |
| case IM_BANDFMT_DPCOMPLEX: CLOOP( double ); break; |
| |
| default: |
| g_assert( 0 ); |
| } |
| |
| *sum = m; |
| |
| return( 0 ); |
| } |
| |
| /** |
| * 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. For complex images, return the average modulus. |
| * |
| * 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 global_sum; |
| gint64 vals, pels; |
| |
| /* Check our args. |
| */ |
| if( im_pincheck( in ) || |
| im_check_noncomplex( "im_avg", in ) || |
| im_check_uncoded( "im_avg", in ) ) |
| return( -1 ); |
| |
| /* Loop over input, summing pixels. |
| */ |
| global_sum = 0.0; |
| if( im__wrapscan( in, |
| avg_start, avg_scan, avg_stop, in, &global_sum ) ) |
| return( -1 ); |
| |
| /* Calculate and return average. For complex, we accumulate re*re + |
| * im*im, so we need to sqrt. |
| */ |
| pels = (gint64) in->Xsize * in->Ysize; |
| vals = pels * in->Bands; |
| *out = global_sum / vals; |
| if( vips_bandfmt_iscomplex( in->BandFmt ) ) |
| *out = sqrt( *out ); |
| |
| return( 0 ); |
| } |
| |
| /* Get the value of pixel (0, 0). Use this to init the min/max value for |
| * im_max()/im_stats()/etc. |
| */ |
| int |
| im__value( IMAGE *im, double *value ) |
| { |
| IMAGE *t; |
| |
| if( !(t = im_open_local( im, "im__value", "p" )) || |
| im_extract_areabands( im, t, 0, 0, 1, 1, 0, 1 ) || |
| im_avg( t, value ) ) |
| return( -1 ); |
| |
| return( 0 ); |
| } |