/* @(#) im_histnD: make a one, two or three dimensional histogram of a 1, 2 or * @(#) 3 band image. Divide each axis into a certain number of bins .. ie. * @(#) output is 1 x bins, binx x bins, or bins x bins x bins bands. * @(#) uchar and ushort only. * @(#) * @(#) Usage: * @(#) int im_histnD( image, hist, bins ) * @(#) IMAGE *image, *hist; * @(#) int bins; * @(#) * @(#) Returns 0 on success and -1 on error * * Written on: 8/7/03 * 10/11/04 * - oops, was not checking the bandfmt coming in */ /* 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 #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ /* Accumulate a histogram in one of these. */ typedef struct { IMAGE *in; IMAGE *out; int bins; unsigned int ***data; /* Gather stats here */ } Histogram; /* Build a Histogram. */ static Histogram * build_hist( IMAGE *in, IMAGE *out, int bins ) { /* How many dimensions we we need to allocate? */ int ilimit = in->Bands > 2 ? bins : 1; int jlimit = in->Bands > 1 ? bins : 1; int i, j; Histogram *hist; if( !(hist = IM_NEW( out, Histogram )) ) return( NULL ); hist->in = in; hist->out = out; hist->bins = bins; if( !(hist->data = IM_ARRAY( out, bins, unsigned int ** )) ) return( NULL ); memset( hist->data, 0, bins * sizeof( unsigned int ** ) ); for( i = 0; i < ilimit; i++ ) { if( !(hist->data[i] = IM_ARRAY( out, bins, unsigned int * )) ) return( NULL ); memset( hist->data[i], 0, bins * sizeof( unsigned int * ) ); for( j = 0; j < jlimit; j++ ) { if( !(hist->data[i][j] = IM_ARRAY( out, bins, unsigned int )) ) return( NULL ); memset( hist->data[i][j], 0, bins * sizeof( unsigned int ) ); } } return( hist ); } /* Build a sub-hist, based on the main hist. */ static void * build_subhist( IMAGE *out, Histogram *mhist ) { return( (void *) build_hist( mhist->in, mhist->out, mhist->bins ) ); } /* Join a sub-hist onto the main hist. */ static int merge_subhist( Histogram *shist, Histogram *mhist ) { int i, j, k; /* Sanity! */ if( shist->in != mhist->in || shist->out != mhist->out ) error_exit( "sanity failure in merge_subhist" ); /* Add on sub-data. */ for( i = 0; i < mhist->bins; i++ ) for( j = 0; j < mhist->bins; j++ ) for( k = 0; k < mhist->bins; k++ ) if( mhist->data[i] && mhist->data[i][j] ) { mhist->data[i][j][k] += shist->data[i][j][k]; /* Zap sub-hist to make sure we * can't add it again. */ shist->data[i][j][k] = 0; } return( 0 ); } #define LOOP( TYPE ) { \ TYPE *p = (TYPE *) line;\ \ for( i = 0, x = 0; x < r->width; x++ ) { \ for( z = 0; z < nb; z++, i++ ) \ index[z] = p[i] / scale; \ \ hist->data[index[2]][index[1]][index[0]]++; \ } \ } static int find_hist( REGION *reg, Histogram *hist ) { Rect *r = ®->valid; IMAGE *im = reg->im; int le = r->left; int to = r->top; int bo = IM_RECT_BOTTOM(r); int nb = im->Bands; int max_val = im->BandFmt == IM_BANDFMT_UCHAR ? 256 : 65536; int scale = max_val / hist->bins; int x, y, z, i; int index[3]; /* Fill these with dimensions, backwards. */ index[0] = index[1] = index[2] = 0; /* Accumulate! */ for( y = to; y < bo; y++ ) { char *line = IM_REGION_ADDR( reg, le, y ); switch( im->BandFmt ) { case IM_BANDFMT_UCHAR: LOOP( unsigned char ); break; case IM_BANDFMT_USHORT: LOOP( unsigned char ); break; default: error_exit( "panic #34847563245" ); } } return( 0 ); } int im_histnD( IMAGE *in, IMAGE *out, int bins ) { int max_val; Histogram *mhist; int x, y, z, i; unsigned int *obuffer; /* Check images. PIO from in, WIO to out. */ if( im_pincheck( in ) || im_outcheck( out ) ) return( -1 ); if( in->Coding != IM_CODING_NONE ) { im_error( "im_histnD", _( " uncoded images only" ) ); return( -1 ); } if( in->BandFmt != IM_BANDFMT_UCHAR && in->BandFmt != IM_BANDFMT_USHORT ) { im_error( "im_histnD", _( " unsigned 8 or 16 bit images only" ) ); return( -1 ); } max_val = in->BandFmt == IM_BANDFMT_UCHAR ? 256 : 65536; if( bins < 1 || bins > max_val ) { im_error( "im_histnD", _( " bins out of range [1,%d]" ), max_val ); return( -1 ); } /* Build main hist we accumulate to. */ if( !(mhist = build_hist( in, out, bins )) ) return( -1 ); /* Accumulate data. */ if( im_iterate( in, build_subhist, find_hist, merge_subhist, mhist, NULL ) ) return( -1 ); /* Make the output image. */ if( im_cp_desc( out, in ) ) return( -1 ); im_initdesc( out, bins, in->Bands > 1 ? bins : 1, in->Bands > 2 ? bins : 1, IM_BBITS_INT, IM_BANDFMT_UINT, IM_CODING_NONE, IM_TYPE_HISTOGRAM, 1.0, 1.0, 0, 0 ); if( im_setupout( out ) ) return( -1 ); /* Interleave to output buffer. */ if( !(obuffer = IM_ARRAY( out, IM_IMAGE_N_ELEMENTS( out ), unsigned int )) ) return( -1 ); for( y = 0; y < out->Ysize; y++ ) { for( i = 0, x = 0; x < out->Xsize; x++ ) for( z = 0; z < out->Bands; z++, i++ ) obuffer[i] = mhist->data[z][y][x]; if( im_writeline( y, out, (PEL *) obuffer ) ) return( -1 ); } return( 0 ); }