Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
264 | f9daq | 1 | // |
2 | // ../bin/FBP2D FBP2D.par |
||
3 | // |
||
4 | // ******************************************************************** |
||
5 | // * License and Disclaimer * |
||
6 | // * * |
||
7 | // * The GAMOS software is copyright of the Copyright Holders of * |
||
8 | // * the GAMOS Collaboration. It is provided under the terms and * |
||
9 | // * conditions of the GAMOS Software License, included in the file * |
||
10 | // * LICENSE and available at http://fismed.ciemat.es/GAMOS/license .* |
||
11 | // * These include a list of copyright holders. * |
||
12 | // * * |
||
13 | // * Neither the authors of this software system, nor their employing * |
||
14 | // * institutes,nor the agencies providing financial support for this * |
||
15 | // * work make any representation or warranty, express or implied, * |
||
16 | // * regarding this software system or assume any liability for its * |
||
17 | // * use. Please see the license in the file LICENSE and URL above * |
||
18 | // * for the full disclaimer and the limitation of liability. * |
||
19 | // * * |
||
20 | // * This code implementation is the result of the scientific and * |
||
21 | // * technical work of the GAMOS collaboration. * |
||
22 | // * By using, copying, modifying or distributing the software (or * |
||
23 | // * any work based on the software) you agree to acknowledge its * |
||
24 | // * use in resulting scientific publications, and indicate your * |
||
25 | // * acceptance of all terms of the GAMOS Software license. * |
||
26 | // ******************************************************************** |
||
27 | // |
||
28 | #include "PETProjDataMgr.h" |
||
29 | |||
30 | |||
31 | static struct PETProjDataMgr mgr; |
||
32 | |||
33 | void SetNPlanes(int n) { |
||
34 | mgr.m_NOfPlanes=n; |
||
35 | }; |
||
36 | void SetNBin(int n) { |
||
37 | mgr.m_NOfBins=n; |
||
38 | }; |
||
39 | void SetNAng(int n) { |
||
40 | mgr.m_NOfAngles=n; |
||
41 | }; |
||
42 | void SetDebug(int n) { |
||
43 | mgr.m_Debug=n; |
||
44 | }; |
||
45 | void SetNumberOfChannels(int n) { |
||
46 | mgr.m_nch=n; |
||
47 | }; |
||
48 | |||
49 | void SetRingDiameter( double x) { |
||
50 | mgr.m_RingDiameter = x; |
||
51 | }; |
||
52 | void SetAxialDistance( double x) { |
||
53 | mgr.m_AxialDistance = x; |
||
54 | }; |
||
55 | |||
56 | //---------------------------------------------------------------------- |
||
57 | |||
58 | //---------------------------------------------------------------------- |
||
59 | struct PETProjDataMgr *GetInstance() { |
||
60 | |||
61 | |||
62 | return &mgr; |
||
63 | |||
64 | } |
||
65 | |||
66 | //----------------------------------------------------------------------- |
||
67 | int PETProjDataMgrInit() { |
||
68 | |||
69 | /* |
||
70 | // ARGUMENTS: |
||
71 | " cout << " -------------------------- \n" |
||
72 | " Arguments convention: \n" |
||
73 | " -a Axial FOV (mm), <theDist_axial=100.0> \n" |
||
74 | " -d Diameter Transaxial FOV (mm), <m_RingDiameter=300.0> \n" |
||
75 | " -i Type of the input file (by default: 0 = Arce_binary), <typeINfile=0> \n" |
||
76 | " \n" |
||
77 | " -m Maximum ring difference (by default: -1 = m_NOfPlanes), <m_MaxRingDifferenceiff> \n" |
||
78 | " -n Name of output file, <m_Filename> \n" |
||
79 | " -p Axial number of planes, <m_NOfPlanes> \n" |
||
80 | " -r Number of bins, \"distancias\", <m_NOfBins> \n" |
||
81 | // -s Span TO DO:span !!!!! |
||
82 | " -t Number of angular views, \"direcciones\", <m_NOfAngles> \n" |
||
83 | " -v Verbosity (by default: 0=silent, 3=debug), <verbos> \n" |
||
84 | " -x Maximum number of coincidences to be stored (by default: -1 = no limit), <Max_Coinci> \n" |
||
85 | " -o Output type (by default: 0 = mcc Interfile, 1 = STIR Interfile), <OutType> \n" |
||
86 | |||
87 | " \n" |
||
88 | " PET Reconstruction. CIEMAT 2009-11 \n" |
||
89 | " mario.canadas@ciemat.es \n" |
||
90 | " -------------------------- \n"; |
||
91 | */ |
||
92 | |||
93 | mgr.m_AxialDistance = (9-1)*2.25; // Axial pixel dimension*NOfPlanes |
||
94 | mgr.m_RingDiameter = 100.0; // notranji premer peta |
||
95 | mgr.m_NOfPlanes = 9; // stevilo ravnin |
||
96 | mgr.m_NOfBins = 128; // stevilo binov v razdalji |
||
97 | mgr.m_nch = 128; // stevilo padov okoli in okoli |
||
98 | mgr.m_NOfAngles = fabs(mgr.m_nch)/2; // stevilo kotov = stevilo padov okoli in okoli /2 |
||
99 | |||
100 | mgr.m_MaxRingDifference = -1; |
||
101 | //mgr.m_MaxRingDifference = 3; // najvecja razdalja med padi |
||
102 | // toDo: theSpan = int(GmParameterMgr::GetInstance()->GetNumericValue("PET:ProjData:Span",1)); |
||
103 | |||
104 | |||
105 | mgr.m_OutFormat = 1; // 1.. projections 0 .. image |
||
106 | |||
107 | mgr.m_Debug=1; |
||
108 | |||
109 | if (mgr.m_MaxRingDifference==-1) mgr.m_MaxRingDifference=mgr.m_NOfPlanes-1; |
||
110 | |||
111 | |||
112 | mgr.m_TotalAxialPlanes=mgr.m_NOfPlanes*mgr.m_NOfPlanes; |
||
113 | if (mgr.m_OutFormat==1) mgr.m_TotalAxialPlanes= (2*mgr.m_NOfPlanes-1 - mgr.m_MaxRingDifference)*mgr.m_MaxRingDifference + mgr.m_NOfPlanes; // total number of Axial planes (segments*planes) in STIR format |
||
114 | |||
115 | /*--- Initialize sino3D ---*/ |
||
116 | mgr.m_projections = (SINO_TYPE ** *) malloc(mgr.m_NOfBins*sizeof(SINO_TYPE **)); |
||
117 | for(int i=0; i<mgr.m_NOfBins; i++) { |
||
118 | mgr.m_projections[i] = (SINO_TYPE **) malloc(mgr.m_NOfAngles*sizeof(SINO_TYPE *)); |
||
119 | for(int j=0; j<mgr.m_NOfAngles; j++) { |
||
120 | mgr.m_projections[i][j] = (SINO_TYPE *) malloc(mgr.m_TotalAxialPlanes *sizeof(SINO_TYPE)); /// ! If mgr.m_OutFormat==1 (STIR output):Matrix size depends on the MAX_Ring_Difference |
||
121 | for(int k=0; k<mgr.m_TotalAxialPlanes; k++) { |
||
122 | mgr.m_projections[i][j][k]=0; |
||
123 | } |
||
124 | } |
||
125 | } |
||
126 | |||
127 | mgr.m_TotalProjectionCoincidences=0; |
||
128 | mgr.m_TotalCoincidences=0; |
||
129 | //OutputType = "pet"; |
||
130 | return 0; |
||
131 | } |
||
132 | |||
133 | //----------------------------------------------------------------------- |
||
134 | void SetProjection( int axialplane, int id) { |
||
135 | for(int i=0; i<mgr.m_NOfBins; i++) { |
||
136 | for(int j=0; j<mgr.m_NOfAngles; j++) { |
||
137 | mgr.m_projections[i][j][axialplane]=H2D_GetBinContent(id,i+1,j+1); |
||
138 | } |
||
139 | } |
||
140 | |||
141 | } |
||
142 | //----------------------------------------------------------------------- |
||
143 | |||
144 | //----------------------------------------------------------- |
||
145 | // from Gate |
||
146 | //------------------------------------------------------------ |
||
147 | double ComputeSinogramS(double X1, double Y1, double X2, double Y2) { |
||
148 | double s; |
||
149 | |||
150 | double denom = (Y1-Y2) * (Y1-Y2) + (X2-X1) * (X2-X1); |
||
151 | |||
152 | if (denom!=0.) { |
||
153 | denom = sqrt(denom); |
||
154 | s = ( X1 * (Y2-Y1) + Y1 * (X1-X2) ) / denom; |
||
155 | } else { |
||
156 | s = 0.; |
||
157 | } |
||
158 | |||
159 | double theta; |
||
160 | if ((X1-X2)!=0.) { |
||
161 | theta=atan((X1-X2) /(Y1-Y2)); |
||
162 | } else { |
||
163 | theta=3.1416/2.; |
||
164 | } |
||
165 | if ((theta > 0.) && ((X1-X2) > 0.)) s = -s; |
||
166 | if ((theta < 0.) && ((X1-X2) < 0.)) s = -s; |
||
167 | if ( theta < 0.) { |
||
168 | theta = theta+3.1416; |
||
169 | s = -s; |
||
170 | } |
||
171 | return s; |
||
172 | } |
||
173 | |||
174 | |||
175 | void AddEvent( const HVector3 pos1 , const HVector3 pos2) { |
||
176 | int z1_i, z2_i; |
||
177 | //for discretization on the crystal: int x1_i, x2_i, y1_i, y2_i; |
||
178 | |||
179 | double z1_abs=pos1.x[2]+mgr.m_AxialDistance/2; |
||
180 | double z2_abs=pos2.x[2]+mgr.m_AxialDistance/2; |
||
181 | double a, b, phi, dis; |
||
182 | int phi_i, dis_i; |
||
183 | int ring_diff; |
||
184 | |||
185 | double _PI=2*asin(1); |
||
186 | |||
187 | mgr.m_TotalCoincidences++; |
||
188 | |||
189 | z1_i=(int)(mgr.m_NOfPlanes* z1_abs/mgr.m_AxialDistance); //round --> mgr.m_NOfPlanes+1 ... |
||
190 | z2_i=(int)(mgr.m_NOfPlanes* z2_abs/mgr.m_AxialDistance); |
||
191 | |||
192 | // control; if z_i out of range: return |
||
193 | |||
194 | if ( (pos1.x[0]==pos2.x[0]) && (pos1.x[1]==pos2.x[1]) ) { |
||
195 | #ifndef GAMOS_NO_VERBOSE |
||
196 | if( mgr.m_Debug ) { |
||
197 | printf( "AddEvent:WARNING! Event_1 == Event_2 ; x= %f y= %f z= %f\n", pos2.x[0], pos2.x[1], pos2.x[2] ); |
||
198 | } |
||
199 | #endif |
||
200 | return; |
||
201 | } |
||
202 | |||
203 | if ( (z1_i<0) || (z2_i<0) || (z1_i>= mgr.m_NOfPlanes) || (z2_i>= mgr.m_NOfPlanes) ) { |
||
204 | #ifndef GAMOS_NO_VERBOSE |
||
205 | if( mgr.m_Debug ) { |
||
206 | printf("PETProjDataMgr::AddEvent:WARNING! Event out of bounds (Axial):"); |
||
207 | printf( "x1= %f y1= %f z1= %f ", pos1.x[0], pos1.x[1], pos1.x[2] ); |
||
208 | printf( "x2= %f y2= %f z2= %f \n", pos2.x[0], pos2.x[1], pos2.x[2] ); |
||
209 | } |
||
210 | #endif |
||
211 | return; |
||
212 | } |
||
213 | |||
214 | ring_diff = (int)fabs(z1_i-z2_i); |
||
215 | |||
216 | // max ring difference; control: |
||
217 | if (ring_diff > mgr.m_MaxRingDifference) { |
||
218 | #ifndef GAMOS_NO_VERBOSE |
||
219 | if( mgr.m_Debug ) { |
||
220 | printf("PETProjDataMgr::AddEvent:WARNING! Event out of bounds (Max. Ring Diff.): %f>%f",ring_diff , mgr.m_MaxRingDifference ); |
||
221 | printf( "x1= %f y1= %f z1= %f ", pos1.x[0], pos1.x[1], pos1.x[2] ); |
||
222 | printf( "x2= %f y2= %f z2= %f \n", pos2.x[0], pos2.x[1], pos2.x[2] ); |
||
223 | } |
||
224 | #endif |
||
225 | return; |
||
226 | } |
||
227 | |||
228 | a=(double)(pos2.x[1]- pos1.x[1]); |
||
229 | b=(double)(pos2.x[0]- pos1.x[0]); |
||
230 | |||
231 | if (a==0.0) { |
||
232 | phi=_PI*0.5; |
||
233 | } else { |
||
234 | phi=atan(b/a); |
||
235 | } |
||
236 | |||
237 | if (phi<0) phi = phi +_PI; |
||
238 | |||
239 | dis=pos1.x[0]*cos(phi) - pos1.x[1]*sin(phi); |
||
240 | //dis=ComputeSinogramS(pos1.x(), pos1.y(), pos2.x(), pos2.x()); |
||
241 | // control; transaxial FOV |
||
242 | if ( fabs(dis) > mgr.m_RingDiameter*0.5 ) { |
||
243 | #ifndef GAMOS_NO_VERBOSE |
||
244 | if( mgr.m_Debug ) { |
||
245 | printf("PETProjDataMgr::AddEvent:WARNING! Event out of bounds (Transaxial):" ); |
||
246 | printf( "x1= %f y1= %f z1= %f ", pos1.x[0], pos1.x[1], pos1.x[2] ); |
||
247 | printf( "x2= %f y2= %f z2= %f \n", pos2.x[0], pos2.x[1], pos2.x[2] ); |
||
248 | } |
||
249 | #endif |
||
250 | return; |
||
251 | } |
||
252 | |||
253 | dis = dis + mgr.m_RingDiameter*0.5; |
||
254 | |||
255 | // discret values: |
||
256 | phi_i=RoundRealToNearestInteger( (double)(mgr.m_NOfAngles-1)*phi/_PI ); |
||
257 | dis_i=RoundRealToNearestInteger( (double)(mgr.m_NOfBins-1)*dis/(double)mgr.m_RingDiameter ); |
||
258 | |||
259 | if ((phi_i>=mgr.m_NOfAngles) || (dis_i>=mgr.m_NOfBins)) return; // only possible "=" because 'round' check it.. |
||
260 | |||
261 | // OLD: (SRRB included) sino3D[dis_i][phi_i][ (z1_i+z2_i)+ring_diff*(mgr.m_NOfPlanes-1) ]++; |
||
262 | |||
263 | int Zpos; |
||
264 | |||
265 | if (mgr.m_OutFormat==0) { |
||
266 | Zpos = (z1_i*mgr.m_NOfPlanes + z2_i); |
||
267 | } else { |
||
268 | |||
269 | if (z1_i>=z2_i) { // SIN Max Ring_Diff: Zpos= ( ((mgr.m_NOfPlanes-ring_diff)*(mgr.m_NOfPlanes-1-ring_diff))/2 + z2_i ); |
||
270 | |||
271 | Zpos= ( ((2*mgr.m_NOfPlanes-1 - mgr.m_MaxRingDifference - ring_diff)*(mgr.m_MaxRingDifference - ring_diff))/2 + z2_i); |
||
272 | |||
273 | } else { |
||
274 | Zpos= ( (mgr.m_TotalAxialPlanes) - ((2*mgr.m_NOfPlanes-1 - mgr.m_MaxRingDifference - ring_diff +1)*(mgr.m_MaxRingDifference - ring_diff +1))/2 + z1_i ); |
||
275 | |||
276 | } |
||
277 | } |
||
278 | |||
279 | mgr.m_projections[dis_i][phi_i][ Zpos ]++; |
||
280 | mgr.m_TotalProjectionCoincidences++; |
||
281 | |||
282 | #ifndef GAMOS_NO_VERBOSE |
||
283 | if( mgr.m_Debug >1) { |
||
284 | printf("PETProjDataMgr::AddEvent:"); |
||
285 | printf( "x1= %f y1= %f z1= %f ", pos1.x[0], pos1.x[1], pos1.x[2] ); |
||
286 | printf( "x2= %f y2= %f z2= %f \n", pos2.x[0], pos2.x[1], pos2.x[2] ); |
||
287 | printf("PETProjDataMgr::AddEvent: Sinogram pos.: distance(s)= %f angular view(phi)= %f Zpos= %f Segment (Ring diff.) =%f\n" , dis_i , phi_i, Zpos , ring_diff ); |
||
288 | } |
||
289 | #endif |
||
290 | |||
291 | |||
292 | } |
||
293 | |||
294 | //----------------------------------------------------------------------- |
||
295 | void PETProjDataMgrFree() { |
||
296 | int i,j; |
||
297 | if (mgr.m_projections){ |
||
298 | for(i=0; i<mgr.m_NOfBins; i++) { |
||
299 | for(j=0; j<mgr.m_NOfAngles; j++) { |
||
300 | if (mgr.m_projections[i][j]) free(mgr.m_projections[i][j]); |
||
301 | mgr.m_projections[i][j]= NULL; |
||
302 | } |
||
303 | if (mgr.m_projections[i]) free(mgr.m_projections[i]); |
||
304 | mgr.m_projections[i]= NULL; |
||
305 | |||
306 | } |
||
307 | free(mgr.m_projections); |
||
308 | mgr.m_projections= NULL; |
||
309 | } |
||
310 | |||
311 | } |
||
312 | |||
313 | |||
314 | //----------------------------------------------------------------------- |
||
315 | void WriteInterfile(const char * Filename ) { |
||
316 | |||
317 | char name_hv[512]; |
||
318 | char name_v[512]; |
||
319 | FILE *fp; |
||
320 | if (mgr.m_OutFormat==0) { |
||
321 | |||
322 | strcpy(name_hv, Filename); |
||
323 | strcpy(name_v, Filename); |
||
324 | strcat(name_hv, ".hv"); |
||
325 | strcat(name_v, ".v"); |
||
326 | fp = fopen(name_hv, "w"); |
||
327 | |||
328 | fprintf (fp, "!INTERFILE := \n"); |
||
329 | fprintf (fp, "name of data file := %s\n", name_v); |
||
330 | fprintf (fp, "!GENERAL DATA := \n"); |
||
331 | fprintf (fp, "!GENERAL IMAGE DATA :=\n"); |
||
332 | fprintf (fp, "!type of data := tomographic\n"); |
||
333 | fprintf (fp, "!version of keys := 3.3\n"); |
||
334 | fprintf (fp, "!data offset in bytes := 0\n"); |
||
335 | fprintf (fp, "imagedata byte order := littleendian\n"); |
||
336 | fprintf (fp, "!PET STUDY (General) :=\n"); |
||
337 | fprintf (fp, "!PET data type := 3D-Sinogram\n"); |
||
338 | fprintf (fp, "process status := Reconstructed\n"); |
||
339 | fprintf (fp, "!number format := unsigned short\n"); |
||
340 | fprintf (fp, "!number of bytes per pixel := 2\n"); |
||
341 | fprintf (fp, "number of dimensions := 3\n"); |
||
342 | fprintf (fp, "matrix axis label [1] := x\n"); |
||
343 | fprintf (fp, "!matrix size [1] := %i\n",mgr.m_NOfBins); |
||
344 | fprintf (fp, "scaling factor (mm/pixel) [1] := %f\n",(float)(mgr.m_RingDiameter/(mgr.m_NOfBins-1.0))); |
||
345 | |||
346 | fprintf (fp, "matrix axis label [2] := y\n"); |
||
347 | fprintf (fp, "!matrix size [2] := %i\n",mgr.m_NOfAngles); |
||
348 | |||
349 | fprintf (fp, "scaling factor (degree/pixel) [2] := %f\n",(float)(360./mgr.m_NOfAngles)); |
||
350 | |||
351 | fprintf (fp, "matrix axis label [3] := z\n"); |
||
352 | fprintf (fp, "!matrix size [3] := %i\n",mgr.m_NOfPlanes*mgr.m_NOfPlanes); |
||
353 | fprintf (fp, "scaling factor (mm/pixel) [3] := %f\n",(float)(mgr.m_AxialDistance/(mgr.m_NOfPlanes-1.0))); |
||
354 | |||
355 | fprintf (fp, "number of slices := %i\n",mgr.m_NOfPlanes*mgr.m_NOfPlanes); |
||
356 | fprintf (fp, "number of time frames := 1\n"); |
||
357 | fprintf (fp, "image scaling factor[1] := 1\n"); |
||
358 | fprintf (fp, "data offset in bytes[1] := 0\n"); |
||
359 | fprintf (fp, "quantification units := 1\n"); |
||
360 | fprintf (fp, "!END OF INTERFILE := \n"); |
||
361 | |||
362 | fclose(fp); |
||
363 | //(size_t)(mgr.m_NOfBins*mgr.m_NOfAngles*mgr.m_NOfPlanes*mgr.m_NOfPlanes); |
||
364 | |||
365 | } else { |
||
366 | |||
367 | strcpy(name_hv, Filename); |
||
368 | strcpy(name_v, Filename); |
||
369 | |||
370 | strcat(name_hv, ".hs"); // STIR extension: .hs .s |
||
371 | strcat(name_v, ".s"); |
||
372 | fp =fopen(name_hv, "w"); |
||
373 | |||
374 | fprintf (fp, "!INTERFILE := \n"); |
||
375 | fprintf (fp, "name of data file := %s\n",name_v); |
||
376 | fprintf (fp, "!GENERAL DATA := \n"); |
||
377 | fprintf (fp, "!GENERAL IMAGE DATA :=\n"); |
||
378 | fprintf (fp, "!type of data := PET\n"); |
||
379 | // fprintf (fp, "!version of keys := 3.3\n"); STIR format is not 3.3 (almost but not completely), ERROR in STIR if it is not removed |
||
380 | // fprintf (fp, "!data offset in bytes := 0\n"); |
||
381 | fprintf (fp, "imagedata byte order := littleendian\n"); |
||
382 | fprintf (fp, "!PET STUDY (General) :=\n"); |
||
383 | fprintf (fp, "!PET data type := Emission\n"); |
||
384 | fprintf (fp, "applied corrections := {arc correction}\n"); // {none}\n"); |
||
385 | // fprintf (fp, "process status := Reconstructed\n"); |
||
386 | fprintf (fp, "!number format := unsigned integer\n"); |
||
387 | fprintf (fp, "!number of bytes per pixel := 2\n"); |
||
388 | |||
389 | fprintf (fp, "number of dimensions := 4\n"); |
||
390 | fprintf (fp, "matrix axis label [4] := segment\n"); |
||
391 | fprintf (fp, "!matrix size [4] := %i\n",mgr.m_MaxRingDifference*2 + 1); |
||
392 | // fprintf (fp, "scaling factor (mm/pixel) [1] := %f\n",(float)(d_FOV/(mgr.m_NOfBins-1))); |
||
393 | fprintf (fp, "matrix axis label [3] := axial coordinate\n"); |
||
394 | fprintf (fp, "!matrix size [3] := { "); |
||
395 | if (mgr.m_MaxRingDifference==0) { |
||
396 | fprintf (fp, "%i}\n", mgr.m_NOfPlanes); |
||
397 | } else { |
||
398 | int m; |
||
399 | for(m=mgr.m_NOfPlanes-mgr.m_MaxRingDifference; m<=mgr.m_NOfPlanes; m++) fprintf (fp, "%i,", m); |
||
400 | for(m=mgr.m_NOfPlanes-1; m>mgr.m_NOfPlanes-mgr.m_MaxRingDifference; m--) fprintf (fp, "%i,", m); |
||
401 | fprintf (fp, "%i}\n", mgr.m_NOfPlanes-mgr.m_MaxRingDifference); |
||
402 | } |
||
403 | fprintf (fp, "matrix axis label [2] := view\n"); |
||
404 | fprintf (fp, "!matrix size [2] := %i\n",mgr.m_NOfAngles); |
||
405 | fprintf (fp, "matrix axis label [1] := tangential coordinate\n"); |
||
406 | fprintf (fp, "!matrix size [1] := %i\n",mgr.m_NOfBins); |
||
407 | |||
408 | fprintf (fp, "minimum ring difference per segment := {"); // TO DO : add SPAN (mgr.m_MaxRingDifferenceiff per seg. variable) |
||
409 | fprintf (fp, "%i", -mgr.m_MaxRingDifference); |
||
410 | int m; |
||
411 | for(m=-mgr.m_MaxRingDifference+1; m<=mgr.m_MaxRingDifference; m++) fprintf (fp, ",%i", m); |
||
412 | fprintf (fp, "}\n"); |
||
413 | fprintf (fp, "maximum ring difference per segment := {"); // TO DO : add SPAN (mgr.m_MaxRingDifferenceiff per seg. variable) |
||
414 | fprintf (fp, "%i", -mgr.m_MaxRingDifference); |
||
415 | for(m=-mgr.m_MaxRingDifference+1; m<=mgr.m_MaxRingDifference; m++) fprintf (fp, ",%i", m); |
||
416 | fprintf (fp, "}\n"); |
||
417 | |||
418 | fprintf (fp, "inner ring diameter (cm) := %f\n", mgr.m_RingDiameter/10); // STIR Required parameter, now assigned to FOV (not detectors) |
||
419 | fprintf (fp, "average depth of interaction (cm) := 0.0001\n"); |
||
420 | fprintf (fp, "default bin size (cm) := %f\n",0.1*((float)mgr.m_RingDiameter/((float)mgr.m_NOfBins-1.0)) ); |
||
421 | fprintf (fp, "number of rings := %i\n",mgr.m_NOfPlanes ); |
||
422 | fprintf (fp, "distance between rings (cm) := %f\n", 0.1*((float)mgr.m_AxialDistance/(float)(mgr.m_NOfPlanes-1)) ); // Axial pixel dimension |
||
423 | |||
424 | fprintf (fp, "number of detectors per ring := %i\n",mgr.m_NOfAngles*2 ); |
||
425 | // fprintf (fp, "number of slices := %i\n",mgr.m_NOfPlanes*mgr.m_NOfPlanes); |
||
426 | fprintf (fp, "number of time frames := 1\n"); |
||
427 | fprintf (fp, "image scaling factor[1] := 1\n"); |
||
428 | fprintf (fp, "data offset in bytes[1] := 0\n"); |
||
429 | fprintf (fp, "quantification units := 1\n"); |
||
430 | fprintf (fp, "!END OF INTERFILE := \n"); |
||
431 | |||
432 | fclose(fp); |
||
433 | |||
434 | } |
||
435 | int mbsize = mgr.m_NOfBins*mgr.m_NOfAngles*mgr.m_TotalAxialPlanes*sizeof(SINO_TYPE); |
||
436 | mgr.m_Buffer = (SINO_TYPE *) malloc( mbsize ); |
||
437 | |||
438 | long unsigned int cont=0; |
||
439 | int i,j,k; |
||
440 | |||
441 | for(k=0; k<mgr.m_TotalAxialPlanes; k++) { |
||
442 | for(j=0; j<mgr.m_NOfAngles; j++) { |
||
443 | for(i=0; i<mgr.m_NOfBins; i++) { |
||
444 | mgr.m_Buffer[cont]=mgr.m_projections[i][j][k]; |
||
445 | cont++; |
||
446 | } |
||
447 | } |
||
448 | } |
||
449 | |||
450 | fp=fopen(name_v, "wb"); |
||
451 | |||
452 | //printf(4096*sizeof(SINO_TYPE) ); |
||
453 | int nb=fwrite(mgr.m_Buffer,1,mbsize, fp); |
||
454 | fclose(fp); |
||
455 | |||
456 | #ifndef GAMOS_NO_VERBOSE |
||
457 | printf("PETProjDataMgr::WriteInterfile: File name: %s\n", Filename ); |
||
458 | printf("PETProjDataMgr::WriteInterfile: Numer of bytes written: %d\n" , nb ); |
||
459 | printf("PETProjDataMgr::WriteInterfile: Planes = %d bins = %d ang_views = %d\n", mgr.m_NOfPlanes, mgr.m_NOfBins, mgr.m_NOfAngles ); |
||
460 | printf("PETProjDataMgr::WriteInterfile: Dimensions (mm): Transaxial FOV = %f ; Axial FOV = %f ; Transaxial_pix =%f ; Plane width = %f\n", mgr.m_RingDiameter , mgr.m_AxialDistance , mgr.m_RingDiameter/(mgr.m_NOfBins-1) , mgr.m_AxialDistance/(mgr.m_NOfPlanes-1) ); // Image Axial Pixel(ssrb) == 0.5*(Plane_Width); |
||
461 | printf("... " ); |
||
462 | |||
463 | printf("PETProjDataMgr::WriteInterfile: Total Coinci: %d\n" , mgr.m_TotalCoincidences ); |
||
464 | printf("PETProjDataMgr::WriteInterfile: Sino3D Coinci: %d\n" ,mgr.m_TotalProjectionCoincidences ); |
||
465 | #endif |
||
466 | |||
467 | } |
||
468 | |||
469 | double Mag2(HVector3 x) { |
||
470 | return x.x[0]*x.x[0]+x.x[1]*x.x[1]+x.x[2]*x.x[2]; |
||
471 | } |
||
472 | |||
473 | |||
474 | double Mag(HVector3 x) { |
||
475 | return sqrt(Mag2(x)); |
||
476 | } |
||
477 | |||
478 | void SetPhi(HVector3 *r,double phi) { |
||
479 | |||
480 | } |
||
481 | void SetTheta(HVector3 *r,double phi) { |
||
482 | |||
483 | } |
||
484 | |||
485 | double Product(HVector3 a, HVector3 b) { |
||
486 | double c=0; |
||
487 | for (int i=0; i<3; i++) c += a.x[i] * b.x[i]; |
||
488 | return c; |
||
489 | } |
||
490 | |||
491 | HVector3 Multiply(double a, HVector3 b) { |
||
492 | HVector3 c; |
||
493 | for (int i=0; i<3; i++) c.x[i]= a* b.x[i]; |
||
494 | return c; |
||
495 | } |
||
496 | |||
497 | HVector3 Add(HVector3 a, HVector3 b) { |
||
498 | HVector3 c; |
||
499 | for (int i=0; i<3; i++) c.x[i]= a.x[i] + b.x[i]; |
||
500 | return c; |
||
501 | } |
||
502 | |||
503 | HVector3 Subtract(HVector3 a, HVector3 b) { |
||
504 | HVector3 c; |
||
505 | for (int i=0; i<3; i++) c.x[i]= a.x[i] - b.x[i]; |
||
506 | return c; |
||
507 | } |
||
508 | |||
509 | |||
510 | HVector3 Hits2Digits(const HVector3 r) { |
||
511 | if (!mgr.m_nch) return r; |
||
512 | float smear=0.5; |
||
513 | |||
514 | if (mgr.m_nch<0) smear=Random(0,1); |
||
515 | |||
516 | double angle = atan2(r.x[0],r.x[1]); // vrne kot med -pi in pi |
||
517 | double twopi=2*Pi(); |
||
518 | if (angle<0) angle+=twopi; |
||
519 | |||
520 | angle= ((int)(angle/twopi*fabs(mgr.m_nch))+smear)*twopi/fabs(mgr.m_nch); |
||
521 | //(mgr.m_rnd->Rndm()-0.5)*mgr.m_AxialDistance; |
||
522 | HVector3 x; |
||
523 | x.x[0]=sin(angle); |
||
524 | x.x[1]=cos(angle); |
||
525 | x.x[2]=0; |
||
526 | return x; // z coordinata ni cisto v redu |
||
527 | |||
528 | } |
||
529 | |||
530 | int FwdProject(double x,double y, double z, int nmax, int h) { |
||
531 | HVector3 r; |
||
532 | r.x[0]=x; |
||
533 | r.x[1]=y; |
||
534 | r.x[2]=z; |
||
535 | int h2d=1; |
||
536 | double tfac=mgr.m_RingDiameter*mgr.m_RingDiameter/4-Mag2(r); |
||
537 | double rfac= mgr.m_AxialDistance/mgr.m_RingDiameter; |
||
538 | for (int i=0; i<nmax; i++) { |
||
539 | |||
540 | double phi= Random(0,Pi()); |
||
541 | HVector3 s; |
||
542 | s.x[0]=1; |
||
543 | s.x[1]=0; |
||
544 | s.x[2]=0; |
||
545 | SetPhi(&s,phi); |
||
546 | double sign = (Random(0,1)>0.5)? 1 : 0; |
||
547 | double theta = acos(Random(0,rfac)); |
||
548 | theta+=sign*Pi(); |
||
549 | |||
550 | SetTheta(&s,theta); |
||
551 | double t=Product(r,s); |
||
552 | HVector3 rx=Add(r,Multiply(-t,s)); |
||
553 | |||
554 | double d=sqrt(t*t+tfac); |
||
555 | |||
556 | HVector3 r1= Add(rx,Multiply(d,s)); |
||
557 | HVector3 r2= Add(rx,Multiply(-d,s)); |
||
558 | |||
559 | //r1=Hits2Digits(r1); |
||
560 | //r2=Hits2Digits(r2); |
||
561 | |||
562 | HVector3 s1=Subtract(r2,r1); |
||
563 | double s1len= Mag(s1); |
||
564 | int niter=(int) (100*s1len/mgr.m_RingDiameter); |
||
565 | for (int j=0; j<niter; j++) { |
||
566 | r2=Add(r1,Multiply(Random(0,1),s1)); |
||
567 | if (h2d) H2D_Fill(h,r2.x[0],r2.x[1],1); |
||
568 | else H3D_Fill(h,r2.x[0],r2.x[1],r2.x[2],1); |
||
569 | } |
||
570 | } |
||
571 | return 0; |
||
572 | } |
||
573 | |||
574 | int FwdProject2d(int img, int h) { |
||
575 | |||
576 | for (int i=0; i<H2D_GetNbinsX(img); i++) { |
||
577 | double x_=H2D_GetXBinCenter( img, i+1 ); |
||
578 | for (int j=0; j<H2D_GetNbinsY(img); j++) { |
||
579 | double y_=H2D_GetYBinCenter(img, j+1 ); |
||
580 | double density= H2D_GetBinContent(img,i+1,j+1); |
||
581 | if (density>0) FwdProject(x_,y_,mgr.m_AxialDistance*(Random(-0.5,0.5)), density,h); |
||
582 | } |
||
583 | } |
||
584 | return 0; |
||
585 | } |
||
586 | |||
587 | |||
588 | int FwdProject3d(int img, int h) { |
||
589 | |||
590 | for (int i=0; i<H3D_GetNbinsX(img); i++) { |
||
591 | double x_=H3D_GetXBinCenter( img, i+1 ); |
||
592 | for (int j=0; j<H3D_GetNbinsY(img); j++) { |
||
593 | double y_=H3D_GetYBinCenter(img, j+1 ); |
||
594 | for (int k=0; k<H3D_GetNbinsZ(img); k++) { |
||
595 | double z_=H3D_GetZBinCenter( img, k+1 ); |
||
596 | double density= H3D_GetBinContent(img, i+1,j+1,k+1); |
||
597 | if (density>0) FwdProject(x_,y_,z_, density,h); |
||
598 | } |
||
599 | } |
||
600 | } |
||
601 | return 0; |
||
602 | } |
||
603 | |||
604 | |||
605 | int Phantom(int kaj) { |
||
606 | int img = H2D_Init(1, "img","Original Image",100,-50,50,100,-50,50); |
||
607 | int i=0; |
||
608 | // izberi sliko 0: kroglice, 1: point source 2: central ball |
||
609 | switch (kaj) { |
||
610 | |||
611 | case 0: |
||
612 | for (i=0; i<H2D_GetNbinsX(img); i++) { |
||
613 | for (int j=0; j<H2D_GetNbinsY(img); j++) { |
||
614 | double x_=H2D_GetXBinCenter( img, i+1 ); |
||
615 | double y_=H2D_GetYBinCenter( img, j+1 ); |
||
616 | double density=1000; |
||
617 | if ((x_*x_+y_*y_)<6) H2D_SetBinContent(img, i+1,j+1,density); |
||
618 | |||
619 | density=500; |
||
620 | if ((x_-25)*(x_-25)+y_*y_<12) H2D_SetBinContent(img,i+1,j+1,density); |
||
621 | density=2000; |
||
622 | if ((y_-25)*(y_-25)+x_*x_<2) H2D_SetBinContent(img,i+1,j+1,density); |
||
623 | } |
||
624 | } |
||
625 | break; |
||
626 | |||
627 | case 2: |
||
628 | for (i=0; i<H2D_GetNbinsX(img); i++) { |
||
629 | for (int j=0; j<H2D_GetNbinsY(img); j++) { |
||
630 | double x_=H2D_GetXBinCenter( img, i+1 ); |
||
631 | double y_=H2D_GetYBinCenter( img, j+1 ); |
||
632 | double density=1000; |
||
633 | if ((x_*x_+y_*y_)<12.5) H2D_SetBinContent(img, i+1,j+1,density); |
||
634 | } |
||
635 | } |
||
636 | break; |
||
637 | |||
638 | case 1: |
||
639 | H2D_Fill(img, 25,25,10000); |
||
640 | break; |
||
641 | |||
642 | } |
||
643 | |||
644 | return img; |
||
645 | } |