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

procrustes.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- 00002 @COPYRIGHT : 00003 Copyright 1993,1994,1995 David MacDonald, 00004 Peter Neelin, Louis Collins, 00005 McConnell Brain Imaging Centre, 00006 Montreal Neurological Institute, McGill University. 00007 Permission to use, copy, modify, and distribute this 00008 software and its documentation for any purpose and without 00009 fee is hereby granted, provided that the above copyright 00010 notice appear in all copies. The author and McGill University 00011 make no representations about the suitability of this 00012 software for any purpose. It is provided "as is" without 00013 express or implied warranty. 00014 ---------------------------------------------------------------------------- */ 00015 00016 /* ----------------------------- MNI Header ----------------------------------- 00017 @NAME : procrustes.c 00018 @DESCRIPTION: File containing routines for doing procrustes calculations. 00019 @METHOD : Contains routines : 00020 procrustes 00021 @CALLS : 00022 @CREATED : January 29, 1992 (Peter Neelin) 00023 @MODIFIED : February 7, 1992 (Peter Neelin) 00024 - added routine transformations_to_homogeneous 00025 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00026 ---------------------------------------------------------------------------- */ 00027 00028 #include <volume_io/internal_volume_io.h> 00029 #include <bicpl/trans.h> 00030 #include <bicpl/numerical.h> 00031 00032 #ifndef lint 00033 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Transforms/procrustes.c,v 1.14 2000/02/06 15:30:50 stever Exp $"; 00034 #endif 00035 00036 private Real trace_of_matrix( 00037 int size, 00038 Real **the_matrix ); 00039 00040 private void translate_points( 00041 int npoints, 00042 int ndim, 00043 Real **points, 00044 Real translation[], 00045 Real **newpoints); 00046 00047 private void calc_centroid( 00048 int npoints, 00049 int ndim, 00050 Real **points, 00051 Real centroid[] ); 00052 00053 /* ----------------------------- MNI Header ----------------------------------- 00054 @NAME : procrustes 00055 @INPUT : npoints - number of input point pairs 00056 ndim - number of dimensions for each point 00057 Apoints - Matrix of point set 1, size npoints by ndim 00058 Bpoints - Matrix of point set 2, size npoints by ndim 00059 @OUTPUT : translation - vector, size ndim, 00060 specifies the translation to be applied to Bpoints to line 00061 up the centroid with that of Apoints. Calling routine must 00062 allocate space for this vector. 00063 centre_of_rotation - vector, size ndim, that 00064 specifies the centre of rotation and scaling (this is 00065 in fact only the centroid of Apoints). Calling routine must 00066 allocate space for this vector. 00067 rotation - matrix, size ndim by ndim, 00068 to rotate translated Bpoints so that they line up with 00069 Apoints. Calling routine must allocate space for this 00070 matrix. 00071 scale - Scalar value giving global scaling to be applied to 00072 translated and rotated Bpoints to match Apoints. 00073 @RETURNS : (nothing) 00074 @DESCRIPTION: Calculates n-dimensional linear transformation from one set 00075 of points to another, minimizing distance between equivalent 00076 points. Transformation from Bpoints to Apoints is calculated. 00077 @METHOD : See Matrix Computations, Golub and Van Loan, pp. 425-426 and 00078 paper by Sibson, Robin, J.R.Statist.Soc. B(1978), Vol. 40, 00079 No. 2, pp 234-238. 00080 Steps of calculations are as follows : 00081 1) Calculate translation that aligns the centroids of the 00082 two point sets. 00083 2) Calculate rotation/reflexion that minimizes residual. 00084 3) Calculate scaling of points to minimize residual. 00085 The process can be broken into independent steps because the 00086 best translation aligns centroids independently of the choice 00087 of rotation/reflexion and scaling and the best rotation/reflexion 00088 can be found independently of scale (after the best translation 00089 has been found). (See Sibson for more). 00090 @GLOBALS : (none) 00091 @CALLS : calc_centroid 00092 translate_points 00093 transpose 00094 matrix_multiply 00095 trace_of_matrix 00096 @CREATED : Long time ago (Sean Marrett) 00097 @MODIFIED : Some time later (Shyan Ku) 00098 Feb. 26, 1990 (Weiqian Dai) 00099 January 30, 1992 (Peter Neelin) 00100 - complete rewrite for roughly NIL-abiding code. Modified 00101 name and calling parameters. 00102 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00103 ---------------------------------------------------------------------------- */ 00104 00105 public void procrustes( 00106 int npoints, 00107 int ndim, 00108 Real **Apoints, 00109 Real **Bpoints, 00110 Real translation[], 00111 Real centre_of_rotation[], 00112 Transform *rotation_transform, 00113 Real *scale_ptr ) 00114 { 00115 int i, j; 00116 Real *Atranslation, *Btranslation, *svd_W; 00117 Real **Ashift, **Bshift, **Atranspose, **Btranspose, **rotation; 00118 Real **svd_V, **svd_VT; 00119 Real **Brotated, **product; 00120 Real trace1, trace2; 00121 Real **svd_U; 00122 00123 /* Get the vectors for centroids */ 00124 00125 ALLOC( Atranslation, ndim ); 00126 ALLOC( Btranslation, ndim ); 00127 ALLOC( svd_W, ndim ); 00128 00129 /* Get various matrices */ 00130 00131 ALLOC2D( rotation, ndim, ndim ); 00132 ALLOC2D( Ashift, npoints, ndim ); 00133 ALLOC2D( Bshift, npoints, ndim ); 00134 ALLOC2D( Atranspose, ndim, npoints ); 00135 ALLOC2D( Btranspose, ndim, npoints ); 00136 ALLOC2D( svd_U, ndim, ndim ); 00137 ALLOC2D( svd_V, ndim, ndim ); 00138 ALLOC2D( svd_VT, ndim, ndim ); 00139 ALLOC2D( Brotated, npoints, ndim ); 00140 ALLOC2D( product, npoints, npoints ); 00141 00142 /* Calculate the centroids, remove them from A and B points and 00143 save the translation */ 00144 00145 calc_centroid( npoints, ndim, Apoints, centre_of_rotation ); 00146 00147 for_less( i, 0, ndim ) 00148 Atranslation[i] = -centre_of_rotation[i]; 00149 00150 translate_points( npoints, ndim, Apoints, Atranslation, Ashift ); 00151 calc_centroid( npoints, ndim, Bpoints, Btranslation ); 00152 00153 for_less( i, 0, ndim ) 00154 Btranslation[i] *= -1.0; 00155 00156 translate_points( npoints, ndim, Bpoints, Btranslation, Bshift ); 00157 00158 for_less( i, 0, ndim ) 00159 translation[i] = Btranslation[i] - Atranslation[i]; 00160 00161 /* Calculate the rotation/reflexion matrix */ 00162 00163 transpose( npoints, ndim, Bshift, Btranspose ); 00164 matrix_multiply( ndim, npoints, ndim, Btranspose, Ashift, svd_U ); 00165 (void) singular_value_decomposition( ndim, ndim, svd_U, svd_W, svd_V ); 00166 transpose( ndim, ndim, svd_V, svd_VT ); 00167 matrix_multiply( ndim, ndim, ndim, svd_U, svd_VT, rotation ); 00168 00169 /* Calculate the scale */ 00170 00171 matrix_multiply( npoints, ndim, ndim, Bshift, rotation, Brotated ); 00172 transpose( npoints, ndim, Ashift, Atranspose ); 00173 matrix_multiply( npoints, ndim, npoints, Brotated, Atranspose, product ); 00174 trace1 = trace_of_matrix( npoints, product ); 00175 matrix_multiply( npoints, ndim, npoints, Bshift, Btranspose, product ); 00176 trace2 = trace_of_matrix( npoints, product ); 00177 00178 if (trace2 != 0.0) 00179 *scale_ptr = trace1 / trace2; 00180 else 00181 *scale_ptr = 0.0; 00182 00183 make_identity_transform( rotation_transform ); 00184 00185 for_less( i, 0, N_DIMENSIONS ) 00186 for_less( j, 0, N_DIMENSIONS ) 00187 Transform_elem( *rotation_transform, i, j ) = rotation[j][i]; 00188 00189 /* Free vectors */ 00190 00191 FREE( Atranslation ); 00192 FREE( Btranslation ); 00193 FREE( svd_W ); 00194 00195 /* Free matrices */ 00196 00197 FREE2D( rotation ); 00198 FREE2D( Ashift ); 00199 FREE2D( Bshift ); 00200 FREE2D( Atranspose ); 00201 FREE2D( Btranspose ); 00202 FREE2D( svd_U ); 00203 FREE2D( svd_V ); 00204 FREE2D( svd_VT ); 00205 FREE2D( Brotated ); 00206 FREE2D( product ); 00207 } 00208 00209 /* ----------------------------- MNI Header ----------------------------------- 00210 @NAME : calc_centroid 00211 @INPUT : npoints - number of points 00212 ndim - number of dimensions 00213 points - points matrix, ndim by npoints 00214 @OUTPUT : centroid - vector of centroid of points, size ndim 00215 @RETURNS : (nothing) 00216 @DESCRIPTION: Calculates the centroid of a number of points in ndim dimensions. 00217 @METHOD : 00218 @GLOBALS : (none) 00219 @CALLS : (nothing special) 00220 @CREATED : Feb. 26, 1990 (Weiqian Dai) 00221 @MODIFIED : January 31, 1992 (Peter Neelin) 00222 - change to roughly NIL-abiding code and modified calling 00223 sequence. 00224 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00225 00226 ---------------------------------------------------------------------------- */ 00227 00228 private void calc_centroid( 00229 int npoints, 00230 int ndim, 00231 Real **points, 00232 Real centroid[] ) 00233 { 00234 int d, p; 00235 00236 /* Loop over each dimension */ 00237 00238 for_less( d, 0, ndim ) 00239 { 00240 /* Add up points and divide by number of points */ 00241 00242 centroid[d] = 0.0; 00243 for_less( p, 0, npoints ) 00244 centroid[d] += points[p][d]; 00245 00246 if( npoints > 0 ) 00247 centroid[d] /= (Real) npoints; 00248 } 00249 } 00250 00251 00252 /* ----------------------------- MNI Header ----------------------------------- 00253 @NAME : translate_points 00254 @INPUT : npoints - number of points 00255 ndim - number of dimensions 00256 points - points matrix, size npoints by ndim 00257 translation - translation vector, size ndim 00258 @OUTPUT : newpoints - translated points matrix (see points). This matrix 00259 can be the original points matrix. 00260 @RETURNS : (nothing) 00261 @DESCRIPTION: Translates a set of points by a given translation. 00262 @METHOD : 00263 @GLOBALS : (none) 00264 @CALLS : (nothing special) 00265 @CREATED : Feb. 26, 1990 (Weiqian Dai) 00266 @MODIFIED : January 31, 1992 (Peter Neelin) 00267 - change to roughly NIL-abiding code and modified calling 00268 sequence. 00269 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00270 ---------------------------------------------------------------------------- */ 00271 00272 private void translate_points( 00273 int npoints, 00274 int ndim, 00275 Real **points, 00276 Real translation[], 00277 Real **newpoints) 00278 { 00279 int p, d; 00280 00281 for_less( p, 0, npoints ) 00282 { 00283 for_less( d, 0, ndim ) 00284 newpoints[p][d] = points[p][d] + translation[d]; 00285 } 00286 } 00287 00288 00289 /* ----------------------------- MNI Header ----------------------------------- 00290 @NAME : trace_of_matrix 00291 @INPUT : size - size of the_matrix (the_matrix should be square) 00292 the_matrix - matrix for which trace should be calculated 00293 @OUTPUT : (none) 00294 @RETURNS : trace of matrix 00295 @DESCRIPTION: Calculates the trace of a matrix, product of diagonal elements. 00296 @METHOD : 00297 @GLOBALS : (none) 00298 @CALLS : (nothing special) 00299 @CREATED : Feb. 26, 1990 (Weiqian Dai) 00300 @MODIFIED : January 31, 1992 (Peter Neelin) 00301 - change to roughly NIL-abiding code and modified calling 00302 sequence. 00303 @MODIFIED : July 4, 1995 D. MacDonald - removed recipes-style code 00304 ---------------------------------------------------------------------------- */ 00305 00306 private Real trace_of_matrix( 00307 int size, 00308 Real **the_matrix ) 00309 { 00310 int i; 00311 Real sum; 00312 00313 sum = 0.0; 00314 00315 for_less( i, 0, size ) 00316 sum += the_matrix[i][i]; 00317 00318 return( sum ); 00319 }

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