/* @(#) Find the coordinates and values of the n maxima of an image. * @(#) * @(#) int im_maxpos_vec( * @(#) IMAGE *im, * @(#) int *xpos, * @(#) int *ypos, * @(#) double *maxima, * @(#) int n * @(#) ); * @(#) * @(#) Find the coordinates and values of the n minima of an image. * @(#) * @(#) int im_minpos_vec( * @(#) IMAGE *im, * @(#) int *xpos, * @(#) int *ypos, * @(#) double *minima, * @(#) int n * @(#) ); * @(#) * * Copyright: 2006, The Nottingham Trent University * Copyright: 2006, Tom Vajzovic * * Author: Tom Vajzovic * * Written on: 2006-09-01 */ /* 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 */ /** HEADERS **/ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include #include #include #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC */ /** TYPE DEFINITIONS **/ typedef struct { int *xs; int *ys; double *vals; int *ptrs; int start; } maxpos_list; /** LOCAL FUNCTIONS DECLARATIONS **/ static maxpos_list *maxpos_list_alloc( int n ); static void maxpos_list_free( maxpos_list *list ); static void maxpos_list_init( maxpos_list *list, int n ); static void *maxpos_vec_start( IMAGE *unrequired, void *, void * ); static int maxpos_vec_scan( REGION *reg, void *seq, void *, void * ); static void add_to_maxpos_list( maxpos_list *list, int x, int y, double val ); static int maxpos_vec_stop( void *seq, void *, void * ); static void minpos_list_init( maxpos_list *list, int n ); static void *minpos_vec_start( IMAGE *unrequired, void *, void * ); static int minpos_vec_scan( REGION *reg, void *seq, void *, void * ); static void add_to_minpos_list( maxpos_list *list, int x, int y, double val ); static int minpos_vec_stop( void *seq, void *, void * ); /** EXPORTED FUNCTIONS **/ int im_maxpos_vec( IMAGE *im, int *xpos, int *ypos, double *maxima, int n ){ #define FUNCTION_NAME "im_maxpos_vec" /* number of sequences used is beyond my control at this level, but I note that */ /* efficiency decreases as more sequences are used - speed may still increase */ int result; int *pointers= im_malloc( NULL, n * sizeof( int* ) ); maxpos_list master_list= { xpos, ypos, maxima, pointers, 0 }; if( im_pincheck( im ) ) return -1; if( !pointers ) return -1; if( ! ( im_isint( im ) || im_isfloat( im ) ) ){ im_error( FUNCTION_NAME, "%s", _( "scalar images only" ) ); return -1; } if( 1 != im-> Bands ){ im_error( FUNCTION_NAME, "%s", _( "single band images only" ) ); return -1; } if( IM_CODING_NONE != im-> Coding ){ im_error( FUNCTION_NAME, "%s", _( "uncoded images only" ) ); return -1; } if( ! xpos || ! ypos || ! maxima || n < 1 ){ im_error( FUNCTION_NAME, "%s", _( "invalid argument" ) ); return -1; } maxpos_list_init( &master_list, n ); result= im_iterate( im, maxpos_vec_start, maxpos_vec_scan, maxpos_vec_stop, &n, &master_list ); im_free( pointers ); return result; #undef FUNCTION_NAME } int im_minpos_vec( IMAGE *im, int *xpos, int *ypos, double *minima, int n ){ #define FUNCTION_NAME "im_minpos_vec" /* number of sequences used is beyond my control at this level, but I note that */ /* effeciency decreases as more sequences are used - speed may still increase */ int result; int *pointers= im_malloc( NULL, n * sizeof( int* ) ); maxpos_list master_list= { xpos, ypos, minima, pointers, 0 }; if( im_pincheck( im ) ) return -1; if( !pointers ) return -1; if( ! ( im_isint( im ) || im_isfloat( im ) ) ){ im_error( FUNCTION_NAME, "%s", _( "scalar images only" ) ); return -1; } if( 1 != im-> Bands ){ im_error( FUNCTION_NAME, "%s", _( "single band images only" ) ); return -1; } if( IM_CODING_NONE != im-> Coding ){ im_error( FUNCTION_NAME, "%s", _( "uncoded images only" ) ); return -1; } if( ! xpos || ! ypos || ! minima || n < 1 ){ im_error( FUNCTION_NAME, "%s", _( "invalid argument" ) ); return -1; } minpos_list_init( &master_list, n ); result= im_iterate( im, minpos_vec_start, minpos_vec_scan, minpos_vec_stop, &n, &master_list ); im_free( pointers ); return result; #undef FUNCTION_NAME } /** LOCAL FUNCTION DEFINITIONS **/ static maxpos_list *maxpos_list_alloc( int n ){ maxpos_list *list= im_malloc( NULL, sizeof( maxpos_list ) ); if( ! list ) return NULL; list-> xs= im_malloc( NULL, 3 * n * sizeof( int ) ); list-> vals= im_malloc( NULL, n * sizeof( double ) ); if( ! list-> xs || ! list-> vals ){ im_free( list-> xs ); im_free( list-> vals ); im_free( list ); return NULL; } list-> ys= list-> xs + n; list-> ptrs= list-> ys + n; return list; } static void maxpos_list_free( maxpos_list *list ){ im_free( list-> xs ); im_free( list-> vals ); im_free( list ); } static void maxpos_list_init( maxpos_list *list, int n ){ int i; for( i= 0; i < n; ++i ){ list-> xs[ i ]= 0; list-> ys[ i ]= 0; list-> vals[ i ]= 0; list-> ptrs[ i ]= i + 1; } list-> ptrs[ n - 1 ]= -1; list-> start= 0; } static void *maxpos_vec_start( IMAGE *unrequired, void *a, void *b ){ int *n = (int *) a; maxpos_list *list= maxpos_list_alloc( *n ); if( ! list ) return NULL; maxpos_list_init( list, *n ); return list; } static int maxpos_vec_scan( REGION *reg, void *seq, void *a, void *b ){ maxpos_list *list = (maxpos_list *) seq; #define MAXPOS_VEC_SCAN( type ){ \ \ int y= reg-> valid. top; \ int x; \ int ymax= y + reg-> valid. height; \ int xmax= reg-> valid. left + reg-> valid. width; \ \ type *row= (type*)IM_REGION_ADDR( reg, reg-> valid. left, y ) - reg-> valid. left; \ size_t skip= IM_REGION_LSKIP( reg ) / sizeof( type ); \ \ for( ; y < ymax; ++y, row+= skip ) \ for( x= reg-> valid. left; x < xmax; ++x ) \ if( row[ x ] > list-> vals[ list-> start ] ) \ add_to_maxpos_list( list, x, y, row[ x ] ); \ } switch( reg-> im-> BandFmt ){ case IM_BANDFMT_UCHAR: MAXPOS_VEC_SCAN( guint8 ) break; case IM_BANDFMT_CHAR: MAXPOS_VEC_SCAN( gint8 ) break; case IM_BANDFMT_USHORT: MAXPOS_VEC_SCAN( guint16 ) break; case IM_BANDFMT_SHORT: MAXPOS_VEC_SCAN( gint16 ) break; case IM_BANDFMT_UINT: MAXPOS_VEC_SCAN( guint32 ) break; case IM_BANDFMT_INT: MAXPOS_VEC_SCAN( gint32 ) break; case IM_BANDFMT_FLOAT: MAXPOS_VEC_SCAN( float ) break; case IM_BANDFMT_DOUBLE: MAXPOS_VEC_SCAN( double ) break; } #undef MAXPOS_VEC_SCAN return 0; } static void add_to_maxpos_list( maxpos_list *list, int x, int y, double val ){ int pointer= list-> start; while( -1 != list-> ptrs[ pointer ] && val > list-> vals[ list-> ptrs[ pointer ] ] ) pointer= list-> ptrs[ pointer ]; list-> xs[ list-> start ]= x; list-> ys[ list-> start ]= y; list-> vals[ list-> start ]= val; if( list-> start != pointer ){ /* we are adding mid-chain not at the very bottom */ int second= list-> ptrs[ list-> start ]; list-> ptrs[ list-> start ]= list-> ptrs[ pointer ]; list-> ptrs[ pointer ]= list-> start; list-> start= second; } } static int maxpos_vec_stop( void *seq, void *a, void *b ){ /* reverse list */ maxpos_list *list = (maxpos_list *) seq; maxpos_list *master_list = (maxpos_list *) b; int prev= -1; int pointer= list-> start; while( -1 != list-> ptrs[ pointer ] ){ int next= list-> ptrs[ pointer ]; list-> ptrs[ pointer ]= prev; prev= pointer; pointer= next; } list-> ptrs[ pointer ]= prev; list-> start= pointer; /* add to main list */ for( ; -1 != pointer; pointer= list-> ptrs[ pointer ] ) /* loop over all the ones found in this sequence */ if( list-> vals[ pointer ] > master_list-> vals[ master_list-> start ] ) add_to_maxpos_list( master_list, list-> xs[ pointer ], list-> ys[ pointer ], list-> vals[ pointer ] ); else break; /* since we are now high->low, if this one isn't big enough, none of the rest are */ maxpos_list_free( list ); return 0; } static void minpos_list_init( maxpos_list *list, int n ){ int i; for( i= 0; i < n; ++i ){ list-> xs[ i ]= 0; list-> ys[ i ]= 0; list-> vals[ i ]= DBL_MAX; list-> ptrs[ i ]= i + 1; } list-> ptrs[ n - 1 ]= -1; list-> start= 0; } static void *minpos_vec_start( IMAGE *unrequired, void *a, void *b ){ int *n = (int *) a; maxpos_list *list= maxpos_list_alloc( *n ); if( ! list ) return NULL; minpos_list_init( list, *n ); return list; } static int minpos_vec_scan( REGION *reg, void *seq, void *a, void *b ){ maxpos_list *list = (maxpos_list *) seq; #define MINPOS_VEC_SCAN( type ){ \ \ int y= reg-> valid. top; \ int x; \ int ymax= y + reg-> valid. height; \ int xmax= reg-> valid. left + reg-> valid. width; \ \ type *row= (type*)IM_REGION_ADDR( reg, reg-> valid. left, y ) - reg-> valid. left; \ size_t skip= IM_REGION_LSKIP( reg ) / sizeof( type ); \ \ for( ; y < ymax; ++y, row+= skip ) \ for( x= reg-> valid. left; x < xmax; ++x ) \ if( row[ x ] < list-> vals[ list-> start ] ) \ add_to_minpos_list( list, x, y, row[ x ] ); \ } switch( reg-> im-> BandFmt ){ case IM_BANDFMT_UCHAR: MINPOS_VEC_SCAN( guint8 ) break; case IM_BANDFMT_CHAR: MINPOS_VEC_SCAN( gint8 ) break; case IM_BANDFMT_USHORT: MINPOS_VEC_SCAN( guint16 ) break; case IM_BANDFMT_SHORT: MINPOS_VEC_SCAN( gint16 ) break; case IM_BANDFMT_UINT: MINPOS_VEC_SCAN( guint32 ) break; case IM_BANDFMT_INT: MINPOS_VEC_SCAN( gint32 ) break; case IM_BANDFMT_FLOAT: MINPOS_VEC_SCAN( float ) break; case IM_BANDFMT_DOUBLE: MINPOS_VEC_SCAN( double ) break; } #undef MINPOS_VEC_SCAN return 0; } static void add_to_minpos_list( maxpos_list *list, int x, int y, double val ){ int pointer= list-> start; while( -1 != list-> ptrs[ pointer ] && val < list-> vals[ list-> ptrs[ pointer ] ] ) pointer= list-> ptrs[ pointer ]; list-> xs[ list-> start ]= x; list-> ys[ list-> start ]= y; list-> vals[ list-> start ]= val; if( list-> start != pointer ){ /* we are adding mid-chain not at the very bottom */ int second= list-> ptrs[ list-> start ]; list-> ptrs[ list-> start ]= list-> ptrs[ pointer ]; list-> ptrs[ pointer ]= list-> start; list-> start= second; } } static int minpos_vec_stop( void *seq, void *a, void *b ){ /* reverse list */ maxpos_list *list = (maxpos_list *) seq; maxpos_list *master_list = (maxpos_list *) b; int prev= -1; int pointer= list-> start; while( -1 != list-> ptrs[ pointer ] ){ int next= list-> ptrs[ pointer ]; list-> ptrs[ pointer ]= prev; prev= pointer; pointer= next; } list-> ptrs[ pointer ]= prev; list-> start= pointer; /* add to main list */ for( ; -1 != pointer; pointer= list-> ptrs[ pointer ] ) /* loop over all the ones found in this sequence */ if( list-> vals[ pointer ] < master_list-> vals[ master_list-> start ] ) add_to_minpos_list( master_list, list-> xs[ pointer ], list-> ys[ pointer ], list-> vals[ pointer ] ); else break; /* since we are now high->low, if this one isn't big enough, none of the rest are */ maxpos_list_free( list ); return 0; }