9#include "tpcclibConfig.h"
23static char *info[] = {
24 "List the time frame information of a PET image in DICOM format.",
25 "The frame start times and lengths can be saved in SIF.",
27 "NOT for production use!",
29 "Usage: @P [-Options] dicomfile [SIF]",
34 "See also: dcmlhdr, dcmmlist, eframe, tacframe",
36 "Keywords: image, DICOM, time, SIF",
55int main(
int argc,
char **argv)
57 int ai, help=0, version=0, verbose=1;
58 char dcmfile[FILENAME_MAX], siffile[FILENAME_MAX];
65 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
66 dcmfile[0]=siffile[0]=(char)0;
68 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
71 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
80 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
85 if(ai<argc)
strlcpy(dcmfile, argv[ai++], FILENAME_MAX);
86 if(ai<argc)
strlcpy(siffile, argv[ai++], FILENAME_MAX);
88 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
93 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
99 printf(
"dcmfile := %s\n", dcmfile);
100 if(siffile[0]) printf(
"siffile := %s\n", siffile);
112 if(verbose>1) {printf(
"fileNr := %d\n", fl.
keyNr); fflush(stdout);}
113 if(verbose>6)
iftWrite(&fl, stdout, NULL);
130 short unsigned int decayCorrection=0;
135 if(verbose>2) printf(
"Decay Correction := %s\n", buf);
136 if(
strcasestr(buf,
"NONE")!=NULL) decayCorrection=0;
137 else if(
strcasestr(buf,
"START")!=NULL) decayCorrection=1;
138 else if(
strcasestr(buf,
"ADMIN")!=NULL) decayCorrection=2;
145 if(verbose>2) printf(
"Decay Correction := %s\n", buf);
146 if(
strcasestr(buf,
"YES")!=NULL) decayCorrection=1;
150 if(verbose>1) printf(
"decayCorrection := %d\n", decayCorrection);
153 char injDateTime[32]; injDateTime[0]=(char)0;
154 if(decayCorrection==2) {
160 else if(verbose>3) printf(
"0018,1078 -> %s\n", injDateTime);
174 sprintf(injDateTime,
"%s %s", s1, s2);
179 if(!injDateTime[0]) {
180 fprintf(stderr,
"Error: missing Tracer Administration Time.\n");
184 if(verbose>1) printf(
"injection_time := %s\n", injDateTime);
190 char seriesDateTime[32]; seriesDateTime[0]=(char)0;
199 sprintf(seriesDateTime,
"%s %s", s1, s2);
202 if(!seriesDateTime[0]) {
203 fprintf(stderr,
"Error: missing Series Date and Time.\n");
206 if(verbose>2) printf(
"seriesDateTime := %s\n", seriesDateTime);
214 if(verbose>1) fprintf(stderr,
"Warning: cannot find series type.\n");
217 if(verbose>1) printf(
"seriesType := %s\n", buf);
219 if(strncasecmp(buf,
"DYNAMIC", 7) && strncasecmp(buf,
"STATIC", 6)) {
220 fprintf(stderr,
"Error: data series type '%s' not supported.\n", buf);
233 fprintf(stderr,
"Error: cannot find image type.\n");
241 if(verbose>1) printf(
"imageType := %s\n", buf);
242 if(
strcasestr(buf,
"DYNAMIC")!=NULL) dynamic=1;
else dynamic=0;
245 if(verbose>1) {printf(
"dynamic := %d\n", dynamic); fflush(stdout);}
253 if(verbose>1) fprintf(stderr,
"Notice: Per-frame Functional Groups Sequence is available.\n");
259 if(verbose>1) {printf(
"reading frame number\n"); fflush(stdout);}
260 unsigned short int frameNr=0;
274 fprintf(stderr,
"Error: cannot find frame number.\n");
280 if(verbose>1) printf(
"frameNr := %u\n", frameNr);
285 if(verbose>1) {printf(
"reading plane number\n"); fflush(stdout);}
286 unsigned short int sliceNr=0;
303 fprintf(stderr,
"Error: cannot find slice number.\n");
306 if(verbose>2) printf(
"sliceNr := %u\n", sliceNr);
310 if(verbose>1) {printf(
"reading isotope\n"); fflush(stdout);}
316 if(verbose>2) printf(
"isotope_halflife := %g\n", halflife);
320 fprintf(stderr,
"Warning: isotope not identified.\n");
325 if(verbose>1) {printf(
"reading accession number\n"); fflush(stdout);}
326 char studyNr[17]; studyNr[0]=(char)0;
334 if(strlen(studyNr)==0) {
335 if(verbose>1) {printf(
"reading series description\n"); fflush(stdout);}
341 char *cptr=strrchr(studyNr,
' ');
if(cptr!=NULL) *cptr=(char)0;
342 cptr=strrchr(studyNr,
'/');
if(cptr!=NULL) *cptr=(char)0;
345 if(verbose>1) printf(
"studyNr := %s\n", studyNr);
352 if(verbose>1) {printf(
"allocating memory for frame times\n"); fflush(stdout);}
356 fprintf(stderr,
"Error: %s\n",
errorMsg(ret));
367 strcpy(tac.
c[0].
name,
"Prompts");
368 strcpy(tac.
c[1].
name,
"Randoms");
369 strcpy(tac.
c[2].
name,
"Trues");
375 for(
int fi=0; fi<frameNr; fi++) tac.
x1[fi]=tac.
x2[fi]=tac.
x[fi]=nan(
"");
381 if(verbose>1) {printf(
"reading frame information\n"); fflush(stdout);}
382 char startDateTime[32]; startDateTime[0]=(char)0;
389 if(verbose>1) {printf(
"frames is separate files\n"); fflush(stdout);}
393 unsigned short int imageIndex=0;
397 fprintf(stderr,
"Error: cannot find Image Index.\n");
403 unsigned short int frameIndex, sliceIndex;
405 div_t meh=div(imageIndex-1, sliceNr);
410 printf(
"imageIndex := %u\n", imageIndex);
411 printf(
"frameIndex := %u\n", frameIndex);
412 printf(
"sliceIndex := %u\n", sliceIndex);
416 if(dynamic && verbose>5) {
421 printf(
"Temporal Position Index := %s\n", buf);
428 printf(
"Stack ID := %s\n", buf);
435 printf(
"In-Stack Position Number := %s\n", buf);
445 if(verbose>5) printf(
"Frame Reference Time := %s\n", buf);
451 char acqDateTime[32]; acqDateTime[0]=(char)0;
457 if(!acqDateTime[0]) {
466 sprintf(acqDateTime,
"%s %s", s1, s2);
470 if(!acqDateTime[0]) {
471 fprintf(stderr,
"Error: missing Acquisition Date and Time.\n");
475 if(verbose>4) printf(
"acqDateTime := %s\n", acqDateTime);
477 if(frameIndex==0) strcpy(startDateTime, acqDateTime);
481 if(decayCorrection==2) {
489 if(frameIndex<frameNr) {
490 if(isnan(tac.
x1[frameIndex])) {
492 tac.
x1[frameIndex]=t1;
493 if(verbose>3) printf(
"t1[%d]=%g at sliceIndex := %u\n", frameIndex, t1, sliceIndex);
498 if(verbose>3) printf(
"t1=%g at sliceIndex := %u\n", t1, sliceIndex);
508 if(verbose>3) printf(
"actualFrameDuration := %g\n", fdur);
510 if(frameIndex<frameNr) tac.
x2[frameIndex]=0.001*fdur;
513 double prompts=0.0, randoms=0.0;
518 if(prompts<1.0E-03) {
523 if(prompts<1.0E-03) {
528 tac.
c[0].
y[frameIndex]=prompts;
533 if(randoms<1.0E-03) {
538 if(randoms<1.0E-03) {
543 tac.
c[1].
y[frameIndex]=randoms;
547 fi++;
if(fi==fl.
keyNr)
break;
558 if(verbose>0 && beds!=0) {
559 fprintf(stdout,
"Note: this seems to be whole-body study\n");
566 if(verbose>1) {printf(
"multi-frame file\n"); fflush(stdout);}
569 char acqDateTime[32]; acqDateTime[0]=(char)0;
573 if(!acqDateTime[0]) {
574 fprintf(stderr,
"Error: missing Acquisition Date and Time.\n");
578 if(verbose>4) printf(
"acqDateTime := %s\n", acqDateTime);
580 strcpy(startDateTime, acqDateTime);
583 char dcDateTime[32]; dcDateTime[0]=(char)0;
588 if(decayCorrection>0 && !dcDateTime[0]) {
589 fprintf(stderr,
"Error: missing Decay Correction DateTime.\n");
593 if(dcDateTime[0] && verbose>4) printf(
"dcDateTime := %s\n", dcDateTime);
599 fprintf(stderr,
"Error: Per Frame Functional Groups Sequence not found.\n");
611 if(verbose>10) printf(
" found Frame Content Sequence\n");
615 if(jptr==NULL) {fptr=fptr->
next_item;
continue;}
617 unsigned short int frameIndex=(
unsigned short int)(
dcmitemGetInt(jptr)-1);
620 char facqDateTime[32]; facqDateTime[0]=(char)0;
622 if(!facqDateTime[0]) {
623 fprintf(stderr,
"Error: missing Frame Acquisition DateTime.\n");
627 if(verbose>20) printf(
"facqDateTime := %s\n", facqDateTime);
630 if(decayCorrection>0) {
638 if(frameIndex<frameNr) {
639 if(isnan(tac.
x1[frameIndex])) {
641 tac.
x1[frameIndex]=t1;
642 if(verbose>29) printf(
"t1[%d]=%g\n", frameIndex, t1);
647 if(verbose>20) printf(
"t1=%g\n", t1);
654 if(jptr==NULL) {fptr=fptr->
next_item;
continue;}
666 if(decayCorrection==2) {
686 if(verbose>1) printf(
"writing %s\n", siffile);
687 fp=fopen(siffile,
"w");
689 fprintf(stderr,
"Error: cannot open file for writing.\n");
694 tacFree(&tac);
if(siffile[0]) fclose(fp);
double strDateTimeDifference(const char *dt1, const char *dt0)
long int dcmitemGetInt(DCMITEM *d)
void dcmfileInit(DCMFILE *d)
DCMITEM * dcmFindTag(DCMITEM *d, const short int omit, DCMTAG *tag, const int verbose)
DCMITEM * dcmFindDownTag(DCMITEM *d, const short int omit, DCMTAG *tag, const int verbose)
void dcmfileFree(DCMFILE *d)
int dcmTagIntRange(DCMITEM *d, DCMTAG *tag, int *mi, int *ma, const int verbose)
void dcmitemPrint(DCMITEM *d)
double dcmitemGetReal(DCMITEM *d)
char * dcmValueString(DCMITEM *d)
int dcmFileList(const char *filename, IFT *ift, TPCSTATUS *status)
List DICOM files belonging to one image.
int dcmFileRead(const char *filename, DCMFILE *dcm, const short int headerOnly, TPCSTATUS *status)
char * dcmDT2intl(const char *orig, char *intl)
char * dcmDA2intl(const char *orig, char *intl)
char * dcmTM2intl(const char *orig, char *intl)
int doubleMatch(const double v1, const double v2, const double lim)
int iftWrite(IFT *ift, FILE *fp, TPCSTATUS *status)
char * isotopeName(int isotope_code)
int isotopeIdentifyHalflife(double halflife)
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
void tpcPrintBuild(const char *program, FILE *fp)
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
int tacWriteSIF(TAC *tac, FILE *fp, int extra, TPCSTATUS *status)
void statusInit(TPCSTATUS *s)
char * errorMsg(tpcerror e)
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
void strReplaceChar(char *s, char c1, char c2)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
char * strcasestr(const char *haystack, const char *needle)
struct DCMITEM * child_item
struct DCMITEM * next_item
unsigned short int element
char name[MAX_TACNAME_LEN+1]
IFT h
Optional (but often useful) header information.
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacAllocate(TAC *tac, int sampleNr, int tacNr)
int tacSetHeaderScanstarttime(IFT *h, const char *s)
int tacSetHeaderIsotope(IFT *h, const char *s)
int tacSetHeaderStudynr(IFT *h, const char *s)
Header file for libtpcdcm.
Header file for library libtpcextensions.
@ ISOTOPE_UNKNOWN
Unknown.
Header file for library libtpctac.
@ TAC_FORMAT_SIF
Scan information file.