TPCCLIB
Loading...
Searching...
No Matches
atnmake.c File Reference

Compute PET attenuation correction data from blank and transmission data for ECAT 931 and GE Advance 2D sinograms in ECAT 6.3 file format. More...

Go to the source code of this file.

Functions

int atnMake (char *trafile, char *blkfile, char *norfile, char *atnfile, char *imgfile, int decay, int limit, int keepNegat, int imgDim, float zoom, float shiftX, float shiftY, float rotation, int maxIterNr, int skipPriorNr, float beta, int maskDim, int osSetNr, char *status, int verbose)

Detailed Description

Compute PET attenuation correction data from blank and transmission data for ECAT 931 and GE Advance 2D sinograms in ECAT 6.3 file format.

Updated from program written by Jarkko Rintaluoma March 1995, and later modified by Sakari Alenius to apply MRP method, with further editions by Vesa Oikonen and Petri Numminen.

Author
Vesa Oikonen

Definition in file atnmake.c.

Function Documentation

◆ atnMake()

int atnMake ( char * trafile,
char * blkfile,
char * norfile,
char * atnfile,
char * imgfile,
int decay,
int limit,
int keepNegat,
int imgDim,
float zoom,
float shiftX,
float shiftY,
float rotation,
int maxIterNr,
int skipPriorNr,
float beta,
int maskDim,
int osSetNr,
char * status,
int verbose )

Read transmission scan file and blank scan file and calculate the attenuation correction data and the logarithmic correction data.

See also
trmrp
Returns
Returns 0 if ok.
Parameters
trafilePointer to transmission sinogram filename.
blkfilePointer to blank sinogram filename.
norfilePointer to normalization sinogram filename.
atnfilePointer to filename for the attenuation data to be written.
imgfilePointer to filename for the transmission image to be written; enter NULL or empty string if not needed.
decayDecay correction for scan time difference: 0=no, 1=yes.
limitLimit: 0=no; 1=attenuation factors are set between 1.0 and ATN_HI_MAX.
keepNegatKeep negative sinogram values (1), or set negative sinogram values to zero (0), like old program scnnorm did.
imgDimImage dimension (size, usually 128 or 256); must be an even number.
zoomZoom factor (for example 2.45 for the brain); 1=no zooming.
shiftXPossible shifting in x dimension (mm).
shiftYPossible shifting in y dimension (mm).
rotationPossible image rotation, -180 - +180 (in degrees).
maxIterNrNr of iterations, for example 150.
skipPriorNrNumber of iterations to skip before prior; usually 1.
betaBeta, 0.01 - 0.9; usually 0.3 for emission, 0.9 for transmission.
maskDimMedian filter mask dimension; 3 or 5 (9 or 21 pixels).
osSetNrNumber of Ordered Subset sets; 1, 2, 4, ... 128.
statusPointer to a string (allocated for at least 64 chars) where error message or other execution status will be written; enter NULL, if not needed
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 111 of file atnmake.c.

155 {
156 int ret;
157
158 /* Check the input */
159 if(status!=NULL) sprintf(status, "invalid filename");
160 if(trafile==NULL || !trafile[0]) return(1);
161 if(blkfile==NULL || !blkfile[0]) return(1);
162 if(norfile==NULL || !blkfile[0]) return(1);
163 if(atnfile==NULL || !atnfile[0]) return(1);
164
165
166 /*
167 * Open the transmission, blank, and normalization sinograms for reading
168 */
169 FILE *fptra=NULL, *fpblk=NULL, *fpnor=NULL;
170 if(verbose>0) printf("opening %s\n", trafile);
171 if((fptra=fopen(trafile, "rb")) == NULL) {
172 if(status!=NULL) sprintf(status, "cannot open transmission sinogram");
173 return(2);
174 }
175 if(verbose>0) printf("opening %s\n", blkfile);
176 if((fpblk=fopen(blkfile, "rb")) == NULL) {
177 if(status!=NULL) sprintf(status, "cannot open blank sinogram");
178 fclose(fptra);
179 return(2);
180 }
181 if(verbose>0) printf("opening %s\n", norfile);
182 if((fpnor=fopen(norfile, "rb")) == NULL) {
183 if(status!=NULL) sprintf(status, "cannot open normalization file");
184 fclose(fptra); fclose(fpblk);
185 return(2);
186 }
187
188 /*
189 * Read main headers
190 */
191 if(verbose>1) printf("reading transmission main header\n");
192 ECAT63_mainheader tra_main_header;
193 if((ret=ecat63ReadMainheader(fptra, &tra_main_header))) {
194 if(status!=NULL) sprintf(status, "cannot read transmission main header");
195 fclose(fptra); fclose(fpblk); fclose(fpnor);
196 return(3);
197 }
198 if(verbose>100) ecat63PrintMainheader(&tra_main_header, stdout);
199 if(verbose>4) printf("file_type := %d\n", tra_main_header.file_type);
200
201 if(verbose>1) printf("reading blank main header\n");
202 ECAT63_mainheader blk_main_header;
203 if((ret=ecat63ReadMainheader(fpblk, &blk_main_header))) {
204 if(status!=NULL) sprintf(status, "cannot read blank main header");
205 fclose(fptra); fclose(fpblk); fclose(fpnor);
206 return(3);
207 }
208 if(verbose>100) ecat63PrintMainheader(&blk_main_header, stdout);
209 if(verbose>4) printf("file_type := %d\n", blk_main_header.file_type);
210
211 if(verbose>1) printf("reading normalization main header\n");
212 ECAT63_mainheader nor_main_header;
213 if((ret=ecat63ReadMainheader(fpnor, &nor_main_header))) {
214 if(status!=NULL) sprintf(status, "cannot read blank main header");
215 fclose(fptra); fclose(fpblk); fclose(fpnor);
216 return(3);
217 }
218 if(verbose>100) ecat63PrintMainheader(&nor_main_header, stdout);
219 if(verbose>4) printf("file_type := %d\n", nor_main_header.file_type);
220
221 /* Check the file_type */
222 if(tra_main_header.file_type!=RAW_DATA || blk_main_header.file_type!=RAW_DATA
223 || nor_main_header.file_type!=RAW_DATA)
224 {
225 if(status!=NULL) sprintf(status, "file is not a sinogram");
226 fclose(fptra); fclose(fpblk); fclose(fpnor);
227 return(3);
228 }
229
230 /* Read scan start times */
231 time_t tra_start, blk_start;
232 tra_start=ecat63Scanstarttime(&tra_main_header);
233 blk_start=ecat63Scanstarttime(&blk_main_header);
234 if(verbose>1) {
235 char buf[32];
236 printf("Blank scan start time := %s\n", ctime_r_int(&blk_start, buf));
237 printf("Transmission scan start time := %s\n", ctime_r_int(&tra_start, buf));
238 }
239 if(decay!=0 && (tra_start==0 || blk_start==0)) {
240 if(status!=NULL) sprintf(status, "missing scan start time");
241 fclose(fptra); fclose(fpblk); fclose(fpnor);
242 return(3);
243 }
244 double start_time_diff=difftime(tra_start, blk_start);
245 if(verbose>1) {printf("scan start time difference := %g\n", start_time_diff);}
246
247 /* Get isotope halflife */
248 double halflife=-1.0;
249 if(tra_main_header.isotope_halflife>0.0) halflife=tra_main_header.isotope_halflife;
250 else if(blk_main_header.isotope_halflife>0.0) halflife=blk_main_header.isotope_halflife;
251 if(verbose>1 && halflife>0.0) {printf("isotope halflife := %g\n", halflife);}
252 if(decay!=0 && halflife<=0.0) {
253 if(status!=NULL) sprintf(status, "missing isotope halflife");
254 fclose(fptra); fclose(fpblk); fclose(fpnor);
255 return(3);
256 }
257
258
259
260 /*
261 * Read the matrix lists
262 */
263 if(verbose>1) printf("reading transmission matrix list\n");
264 static MATRIXLIST tra_mlist; ecat63InitMatlist(&tra_mlist);
265 ret=ecat63ReadMatlist(fptra, &tra_mlist, verbose-2);
266 if(ret) {
267 if(status!=NULL) sprintf(status, "cannot read sinogram matrix list");
268 fclose(fptra); fclose(fpblk); fclose(fpnor);
269 return(3);
270 }
271
272 if(verbose>1) printf("reading blank matrix list\n");
273 static MATRIXLIST blk_mlist; ecat63InitMatlist(&blk_mlist);
274 ret=ecat63ReadMatlist(fpblk, &blk_mlist, verbose-2);
275 if(ret) {
276 if(status!=NULL) sprintf(status, "cannot read blank matrix list");
277 ecat63EmptyMatlist(&tra_mlist);
278 fclose(fptra); fclose(fpblk); fclose(fpnor);
279 return(3);
280 }
281
282 if(verbose>1) printf("reading normalization matrix list\n");
283 static MATRIXLIST nor_mlist; ecat63InitMatlist(&nor_mlist);
284 ret=ecat63ReadMatlist(fpnor, &nor_mlist, verbose-2);
285 if(ret) {
286 if(status!=NULL) sprintf(status, "cannot read normalization matrix list");
287 ecat63EmptyMatlist(&tra_mlist); ecat63EmptyMatlist(&blk_mlist);
288 fclose(fptra); fclose(fpblk); fclose(fpnor);
289 return(3);
290 }
291
292 /* Check the contents of matrix lists */
293 if(tra_mlist.matrixNr<=0 || blk_mlist.matrixNr<=0 || nor_mlist.matrixNr<=0) {
294 if(status!=NULL) sprintf(status, "empty matrix list");
295 ecat63EmptyMatlist(&tra_mlist); ecat63EmptyMatlist(&blk_mlist);
296 ecat63EmptyMatlist(&nor_mlist);
297 fclose(fptra); fclose(fpblk); fclose(fpnor);
298 return(3);
299 }
300 if(ecat63CheckMatlist(&tra_mlist) || ecat63CheckMatlist(&blk_mlist) ||
301 ecat63CheckMatlist(&nor_mlist))
302 {
303 if(status!=NULL) sprintf(status, "invalid matrix list");
304 ecat63EmptyMatlist(&tra_mlist); ecat63EmptyMatlist(&blk_mlist);
305 ecat63EmptyMatlist(&nor_mlist);
306 fclose(fptra); fclose(fpblk); fclose(fpnor);
307 return(3);
308 }
309 if(verbose>3) {
310 printf("transmission_matrixNr := %d\n", tra_mlist.matrixNr);
311 printf("blank_matrixNr := %d\n", blk_mlist.matrixNr);
312 printf("normalization_matrixNr := %d\n", nor_mlist.matrixNr);
313 }
314 if(tra_mlist.matrixNr!=blk_mlist.matrixNr ||
315 tra_mlist.matrixNr!=nor_mlist.matrixNr ||
316 tra_main_header.num_planes != blk_main_header.num_planes ||
317 tra_main_header.num_planes != nor_main_header.num_planes)
318 {
319 if(status!=NULL) sprintf(status, "different plane numbers");
320 ecat63EmptyMatlist(&tra_mlist); ecat63EmptyMatlist(&blk_mlist);
321 ecat63EmptyMatlist(&nor_mlist);
322 fclose(fptra); fclose(fpblk); fclose(fpnor);
323 return(3);
324 }
325
326 /*
327 * Open output file(s) and write main header(s)
328 */
329 if(verbose>0) printf("writing main header in %s\n", atnfile);
330 ECAT63_mainheader atn_main_header;
331 ecat63CopyMainheader(&tra_main_header, &atn_main_header);
332 atn_main_header.data_type = IEEE_R4; /* float */
333 atn_main_header.file_type = ATTN_DATA;
334 atn_main_header.calibration_units = 2;
335 strcpy(atn_main_header.user_process_code, "tMRP");
336 FILE *fpatn=NULL;
337 fpatn=ecat63Create(atnfile, &atn_main_header);
338 if(fpatn==NULL) {
339 if(status!=NULL) sprintf(status, "cannot write attenuation file\n");
340 ecat63EmptyMatlist(&tra_mlist); ecat63EmptyMatlist(&blk_mlist);
341 ecat63EmptyMatlist(&nor_mlist);
342 fclose(fptra); fclose(fpblk); fclose(fpnor);
343 return(11);
344 }
345
346 FILE *fpimg=NULL;
347 if(imgfile!=NULL && imgfile[0]) {
348 if(verbose>0) printf("writing main header in %s\n", imgfile);
349 ECAT63_mainheader img_main_header;
350 ecat63CopyMainheader(&tra_main_header, &img_main_header);
351 img_main_header.file_type = IMAGE_DATA;
352 img_main_header.data_type = SUN_I2; /* short int */
353 img_main_header.calibration_units = 2;
354 img_main_header.num_frames=1;
355 strcpy(img_main_header.user_process_code, "tMRP");
356 fpimg=ecat63Create(imgfile, &img_main_header);
357 if(fpimg==NULL) {
358 if(status!=NULL) sprintf(status, "cannot write transmission image\n");
359 ecat63EmptyMatlist(&tra_mlist); ecat63EmptyMatlist(&blk_mlist);
360 ecat63EmptyMatlist(&nor_mlist);
361 fclose(fptra); fclose(fpblk); fclose(fpnor);
362 remove(atnfile);
363 return(12);
364 }
365 }
366
367
368 /*
369 * Process one matrix at a time
370 */
371 if(verbose>0) printf("processing matrices...\n");
372 int cret=0;
373 for(int mi=0; mi<tra_mlist.matrixNr; mi++) {
374 if(verbose==1) {fprintf(stdout, "."); fflush(stdout);}
375
376 FILE *lfptra=fptra;
377 FILE *lfpblk=fpblk;
378 FILE *lfpnor=fpnor;
379 FILE *lfpatn=fpatn;
380 FILE *lfpimg=fpimg;
381
382 ECAT63_scanheader tra_header, blk_header, nor_header;
383 ECAT63_attnheader atn_header;
384 ECAT63_imageheader img_header;
385 Matval matval;
386 int dimx, dimy, scnpxlNr=0, imgpxlNr=0, matnum=0, ni=0, bi=0;
387 float *tramat, *blkmat, *normat, f;
388 int ret=0;
389
390 /* Get plane and frame nr */
391 mat_numdoc(tra_mlist.matdir[mi].matnum, &matval);
392
393 /* Read transmission sinogram subheader and scaled data */
394 if(verbose>1) printf("reading transmission matrix %d\n", 1+mi);
395 ret=ecat63ReadScanMatrix(lfptra, tra_mlist.matdir[mi].strtblk,
396 tra_mlist.matdir[mi].endblk, &tra_header, &tramat);
397 if(ret) {
398 if(status!=NULL)
399 sprintf(status, "cannot read transmission sinogram matrix %u", tra_mlist.matdir[mi].matnum);
400 cret=ret;
401 continue;
402 }
403 if(verbose>2)
404 printf("Matrix: plane %d frame %d gate %d bed %d\n",
405 matval.plane, matval.frame, matval.gate, matval.bed);
406 if(verbose>200) {
407 ecat63PrintScanheader(&tra_header, stdout);
408 } else if(verbose>1 && mi==0) {
409 printf("Transmission sinogram dimensions := %d x %d\n",
410 tra_header.dimension_1, tra_header.dimension_2);
411 printf("Transmission sinogram frame duration := %g\n",
412 0.001*(double)tra_header.frame_duration);
413 printf("Transmission sinogram dead-time correction := %g\n",
414 tra_header.loss_correction_fctr);
415 }
416 dimx=tra_header.dimension_1;
417 dimy=tra_header.dimension_2;
418 scnpxlNr=dimx*dimy;
419 if(imgDim<2) imgDim=dimx; // transmission dim to number of rays by default
420 /* Dead-time correction */
421 if(tra_header.loss_correction_fctr>0.0) {
422 for(int i=0; i<scnpxlNr; i++)
423 tramat[i]*=tra_header.loss_correction_fctr;
424 }
425 /* Divide counts by frame duration */
426 if(tra_header.frame_duration<1) {
427 if(status!=NULL) sprintf(status, "missing frame duration in transmission sinogram");
428 free(tramat);
429 cret=ret;
430 continue;
431 }
432 f=1000.0/tra_header.frame_duration;
433 for(int i=0; i<scnpxlNr; i++) tramat[i]*=f;
434
435 /* Search corresponding matrix from the normalization file */
436 matnum=mat_numcod(matval.frame, matval.plane, matval.gate, matval.data, matval.bed);
437 for(ni=0; ni<nor_mlist.matrixNr; ni++)
438 if(nor_mlist.matdir[ni].matnum==matnum)
439 break;
440 if(ni>=nor_mlist.matrixNr) {
441 if(status!=NULL)
442 sprintf(status, "cannot find matrix %u in normalization sinogram",
443 nor_mlist.matdir[ni].matnum);
444 free(tramat);
445 cret=ret;
446 continue;
447 }
448 /* Read normalization subheader and scaled data */
449 if(verbose>1) printf("reading normalization matrix %d\n", 1+ni);
450 ret=ecat63ReadScanMatrix(lfpnor, nor_mlist.matdir[ni].strtblk,
451 nor_mlist.matdir[ni].endblk, &nor_header, &normat);
452 if(ret) {
453 if(status!=NULL)
454 sprintf(status, "cannot read blank sinogram matrix %u", nor_mlist.matdir[ni].matnum);
455 free(tramat);
456 cret=ret;
457 continue;
458 }
459 if(verbose>200) {
460 ecat63PrintScanheader(&nor_header, stdout);
461 } else if(verbose>1 && mi==0) {
462 printf("Normalization sinogram dimensions := %d x %d\n",
463 nor_header.dimension_1, nor_header.dimension_2);
464 printf("Normalization sinogram frame duration := %g\n",
465 0.001*(double)nor_header.frame_duration);
466 printf("Normalization sinogram dead-time correction := %g\n",
467 nor_header.loss_correction_fctr);
468 }
469 if(tra_header.dimension_1!=nor_header.dimension_1
470 || tra_header.dimension_2!=nor_header.dimension_2)
471 {
472 if(status!=NULL) sprintf(status, "incompatible matrix dimensions");
473 free(tramat); free(normat);
474 cret=ret;
475 continue;
476 }
477
478 /* Normalization correction for transmission sinogram */
479 for(int i=0; i<scnpxlNr; i++) tramat[i]*=normat[i];
480 /* Set negatives to zero */
481 if(keepNegat==0)
482 for(int i=0; i<scnpxlNr; i++) if(tramat[i]<0.0) tramat[i]=0.0;
483
484 /* Search corresponding matrix from the blank file */
485 matnum=mat_numcod(matval.frame, matval.plane, matval.gate, matval.data,
486 matval.bed);
487 for(bi=0; bi<blk_mlist.matrixNr; bi++)
488 if(blk_mlist.matdir[bi].matnum==matnum)
489 break;
490 if(bi>=blk_mlist.matrixNr) {
491 if(status!=NULL)
492 sprintf(status, "cannot find matrix %u in blank sinogram", blk_mlist.matdir[bi].matnum);
493 free(tramat); free(normat);
494 cret=ret;
495 continue;
496 }
497 /* Read blank subheader and scaled data */
498 if(verbose>1) printf("reading blank matrix %d\n", 1+bi);
499 ret=ecat63ReadScanMatrix(lfpblk, blk_mlist.matdir[bi].strtblk,
500 blk_mlist.matdir[bi].endblk, &blk_header, &blkmat);
501 if(ret) {
502 if(status!=NULL)
503 sprintf(status, "cannot read blank sinogram matrix %u", blk_mlist.matdir[bi].matnum);
504 free(tramat); free(normat);
505 cret=ret;
506 continue;
507 }
508 if(verbose>200) {
509 ecat63PrintScanheader(&blk_header, stdout);
510 } else if(verbose>1 && mi==0) {
511 printf("Blank sinogram dimensions := %d x %d\n",
512 blk_header.dimension_1, blk_header.dimension_2);
513 printf("Blank sinogram frame duration := %g\n",
514 0.001*(double)blk_header.frame_duration);
515 printf("Blank sinogram dead-time correction := %g\n",
516 blk_header.loss_correction_fctr);
517 }
518 if(tra_header.dimension_1!=blk_header.dimension_1
519 || tra_header.dimension_2!=blk_header.dimension_2)
520 {
521 if(status!=NULL) sprintf(status, "incompatible matrix dimensions");
522 free(tramat); free(normat); free(blkmat);
523 cret=ret;
524 continue;
525 }
526 /* Dead-time correction */
527 if(blk_header.loss_correction_fctr>0.0) {
528 for(int i=0; i<scnpxlNr; i++)
529 blkmat[i]*=blk_header.loss_correction_fctr;
530 }
531 /* Divide counts by frame duration */
532 if(blk_header.frame_duration<1) {
533 if(status!=NULL) sprintf(status, "missing frame duration in blank sinogram");
534 free(tramat); free(normat); free(blkmat);
535 cret=ret;
536 continue;
537 }
538 f=1000.0/blk_header.frame_duration;
539 for(int i=0; i<scnpxlNr; i++) blkmat[i]*=f;
540
541 /* Normalization correction for blank sinogram */
542 for(int i=0; i<scnpxlNr; i++) blkmat[i]*=normat[i];
543 /* Set negatives to zero */
544 if(keepNegat==0) for(int i=0; i<scnpxlNr; i++) if(blkmat[i]<0.0) blkmat[i]=0.0;
545
546
547 /* Correct transmission scan for the isotope decay in radiation source
548 that may have happened between blank and transmission scans;
549 it is not important in patient scans, but may be very important for
550 phantom studies and calibration measurements.
551 Frame scan durations are considered to be insignificant for decay.
552 */
553 double dcf=1.0;
554 if(decay!=0) {
555 double lambda=hl2lambda(halflife);
556 double t=start_time_diff;
557 t+=0.001*(double)tra_header.frame_start_time;
558 t-=0.001*(double)blk_header.frame_start_time;
559 dcf=hlLambda2factor(lambda, t, -1.0);
560 if(verbose>1 && mi==0) {
561 printf("frame start time difference := %g\n", t);
562 printf("decay correction factor := %g\n", dcf);
563 }
564 for(int i=0; i<scnpxlNr; i++) tramat[i]*=dcf;
565 }
566
567
568 /* Set up the attenuation sub header information */
569 if(verbose>3) printf("setting attenuation sub-header\n");
570 if(mi==0) {
571 /* Set fields that are common for all matrices */
572 memset(&atn_header, 0, sizeof(ECAT63_attnheader));
573 atn_header.data_type=IEEE_R4; /* float */
574 atn_header.attenuation_type=1; /* 1 for measured attenuation */
575 atn_header.scale_factor=1.0;
576 atn_header.x_origin=0.0;
577 atn_header.y_origin=0.0;
578 atn_header.x_radius=0.0;
579 atn_header.y_radius=0.0;
580 atn_header.tilt_angle=tra_main_header.gantry_tilt;
581 atn_header.attenuation_coeff=1.0;
582 atn_header.sample_distance=tra_header.sample_distance;
583 }
584 atn_header.dimension_1 = tra_header.dimension_1;
585 atn_header.dimension_2 = tra_header.dimension_2;
586
587 /* Set up the log attenuation sub header information, if needed */
588 if(lfpimg!=NULL && mi==0) {
589 if(verbose>6) printf("setting transmission image sub-header\n");
590 /* Set fields that are common for all matrices */
591 img_header.data_type=SUN_I2; /* short int */
592 img_header.num_dimensions=2;
593 img_header.dimension_1=imgDim;
594 img_header.dimension_2=imgDim;
595 img_header.x_origin=10.0*shiftX;
596 img_header.y_origin=10.0*shiftY;
597 img_header.recon_scale=zoom;
598 img_header.quant_scale=1.0;
599 img_header.pixel_size=tra_header.sample_distance*(float)dimx/(zoom*(float)imgDim);
600 img_header.slice_width=tra_main_header.plane_separation;
601 img_header.frame_start_time=0;
602 img_header.frame_duration=0; // to prevent accidental decay correction
603 img_header.frame_duration=0;
604 img_header.filter_code=3;
605 img_header.image_rotation=rotation;
606 img_header.decay_corr_fctr=dcf;
607 img_header.loss_corr_fctr=1.0;
608 img_header.quant_units=2;
609 img_header.ecat_calibration_fctr=1.0;
610 img_header.filter_params[0]=beta;
611 img_header.filter_params[1]=(float)maskDim;
612 img_header.filter_params[2]=(float)maxIterNr;
613 img_header.filter_params[3]=(float)1;
614 img_header.filter_params[4]=(float)osSetNr;
615 img_header.filter_params[5]=(float)skipPriorNr;
616 strcpy(img_header.annotation, "tMRP");
617 }
618 if(lfpimg!=NULL) { // separately for each matrix
619 img_header.plane_eff_corr_fctr=nor_header.scale_factor;
620 img_header.scan_matrix_num=tra_mlist.matdir[mi].matnum;
621 img_header.norm_matrix_num=nor_mlist.matdir[ni].matnum;
622 img_header.atten_cor_mat_num=tra_mlist.matdir[mi].matnum;
623 }
624
625
626 /*
627 * Reconstruct image containing log-transformed attenuation correction factors.
628 * It must be log-transformed, because actual attenuation factors are >1 for the whole sinogram.
629 * At this step there must be no zoom, shifts, or rotation, and
630 * image dimension must be the same as sinogram width (nr or rays or bins).
631 */
632 if(verbose>1) {printf("matrix reconstruction\n"); fflush(stdout);}
633 imgpxlNr=dimx*dimx;
634 float imgmat[imgpxlNr];
635 ret=trmrp(blkmat, tramat, dimx, imgmat, 120, 1,
636 dimx, dimy, maskDim, 1.0, beta,
637 10.0*tra_main_header.axial_fov, 10.0*tra_header.sample_distance,
638 1, 1, 0.0, 0.0, 0.0,
639 verbose-6);
640 if(ret) {
641 if(status!=NULL) sprintf(status, "cannot calculate attenuation correction factors");
642 if(verbose>1) printf("trmrp_return_value := %d\n", ret);
643 free(tramat); free(normat); free(blkmat);
644 cret=ret;
645 continue;
646 }
647 if(verbose>1) {
648 for(int i=0; i<imgpxlNr; i++)
649 if(!isfinite(imgmat[i])) {
650 printf(" inf in the image!\n");
651 break;
652 }
653 }
654
655
656 /*
657 * If requested transmission image dimension is the same as scan ray number, and
658 * zoom, shifts or rotation were not set, then simply save the reconstructed image;
659 * otherwise we have to reconstruct it later again.
660 */
661 if(lfpimg!=NULL && imgDim==dimx && zoom==1.0 && shiftX==0.0 && shiftY==0.0 && rotation==0.0) {
662 if(verbose>1) printf("writing transmission image matrix\n");
663 matnum=mat_numcod(1, matval.plane, matval.gate, matval.data, matval.bed);
664 ret=ecat63WriteImageMatrix(lfpimg, matnum, &img_header, imgmat);
665 if(ret) {
666 if(status!=NULL) sprintf(status, "cannot write transmission image matrix");
667 if(verbose>1) printf("ret := %d\n", ret);
668 free(tramat); free(normat); free(blkmat);
669 cret=ret;
670 continue;
671 }
672 }
673
674 /*
675 * Reprojection to sinogram space
676 */
677 if(verbose>1) {printf("matrix reprojection\n"); fflush(stdout);}
678 float atnmat[scnpxlNr];
679 ret=reprojection(imgmat, dimx, dimx, dimy, 1.0, atnmat, verbose-10);
680 if(ret) {
681 if(status!=NULL) sprintf(status, "cannot reproject attenuation correction data");
682 if(verbose>1) printf("trmrp_return_value := %d\n", ret);
683 free(tramat); free(normat); free(blkmat);
684 cret=ret;
685 continue;
686 }
687 if(verbose>1) {
688 for(int i=0; i<scnpxlNr; i++)
689 if(!isfinite(atnmat[i])) {
690 printf(" inf in the log attenuation data!\n");
691 break;
692 }
693 }
694
695 /*
696 * Convert from log values to correction factors for attenuation file
697 */
698 if(verbose>2) {printf("conversion from logarithms\n"); fflush(stdout);}
699#if(0)
700 if(tra_header.sample_distance>0.001) f=10.0*tra_header.sample_distance;
701 else f=1.0;
702 for(int i=0; i<scnpxlNr; i++) atnmat[i]=expf(atnmat[i]*f);
703#endif
704 for(int i=0; i<scnpxlNr; i++) atnmat[i]=expf(atnmat[i]);
705 if(verbose>1) {
706 for(int i=0; i<scnpxlNr; i++)
707 if(!isfinite(atnmat[i])) {
708 printf(" inf in the attenuation data!\n");
709 break;
710 }
711 }
712 for(int i=0; i<scnpxlNr; i++) if(!isfinite(atnmat[i])) atnmat[i]=1.0;
713
714 /* Fix too low and high values, if requested */
715 if(limit>0) {
716 for(int i=0; i<scnpxlNr; i++) {
717 if(!(atnmat[i]>=1.0)) atnmat[i]=1.0;
718 else if(atnmat[i]>ATN_HI_MAX) atnmat[i]=ATN_HI_MAX;
719 }
720 }
721
722
723 /* Write the attenuation matrix */
724 if(verbose>1) printf("writing attenuation matrix\n");
725 matnum=mat_numcod(1, matval.plane, matval.gate, matval.data, matval.bed);
726 ret=ecat63WriteAttn(lfpatn, matnum, &atn_header, atnmat);
727 if(ret) {
728 if(status!=NULL) sprintf(status, "cannot write attenuation matrix");
729 if(verbose>1) printf("ret := %d\n", ret);
730 free(tramat); free(normat); free(blkmat);
731 cret=ret;
732 continue;
733 }
734
735
736 /*
737 * Reconstruct and save transmission image, in case user requested it, and
738 * user gave zoom, shifts, rotation, or image dimensions that is different
739 * from the sinogram width (nr or rays or bins).
740 */
741 if(lfpimg!=NULL && (imgDim!=dimx || zoom!=1.0 || shiftX!=0.0 || shiftY!=0.0 || rotation!=0.0)) {
742 if(verbose>1) {printf("transmission matrix reconstruction\n"); fflush(stdout);}
743 imgpxlNr=imgDim*imgDim;
744 float imgmat2[imgpxlNr];
745 ret=trmrp(blkmat, tramat, imgDim, imgmat2, maxIterNr, osSetNr,
746 dimx, dimy, maskDim, zoom, beta,
747 10.0*tra_main_header.axial_fov, 10.0*tra_header.sample_distance,
748 skipPriorNr, 1, shiftX, shiftY, rotation,
749 verbose-7);
750 if(ret) {
751 if(status!=NULL) sprintf(status, "cannot reconstruct transmission image");
752 if(verbose>1) printf("trmrp_return_value := %d\n", ret);
753 } else {
754 f=10.0*tra_header.sample_distance;
755 for(int i=0; i<imgpxlNr; i++) imgmat2[i]*=f;
756 if(verbose>1) printf("writing transmission image matrix\n");
757 matnum=mat_numcod(1, matval.plane, matval.gate, matval.data, matval.bed);
758 ret=ecat63WriteImageMatrix(lfpimg, matnum, &img_header, imgmat2);
759 if(ret) {
760 if(status!=NULL) sprintf(status, "cannot write transmission image matrix");
761 if(verbose>1) printf("ret := %d\n", ret);
762 }
763 }
764 if(ret) {
765 free(tramat); free(normat); free(blkmat);
766 cret=ret;
767 continue;
768 }
769 }
770
771 free(tramat); free(normat); free(blkmat);
772 } /* next matrix */
773 if(verbose==1) {fprintf(stdout, "\n"); fflush(stdout);}
774 if(verbose>0) {fprintf(stdout, "done.\n"); fflush(stdout);}
775
776
777 fclose(fpatn); if(fpimg!=NULL) fclose(fpimg);
778 ecat63EmptyMatlist(&tra_mlist); ecat63EmptyMatlist(&blk_mlist);
779 ecat63EmptyMatlist(&nor_mlist);
780 fclose(fptra); fclose(fpblk); fclose(fpnor);
781 if(cret) {remove(atnfile); if(fpimg!=NULL) remove(imgfile);}
782 return(cret);
783}
char * ctime_r_int(const time_t *t, char *buf)
Convert calendard time t into a null-terminated string of the form YYYY-MM-DD hh:mm:ss,...
Definition datetime.c:110
int ecat63CopyMainheader(ECAT63_mainheader *h1, ECAT63_mainheader *h2)
Definition ecat63h.c:16
int ecat63ReadMatlist(FILE *fp, MATRIXLIST *ml, int verbose)
Definition ecat63ml.c:46
void ecat63InitMatlist(MATRIXLIST *mlist)
Definition ecat63ml.c:20
void ecat63EmptyMatlist(MATRIXLIST *mlist)
Definition ecat63ml.c:31
int mat_numcod(int frame, int plane, int gate, int data, int bed)
Definition ecat63ml.c:242
int ecat63CheckMatlist(MATRIXLIST *ml)
Definition ecat63ml.c:324
void mat_numdoc(int matnum, Matval *matval)
Definition ecat63ml.c:254
void ecat63PrintMainheader(ECAT63_mainheader *h, FILE *fp)
Definition ecat63p.c:16
void ecat63PrintScanheader(ECAT63_scanheader *h, FILE *fp)
Definition ecat63p.c:137
int ecat63ReadScanMatrix(FILE *fp, int first_block, int last_block, ECAT63_scanheader *h, float **fdata)
Definition ecat63r.c:731
int ecat63ReadMainheader(FILE *fp, ECAT63_mainheader *h)
Definition ecat63r.c:25
int ecat63WriteAttn(FILE *fp, int matnum, ECAT63_attnheader *h, void *data)
Definition ecat63w.c:563
int ecat63WriteImageMatrix(FILE *fp, int matnum, ECAT63_imageheader *h, float *fdata)
Definition ecat63w.c:697
FILE * ecat63Create(const char *fname, ECAT63_mainheader *h)
Definition ecat63w.c:365
time_t ecat63Scanstarttime(const ECAT63_mainheader *h)
Get calendar time from ECAT 6.3 main header.
Definition ecat63w.c:925
double hl2lambda(double halflife)
Definition halflife.c:84
double hlLambda2factor(double lambda, double frametime, double framedur)
Definition halflife.c:98
#define ATTN_DATA
#define IEEE_R4
#define RAW_DATA
#define IMAGE_DATA
#define SUN_I2
int trmrp(float *bla, float *tra, int dim, float *image, int iter, int sets, int rays, int views, int maskdim, float zoom, float beta, float axial_fov, float sample_distance, int skip_prior, int osl, float shiftX, float shiftY, float rotation, int verbose)
Definition trmrp.c:17
int reprojection(float *image, int dim, int rays, int views, float bpzoom, float *sinogram, int verbose)
short int dimension_1
short int dimension_2
short int attenuation_type
short int num_dimensions
short int calibration_units
char user_process_code[10]
short int dimension_2
short int dimension_1
MatDir * matdir
int endblk
int matnum
int strtblk
int frame
int plane

Referenced by atnMake().