emse_read_reg - Read EMSE/MRVU coregistration matrices [reg] = emse_read_reg(file) reg is a struct with the following fields: reg.translation - the translation in meters along the x, y and z axes respectively, from the MRI image frame to head/elec frame. reg.rotation - The rotation vector contains the angles (in radians) about the x, y and z axes, also from the MRI image frame to the head/elec frame. reg.elec2mri - 'HeadToImageMatrix' is the 4 x 4 matrix containing the electrode to MRI translation and rotation transformations in homogeneous coordinates: * the upper left 3 x 3 submatrix is rotations around z, y, x in that order; * the rightmost 3 x 1 column is a projection vector (all zeros here); * the bottom 1 x 3 row is a translation vector, equal to -1 * reg.translation here; and * the bottom right (1 x 1) scalar is the homogenous scale unit, usually 1 reg.mri2elec - 'ImageToHeadMatrix' is the inverse of elec2mri, ie, reg.mri2elec = inv(reg.elec2mri). This function also reads the fiducial points and the electrode coordinates from the registration file, they are returned into: reg.RPA, reg.LPA, reg.NAS, reg.Helec, and reg.Melec. Each of the fiducial structs (RPA,LPA,NAS) contains the electrode fiducials in the head space (Hh) and the MRI space (Hm), plus the MRI fiducials in the head space (Mh) and the MRI space (Mm). The transformation matrices (T) multiply a column vector, so that [x', y', z', 1] = [x, y, z, 1] * T; where x',y',z' are in the other coordinate system. For example, MRI coordinates into head space: tmp = [ reg.Melec ones(size(reg.Melec,1),1) ] * reg.mri2elec; Note reg.Helec ~= tmp(:,1:3) due to floating point rounding only. Similarly, head space (electrodes) into MRI coordinates: tmp = [ reg.Helec ones(size(reg.Helec,1),1) ] * reg.elec2mri; Note reg.Melec ~= tmp(:,1:3) due to floating point rounding only. EMSE Note: The origin in the head frame is at or near the center of the skull, while the origin in the image frame is located at the bottom right front corner of the bounding box (and so would be located at the upper left corner of the first axial slice as displayed by MR Viewer). A useful chapter on homogeneous coordinates, among other things, may be found in Mortenson, M. (1985, Chpt. 8), Geometric Modelling, New York: John Wiley & Sons.
0001 function [reg] = emse_read_reg(file) 0002 0003 % emse_read_reg - Read EMSE/MRVU coregistration matrices 0004 % 0005 % [reg] = emse_read_reg(file) 0006 % 0007 % reg is a struct with the following fields: 0008 % 0009 % reg.translation - the translation in meters along the 0010 % x, y and z axes respectively, from 0011 % the MRI image frame to head/elec frame. 0012 % 0013 % reg.rotation - The rotation vector contains the angles 0014 % (in radians) about the x, y and z axes, 0015 % also from the MRI image frame to the 0016 % head/elec frame. 0017 % 0018 % reg.elec2mri - 'HeadToImageMatrix' is the 4 x 4 matrix 0019 % containing the electrode to MRI translation and 0020 % rotation transformations in homogeneous coordinates: 0021 % * the upper left 3 x 3 submatrix is rotations 0022 % around z, y, x in that order; 0023 % * the rightmost 3 x 1 column is a projection 0024 % vector (all zeros here); 0025 % * the bottom 1 x 3 row is a translation vector, 0026 % equal to -1 * reg.translation here; and 0027 % * the bottom right (1 x 1) scalar is the 0028 % homogenous scale unit, usually 1 0029 % 0030 % reg.mri2elec - 'ImageToHeadMatrix' is the inverse of elec2mri, 0031 % ie, reg.mri2elec = inv(reg.elec2mri). 0032 % 0033 % This function also reads the fiducial points and the electrode 0034 % coordinates from the registration file, they are returned into: 0035 % reg.RPA, reg.LPA, reg.NAS, reg.Helec, and reg.Melec. Each of 0036 % the fiducial structs (RPA,LPA,NAS) contains the electrode 0037 % fiducials in the head space (Hh) and the MRI space (Hm), plus the 0038 % MRI fiducials in the head space (Mh) and the MRI space (Mm). 0039 % 0040 % The transformation matrices (T) multiply a column vector, so that 0041 % [x', y', z', 1] = [x, y, z, 1] * T; 0042 % where x',y',z' are in the other coordinate system. For example, 0043 % MRI coordinates into head space: 0044 % tmp = [ reg.Melec ones(size(reg.Melec,1),1) ] * reg.mri2elec; 0045 % Note reg.Helec ~= tmp(:,1:3) due to floating point rounding only. 0046 % Similarly, head space (electrodes) into MRI coordinates: 0047 % tmp = [ reg.Helec ones(size(reg.Helec,1),1) ] * reg.elec2mri; 0048 % Note reg.Melec ~= tmp(:,1:3) due to floating point rounding only. 0049 % 0050 % EMSE Note: The origin in the head frame is at or near the center of 0051 % the skull, while the origin in the image frame is located at the 0052 % bottom right front corner of the bounding box (and so would be 0053 % located at the upper left corner of the first axial slice as 0054 % displayed by MR Viewer). 0055 % 0056 % A useful chapter on homogeneous coordinates, among other things, 0057 % may be found in Mortenson, M. (1985, Chpt. 8), Geometric Modelling, 0058 % New York: John Wiley & Sons. 0059 % 0060 0061 0062 % $Revision: 1.1 $ $Date: 2004/11/12 01:32:34 $ 0063 0064 % Licence: GNU GPL, no express or implied warranties 0065 % History: 06/2002, Darren.Weber@flinders.edu.au 0066 % 09/2002, Darren.Weber@flinders.edu.au 0067 % - transposed HeadToImageMatrix so it 0068 % can be used as described above 0069 % - added reading of most other fields 0070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0071 0072 0073 if ~exist('file','var'), 0074 fprintf('No input file - see help open_emse_reg\n'); 0075 return; 0076 end 0077 0078 [path,name,ext] = fileparts(file); 0079 file = fullfile(path,[name ext]); 0080 0081 [fid,msg] = fopen(file,'r'); 0082 if ~isempty(msg), error(msg); end 0083 0084 fprintf('OPEN_EMSE_REG: Reading registration data...'); 0085 tic 0086 fid = fopen(file,'r','ieee-le'); 0087 reg = read_reg(fid); 0088 fclose(fid); 0089 t = toc; 0090 fprintf('done (%6.2f sec).\n',t); 0091 0092 return 0093 0094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0096 function [reg] = read_reg(fid) 0097 0098 while 1, 0099 text = fgetl(fid); 0100 if ~ischar(text), break, end 0101 0102 if strmatch('Offset',text), 0103 % Offset is the translation in meters along the x, y and z axes 0104 % respectively, from the MRI image frame to head/elec frame. 0105 text = strrep(text,sscanf(text,'%c',8),''); 0106 text = strrep(text,']',''); 0107 text = strrep(text,',',''); 0108 reg.translation = sscanf(text,'%f')'; 0109 end 0110 if strmatch('Rotation',text), 0111 % The Rotation vector contains the angles (in radians) about 0112 % the x, y and z axes, also from the MRI image frame to the 0113 % head/elec frame. 0114 text = strrep(text,sscanf(text,'%c',10),''); 0115 text = strrep(text,']',''); 0116 text = strrep(text,',',''); 0117 reg.rotation = sscanf(text,'%f')'; 0118 end 0119 if strmatch('HeadToImageMatrix',text), 0120 reg.elec2mri = zeros(4,4); 0121 for i=1:4, 0122 text = fgetl(fid); 0123 reg.elec2mri(i,:) = sscanf(text,'%f')'; 0124 end 0125 % The emse matrix requires transposition 0126 reg.elec2mri = reg.elec2mri'; 0127 % It is more accurate to do this: 0128 reg.mri2elec = inv(reg.elec2mri); 0129 end 0130 % See inverse calculation above to get reg.mri2elec 0131 %if strmatch('ImageToHeadMatrix',text), 0132 % reg.mri2elec = zeros(4,4); 0133 % for i=1:4, 0134 % text = fgetl(fid); 0135 % reg.mri2elec(i,:) = sscanf(text,'%f')'; 0136 % end 0137 % % The emse matrix requires transposition 0138 % reg.mri2elec = reg.mri2elec'; 0139 %end 0140 0141 % The coordinates of the three fiducials are given in both frames. 0142 % For example, Head lists the fiducial coordinates (taken from the 0143 % electrode data) in the head frame, while Head' are the fiducial 0144 % coordinates from the image data expressed in the head frame. 0145 % Similarly, Image lists the fiducial coordinates from the image 0146 % data in the image frame while Image' lists those from the electrode 0147 % data in the image frame. The two sets of numbers should be close but 0148 % not identical. 0149 0150 if strmatch('RPA',text,'exact'), 0151 format = '%7c %f %f %f'; 0152 % Read the Right Preauricular coordinates 0153 text = fgetl(fid); 0154 tmp = sscanf(text,format)'; 0155 reg.RPA.Hh = tmp(8:10); 0156 text = fgetl(fid); 0157 tmp = sscanf(text,format)'; 0158 reg.RPA.Mh = tmp(8:10); 0159 text = fgetl(fid); 0160 tmp = sscanf(text,format)'; 0161 reg.RPA.Mm = tmp(8:10); 0162 text = fgetl(fid); 0163 tmp = sscanf(text,format)'; 0164 reg.RPA.Hm = tmp(8:10); 0165 end 0166 0167 if strmatch('LPA',text,'exact'), 0168 format = '%7c %f %f %f'; 0169 % Read the Left Preauricular coordinates 0170 text = fgetl(fid); 0171 tmp = sscanf(text,format)'; 0172 reg.LPA.Hh = tmp(8:10); 0173 text = fgetl(fid); 0174 tmp = sscanf(text,format)'; 0175 reg.LPA.Mh = tmp(8:10); 0176 text = fgetl(fid); 0177 tmp = sscanf(text,format)'; 0178 reg.LPA.Mm = tmp(8:10); 0179 text = fgetl(fid); 0180 tmp = sscanf(text,format)'; 0181 reg.LPA.Hm = tmp(8:10); 0182 end 0183 0184 if strmatch('Nasion',text,'exact'), 0185 format = '%7c %f %f %f'; 0186 % Read the Nasion coordinates 0187 text = fgetl(fid); 0188 tmp = sscanf(text,format)'; 0189 reg.NAS.Hh = tmp(8:10); 0190 text = fgetl(fid); 0191 tmp = sscanf(text,format)'; 0192 reg.NAS.Mh = tmp(8:10); 0193 text = fgetl(fid); 0194 tmp = sscanf(text,format)'; 0195 reg.NAS.Mm = tmp(8:10); 0196 text = fgetl(fid); 0197 tmp = sscanf(text,format)'; 0198 reg.NAS.Hm = tmp(8:10); 0199 end 0200 0201 % The Electrode Positions block lists the coordinates (x, y, and z) 0202 % first in the head frame and then in the image frame. 0203 if strmatch('Electrode Positions',text), 0204 reg.Helec = zeros(1,3); 0205 reg.Melec = zeros(1,3); 0206 n = 1; 0207 while n < 400, 0208 % Read the Head space coordinates 0209 text = fgetl(fid); 0210 if isempty(text), break; end 0211 tmp = sscanf(text,'%f : %f %f')'; 0212 reg.Helec(n,1:3) = tmp(2:4); 0213 % Read the MRI space coordinates 0214 text = fgetl(fid); 0215 tmp = sscanf(text,'%s %f %f %f')'; 0216 reg.Melec(n,1:3) = tmp(2:4); 0217 n = n + 1; 0218 end 0219 end 0220 0221 end 0222 0223 % Create essential fiducial marker matrices 0224 % The order of these points in the matrices is very 0225 % important if they are used for coregistration 0226 reg.fiducials.head = [ reg.NAS.Hh; reg.RPA.Hh; reg.LPA.Hh ]; 0227 reg.fiducials.mri = [ reg.NAS.Mm; reg.RPA.Mm; reg.LPA.Mm ]; 0228 0229 0230 return