Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

histogram.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- 00002 @COPYRIGHT : 00003 Copyright 1993,1994,1995 David MacDonald, 00004 McConnell Brain Imaging Centre, 00005 Montreal Neurological Institute, McGill University. 00006 Permission to use, copy, modify, and distribute this 00007 software and its documentation for any purpose and without 00008 fee is hereby granted, provided that the above copyright 00009 notice appear in all copies. The author and McGill University 00010 make no representations about the suitability of this 00011 software for any purpose. It is provided "as is" without 00012 express or implied warranty. 00013 ---------------------------------------------------------------------------- */ 00014 00015 #include <volume_io/internal_volume_io.h> 00016 #include <bicpl/numerical.h> 00017 00018 #ifndef lint 00019 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Numerical/histogram.c,v 1.11 2000/02/06 15:30:39 stever Exp $"; 00020 #endif 00021 00022 /* ----------------------------- MNI Header ----------------------------------- 00023 @NAME : initialize_histogram 00024 @INPUT : delta 00025 offset 00026 @OUTPUT : histogram 00027 @RETURNS : 00028 @DESCRIPTION: Initializes a histogram of boxes whose boundaries are integer 00029 multiples of delta from offset. 00030 @METHOD : 00031 @GLOBALS : 00032 @CALLS : 00033 @CREATED : 1993 David MacDonald 00034 @MODIFIED : 00035 ---------------------------------------------------------------------------- */ 00036 00037 public void initialize_histogram( 00038 histogram_struct *histogram, 00039 Real delta, 00040 Real offset ) 00041 { 00042 histogram->delta = delta; 00043 histogram->offset = offset; 00044 00045 histogram->min_index = 0; 00046 histogram->max_index = -1; 00047 } 00048 00049 /* ----------------------------- MNI Header ----------------------------------- 00050 @NAME : delete_histogram 00051 @INPUT : histogram 00052 @OUTPUT : 00053 @RETURNS : 00054 @DESCRIPTION: Deletes the histogram. 00055 @METHOD : 00056 @GLOBALS : 00057 @CALLS : 00058 @CREATED : 1993 David MacDonald 00059 @MODIFIED : 00060 ---------------------------------------------------------------------------- */ 00061 00062 public void delete_histogram( 00063 histogram_struct *histogram ) 00064 { 00065 if( histogram->max_index >= histogram->min_index ) 00066 { 00067 FREE( histogram->counts ); 00068 } 00069 } 00070 00071 /* ----------------------------- MNI Header ----------------------------------- 00072 @NAME : get_histogram_index 00073 @INPUT : histogram 00074 value 00075 @OUTPUT : 00076 @RETURNS : box index 00077 @DESCRIPTION: Converts a real value to a histogram box index, which can be 00078 positive, zero, or negative. 00079 @METHOD : 00080 @GLOBALS : 00081 @CALLS : 00082 @CREATED : 1993 David MacDonald 00083 @MODIFIED : 00084 ---------------------------------------------------------------------------- */ 00085 00086 private int get_histogram_index( 00087 histogram_struct *histogram, 00088 Real value ) 00089 { 00090 int ind; 00091 00092 ind = FLOOR( (value - histogram->offset) / histogram->delta ); 00093 00094 return( ind ); 00095 } 00096 00097 /* ----------------------------- MNI Header ----------------------------------- 00098 @NAME : convert_real_index_to_value 00099 @INPUT : histogram 00100 ind 00101 @OUTPUT : 00102 @RETURNS : value 00103 @DESCRIPTION: Converts a histogram box index to a real value. 00104 @METHOD : 00105 @GLOBALS : 00106 @CALLS : 00107 @CREATED : 1993 David MacDonald 00108 @MODIFIED : 00109 ---------------------------------------------------------------------------- */ 00110 00111 private Real convert_real_index_to_value( 00112 histogram_struct *histogram, 00113 Real ind ) 00114 { 00115 return( ind * histogram->delta + histogram->offset ); 00116 } 00117 00118 /* ----------------------------- MNI Header ----------------------------------- 00119 @NAME : convert_index_to_value 00120 @INPUT : histogram 00121 ind 00122 @OUTPUT : 00123 @RETURNS : value 00124 @DESCRIPTION: Converts a histogram box index to a real value, which is the 00125 left edge of the ind'th box. 00126 @METHOD : 00127 @GLOBALS : 00128 @CALLS : 00129 @CREATED : 1993 David MacDonald 00130 @MODIFIED : 00131 ---------------------------------------------------------------------------- */ 00132 00133 private Real convert_index_to_value( 00134 histogram_struct *histogram, 00135 int ind ) 00136 { 00137 return( convert_real_index_to_value( histogram, (Real) ind ) ); 00138 } 00139 00140 /* ----------------------------- MNI Header ----------------------------------- 00141 @NAME : add_to_histogram 00142 @INPUT : histogram 00143 value 00144 @OUTPUT : 00145 @RETURNS : 00146 @DESCRIPTION: Adds a value to the histogram, by finding the box it belongs in, 00147 expanding the list of histogram boxes, if needed, and incrementing 00148 the box count for that box. 00149 @METHOD : 00150 @GLOBALS : 00151 @CALLS : 00152 @CREATED : 1993 David MacDonald 00153 @MODIFIED : 00154 ---------------------------------------------------------------------------- */ 00155 00156 public void add_to_histogram( 00157 histogram_struct *histogram, 00158 Real value ) 00159 { 00160 int ind, i, prev_size, new_size; 00161 00162 ind = get_histogram_index( histogram, value ); 00163 00164 if( histogram->min_index > histogram->max_index ) /* first box */ 00165 { 00166 ALLOC( histogram->counts, 1 ); 00167 histogram->counts[0] = 0; 00168 histogram->min_index = ind; 00169 histogram->max_index = ind; 00170 } 00171 else if( ind < histogram->min_index ) /* need to expand below */ 00172 { 00173 prev_size = histogram->max_index - histogram->min_index + 1; 00174 new_size = histogram->max_index - ind + 1; 00175 SET_ARRAY_SIZE( histogram->counts, prev_size, new_size, 1 ); 00176 00177 for_down( i, histogram->max_index, histogram->min_index ) 00178 { 00179 histogram->counts[i-ind] = 00180 histogram->counts[i-histogram->min_index]; 00181 } 00182 00183 for_less( i, ind, histogram->min_index ) 00184 histogram->counts[i-ind] = 0; 00185 00186 histogram->min_index = ind; 00187 } 00188 else if( ind > histogram->max_index ) /* need to expand above */ 00189 { 00190 prev_size = histogram->max_index - histogram->min_index + 1; 00191 new_size = ind - histogram->min_index + 1; 00192 SET_ARRAY_SIZE( histogram->counts, prev_size, new_size, 1 ); 00193 00194 for_inclusive( i, histogram->max_index + 1, ind ) 00195 histogram->counts[i-histogram->min_index] = 0; 00196 00197 histogram->max_index = ind; 00198 } 00199 00200 ++histogram->counts[ind-histogram->min_index]; 00201 } 00202 00203 /* ----------------------------- MNI Header ----------------------------------- 00204 @NAME : get_histogram_range 00205 @INPUT : histogram 00206 @OUTPUT : min_value 00207 max_value 00208 @RETURNS : 00209 @DESCRIPTION: Passes back the range of the histogram, which is the left 00210 edge of the first box, and the right edge of the last box. 00211 @METHOD : 00212 @GLOBALS : 00213 @CALLS : 00214 @CREATED : 1993 David MacDonald 00215 @MODIFIED : 00216 ---------------------------------------------------------------------------- */ 00217 00218 private void get_histogram_range( 00219 histogram_struct *histogram, 00220 Real *min_value, 00221 Real *max_value ) 00222 { 00223 *min_value = convert_index_to_value( histogram, histogram->min_index ); 00224 *max_value = convert_index_to_value( histogram, histogram->max_index + 1 ); 00225 } 00226 00227 /* ----------------------------- MNI Header ----------------------------------- 00228 @NAME : get_histogram_max_count 00229 @INPUT : histogram 00230 @OUTPUT : 00231 @RETURNS : maximum count 00232 @DESCRIPTION: Finds the maximum number of counts in the histogram boxes. 00233 @METHOD : 00234 @GLOBALS : 00235 @CALLS : 00236 @CREATED : 1993 David MacDonald 00237 @MODIFIED : 00238 ---------------------------------------------------------------------------- */ 00239 00240 private int get_histogram_max_count( 00241 histogram_struct *histogram ) 00242 { 00243 int ind, max_count; 00244 00245 max_count = 0; 00246 for_inclusive( ind, histogram->min_index, histogram->max_index ) 00247 { 00248 if( ind == 0 || 00249 histogram->counts[ind-histogram->min_index] > max_count ) 00250 max_count = histogram->counts[ind-histogram->min_index]; 00251 } 00252 00253 return( max_count ); 00254 } 00255 00256 /* ----------------------------- MNI Header ----------------------------------- 00257 @NAME : box_filter_histogram 00258 @INPUT : n 00259 counts 00260 half_width 00261 @OUTPUT : new_counts 00262 @RETURNS : 00263 @DESCRIPTION: Box filters the histogram boxes into another set of boxes 00264 which corresponds to the average number of counts in the 00265 range i - half_width to i + half_width. 00266 @METHOD : 00267 @GLOBALS : 00268 @CALLS : 00269 @CREATED : 1993 David MacDonald 00270 @MODIFIED : 00271 ---------------------------------------------------------------------------- */ 00272 00273 private void box_filter_histogram( 00274 int n, 00275 Real counts[], 00276 Real new_counts[], 00277 int half_width ) 00278 { 00279 int i, window_width, start_index, end_index; 00280 Real current_value; 00281 00282 start_index = - half_width; 00283 end_index = half_width; 00284 00285 current_value = 0.0; 00286 for_inclusive( i, 0, MIN( end_index, n-1 ) ) 00287 current_value += counts[i]; 00288 00289 for_less( i, 0, n ) 00290 { 00291 window_width = MIN( end_index, n-1 ) - MAX( start_index, 0 ) + 1; 00292 new_counts[i] = (Real) current_value / (Real) window_width; 00293 if( start_index >= 0 ) 00294 current_value -= counts[start_index]; 00295 ++start_index; 00296 ++end_index; 00297 if( end_index < n ) 00298 current_value += counts[end_index]; 00299 } 00300 } 00301 00302 /* ----------------------------- MNI Header ----------------------------------- 00303 @NAME : get_histogram_counts 00304 @INPUT : histogram 00305 filter_width 00306 @OUTPUT : counts 00307 scale_factor 00308 trans_factor 00309 @RETURNS : n 00310 @DESCRIPTION: Gets the histogram counts, after filtering as necessary. 00311 and a scale and trans factor for converting counts indices 00312 to real values. 00313 @METHOD : 00314 @GLOBALS : 00315 @CALLS : 00316 @CREATED : 1993 David MacDonald 00317 @MODIFIED : 00318 ---------------------------------------------------------------------------- */ 00319 00320 public int get_histogram_counts( 00321 histogram_struct *histogram, 00322 Real *counts[], 00323 Real filter_width, 00324 Real *scale_factor, 00325 Real *trans_factor ) 00326 { 00327 int i, n, width; 00328 Real *tmp_counts; 00329 00330 n = histogram->max_index - histogram->min_index + 1; 00331 00332 if( n <= 0 ) 00333 return( 0 ); 00334 00335 ALLOC( tmp_counts, n ); 00336 ALLOC( *counts, n ); 00337 00338 for_less( i, 0, n ) 00339 tmp_counts[i] = (Real) histogram->counts[i]; 00340 00341 width = ROUND( filter_width / histogram->delta / 2.0 ); 00342 00343 box_filter_histogram( n, tmp_counts, *counts, width ); 00344 00345 FREE( tmp_counts ); 00346 00347 *scale_factor = histogram->delta; 00348 *trans_factor = convert_real_index_to_value( histogram, 00349 (Real) histogram->min_index + 0.5 ); 00350 00351 return( n ); 00352 } 00353 00354 /* ----------------------------- MNI Header ----------------------------------- 00355 @NAME : resample_histogram 00356 @INPUT : histogram 00357 x_size 00358 y_size 00359 @OUTPUT : x_scale 00360 y_scale 00361 height 00362 @RETURNS : 00363 @DESCRIPTION: Resamples the histogram to fit in a grid of x_size boxes by 00364 max y_size counts. 00365 @METHOD : 00366 @GLOBALS : 00367 @CALLS : 00368 @CREATED : 1993 David MacDonald 00369 @MODIFIED : 00370 ---------------------------------------------------------------------------- */ 00371 00372 private void resample_histogram( 00373 histogram_struct *histogram, 00374 int x_size, 00375 int y_size, 00376 Real *x_scale, 00377 Real *x_trans, 00378 Real height[] ) 00379 { 00380 int ind, x, max_count, left_ind, right_ind; 00381 Real weight, sum_count, min_value, max_value; 00382 Real left_side, right_side, left, right; 00383 00384 get_histogram_range( histogram, &min_value, &max_value ); 00385 00386 if( max_value <= min_value ) 00387 { 00388 for_less( x, 0, x_size ) 00389 height[x] = 0.0; 00390 *x_scale = 1.0; 00391 *x_trans = 0.0; 00392 return; 00393 } 00394 00395 max_count = get_histogram_max_count( histogram ); 00396 00397 *x_scale = 1.0 / (Real) x_size * (max_value - min_value); 00398 *x_trans = min_value + 0.5 * (*x_scale); 00399 00400 for_less( x, 0, x_size ) 00401 { 00402 left = min_value + (Real) x / (Real) x_size * (max_value - min_value); 00403 right = min_value + (Real) (x+1) / (Real) x_size * 00404 (max_value - min_value); 00405 00406 left_ind = get_histogram_index( histogram, left ); 00407 right_ind = get_histogram_index( histogram, right ); 00408 00409 sum_count = 0.0; 00410 00411 for_inclusive( ind, left_ind, right_ind ) 00412 { 00413 left_side = convert_index_to_value( histogram, ind ); 00414 right_side = convert_index_to_value( histogram, ind+1 ); 00415 00416 weight = MIN( right_side, right ) - MAX( left_side, left ); 00417 00418 sum_count += weight * 00419 (Real) histogram->counts[ind-histogram->min_index]; 00420 } 00421 00422 height[x] = sum_count / (right - left) * (Real) y_size / 00423 (Real) max_count; 00424 } 00425 } 00426 00427 /* ----------------------------- MNI Header ----------------------------------- 00428 @NAME : display_histogram 00429 @INPUT : histogram 00430 x_size 00431 y_size 00432 @OUTPUT : 00433 @RETURNS : 00434 @DESCRIPTION: Displays the histogram as an ascii plot. 00435 @METHOD : 00436 @GLOBALS : 00437 @CALLS : 00438 @CREATED : 1993 David MacDonald 00439 @MODIFIED : 00440 ---------------------------------------------------------------------------- */ 00441 00442 public void display_histogram( 00443 histogram_struct *histogram, 00444 int x_size, 00445 int y_size ) 00446 { 00447 int x, y, max_count; 00448 Real min_value, max_value, *n_chars, x_scale, x_trans; 00449 00450 ALLOC( n_chars, x_size ); 00451 00452 resample_histogram( histogram, x_size, y_size, &x_scale, &x_trans, 00453 n_chars ); 00454 00455 for( y = y_size-1; y >= 0; --y ) 00456 { 00457 for_less( x, 0, x_size ) 00458 { 00459 if( y < ROUND(n_chars[x]) ) 00460 print( "#" ); 00461 else 00462 print( " " ); 00463 } 00464 00465 print( "\n" ); 00466 } 00467 00468 get_histogram_range( histogram, &min_value, &max_value ); 00469 max_count = get_histogram_max_count( histogram ); 00470 00471 print( "%g to %g with max count = %d\n", min_value, max_value, max_count ); 00472 00473 FREE( n_chars ); 00474 } 00475 00476 /* ----------------------------- MNI Header ----------------------------------- 00477 @NAME : create_histogram_line 00478 @INPUT : histogram 00479 x_size 00480 y_size 00481 filter_width 00482 @OUTPUT : lines 00483 @RETURNS : 00484 @DESCRIPTION: Creates a lines structure corresponding to the histogram. 00485 @METHOD : 00486 @GLOBALS : 00487 @CALLS : 00488 @CREATED : 1993 David MacDonald 00489 @MODIFIED : 00490 ---------------------------------------------------------------------------- */ 00491 00492 public void create_histogram_line( 00493 histogram_struct *histogram, 00494 int x_size, 00495 int y_size, 00496 Real filter_width, 00497 lines_struct *lines ) 00498 { 00499 int x, width; 00500 Real *height, *smooth_height, x_scale, x_trans; 00501 Point p; 00502 00503 ALLOC( height, x_size ); 00504 00505 resample_histogram( histogram, x_size, y_size, &x_scale, &x_trans, height ); 00506 00507 width = ROUND( filter_width / x_scale / 2.0 ); 00508 00509 ALLOC( smooth_height, x_size ); 00510 00511 box_filter_histogram( x_size, height, smooth_height, width ); 00512 00513 initialize_lines( lines, WHITE ); 00514 00515 for_less( x, 0, x_size ) 00516 { 00517 fill_Point( p, (Real) x * x_scale + x_trans, smooth_height[x], 0.0 ); 00518 add_point_to_line( lines, &p ); 00519 } 00520 00521 FREE( height ); 00522 FREE( smooth_height ); 00523 }

Generated on Wed Jul 28 09:10:57 2004 for BICPL by doxygen 1.3.7