9#include "tpcclibConfig.h"
29static char *info[] = {
30 "Calculating regional time-radioactivity concentration curves (TACs) from",
31 "a PET image in ECAT, Analyze 7.5, or NIfTI-1 format, when",
32 "regions-of-interests (ROIs) are given in ECAT 6.3 format ROI files,",
33 "as mask image, or as vrd file.",
34 "Regional TACs are written in output file in DFT format.",
35 "If file name for output file is not specified, it will be saved in the",
36 "default path replacing the extension of image file name with '.dft'.",
38 "Usage: @P [Options] image roifile(s) [tacfile]",
42 " Calculate all ROIs on all planes, or on specified plane;",
43 " by default, ROIs are calculated only on planes where they were drawn.",
44 " Effective only with ROI files, not with mask image.",
46 " In addition to regional pixel value averages, either standard",
47 " deviation (sd), percentual coefficient of variation (cv), or",
48 " variance inside ROI(s) are calculated and saved in separate files",
49 " with extensions .sd, .cv, or .var, respectively.",
50 " Effective only with ROI files, not with mask file.",
51 " -tm Write time frame mid times instead of start and end times.",
53 " Calculates ROI median instead of ROI average.",
54 " Effective only with ROI files, not with mask image.",
55 " -lms Calculates least median of squares estimate instead of ROI average.",
56 " Effective only with ROI files, not with mask image.",
57 " -lts Calculates least trimmed square estimate instead of ROI average.",
58 " Effective only with ROI files, not with mask image.",
61 "Options -median, -lms and -lts can only be used for parametric or",
65 " @P a1204dy1.img a1204*.roi a1204dy1.dft",
67 " @P -P=4,6,8,10 us4321dy1.img us4321*.roi",
69 " @P -V=sd uo286suv.v uo286*.roi ",
71 " @P uo286suv.v uo286mask.v",
73 "See also: roilist, lmlist, eroi2img, roipxl, imgthrs, pxl2tac, tacformat",
75 "Keywords: image, ROI, mask, ECAT, TAC, analysis, modelling",
95int main(
int argc,
char **argv)
97 int ai, help=0, version=0, verbose=1;
98 int ret, pxlNr, voi=0;
104 int median=0, lms=0, lts=0;
108 char *cptr, type[12], maskfile[FILENAME_MAX];
109 char imgfile[FILENAME_MAX], roifile[FILENAME_MAX],
110 dftfile[FILENAME_MAX], varfile[FILENAME_MAX];
126 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
127 imgfile[0]=roifile[0]=dftfile[0]=varfile[0]=maskfile[0]=(char)0;
129 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
130 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
132 if(strcasecmp(cptr,
"TM")==0) {
134 }
else if(strncasecmp(cptr,
"MEDIAN", 1)==0) {
136 }
else if(strcasecmp(cptr,
"LMS")==0) {
138 }
else if(strcasecmp(cptr,
"LTS")==0) {
140 }
else if(strcasecmp(cptr,
"P")==0 || strcasecmp(cptr,
"PLANES")==0) {
141 allplanes=1;
continue;
142 }
else if(strncasecmp(cptr,
"P=", 2)==0) {
143 cptr+=2;
if(strlen(cptr)>0) {
if(
intExpand(cptr, &ilist)==0)
continue;}
144 }
else if(strncasecmp(cptr,
"V=", 2)==0) {
146 if(strncasecmp(cptr,
"VAR", 1)==0) {variance=1;
continue;}
147 if(strncasecmp(cptr,
"SD", 1)==0) {variance=2;
continue;}
148 if(strncasecmp(cptr,
"CV", 1)==0) {variance=3;
continue;}
149 if(strlen(cptr)<1) {variance=1;
continue;}
150 else if(*cptr==
's' || *cptr==
'S') {variance=2;
continue;}
151 else if(*cptr==
'c' || *cptr==
'C') {variance=3;
continue;}
153 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
164 strlcpy(imgfile, argv[ai], FILENAME_MAX); ai++;
169 for(; ai<argc; ai++) {
171 cptr=strrchr(argv[ai],
'.');
173 if(cptr!=NULL && strcasecmp(cptr,
".roi")==0) {
174 strlcpy(roifile, argv[ai], FILENAME_MAX);
175 if(verbose>1) printf(
"roifile[%d] := %s\n", roifileNr+1, roifile);
178 fprintf(stderr,
"Error in reading '%s': %s\n", roifile,
roierrmsg);
182 roifileNr++;
continue;
183 }
else if(!maskfile[0] && roifileNr==0) {
184 strlcpy(maskfile, argv[ai], FILENAME_MAX);
187 }
else if(!dftfile[0]) {
188 strlcpy(dftfile, argv[ai], FILENAME_MAX);
continue;
191 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
197 if(!imgfile[0]) {
tpcPrintUsage(argv[0], info, stdout);
return(1);}
198 if((!roifile[0] || rlist.
nr<=0) && !maskfile[0]) {
199 fprintf(stderr,
"Error: no ROI or mask file found.\n");
204 if((variance>0 || median || lms || lts) && maskfile[0]) {
205 fprintf(stderr,
"Error: mask file cannot be used with given options.\n");
209 if(variance>0 && (median || lms || lts)) {
210 fprintf(stderr,
"Error: invalid combination of options.\n");
217 strlcpy(dftfile, imgfile, FILENAME_MAX);
218 cptr=strrchr(dftfile,
'.');
if(cptr!=NULL) *cptr=(char)0;
219 strcat(dftfile,
".dft");
222 strlcpy(varfile, dftfile, FILENAME_MAX);
223 cptr=strrchr(varfile,
'.');
if(cptr!=NULL) *cptr=(char)0;
224 if(variance==1) strcat(varfile,
".var");
225 else if(variance==2) strcat(varfile,
".sd");
226 else strcat(varfile,
".cv");
232 for(ai=0; ai<argc; ai++)
233 printf(
"%s ", argv[ai]);
235 printf(
"imgfile := %s\n", imgfile);
236 printf(
"dftfile := %s\n", dftfile);
237 printf(
"varfile := %s\n", varfile);
238 printf(
"roifileNr := %d\n", roifileNr);
239 if(allplanes) printf(
"ROIs are calculated on all image planes.\n");
241 printf(
"ROIs are calculated on %d image planes:\n %d",
242 ilist.
nr, ilist.
i[0]);
243 for(
int i=1; i<ilist.
nr; i++) printf(
", %d", ilist.
i[i]);
246 printf(
"maskfile := %s\n", maskfile);
247 printf(
"timetype := %d\n", timetype);
248 printf(
"median := %d\n", median);
249 printf(
"lms := %d\n", lms);
250 printf(
"lts := %d\n", lts);
251 printf(
"variance := %d\n", variance);
253 if(verbose>2 && rlist.
nr>0) {
255 printf(
"ROI# Name Plane Type Zoom RZoom Image\n");
262 else strcpy(type,
"???");
264 printf(
"%4d %-8.8s %3d %-5.5s %4.0f %5.0f %s\n",
275 if(verbose>0) fprintf(stdout,
"reading %s\n", imgfile);
278 fprintf(stderr,
"Error in reading image: %s\n", img.
statmsg);
283 printf(
"dimt := %d\n", img.
dimt);
284 printf(
"dimx := %d\n", img.
dimx);
285 printf(
"dimy := %d\n", img.
dimy);
286 printf(
"dimz := %d\n", img.
dimz);
289 if((median || lms || lts) && img.
dimt!=1){
290 fprintf(stderr,
"Error: do not use robust estimation for dynamic image.\n");
297 fprintf(stderr,
"Warning: file is not an image.\n");
316 if(ret>0) fprintf(stderr,
317 "Warning: ROI(s) may have been drawn to image with different reconstruction zoom.\n");
325 if(verbose>0) {fprintf(stdout,
"reading %s\n", maskfile); fflush(stdout);}
332 fprintf(stderr,
"Warning: mask file is not an image.\n");
335 fprintf(stderr,
"Error: ROI mask image contains more than one frame.\n");
341 fprintf(stderr,
"Error: invalid image dimensions in ROI mask image.\n");
345 if(verbose>1) printf(
"mask image was read.\n");
347 if(verbose>1) printf(
"trying to read VRD file\n");
349 ret=
vrdRead(maskfile, &vr, NULL);
351 if(ret==0) ret=
vrd2vol(&vr, &vol, 1.0, 0.0, NULL);
355 if(ret==0 && verbose>1) printf(
"vrd file was read.\n");
358 fprintf(stderr,
"Error: cannot read mask or volume range definition file\n");
365 if(ret!=0 || mlist.
nr==0) {
366 fprintf(stderr,
"Error: invalid ROI mask image.\n");
367 if(verbose>1) printf(
"ret := %d\n", ret);
371 if(verbose>1) printf(
"ROI nr in mask image := %d\n", mlist.
nr);
378 if(verbose>1) {fprintf(stdout,
"allocating memory for regional TACs\n"); fflush(stdout);}
383 fprintf(stderr,
"Error: cannot allocate memory.\n");
389 if(verbose>2) fprintf(stdout,
"preparing DFT\n");
392 char *cptr=strrchr(dftfile,
'.');
393 if(cptr!=NULL && strcasecmp(cptr,
".TAC")==0)
402 for(
int fi=0; fi<img.
dimt; fi++) {dft.
x1[fi]/=60.0; dft.
x2[fi]/=60.0; dft.
x[fi]/=60.0;}
413 if(verbose>0) {fprintf(stdout,
"calculating mask VOIs\n"); fflush(stdout);}
415 for(voi=0; voi<mlist.
nr; voi++) {
418 fprintf(stderr,
"Error: cannot use ROI mask (%d).\n", -pxlNr);
439 if(verbose>1) fprintf(stdout,
"saving the TACs\n");
442 fprintf(stderr,
"Error in writing '%s': %s\n", dftfile,
dfterrmsg);
445 if(verbose>0) fprintf(stdout,
"%d regional TACs written in %s\n", dft.
voiNr, dftfile);
456 if(verbose>0) {fprintf(stdout,
"processing ROIs\n"); fflush(stdout);}
457 int fi, ri, xi, yi, plane=0;
459 double v,
mean, var, *helpv;
464 int max_roi_zoom=0.0;
466 if((
int)roundf(rptr->
roi->
zoom) > max_roi_zoom) max_roi_zoom=(int)roundf(rptr->
roi->
zoom);
469 if(verbose>2) printf(
"max_roi_zoom := %d\n", max_roi_zoom);
474 int roidimx=max_roi_zoom*img.
dimx;
475 int roidimy=max_roi_zoom*img.
dimy;
477 helpv=malloc(roidimy*roidimx*
sizeof(
double));
478 onoff=malloc(roidimx*
sizeof(
char*));
479 if(helpv==NULL || onoff==NULL) {
480 fprintf(stderr,
"Error: out of memory.\n");
485 for(xi=0; xi<roidimx; xi++) {
486 onoff[xi]=malloc(roidimy*
sizeof(
char));
487 if(onoff[xi]==NULL) {
488 fprintf(stderr,
"Error: out of memory.\n");
491 free(helpv);
return(5);
494 scaled_img=malloc(img.
dimt*
sizeof(
float**));
495 if(scaled_img==NULL) {
496 fprintf(stderr,
"Error: out of memory.\n");
499 for(xi=0; xi<roidimx; xi++) free(onoff[xi]);
501 free(helpv);
return(5);
503 for(fi=0; fi<img.
dimt; fi++){
504 scaled_img[fi]=malloc(roidimy*
sizeof(
float*));
505 if(scaled_img[fi]==NULL) {
506 fprintf(stderr,
"Error: out of memory.\n");
509 for(xi=0; xi<roidimx; xi++) free(onoff[xi]);
511 free(helpv);
return(5);
513 for(yi=0; yi<roidimy; yi++) {
514 scaled_img[fi][yi]=malloc(roidimx*
sizeof(
float));
515 if(scaled_img[fi][yi]==NULL) {
516 fprintf(stderr,
"Error: out of memory.\n");
519 for(xi=0; xi<roidimx; xi++) free(onoff[xi]);
521 free(helpv);
return(5);
531 fprintf(stdout,
"-----------\n Processing ROI %d\n", rptr->
roi->
roi);
532 fprintf(stdout,
" ROI was drawn with zoom %f\n", rptr->
roi->
zoom);
538 if(verbose>4) {fprintf(stdout,
" ROI plane %d\n", plane); fflush(stdout);}
551 fprintf(stderr,
"Error(%d) in setting ROI: %s\n", ret,
roierrmsg);
554 printf(
"dim_x=%d dim_y=%d zoom=%g\n", img.
dimx, img.
dimy, img.
zoom);
558 for(xi=0; xi<roidimx; xi++) free(onoff[xi]);
560 for(fi=0; fi<img.
dimt; fi++) {
561 for(yi=0; yi<roidimy; yi++) free(scaled_img[fi][yi]);
562 free(scaled_img[fi]);
565 free(helpv);
return(6);
570 for(
int zi=0; zi<img.
dimz; zi++) {
575 }
else if(ilist.
nr>0) {
576 for(
int i=0; i<ilist.
nr; i++)
if(ilist.
i[i]==img.
planeNumber[zi]) {isRoi=1;
break;}
580 if(isRoi==0)
continue;
581 if(verbose>4) {fprintf(stdout,
" image plane %d\n", img.
planeNumber[zi]); fflush(stdout);}
584 if(dft.
voiNr>=dft._voidataNr) {
587 fprintf(stderr,
"Error: cannot reallocate memory for TACs.\n");
590 for(xi=0; xi<roidimx; xi++) free(onoff[xi]);
592 for(fi=0; fi<img.
dimt; fi++) {
593 for(yi=0; yi<roidimy; yi++) free(scaled_img[fi][yi]);
594 free(scaled_img[fi]);
597 free(helpv);
return(6);
602 for(fi=0; fi<img.
dimt; fi++) {
607 pxlNr=0; voi=dft.
voiNr;
610 if(onoff[xi][yi]>0) {
611 for(fi=0; fi<img.
dimt; fi++) {
612 if(!(median||lms||lts)){
613 if(verbose>100) printf(
" %g\n", scaled_img[fi][yi][xi]);
614 dft.
voi[voi].
y[fi]+=(double)scaled_img[fi][yi][xi];
616 helpv[pxlNr]=(double)scaled_img[fi][yi][xi];
624 printf(
"\n ROI %d\n", voi);
625 if(verbose>2) printf(
" number_of_pixels := %d\n", pxlNr);
626 if(verbose>2 && !(median||lms||lts)) printf(
" sum_of_pixels := %g\n", dft.
voi[voi].
y[0]);
628 if(!(median||lms||lts)) {
629 if(pxlNr>0)
for(fi=0; fi<img.
dimt; fi++) dft.
voi[voi].
y[fi]/=(
double)pxlNr;
646 dft.
voi[voi].
y2[0]=var;
650 if(onoff[xi][yi]>0) {
651 for(fi=0; fi<img.
dimt; fi++) {
652 v=scaled_img[fi][yi][xi]-dft.
voi[voi].
y[fi];
653 dft.
voi[voi].
y2[fi]+=v*v;
657 if(pxlNr>1)
for(fi=0; fi<img.
dimt; fi++) dft.
voi[voi].
y2[fi]/=(
double)(pxlNr-1);
659 if(variance>1)
for(fi=0; fi<img.
dimt; fi++)
660 if(dft.
voi[voi].
y2[fi]>0.0)
661 dft.
voi[voi].
y2[fi]=sqrt(dft.
voi[voi].
y2[fi]);
662 if(variance==3)
for(fi=0; fi<img.
dimt; fi++)
663 if(fabs(dft.
voi[voi].
y[fi])>1.0e-12) {
665 dft.
voi[voi].
y2[fi]*=100.0;
683 strcat(dft.
voi[voi].
name,
"__");
697 if(strcasecmp(tmp,
"D")==0) {
699 }
else if(strcasecmp(tmp,
"S")==0 || strcasecmp(tmp,
"SI")==0) {
703 strcat(dft.
voi[voi].
name,
"_");
704 strcat(dft.
voi[voi].
name, tmp);
707 strcat(dft.
voi[voi].
name,
"_");
712 if(verbose>0) {fprintf(stdout,
" calculated %s\n", dft.
voi[voi].
name); fflush(stdout);}
721 for(xi=0; xi<roidimx; xi++) free(onoff[xi]);
723 for(fi=0; fi<img.
dimt; fi++) {
724 for(yi=0; yi<roidimy; yi++) free(scaled_img[fi][yi]);
725 free(scaled_img[fi]);
734 if(verbose>1) fprintf(stdout,
"saving the TACs\n");
736 if(median) sprintf(dft.
comments,
"# Median values for ROIs.\n");
737 if(lms) sprintf(dft.
comments,
"# Least median of squares values for ROIs.\n");
738 if(lts) sprintf(dft.
comments,
"# Least trimmed square values for ROIs.\n");
742 fprintf(stderr,
"Error in writing '%s': %s\n", dftfile,
dfterrmsg);
745 if(verbose>0) fprintf(stdout,
"%d regional TACs written in %s\n", dft.
voiNr, dftfile);
752 if(verbose>0) fprintf(stdout,
"saving the variance curves\n");
753 sprintf(dft.
comments,
"# variances\n");
755 else if(variance==3) strcpy(dft.
unit,
"%");
756 for(ri=0; ri<dft.
voiNr; ri++)
for(fi=0; fi<dft.
frameNr; fi++)
761 fprintf(stderr,
"Error in writing '%s': %s\n", varfile,
dfterrmsg);
765 fprintf(stdout,
"%d regional variance curves written in %s\n", dft.
voiNr, varfile);
768 if(verbose>=0) printf(
"\n");
int dftAddmem(DFT *dft, int voiNr)
int dftWrite(DFT *data, char *filename)
void mat_numdoc(int matnum, Matval *matval)
void roi_empty(ROI_list *rl)
void roi_init(ROI_list *rl)
int roi_read(const char *fname, ROI_list *rl)
int roi_onoff(ROI *roi, int dimx, int dimy, char **m)
void roiOnOffPrint(int dimx, int dimy, char **m)
int roiOnOff(ROI *roi, int dimx, int dimy, char **m)
int imgAllocate(IMG *image, int planes, int rows, int columns, int frames)
void imgEmpty(IMG *image)
int imgMaskRoiNr(IMG *img, INTEGER_LIST *list)
int imgVoiMaskTAC(IMG *img, IMG *mask, int mv, double *tac, int verbose)
int imgRead(const char *fname, IMG *img)
char * imgUnit(int dunit)
int integerListEmpty(INTEGER_LIST *l)
int integerListInit(INTEGER_LIST *l)
int intExpand(char *text, INT_list *list)
void intInit(INT_list *l)
void intEmpty(INT_list *l)
Header file for libtpccurveio.
#define DFT_FORMAT_STANDARD
#define DFT_TIME_STARTEND
Header file for libtpcidi.
Header file for libtpcimgio.
int volAllocate(VOL *vol, int planes, int rows, int columns)
int vrd2vol(VOL_RANGE *r, VOL *vol, float in, float out, char *status)
int vrdRead(char *vdffile, VOL_RANGE *vol_range, char *status)
int vol2img(VOL *vol, IMG *img, int frame)
Header file for libtpcimgp.
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
#define MAX_REGIONNAME_LEN
int strTokenNCpy(const char *str1, const char *str2, int i, char *str3, int count)
int strTokenNr(const char *str1, const char *str2)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
int studynr_from_fname(char *fname, char *studynr)
size_t strlcat(char *dst, const char *src, size_t dstsize)
void tpcPrintBuild(const char *program, FILE *fp)
#define MAX_REGIONSUBNAME_LEN
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Header file for libtpcmodel.
double least_median_of_squares(double *data, int n)
Fit a constant (horisontal straight line) to the data by minimising the median of squared residuals.
double dmedian(double *data, int n)
int mean(double *x, double *y, int nr, double *xmean, double *xsd, double *ymean, double *ysd)
int least_trimmed_square(double data[], long int n, double *mean, double *variance)
Header file for libtpcmodext.
int dftAllocateWithIMG(DFT *dft, int tacNr, IMG *img)
Header file for libtpcroi.
char studynr[MAX_STUDYNR_LEN+1]
char comments[_DFT_COMMENT_LEN+1]
char unit[MAX_UNITS_LEN+1]
char imgfile[FILENAME_MAX]
char voiname[MAX_REGIONSUBNAME_LEN+1]
char name[MAX_REGIONNAME_LEN+1]
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char place[MAX_REGIONSUBNAME_LEN+1]