ODIN
gencoil.cpp
1 #include <odinpara/reco.h>
2 
3 #include <odindata/image.h>
4 #include <odindata/data.h>
5 #include <odindata/gridding.h>
6 #include <odindata/fitting.h>
7 
14 void usage() {
15  STD_cout << STD_endl;
16  STD_cout << "gencoil: Generates a virtual coil suitable for sequence simulation in ODIN" << STD_endl;
17  STD_cout << configInfo() << STD_endl;
18  STD_cout << STD_endl;
19  STD_cout << "Usage and options:" << STD_endl;
20  STD_cout << " Generate a radially inhomogenous coil:" << STD_endl;
21  STD_cout << " gencoil -rad -n <inplane-size> -fov <FOV> -R <radial-inhomogeneity[%]> -o <Coil-file>" << STD_endl;
22  STD_cout << " Generate an array coil by rotating pre-existing image file:" << STD_endl;
23  STD_cout << " gencoil -rot -n <inplane-size> -fov <FOV> -nc <numof-rotated-subcoils> -i <input-image> -sl <selected-slice> -o <Coil-file>" << STD_endl;
24  STD_cout << " Generate an array coil consisting of simple loops:" << STD_endl;
25  STD_cout << " gencoil -arr -n <inplane-size> -nc <numof-rotated-loops> -fov <FOV> -R <array-radius> -o <Coil-file>" << STD_endl;
26  STD_cout << " Generate coil with a B1 gradient:" << STD_endl;
27  STD_cout << " gencoil -grad -n <inplane-size> -fov <FOV> -g <B1-gradient-endpoint> -o <Coil-file>" << STD_endl;
28  STD_cout << "Other options:" << STD_endl;
29  STD_cout << "\t" << LogBase::get_usage() << STD_endl;
30  STD_cout << "\t" << helpUsage() << STD_endl;
31 }
32 
33 int main(int argc, char* argv[]) {
34  LogBase::set_log_levels(argc,argv);
35  Log<Para> odinlog("gencoil","main");
36 
37  if(hasHelpOption(argc,argv)) {usage(); return 0;}
38 
39  Range all=Range::all();
40 
41  char optval[ODIN_MAXCHAR];
42 
43  STD_string coil_fname;
44  if(getCommandlineOption(argc,argv,"-o",optval,ODIN_MAXCHAR)) coil_fname=optval; else {usage();exit(0);}
45 
46  CoilSensitivity sens("Coil Sensitivity");
47 
48  bool valid_mode=false;
49 
50 
52 
53  if(isCommandlineOption(argc,argv,"-rad")) {
54 
55  int n;
56  float R,fov;
57  if(getCommandlineOption(argc,argv,"-n",optval,ODIN_MAXCHAR)) n=atoi(optval); else {usage();exit(0);}
58  if(getCommandlineOption(argc,argv,"-R",optval,ODIN_MAXCHAR)) R=0.01*atof(optval); else {usage();exit(0);}
59  if(getCommandlineOption(argc,argv,"-fov",optval,ODIN_MAXCHAR)) fov=atof(optval); else {usage();exit(0);}
60 
61  carray sens_map(1,1,n,n);
62 
63  int nx_center=n/2;
64  int ny_center=n/2;
65 
66  double a=-4.0*R;
67  double c=1.0+R;
68 
69  STD_complex b1factor;
70 
71  ndim nn=sens_map.get_extent();
72  ndim indexvec;
73 
74  for(unsigned int i=0; i<nn.total(); i++) {
75  indexvec=nn.index2extent(i);
76 
77  int ix=indexvec[3];
78  int iy=indexvec[2];
79 
80  double rx=secureDivision(fabs(double(ix-nx_center)),nx_center);
81  double ry=secureDivision(fabs(double(iy-ny_center)),ny_center);
82  double radius=sqrt(rx*rx+ry*ry);
83 
84  double re=a*radius*radius+c;
85  if(re<0.0) re=0.0;
86 
87  b1factor=STD_complex(re,0.0);
88  sens_map(indexvec)=b1factor;
89  }
90 
91  sens.set_sensitivity_map(sens_map,fov,fov,fov);
92 
93  valid_mode=true;
94  }
95 
97 
98  if(isCommandlineOption(argc,argv,"-rot")) {
99 
100  int n,nc,sl;
101  float fov;
102  STD_string input_fname;
103  if(getCommandlineOption(argc,argv,"-n",optval,ODIN_MAXCHAR)) n=atoi(optval); else {usage();exit(0);}
104  if(getCommandlineOption(argc,argv,"-nc",optval,ODIN_MAXCHAR)) nc=atoi(optval); else {usage();exit(0);}
105  if(getCommandlineOption(argc,argv,"-fov",optval,ODIN_MAXCHAR)) fov=atof(optval); else {usage();exit(0);}
106  if(getCommandlineOption(argc,argv,"-i",optval,ODIN_MAXCHAR)) input_fname=optval; else {usage();exit(0);}
107  if(getCommandlineOption(argc,argv,"-sl",optval,ODIN_MAXCHAR)) sl=atoi(optval); else {usage();exit(0);}
108 
109  Image img;
110  ODINLOG(odinlog,infoLog) << "Loading image file ... " << STD_endl;
111  if(img.load(input_fname)<0) {
112  ODINLOG(odinlog,errorLog) << "unable to load ODIN image file " << input_fname << STD_endl;
113  return -1;
114  }
115 
116  TinyMatrix<float,2,2> rotation;
117  TinyVector<float,2> offset;
118  offset=0.0;
119 
120  carray sens_map(nc,1,n,n);
121 
122  Data<float,4> imgdata(img.get_magnitude());
123 
124  TinyVector<int,2> newshape(n,n);
125 
126  ODINLOG(odinlog,infoLog) << "Congridding map ... " << STD_endl;
127  Data<float,2> onecoil=imgdata(0,sl,all,all);
128  onecoil.congrid(newshape);
129  float maxmap=max(onecoil);
130  float sum=0.0;
131  float nvals=0.0;
132  for(unsigned int i=0; i<onecoil.numElements(); i++) {
133  float val=onecoil(onecoil.create_index(i));
134  if(val>0.1*maxmap) {
135  sum+=val;
136  nvals+=1.0;
137  }
138  }
139  float mean=sum/nvals;
140  onecoil/=(2.0*mean); // factor to account for overlapping adjacent coils
141 
142 
143  ODINLOG(odinlog,infoLog) << "Polynomial fit ... " << STD_endl;
144  onecoil=polyniomial_fit(onecoil,onecoil,2,6.0);
145 
146  Data<float,2> onecoil_transform(newshape);
147 
148 
149  for(int ic=0; ic<nc; ic++) {
150  ODINLOG(odinlog,infoLog) << "Rotating coil " << ic << " ... " << STD_endl;
151  float phi=2.0*PII*float(ic)/float(nc);
152  rotation(0,0)=cos(phi); rotation(0,1)=sin(phi);
153  rotation(1,0)=-sin(phi); rotation(1,1)=cos(phi);
154 
155  CoordTransformation<float,2> rotate(onecoil_transform.shape(), rotation, offset, 2.0);
156  onecoil_transform=rotate(onecoil);
157 
158  for(int iy=0; iy<n; iy++) {
159  for(int ix=0; ix<n; ix++) {
160  sens_map(ic,0,iy,ix)=STD_complex(onecoil_transform(iy,ix));
161  }
162  }
163  }
164 
165  sens.set_sensitivity_map(sens_map,fov,fov,fov);
166 
167  valid_mode=true;
168  }
169 
170 
172 
173 
174  if(isCommandlineOption(argc,argv,"-arr")) {
175 
176  int n,nc;
177  float fov,R;
178  if(getCommandlineOption(argc,argv,"-n",optval,ODIN_MAXCHAR)) n=atoi(optval); else {usage();exit(0);}
179  if(getCommandlineOption(argc,argv,"-nc",optval,ODIN_MAXCHAR)) nc=atoi(optval); else {usage();exit(0);}
180  if(getCommandlineOption(argc,argv,"-fov",optval,ODIN_MAXCHAR)) fov=atof(optval); else {usage();exit(0);}
181  if(getCommandlineOption(argc,argv,"-R",optval,ODIN_MAXCHAR)) R=atof(optval); else {usage();exit(0);}
182 
183 
184  carray sens_map(nc,1,n,n);
185 
186  int nx_center=n/2;
187  int ny_center=n/2;
188 
189  ndim nn=sens_map.get_extent();
190  ndim indexvec;
191 
192  float overlap=2.0;
193  float loopR=overlap*PII*R/float(nc); //estimate sub-loop size from overall radius and num of sub-loops
194 
195 
196  Array<float,2> rotmat[nc];
197  Array<float,1> offset[nc];
198 
199  ODINLOG(odinlog,infoLog) << "Preparing rotmat/offset ... " << STD_endl;
200  for(int icoil=0; icoil<nc; icoil++) {
201  float ang=2.0*PII*float(icoil)/float(nc);
202 
203  rotmat[icoil].resize(3,3);
204  rotmat[icoil]=0.0;
205  rotmat[icoil](0,0)=cos(ang); rotmat[icoil](0,1)=-sin(ang);
206  rotmat[icoil](1,0)=sin(ang); rotmat[icoil](1,1)=cos(ang);
207  rotmat[icoil](2,2)=1.0;
208 
209  offset[icoil].resize(3);
210  offset[icoil](0)=R*cos(ang);
211  offset[icoil](1)=R*sin(ang);
212  offset[icoil](2)=0.0;
213  }
214 
215 
216  ODINLOG(odinlog,infoLog) << "Calculating sens_map ..." << STD_endl;
217  for(unsigned int i=0; i<nn.total(); i++) {
218  indexvec=nn.index2extent(i);
219 
220  int icoil=indexvec[0];
221  int iy=indexvec[2];
222  int ix=indexvec[3];
223 
224  Array<float,1> x(3);
225  x(0)=fov*secureDivision(double(ix-nx_center),nx_center);
226  x(1)=fov*secureDivision(double(iy-ny_center),ny_center);
227  x(2)=0.0;
228 
229 
230  int nloopsegments=100;
231  float dphi=2.0*PII/nloopsegments;
232  Array<float,1> dl(3);
233  Array<float,1> r(3);
234  Array<float,1> r0(3);
235  Array<float,1> dB(3);
236  STD_complex B1(0.0);
237  for(int iseg=0; iseg<nloopsegments; iseg++) {
238  float phi=2.0*PII*float(iseg)/float(nloopsegments);
239  dl(0)=0.0;
240  dl(1)= loopR*cos(phi)*dphi;
241  dl(2)=-loopR*sin(phi)*dphi;
242 
243  dl=matrix_product(rotmat[icoil], dl);
244 
245  r0(0)=0.0;
246  r0(1)=loopR*sin(phi);
247  r0(2)=loopR*cos(phi);
248 
249  r0=matrix_product(rotmat[icoil], r0) + offset[icoil];
250 
251  r=x-r0;
252 
253  dB=vector_product(dl,r);
254 
255  float r2=sum(r*r);
256  if(r2>0.0) {
257  B1+=STD_complex(dB(0),dB(1))/r2;
258  }
259 
260  }
261  sens_map(indexvec)=B1/float(2.0*PII); // will be normalized to ~ 1 at center of loop
262  }
263 
264  sens.set_sensitivity_map(sens_map,fov,fov,fov);
265 
266 
267 
268  valid_mode=true;
269  }
270 
271 
273 
274  if(isCommandlineOption(argc,argv,"-grad")) {
275 
276  int n;
277  float fov,grad;
278  if(getCommandlineOption(argc,argv,"-n",optval,ODIN_MAXCHAR)) n=atoi(optval); else {usage();exit(0);}
279  if(getCommandlineOption(argc,argv,"-g",optval,ODIN_MAXCHAR)) grad=atof(optval); else {usage();exit(0);}
280  if(getCommandlineOption(argc,argv,"-fov",optval,ODIN_MAXCHAR)) fov=atof(optval); else {usage();exit(0);}
281 
282  carray sens_map(1,1,n,n);
283 
284  int nx_center=n/2;
285 
286  ndim nn=sens_map.get_extent();
287  ndim indexvec;
288 
289  for(unsigned int i=0; i<nn.total(); i++) {
290  indexvec=nn.index2extent(i);
291  int ix=indexvec[3];
292  sens_map(indexvec)=STD_complex(1.0+grad*float(ix-nx_center)/float(nx_center),0.0);
293  }
294 
295  sens.set_sensitivity_map(sens_map,fov,fov,fov);
296 
297  valid_mode=true;
298  }
299 
300 
301 
302  if(!valid_mode) {usage();exit(0);}
303 
304  ODINLOG(odinlog,infoLog) << "Writing coil file ... " << STD_endl;
305  sens.write(coil_fname);
306 
307  return 0;
308 }
void congrid(const TinyVector< int, N_rank > &newshape, const TinyVector< float, N_rank > *subpixel_shift=0, bool left_to_right=false)
TinyVector< int, N_rank > create_index(unsigned long index) const
Definition: image.h:37
const farray & get_magnitude() const
Definition: image.h:69
int load(const STD_string &filename, const LDRserBase &serializer=LDRserJDX())
static bool set_log_levels(int argc, char *argv[], bool trigger_error=true)
static STD_string get_usage()
Definition: tjlog.h:218
Definition: tjarray.h:41
unsigned long total() const
ndim index2extent(unsigned long index) const
Array< float, N_rank > polyniomial_fit(const Array< float, N_rank > &value_map, const Array< float, N_rank > &reliability_map, unsigned int polynom_order, float kernel_size, bool only_zero_reliability=false)
Definition: fitting.h:554
Array< T, 1 > vector_product(const Array< T, 1 > &u, const Array< T, 1 > &v)
Definition: utils.h:109
Array< T, 1 > matrix_product(const Array< T, 2 > &matrix, const Array< T, 1 > &vector)
Definition: utils.h:42
const char * configInfo()
int isCommandlineOption(int argc, char *argv[], const char *option, bool modify=true)
double secureDivision(double numerator, double denominator)
int hasHelpOption(int argc, char *argv[])
int getCommandlineOption(int argc, char *argv[], const char *option, char *returnvalue, int maxchar, bool modify=true)
const char * helpUsage()