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

pixels.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/objects.h> 00017 #include <bicpl/geom.h> 00018 #include <bicpl/trans.h> 00019 00020 #ifndef lint 00021 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Objects/pixels.c,v 1.26 2000/02/06 15:30:45 stever Exp $"; 00022 #endif 00023 00024 /* ----------------------------- MNI Header ----------------------------------- 00025 @NAME : initialize_pixels 00026 @INPUT : x_position 00027 y_position 00028 x_size 00029 y_size 00030 x_zoom 00031 y_zoom 00032 pixel_type 00033 @OUTPUT : pixels 00034 @RETURNS : 00035 @DESCRIPTION: Initializes the pixels struct and allocates memory as needed. 00036 @METHOD : 00037 @GLOBALS : 00038 @CALLS : 00039 @CREATED : 1993 David MacDonald 00040 @MODIFIED : 00041 ---------------------------------------------------------------------------- */ 00042 00043 public void initialize_pixels( 00044 pixels_struct *pixels, 00045 int x_position, 00046 int y_position, 00047 int x_size, 00048 int y_size, 00049 Real x_zoom, 00050 Real y_zoom, 00051 Pixel_types pixel_type ) 00052 { 00053 int n_alloced; 00054 00055 n_alloced = 0; 00056 00057 pixels->pixel_type = pixel_type; 00058 pixels->x_size = -1; 00059 pixels->y_size = -1; 00060 pixels->x_position = x_position; 00061 pixels->y_position = y_position; 00062 pixels->x_zoom = x_zoom; 00063 pixels->y_zoom = y_zoom; 00064 00065 modify_pixels_size( &n_alloced, pixels, x_size, y_size, pixel_type ); 00066 } 00067 00068 /* ----------------------------- MNI Header ----------------------------------- 00069 @NAME : delete_pixels 00070 @INPUT : pixels 00071 @OUTPUT : 00072 @RETURNS : 00073 @DESCRIPTION: Deletes the pixels. 00074 @METHOD : 00075 @GLOBALS : 00076 @CALLS : 00077 @CREATED : 1993 David MacDonald 00078 @MODIFIED : 00079 ---------------------------------------------------------------------------- */ 00080 00081 public void delete_pixels( pixels_struct *pixels ) 00082 { 00083 if( pixels->x_size > 0 && pixels->y_size > 0 ) 00084 { 00085 switch( pixels->pixel_type ) 00086 { 00087 case COLOUR_INDEX_8BIT_PIXEL: 00088 FREE( pixels->data.pixels_8bit_colour_index ); 00089 break; 00090 00091 case COLOUR_INDEX_16BIT_PIXEL: 00092 FREE( pixels->data.pixels_16bit_colour_index ); 00093 break; 00094 00095 case RGB_PIXEL: 00096 FREE( pixels->data.pixels_rgb ); 00097 break; 00098 } 00099 } 00100 00101 pixels->x_size = 0; 00102 pixels->y_size = 0; 00103 } 00104 00105 /* ----------------------------- MNI Header ----------------------------------- 00106 @NAME : modify_pixels_size 00107 @INPUT : n_pixels_alloced 00108 pixels 00109 x_size 00110 y_size 00111 pixel_type 00112 @OUTPUT : 00113 @RETURNS : 00114 @DESCRIPTION: Changes the size of the pixels struct, reallocating as necessary. 00115 @METHOD : 00116 @GLOBALS : 00117 @CALLS : 00118 @CREATED : 1993 David MacDonald 00119 @MODIFIED : 00120 ---------------------------------------------------------------------------- */ 00121 00122 public void modify_pixels_size( 00123 int *n_pixels_alloced, 00124 pixels_struct *pixels, 00125 int x_size, 00126 int y_size, 00127 Pixel_types pixel_type ) 00128 { 00129 int new_n_pixels; 00130 Colour *tmp_int_ptr; 00131 00132 if( pixel_type != pixels->pixel_type ) 00133 { 00134 if( *n_pixels_alloced > 0 ) 00135 delete_pixels( pixels ); 00136 *n_pixels_alloced = 0; 00137 pixels->pixel_type = pixel_type; 00138 } 00139 00140 if( x_size > 0 && y_size > 0 ) 00141 new_n_pixels = x_size * y_size; 00142 else 00143 new_n_pixels = 0; 00144 00145 pixels->x_size = x_size; 00146 pixels->y_size = y_size; 00147 00148 /*--- if the new size is equal to or smaller than the current size */ 00149 00150 if( new_n_pixels > 0 && new_n_pixels <= *n_pixels_alloced ) 00151 return; 00152 00153 switch( pixel_type ) 00154 { 00155 case COLOUR_INDEX_8BIT_PIXEL: /* make sure it's word aligned */ 00156 tmp_int_ptr = (Colour *) (void *) 00157 pixels->data.pixels_8bit_colour_index; 00158 00159 SET_ARRAY_SIZE( tmp_int_ptr, (*n_pixels_alloced + 3) / 4, 00160 (new_n_pixels + 3) / 4, DEFAULT_CHUNK_SIZE ); 00161 pixels->data.pixels_8bit_colour_index = (unsigned char *) 00162 ((void *) tmp_int_ptr ); 00163 break; 00164 00165 case COLOUR_INDEX_16BIT_PIXEL: /* make sure it's word aligned */ 00166 tmp_int_ptr = (Colour *) (void *) 00167 pixels->data.pixels_16bit_colour_index; 00168 SET_ARRAY_SIZE( tmp_int_ptr, (*n_pixels_alloced + 1) / 2, 00169 (new_n_pixels + 1) / 2, DEFAULT_CHUNK_SIZE ); 00170 pixels->data.pixels_16bit_colour_index = (unsigned short *) 00171 ((void *) tmp_int_ptr ); 00172 break; 00173 00174 case RGB_PIXEL: 00175 SET_ARRAY_SIZE( pixels->data.pixels_rgb, *n_pixels_alloced, 00176 new_n_pixels, DEFAULT_CHUNK_SIZE ); 00177 break; 00178 } 00179 00180 *n_pixels_alloced = new_n_pixels; 00181 } 00182 00183 /* ----------------------------- MNI Header ----------------------------------- 00184 @NAME : convert_pixels24_to_pixels8 00185 @INPUT : pixels_rgb 00186 @OUTPUT : pixels_8 00187 @RETURNS : 00188 @DESCRIPTION: Converts the 24 bit pixels to an 8 bit (3-3-2 bit) lookup. 00189 @METHOD : 00190 @GLOBALS : 00191 @CALLS : 00192 @CREATED : 1993 David MacDonald 00193 @MODIFIED : 00194 ---------------------------------------------------------------------------- */ 00195 00196 public void convert_pixels24_to_pixels8( 00197 pixels_struct *pixels_rgb, 00198 pixels_struct *pixels_8 ) 00199 { 00200 int x, y; 00201 00202 initialize_pixels( pixels_8, pixels_rgb->x_position, pixels_rgb->y_position, 00203 pixels_rgb->x_size, pixels_rgb->y_size, 00204 pixels_rgb->x_zoom, pixels_rgb->y_zoom, 00205 COLOUR_INDEX_8BIT_PIXEL ); 00206 00207 for_less( x, 0, pixels_rgb->x_size ) 00208 { 00209 for_less( y, 0, pixels_rgb->y_size ) 00210 { 00211 PIXEL_COLOUR_INDEX_8(*pixels_8,x,y) = 00212 (unsigned char) convert_rgb_pixel_to_8bit_lookup( 00213 PIXEL_RGB_COLOUR(*pixels_rgb,x,y) ); 00214 } 00215 } 00216 } 00217 00218 /* ----------------------------- MNI Header ----------------------------------- 00219 @NAME : convert_pixels24_to_index8 00220 @INPUT : pixels_rgb 00221 n_colours 00222 colour_table 00223 @OUTPUT : pixels_8 00224 @RETURNS : 00225 @DESCRIPTION: Converts the rgb pixels to the 8-bit colour index pixels, 00226 given a colour table. 00227 @METHOD : 00228 @GLOBALS : 00229 @CALLS : 00230 @CREATED : 1993 David MacDonald 00231 @MODIFIED : 00232 ---------------------------------------------------------------------------- */ 00233 00234 public void convert_pixels24_to_index8( 00235 pixels_struct *pixels_rgb, 00236 pixels_struct *pixels_8, 00237 int n_colours, 00238 Colour colour_table[] ) 00239 { 00240 Colour col; 00241 int x, y; 00242 00243 initialize_pixels( pixels_8, pixels_rgb->x_position, pixels_rgb->y_position, 00244 pixels_rgb->x_size, pixels_rgb->y_size, 00245 pixels_rgb->x_zoom, pixels_rgb->y_zoom, 00246 COLOUR_INDEX_8BIT_PIXEL ); 00247 00248 for_less( x, 0, pixels_rgb->x_size ) 00249 { 00250 for_less( y, 0, pixels_rgb->y_size ) 00251 { 00252 col = PIXEL_RGB_COLOUR(*pixels_rgb,x,y); 00253 00254 PIXEL_COLOUR_INDEX_8(*pixels_8,x,y) = 00255 (unsigned char) find_closest_colour( get_Colour_r(col), 00256 get_Colour_g(col), 00257 get_Colour_b(col), 00258 n_colours, colour_table ); 00259 } 00260 } 00261 } 00262 00263 /* ----------------------------- MNI Header ----------------------------------- 00264 @NAME : convert_index8_to_pixels24 00265 @INPUT : pixels_8 00266 colour_table 00267 @OUTPUT : pixels_rgb 00268 @RETURNS : 00269 @DESCRIPTION: Creates an rgb pixel map from 8 bit indices and a colour table. 00270 @METHOD : 00271 @GLOBALS : 00272 @CALLS : 00273 @CREATED : 1993 David MacDonald 00274 @MODIFIED : 00275 ---------------------------------------------------------------------------- */ 00276 00277 public void convert_index8_to_pixels24( 00278 pixels_struct *pixels_8, 00279 Colour colour_table[], 00280 pixels_struct *pixels_rgb ) 00281 { 00282 int x, y; 00283 00284 initialize_pixels( pixels_rgb, pixels_8->x_position, pixels_8->y_position, 00285 pixels_8->x_size, pixels_8->y_size, 00286 pixels_8->x_zoom, pixels_8->y_zoom, RGB_PIXEL ); 00287 00288 for_less( x, 0, pixels_rgb->x_size ) 00289 { 00290 for_less( y, 0, pixels_rgb->y_size ) 00291 { 00292 PIXEL_RGB_COLOUR(*pixels_rgb,x,y) = colour_table[ 00293 (int) PIXEL_COLOUR_INDEX_8(*pixels_8,x,y)]; 00294 } 00295 } 00296 } 00297 00298 /* ----------------------------- MNI Header ----------------------------------- 00299 @NAME : convert_pixels24_to_gray_scale 00300 @INPUT : pixels_rgb 00301 @OUTPUT : pixels_8 00302 @RETURNS : 00303 @DESCRIPTION: Converts 24 bit pixels to 8 bit gray scale. 00304 @METHOD : 00305 @GLOBALS : 00306 @CALLS : 00307 @CREATED : 1993 David MacDonald 00308 @MODIFIED : 00309 ---------------------------------------------------------------------------- */ 00310 00311 public void convert_pixels24_to_gray_scale( 00312 pixels_struct *pixels_rgb, 00313 pixels_struct *pixels_8 ) 00314 { 00315 int x, y; 00316 00317 initialize_pixels( pixels_8, 0, 0, pixels_rgb->x_size, pixels_rgb->y_size, 00318 1.0, 1.0, 00319 COLOUR_INDEX_8BIT_PIXEL ); 00320 00321 for_less( x, 0, pixels_rgb->x_size ) 00322 { 00323 for_less( y, 0, pixels_rgb->y_size ) 00324 { 00325 PIXEL_COLOUR_INDEX_8(*pixels_8,x,y) = (unsigned char) 00326 get_Colour_luminance( PIXEL_RGB_COLOUR(*pixels_rgb,x,y) ); 00327 } 00328 } 00329 } 00330 00331 /* ----------------------------- MNI Header ----------------------------------- 00332 @NAME : convert_pixels24_to_dithered 00333 @INPUT : pixels_rgb 00334 n_colours 00335 colour_table 00336 @OUTPUT : pixels_8 00337 @RETURNS : 00338 @DESCRIPTION: Performs Floyd-Steinberg error diffusion to convert a 24 bit 00339 image to an 8 bit image with the given colour map. 00340 @METHOD : 00341 @GLOBALS : 00342 @CALLS : 00343 @CREATED : 1993 David MacDonald 00344 @MODIFIED : 00345 ---------------------------------------------------------------------------- */ 00346 00347 public void convert_pixels24_to_dithered( 00348 pixels_struct *pixels_rgb, 00349 pixels_struct *pixels_8, 00350 int n_colours, 00351 Colour colour_table[] ) 00352 { 00353 int x, y, dir, error_row, c, comp[3], used[3]; 00354 int first_x, last_x, ind, one, three, five, seven, error; 00355 Colour col; 00356 short ***errors; 00357 00358 initialize_pixels( pixels_8, 0, 0, pixels_rgb->x_size, pixels_rgb->y_size, 00359 1.0, 1.0, 00360 COLOUR_INDEX_8BIT_PIXEL ); 00361 00362 ALLOC3D( errors, 2, 3, pixels_rgb->x_size ); 00363 00364 for_less( x, 0, pixels_rgb->x_size ) 00365 { 00366 errors[0][0][x] = 0; 00367 errors[0][1][x] = 0; 00368 errors[0][2][x] = 0; 00369 errors[1][0][x] = 0; 00370 errors[1][1][x] = 0; 00371 errors[1][2][x] = 0; 00372 } 00373 00374 error_row = 0; 00375 dir = 1; 00376 00377 for_less( y, 0, pixels_rgb->y_size ) 00378 { 00379 if( dir > 0 ) 00380 { 00381 first_x = 0; 00382 last_x = pixels_rgb->x_size; 00383 } 00384 else 00385 { 00386 first_x = pixels_rgb->x_size-1; 00387 last_x = -1; 00388 } 00389 for( x = first_x; x != last_x; x += dir ) 00390 { 00391 col = PIXEL_RGB_COLOUR(*pixels_rgb,x,y); 00392 comp[0] = get_Colour_r( col ) + errors[error_row][0][x]; 00393 comp[1] = get_Colour_g( col ) + errors[error_row][1][x]; 00394 comp[2] = get_Colour_b( col ) + errors[error_row][2][x]; 00395 00396 ind = find_closest_colour( comp[0], comp[1], comp[2], 00397 n_colours, colour_table ); 00398 00399 used[0] = get_Colour_r( colour_table[ind] ); 00400 used[1] = get_Colour_g( colour_table[ind] ); 00401 used[2] = get_Colour_b( colour_table[ind] ); 00402 00403 for_less( c, 0, 3 ) 00404 { 00405 error = comp[c] - used[c]; 00406 seven = ROUND( (Real) error * 7.0/ 16.0 ); 00407 five = ROUND( (Real) error * 5.0 / 16.0 ); 00408 three = ROUND( (Real) error * 3.0 / 16.0 ); 00409 one = error - seven - five - three; 00410 00411 if( x + dir >= 0 && x + dir < pixels_rgb->x_size ) 00412 { 00413 errors[error_row][c][x+dir] += seven; 00414 errors[1-error_row][c][x+dir] += one; 00415 } 00416 00417 if( x - dir >= 0 && x - dir < pixels_rgb->x_size ) 00418 errors[1-error_row][c][x-dir] += three; 00419 00420 errors[1-error_row][c][x] += five; 00421 } 00422 00423 PIXEL_COLOUR_INDEX_8(*pixels_8,x,y) = (unsigned char) ind; 00424 } 00425 00426 error_row = 1 - error_row; 00427 dir = - dir; 00428 00429 for_less( x, 0, pixels_rgb->x_size ) 00430 { 00431 errors[1-error_row][0][x] = 0; 00432 errors[1-error_row][1][x] = 0; 00433 errors[1-error_row][2][x] = 0; 00434 } 00435 } 00436 00437 FREE3D( errors ); 00438 } 00439 00440 /* ----------------------------- MNI Header ----------------------------------- 00441 @NAME : resample_pixels 00442 @INPUT : pixels 00443 transform 00444 n_samples 00445 background_colour 00446 @OUTPUT : new_pixels 00447 @RETURNS : 00448 @DESCRIPTION: Resamples the pixels in the transformed space. 00449 @METHOD : 00450 @GLOBALS : 00451 @CALLS : 00452 @CREATED : 1993 David MacDonald 00453 @MODIFIED : 00454 ---------------------------------------------------------------------------- */ 00455 00456 public void resample_pixels( 00457 pixels_struct *pixels, 00458 Transform_2d *transform, 00459 int n_samples, 00460 pixels_struct *new_pixels, 00461 Colour background_colour ) 00462 { 00463 int x, y, i, j; 00464 Real xs, ys, r_sum, g_sum, b_sum; 00465 Real x_trans, y_trans, weight; 00466 Colour colour; 00467 Transform_2d inverse; 00468 00469 if( pixels->pixel_type != RGB_PIXEL || 00470 new_pixels->pixel_type != RGB_PIXEL ) 00471 { 00472 print_error( "Can only resample 24 bit rgb pixels.\n" ); 00473 return; 00474 } 00475 00476 weight = 1.0 / (Real) n_samples / (Real) n_samples; 00477 get_inverse_transform_2d( transform, &inverse ); 00478 00479 for_less( x, 0, new_pixels->x_size ) 00480 { 00481 for_less( y, 0, new_pixels->y_size ) 00482 { 00483 if( n_samples == 1 ) 00484 { 00485 transform_point_2d( &inverse, (Real) x, (Real) y, 00486 &x_trans, &y_trans ); 00487 if( x_trans >= -0.5 && x_trans < (Real) pixels->x_size - 0.5 && 00488 y_trans >= -0.5 && y_trans < (Real) pixels->y_size - 0.5 ) 00489 { 00490 colour = PIXEL_RGB_COLOUR(*pixels,ROUND(x_trans), 00491 ROUND(y_trans)); 00492 } 00493 else 00494 { 00495 colour = background_colour; 00496 } 00497 } 00498 else 00499 { 00500 r_sum = 0.0; 00501 g_sum = 0.0; 00502 b_sum = 0.0; 00503 for_less( i, 0, n_samples ) 00504 { 00505 xs = (Real) x - 0.5 + ((Real) i + 0.5) / (Real) n_samples; 00506 00507 for_less( j, 0, n_samples ) 00508 { 00509 ys = (Real) y - 0.5 + ((Real) j + 0.5) /(Real)n_samples; 00510 transform_point_2d( &inverse, xs, ys, 00511 &x_trans, &y_trans ); 00512 if( x_trans >= -0.5 && 00513 x_trans < (Real) pixels->x_size - 0.5 && 00514 y_trans >= -0.5 && 00515 y_trans < (Real) pixels->y_size - 0.5 ) 00516 { 00517 colour = PIXEL_RGB_COLOUR(*pixels,ROUND(x_trans), 00518 ROUND(y_trans)); 00519 } 00520 else 00521 { 00522 colour = background_colour; 00523 } 00524 r_sum += (Real) get_Colour_r(colour); 00525 g_sum += (Real) get_Colour_g(colour); 00526 b_sum += (Real) get_Colour_b(colour); 00527 } 00528 } 00529 00530 colour = make_Colour( (int) (r_sum * weight), 00531 (int) (g_sum * weight), 00532 (int) (b_sum * weight) ); 00533 } 00534 00535 PIXEL_RGB_COLOUR( *new_pixels, x, y ) = colour; 00536 } 00537 } 00538 } 00539 00540 /* ----------------------------- MNI Header ----------------------------------- 00541 @NAME : copy_pixel_region 00542 @INPUT : pixels 00543 x_min 00544 x_max 00545 y_min 00546 y_max 00547 @OUTPUT : new_pixels 00548 @RETURNS : 00549 @DESCRIPTION: Copies the subset of the pixels, creating new_pixels. 00550 @METHOD : 00551 @GLOBALS : 00552 @CALLS : 00553 @CREATED : 1993 David MacDonald 00554 @MODIFIED : 00555 ---------------------------------------------------------------------------- */ 00556 00557 public void copy_pixel_region( 00558 pixels_struct *pixels, 00559 int x_min, 00560 int x_max, 00561 int y_min, 00562 int y_max, 00563 pixels_struct *new_pixels ) 00564 { 00565 int y, y_dest, x_size, y_size; 00566 00567 x_min -= pixels->x_position; 00568 y_min -= pixels->y_position; 00569 x_max -= pixels->x_position; 00570 y_max -= pixels->y_position; 00571 00572 if( x_min < 0 ) 00573 x_min = 0; 00574 if( x_max >= pixels->x_size ) 00575 x_max = pixels->x_size-1; 00576 00577 if( y_min < 0 ) 00578 y_min = 0; 00579 if( y_max >= pixels->y_size ) 00580 y_max = pixels->y_size-1; 00581 00582 x_size = MAX( 0, x_max - x_min + 1 ); 00583 y_size = MAX( 0, y_max - y_min + 1 ); 00584 00585 initialize_pixels( new_pixels, pixels->x_position + x_min, 00586 pixels->y_position + y_min, 00587 x_size, y_size, pixels->x_zoom, 00588 pixels->y_zoom, pixels->pixel_type ); 00589 00590 if( x_size == 0 || y_size == 0 ) 00591 return; 00592 00593 for_inclusive( y, y_min, y_max ) 00594 { 00595 y_dest = y - y_min; 00596 00597 switch( pixels->pixel_type ) 00598 { 00599 case COLOUR_INDEX_8BIT_PIXEL: 00600 (void) memcpy( (void *) &PIXEL_COLOUR_INDEX_8(*new_pixels,0,y_dest), 00601 (void *) &PIXEL_COLOUR_INDEX_8(*pixels,x_min,y), 00602 (size_t) x_size * 00603 sizeof(PIXEL_COLOUR_INDEX_8(*new_pixels,0,0)) ); 00604 break; 00605 00606 case COLOUR_INDEX_16BIT_PIXEL: 00607 (void) memcpy( (void *)&PIXEL_COLOUR_INDEX_16(*new_pixels,0,y_dest), 00608 (void *) &PIXEL_COLOUR_INDEX_16(*pixels,x_min,y), 00609 (size_t) x_size * 00610 sizeof(PIXEL_COLOUR_INDEX_16(*new_pixels,0,0)) ); 00611 break; 00612 00613 case RGB_PIXEL: 00614 (void) memcpy( (void *) &PIXEL_RGB_COLOUR(*new_pixels,0,y_dest), 00615 (void *) &PIXEL_RGB_COLOUR(*pixels,x_min,y), 00616 (size_t) x_size * 00617 sizeof(PIXEL_RGB_COLOUR(*new_pixels,0,0)) ); 00618 break; 00619 } 00620 } 00621 }

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