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

compute_xfm.c

Go to the documentation of this file.
00001 00002 /* ---------------------------------------------------------------------------- 00003 @COPYRIGHT : 00004 Copyright 1993,1994,1995 David MacDonald, 00005 Peter Neelin, Louis Collins, 00006 McConnell Brain Imaging Centre, 00007 Montreal Neurological Institute, McGill University. 00008 Permission to use, copy, modify, and distribute this 00009 software and its documentation for any purpose and without 00010 fee is hereby granted, provided that the above copyright 00011 notice appear in all copies. The author and McGill University 00012 make no representations about the suitability of this 00013 software for any purpose. It is provided "as is" without 00014 express or implied warranty. 00015 ---------------------------------------------------------------------------- */ 00016 00017 /* ----------------------------- MNI Header ----------------------------------- 00018 @NAME : compute_xfm.c 00019 @DESCRIPTION: Routine to calculate a General_transform from a pair of tag 00020 point lists. 00021 @METHOD : 00022 @GLOBALS : 00023 @CREATED : August 30, 1993 (Peter Neelin) 00024 @MODIFIED : $Log: compute_xfm.c,v $ 00025 @MODIFIED : Revision 1.17 2000/02/06 15:30:50 stever 00026 @MODIFIED : rearranged header file structure; add gcc -Wall fixes 00027 @MODIFIED : 00028 @MODIFIED : Revision 1.16 2000/02/05 21:27:20 stever 00029 @MODIFIED : change include lines <foo.h> --> <bicpl/foo.h> 00030 @MODIFIED : 00031 @MODIFIED : Revision 1.15 1995/07/31 13:46:00 david 00032 @MODIFIED : check_in_all 00033 @MODIFIED : 00034 * Revision 1.14 1995/07/10 18:02:50 david 00035 * check_in_all 00036 * 00037 * Revision 1.13 1995/07/10 14:36:10 david 00038 * check_in_all 00039 * 00040 * Revision 1.12 1995/07/08 03:38:04 david 00041 * *** empty log message *** 00042 * 00043 * Revision 1.11 1995/07/07 18:51:24 david 00044 * *** empty log message *** 00045 * 00046 * Revision 1.10 1995/07/07 18:18:23 david 00047 * check_in_all 00048 * 00049 * Revision 1.9 1995/07/07 18:16:45 david 00050 * *** empty log message *** 00051 * 00052 * Revision 1.8 1995/07/05 14:52:06 david 00053 * *** empty log message *** 00054 * 00055 * Revision 1.7 1995/06/23 14:24:37 david 00056 * check_in_all 00057 * 00058 * Revision 1.6 1995/05/19 21:51:21 david 00059 * *** empty log message *** 00060 * 00061 * Revision 1.5 1995/04/04 03:42:05 david 00062 * check_in_all 00063 * 00064 * Revision 1.4 1995/03/07 18:54:49 david 00065 * check_in_all 00066 * 00067 * Revision 1.3 95/02/27 17:20:20 david 00068 * *** empty log message *** 00069 * 00070 * Revision 1.2 94/11/25 14:23:13 david 00071 * check_in_all 00072 * 00073 * Revision 1.1 94/11/04 14:45:47 david 00074 * Initial revision 00075 * 00076 * Revision 1.4 93/09/10 11:52:58 neelin 00077 * Fixed 9 and 10 parameter fitting. 00078 * 00079 * Revision 1.3 93/09/08 15:45:00 neelin 00080 * Added 9 and 10 parameter linear fitting. 00081 * 00082 * Revision 1.2 93/09/01 15:35:17 neelin 00083 * Changed calls to lfit to lfit_vector. 00084 * 00085 * Revision 1.1 93/09/01 15:25:25 neelin 00086 * Initial revision 00087 * 00088 * Revision 1.1 93/09/01 13:21:30 neelin 00089 * Initial revision 00090 * 00091 ---------------------------------------------------------------------------- */ 00092 00093 #include <volume_io/internal_volume_io.h> 00094 #include <bicpl/trans.h> 00095 #include <bicpl/numerical.h> 00096 00097 #ifndef lint 00098 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Transforms/compute_xfm.c,v 1.17 2000/02/06 15:30:50 stever Exp $"; 00099 #endif 00100 00101 /* Function declarations */ 00102 00103 private void compute_procrustes_transform(int npoints, 00104 Real **tag_list1, 00105 Real **tag_list2, 00106 Trans_type trans_type, 00107 General_transform *transform); 00108 private void compute_arb_param_transform(int npoints, 00109 Real **tag_list1, 00110 Real **tag_list2, 00111 Trans_type trans_type, 00112 General_transform *transform); 00113 private void compute_12param_transform(int npoints, 00114 Real **tag_list1, 00115 Real **tag_list2, 00116 Trans_type trans_type, 00117 General_transform *transform); 00118 private void compute_tps_transform(int npoints, 00119 Real **tag_list1, 00120 Real **tag_list2, 00121 Trans_type trans_type, 00122 General_transform *transform); 00123 00124 private void concat_transformation_matrix( 00125 Transform *lt, 00126 Real center[], 00127 Real translations[], 00128 Real scales[], 00129 Real shears[], 00130 Transform *rotation ); 00131 00132 /* ----------------------------- MNI Header ----------------------------------- 00133 @NAME : compute_transform_from_tags 00134 @INPUT : npoints - number of pairs of tag points 00135 tag_list1 - first list of tag points 00136 tag_list2 - second list of tag points 00137 trans_type - type of transformation to calculate 00138 @OUTPUT : transform - computed transform 00139 @RETURNS : (nothing) 00140 @DESCRIPTION: Routine to calculate a general transform from a pair of lists 00141 of tag points. The transform is from tag_list2 to tag_list1. 00142 @METHOD : 00143 @GLOBALS : 00144 @CALLS : 00145 @CREATED : August 30, 1993 (Peter Neelin) 00146 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00147 ---------------------------------------------------------------------------- */ 00148 00149 public void compute_transform_from_tags( 00150 int npoints, 00151 Real **tag_list1, 00152 Real **tag_list2, 00153 Trans_type trans_type, 00154 General_transform *transform) 00155 { 00156 /* Check number of points for linear transformation */ 00157 00158 if( ((trans_type == TRANS_LSQ6) || 00159 (trans_type == TRANS_LSQ7) || 00160 (trans_type == TRANS_LSQ9) || 00161 (trans_type == TRANS_LSQ10) || 00162 (trans_type == TRANS_LSQ12)) && 00163 (npoints < MIN_POINTS_LINEAR) ) 00164 { 00165 create_linear_transform(transform, NULL); 00166 return; 00167 } 00168 00169 /* Check number of points for thin-plate spline transformation */ 00170 00171 if( (trans_type == TRANS_TPS) && (npoints < MIN_POINTS_TPS) ) 00172 { 00173 create_linear_transform(transform, NULL); 00174 return; 00175 } 00176 00177 switch (trans_type) 00178 { 00179 case TRANS_LSQ6: 00180 case TRANS_LSQ7: 00181 compute_procrustes_transform( npoints, tag_list1, tag_list2, 00182 trans_type, transform ); 00183 break; 00184 00185 case TRANS_LSQ9: 00186 case TRANS_LSQ10: 00187 compute_arb_param_transform( npoints, tag_list1, tag_list2, 00188 trans_type, transform ); 00189 break; 00190 00191 case TRANS_LSQ12: 00192 compute_12param_transform( npoints, tag_list1, tag_list2, 00193 trans_type, transform ); 00194 break; 00195 00196 case TRANS_TPS: 00197 compute_tps_transform( npoints, tag_list1, tag_list2, 00198 trans_type, transform ); 00199 break; 00200 00201 default: 00202 print_error( 00203 "Invalid transform type in compute_transform_from tags\n" ); 00204 00205 exit(EXIT_FAILURE); 00206 } 00207 } 00208 00209 /* ----------------------------- MNI Header ----------------------------------- 00210 @NAME : compute_procrustes_transform 00211 @INPUT : npoints - number of pairs of tag points 00212 tag_list1 - first list of tag points 00213 tag_list2 - second list of tag points 00214 trans_type - type of transformation to calculate 00215 @OUTPUT : transform - computed transform 00216 @RETURNS : (nothing) 00217 @DESCRIPTION: Routine to calculate a general transform from a pair of lists 00218 of tag points. The transform is from tag_list2 to tag_list1. 00219 Uses 6 or 7 parameter procrustes transformation. 00220 @METHOD : 00221 @GLOBALS : 00222 @CALLS : 00223 @CREATED : August 30, 1993 (Peter Neelin) 00224 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00225 ---------------------------------------------------------------------------- */ 00226 00227 private void compute_procrustes_transform( 00228 int npoints, 00229 Real **tag_list1, 00230 Real **tag_list2, 00231 Trans_type trans_type, 00232 General_transform *transform) 00233 { 00234 Transform rotation; 00235 int i; 00236 Real translation[N_DIMENSIONS]; 00237 Real centre_of_rotation[N_DIMENSIONS]; 00238 Real scale, scales[N_DIMENSIONS]; 00239 Real shears[N_DIMENSIONS]; 00240 Transform linear_transform; 00241 00242 /* Do procrustes fit */ 00243 00244 procrustes( npoints, N_DIMENSIONS, tag_list1, tag_list2, translation, 00245 centre_of_rotation, &rotation, &scale ); 00246 00247 /* Set scale appropriately */ 00248 00249 if( trans_type == TRANS_LSQ6 ) 00250 scale = 1.0; 00251 00252 for_less( i, 0, N_DIMENSIONS ) 00253 { 00254 scales[i] = scale; 00255 shears[i] = 0.0; 00256 } 00257 00258 /* Concatenate translation, scale, shear and rotation */ 00259 00260 concat_transformation_matrix( &linear_transform, centre_of_rotation, 00261 translation, scales, shears, &rotation ); 00262 00263 create_linear_transform( transform, &linear_transform ); 00264 } 00265 00266 /* ----------------------------- MNI Header ----------------------------------- 00267 @NAME : compute_arb_param_transform 00268 @INPUT : npoints - number of pairs of tag points 00269 tag_list1 - first list of tag points 00270 tag_list2 - second list of tag points 00271 trans_type - type of transformation to calculate 00272 @OUTPUT : transform - computed transform 00273 @RETURNS : (nothing) 00274 @DESCRIPTION: Routine to calculate a general transform from a pair of lists 00275 of tag points. The transform is from tag_list2 to tag_list1. 00276 Computes a linear transform using arbitrary parameters. 00277 @METHOD : 00278 @GLOBALS : 00279 @CALLS : 00280 @CREATED : August 30, 1993 (Louis Collins and Peter Neelin) 00281 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00282 ---------------------------------------------------------------------------- */ 00283 00284 private void compute_arb_param_transform( 00285 int npoints, 00286 Real **tag_list1, 00287 Real **tag_list2, 00288 Trans_type trans_type, 00289 General_transform *transform ) 00290 { 00291 Transform rotation; 00292 Real translation[N_DIMENSIONS]; 00293 Real centre_of_rotation[N_DIMENSIONS], scale; 00294 Real scales[N_DIMENSIONS]; 00295 Real shears[N_DIMENSIONS], angles[N_DIMENSIONS]; 00296 int i; 00297 Transform linear_transform; 00298 00299 if( trans_type != TRANS_LSQ9 && trans_type != TRANS_LSQ10 ) 00300 { 00301 print_error( "Error in compute_arb_param_transform().\n" ); 00302 print_error( "Trans_type (=%d) requested is not LSQ9 or LSQ10.\n", 00303 trans_type ); 00304 exit(EXIT_FAILURE); 00305 } 00306 00307 /* Do procrustes fit */ 00308 00309 procrustes( npoints, N_DIMENSIONS, tag_list1, tag_list2, translation, 00310 centre_of_rotation, &rotation, &scale ); 00311 00312 if( !rotmat_to_ang( &rotation, angles ) ) 00313 { 00314 print_error( "Error in compute_arb_param_transform().\n"); 00315 print_error( "Cannot extract angles from rotation matrix.\n"); 00316 exit(EXIT_FAILURE); 00317 } 00318 00319 for_less( i, 0, N_DIMENSIONS ) 00320 { 00321 shears[i] = 0.0; 00322 scales[i] = scale; 00323 } 00324 00325 if( !optimize_simplex( tag_list1, tag_list2, 00326 npoints, trans_type, 00327 centre_of_rotation, 00328 translation, 00329 scales, 00330 shears, 00331 angles) ) 00332 { 00333 print_error( "Error in compute_arb_param_transform(),\n"); 00334 print_error( "in call to optimize_simplex().\n"); 00335 exit(EXIT_FAILURE); 00336 } 00337 00338 build_transformation_matrix( &linear_transform, 00339 centre_of_rotation, 00340 translation, 00341 scales, 00342 shears, 00343 angles ); 00344 00345 00346 create_linear_transform( transform, &linear_transform ); 00347 } 00348 00349 /* ----------------------------- MNI Header ----------------------------------- 00350 @NAME : make_rots 00351 @INPUT : rot_x, rot_y, rot_z - three rotation angles, in radians. 00352 @OUTPUT : xmat, a linear transform 00353 @RETURNS : nothing 00354 @DESCRIPTION: to be applied by premultiplication, ie rot*vec = newvec 00355 @METHOD : 00356 @GLOBALS : 00357 @CALLS : 00358 @CREATED : Tue Jun 8 08:44:59 EST 1993 LC 00359 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00360 ---------------------------------------------------------------------------- */ 00361 00362 private void make_rots( 00363 Transform *xmat, 00364 Real rot_x, 00365 Real rot_y, 00366 Real rot_z ) 00367 { 00368 Transform tx, ty, tz; 00369 00370 make_rotation_transform( -rot_x, X, &tx ) ; 00371 make_rotation_transform( -rot_y, Y, &ty ) ; 00372 make_rotation_transform( -rot_z, Z, &tz ) ; 00373 00374 concat_transforms( xmat, &tx, &ty ); 00375 concat_transforms( xmat, xmat, &tz ); 00376 } 00377 00378 /* ----------------------------- MNI Header ----------------------------------- 00379 @NAME : concat_transformation_matrix 00380 @INPUT : center, translations, scales, rotations 00381 @OUTPUT : lt - a linear transformation matrix 00382 @RETURNS : nothing 00383 @DESCRIPTION: mat = (c)(sh)(s*r)(-c)(t), 00384 the matrix is to be PREmultiplied with a vector (mat*vec) 00385 when used in the application 00386 @METHOD : 00387 @GLOBALS : 00388 @CALLS : 00389 @CREATED : Thu Jun 3 09:37:56 EST 1993 lc 00390 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00391 ---------------------------------------------------------------------------- */ 00392 00393 private void concat_transformation_matrix( 00394 Transform *lt, 00395 Real center[], 00396 Real translations[], 00397 Real scales[], 00398 Real shears[], 00399 Transform *rotation ) 00400 { 00401 Transform T, SH, S, C; 00402 00403 /* mat = (C)(SH)(S)(R)(-C)(T) */ 00404 00405 /* make (T)(-C) */ 00406 00407 make_translation_transform( translations[X] - center[X], 00408 translations[Y] - center[Y], 00409 translations[Z] - center[Z], &T ); 00410 00411 /* make shear rotation matrix */ 00412 00413 make_rots( &SH, shears[0], shears[1], shears[2] ); 00414 00415 /* make scaling matrix */ 00416 00417 make_scale_transform( scales[X], scales[Y], scales[Z], &S ); 00418 00419 /* make translation back to centre */ 00420 00421 make_translation_transform( center[X], center[Y], center[Z], &C ); 00422 00423 concat_transforms( lt, &T, rotation ); 00424 concat_transforms( lt, lt, &S ); 00425 concat_transforms( lt, lt, &SH ); 00426 concat_transforms( lt, lt, &C ); 00427 } 00428 00429 /* ----------------------------- MNI Header ----------------------------------- 00430 @NAME : build_transformation_matrix 00431 @INPUT : center, translations, scales, rotations 00432 @OUTPUT : lt - a linear transformation matrix 00433 @RETURNS : nothing 00434 @DESCRIPTION: mat = (c)(s*r)(-c)(t), 00435 the matrix is to be PREmultiplied with a vector (mat*vec) 00436 when used in the application 00437 @METHOD : 00438 @GLOBALS : 00439 @CALLS : 00440 @CREATED : Thu Jun 3 09:37:56 EST 1993 lc 00441 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00442 ---------------------------------------------------------------------------- */ 00443 00444 public void build_transformation_matrix( 00445 Transform *lt, 00446 Real center[], 00447 Real translations[], 00448 Real scales[], 00449 Real shears[], 00450 Real rotations[] ) 00451 { 00452 Transform R; 00453 00454 /* make rotation matix */ 00455 00456 make_rots( &R, rotations[0], rotations[1], rotations[2] ); 00457 00458 concat_transformation_matrix( lt, center, translations, scales, 00459 shears, &R ); 00460 } 00461 00462 /* ----------------------------- MNI Header ----------------------------------- 00463 @NAME : compute_12param_transform 00464 @INPUT : npoints - number of pairs of tag points 00465 tag_list1 - first list of tag points 00466 tag_list2 - second list of tag points 00467 trans_type - type of transformation to calculate 00468 @OUTPUT : transform - computed transform 00469 @RETURNS : (nothing) 00470 @DESCRIPTION: Routine to calculate a general transform from a pair of lists 00471 of tag points. The transform is from tag_list2 to tag_list1. 00472 Uses 12 parameter linear transformation, and simply solves 00473 the linear least squares problem for each of the x, y, and 00474 z components independently. 00475 @METHOD : 00476 @GLOBALS : 00477 @CALLS : 00478 @CREATED : August 30, 1993 (Peter Neelin) 00479 @MODIFIED : 00480 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00481 ---------------------------------------------------------------------------- */ 00482 00483 private void compute_12param_transform( 00484 int npoints, 00485 Real **tag_list1, 00486 Real **tag_list2, 00487 Trans_type trans_type, 00488 General_transform *transform) 00489 { 00490 Real *x, solution[N_DIMENSIONS + 1]; 00491 int d, dim; 00492 int point; 00493 Transform linear_transform; 00494 00495 /*--- Check transformation type */ 00496 00497 if( trans_type != TRANS_LSQ12 ) 00498 { 00499 print_error( "Internal error in compute_12param_transform!\n"); 00500 exit(EXIT_FAILURE); 00501 } 00502 00503 /*--- initialize the solution */ 00504 00505 make_identity_transform( &linear_transform ); 00506 00507 ALLOC( x, npoints ); 00508 00509 /*--- for each dimension, find the linear least squares solution */ 00510 00511 for_less( dim, 0, N_DIMENSIONS ) 00512 { 00513 /*--- Copy the data points into a 1-D array */ 00514 00515 for_less( point, 0, npoints ) 00516 x[point] = tag_list1[point][dim]; 00517 00518 /*--- find the solution */ 00519 00520 least_squares( npoints, N_DIMENSIONS, tag_list2, x, solution ); 00521 00522 /*--- record solution in the linear transform */ 00523 00524 Transform_elem( linear_transform, dim, N_DIMENSIONS ) = solution[0]; 00525 for_less( d, 0, N_DIMENSIONS ) 00526 Transform_elem( linear_transform, dim, d ) = solution[1+d]; 00527 } 00528 00529 /*--- Create general transform */ 00530 00531 create_linear_transform( transform, &linear_transform ); 00532 00533 /* Free matrices and vectors */ 00534 00535 FREE( x ); 00536 } 00537 00538 /* ----------------------------- MNI Header ----------------------------------- 00539 @NAME : compute_tps_transform 00540 @INPUT : npoints - number of pairs of tag points 00541 tag_list1 - first list of tag points 00542 tag_list2 - second list of tag points 00543 trans_type - type of transformation to calculate 00544 @OUTPUT : transform - computed transform 00545 @RETURNS : (nothing) 00546 @DESCRIPTION: Routine to calculate a general transform from a pair of lists 00547 of tag points. The transform is from tag_list2 to tag_list1. 00548 Uses thin-plate spline transform. 00549 @METHOD : We calculate the tranformation from tag_list1 to tag_list2 00550 and then invert it so that resampling volumes is faster 00551 (doing a forward transformation, rather than a iterative 00552 inverse). 00553 @GLOBALS : 00554 @CALLS : 00555 @CREATED : August 30, 1993 (Peter Neelin) 00556 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00557 ---------------------------------------------------------------------------- */ 00558 00559 private void compute_tps_transform( 00560 int npoints, 00561 Real **tag_list1, 00562 Real **tag_list2, 00563 Trans_type trans_type, 00564 General_transform *transform) 00565 { 00566 Real **displacements; 00567 General_transform inv_transform; 00568 00569 /* Check trans_type */ 00570 00571 if (trans_type != TRANS_TPS) 00572 { 00573 print_error( "Wrong trans type in compute_tps_transform\n"); 00574 exit(EXIT_FAILURE); 00575 } 00576 00577 /* Allocate matrices */ 00578 00579 ALLOC2D( displacements, npoints+1+N_DIMENSIONS, N_DIMENSIONS ); 00580 00581 get_nonlinear_warp( tag_list1, tag_list2, displacements, npoints, 00582 N_DIMENSIONS, N_DIMENSIONS ); 00583 00584 /* ---- Create general transform */ 00585 00586 create_thin_plate_transform_real( &inv_transform, N_DIMENSIONS, npoints, 00587 tag_list1, displacements ); 00588 00589 /* ---- Invert general transform */ 00590 00591 create_inverse_general_transform( &inv_transform, transform ); 00592 00593 /* ---- Free inverse transform */ 00594 00595 delete_general_transform(&inv_transform); 00596 00597 /* ---- Free displacements */ 00598 00599 FREE2D( displacements ); 00600 }

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