TPCCLIB
Loading...
Searching...
No Matches
imgratio.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <math.h>
13#include <string.h>
14#include <unistd.h>
15#include <time.h>
16/*****************************************************************************/
17#include "libtpcmisc.h"
18#include "libtpcimgio.h"
19#include "libtpcimgp.h"
20#include "libtpccurveio.h"
21#include "libtpcmodel.h"
22#include "libtpcmodext.h"
23/*****************************************************************************/
24
25/*****************************************************************************/
26static char *info[] = {
27 "Computes an AUC ratio image from dynamic PET image and reference region TTAC.",
28 "AUCs are calculated between start and end time given in minutes.",
29 "Image data can be in ECAT, Analyze 7.5, or NIfTI-1 format.",
30 " ",
31 "Usage: @P [Options] imgfile ttacfile starttime endtime outputfile",
32 " ",
33 "Options:",
34 " -Bound",
35 " Instead of VOXEL/REF, (VOXEL-REF)/REF ratio is calculated.",
36 " -Thr=<threshold%>",
37 " Pixels with AUC less than (threshold/100 x ref AUC) are set to zero;",
38 " default is 10%.",
39 " -max=<Max value>",
40 " Upper limit for output pixel values.",
41 " -noneg",
42 " Negative pixel values are set to zero.",
43 " -stdoptions", // List standard options like --help, -v, etc
44 " ",
45 "Example:",
46 " @P ua2918dy1.v ua2918cer.tac 60 90 ua2918ratio.v",
47 " ",
48 "See also: imginteg, imgcalc, dftratio, imgcbv, imgunit, tacunit",
49 " ",
50 "Keywords: image, modelling",
51 0};
52/*****************************************************************************/
53
54/*****************************************************************************/
55/* Turn on the globbing of the command line, since it is disabled by default in
56 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
57 In Unix&Linux wildcard command line processing is enabled by default. */
58/*
59#undef _CRT_glob
60#define _CRT_glob -1
61*/
62int _dowildcard = -1;
63/*****************************************************************************/
64
65/*****************************************************************************/
74 const char *file1,
76 const char *file2,
78 int verbose
79) {
80 int ii, mi, ret;
81 char tmp[1024];
82 ECAT_HEADERS ehdr;
83
84 if(verbose>1) printf("ecatCopyHeadersNoQuant(%s, %s)\n", file1, file2);
85 if(file1==NULL || file2==NULL) return(1);
86
87
88 /* Read headers */
89 ehdrInitiate(&ehdr);
90 ret=ecat7ReadHeaders(file1, &ehdr, verbose-1); if(ret!=0) return(10);
91 /* Remove main header information that should NOT be copied */
92 strcpy(tmp, "user_process_code");
93 ii=iftGet(&ehdr.mh, tmp, 0); iftDeleteItem(&ehdr.mh, ii, 0);
94 strcpy(tmp, "ecat_calibration_factor");
95 ii=iftGet(&ehdr.mh, tmp, 0); iftDeleteItem(&ehdr.mh, ii, 0);
96 strcpy(tmp, "calibration_units");
97 ii=iftGet(&ehdr.mh, tmp, 0); iftDeleteItem(&ehdr.mh, ii, 0);
98 strcpy(tmp, "calibration_units_label");
99 ii=iftGet(&ehdr.mh, tmp, 0); iftDeleteItem(&ehdr.mh, ii, 0);
100 strcpy(tmp, "num_frames");
101 ii=iftGet(&ehdr.mh, tmp, 0); iftDeleteItem(&ehdr.mh, ii, 0);
102
103 /* Remove subheader information that should NOT be copied */
104 for(mi=0; mi<ehdr.nr; mi++) {
105 strcpy(tmp, "scale_factor");
106 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
107 strcpy(tmp, "image_min");
108 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
109 strcpy(tmp, "image_max");
110 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
111 strcpy(tmp, "scan_min");
112 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
113 strcpy(tmp, "scan_max");
114 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
115 strcpy(tmp, "frame_duration");
116 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
117 strcpy(tmp, "frame_start_time");
118 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
119 strcpy(tmp, "decay_corr_fctr");
120 ii=iftGet(&ehdr.m[mi].sh, tmp, 0); iftDeleteItem(&ehdr.m[mi].sh, ii, 0);
121 }
122
123 /* Write headers */
124 ret=ecat7WriteHeaders(file2, &ehdr, verbose-1);
125 ehdrEmpty(&ehdr);
126 if(ret!=0) return(10+ret);
127
128 return 0;
129}
130/*****************************************************************************/
131
132/*****************************************************************************/
136int main(int argc, char **argv)
137{
138 int ai, help=0, version=0, verbose=1;
139 int ret;
140 int b_per_r=0; // 0 or 1
141 char tacfile[FILENAME_MAX], petfile[FILENAME_MAX], ratfile[FILENAME_MAX];
142 char tmp[512];
143 float calcThreshold=0.10;
144 float upperLimit=-1.0;
145 int nonnegativity_constraint=0;
146 DFT tac;
147 IMG img;
148 double v, tstart, tstop, aucref;
149
150
151 /*
152 * Get arguments
153 */
154 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
155 tacfile[0]=petfile[0]=ratfile[0]=(char)0;
156 imgInit(&img); dftInit(&tac);
157 tstart=tstop=nan("");
158 /* Options */
159 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
160 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
161 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
162 if(strncasecmp(cptr, "BOUND", 1)==0) {
163 b_per_r=1; continue;
164 } else if(strncasecmp(cptr, "THR=", 4)==0) {
165 double v;
166 if(atof_with_check(cptr+4, &v)==0) {
167 calcThreshold=0.01*v; if(calcThreshold<=2.0) continue;
168 }
169 } else if(strncasecmp(cptr, "MAX=", 4)==0) {
170 double v; if(atof_with_check(cptr+4, &v)==0 && v>0.0) {upperLimit=(float)v; continue;}
171 } else if(strncasecmp(cptr, "NONEG", 3)==0) {
172 nonnegativity_constraint=1; continue;
173 }
174 fprintf(stderr, "Error: unknown option '%s'.\n", argv[ai]);
175 return(1);
176 } else break;
177
178 /* Print help or version? */
179 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
180 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
181 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
182
183 /* Process other arguments, starting from the first non-option */
184 if(ai<argc) {strlcpy(petfile, argv[ai], FILENAME_MAX); ai++;}
185 if(ai<argc) {strlcpy(tacfile, argv[ai], FILENAME_MAX); ai++;}
186 if(ai<argc && atof_with_check(argv[ai], &v)==0) {tstart=v; ai++;}
187 if(ai<argc && atof_with_check(argv[ai], &v)==0) {tstop=v; ai++;}
188 if(ai<argc) {strlcpy(ratfile, argv[ai], FILENAME_MAX); ai++;}
189 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
190
191 /* Is something missing? */
192 if(!ratfile[0]) {
193 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
194 return(1);
195 }
196 if(tstop<tstart || tstart<0.0) {
197 fprintf(stderr, "Error: invalid time range arguments.\n");
198 return(1);
199 }
200 if(strcasecmp(petfile, ratfile)==0) {
201 fprintf(stderr, "Error: check the output filename.\n");
202 return(1);
203 }
204
205 /* In verbose mode print arguments and options */
206 if(verbose>1) {
207 printf("tacfile := %s\n", tacfile);
208 printf("petfile := %s\n", petfile);
209 printf("ratfile := %s\n", ratfile);
210 printf("tstart := %g\n", tstart);
211 printf("tstop := %g\n", tstop);
212 printf("b_per_r := %d\n", b_per_r);
213 printf("calcThreshold := %g%%\n", 100.*calcThreshold);
214 printf("max := %f\n", upperLimit);
215 printf("nonnegativity_constraint := %d\n", nonnegativity_constraint);
216 }
217
218
219 /*
220 * Read PET image and reference TTAC
221 */
222 {
223 if(verbose>1) printf("reading data files\n");
224 double endtime=-1.0;
225 FILE *lfp; if(verbose>1) lfp=stdout; else lfp=NULL;
227 petfile, NULL, tacfile, NULL, NULL, &endtime, &ai, &img,
228 NULL, &tac, 0, lfp, verbose-2, tmp);
229 if(ret!=0) {
230 fprintf(stderr, "Error in reading data: %s.\n", tmp);
231 if(verbose>1) printf(" ret := %d\n", ret);
232 return(2);
233 }
234 if(imgNaNs(&img, 1)>0)
235 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
236 if(verbose>2) printf("endtime := %g min\n", endtime);
237 /* Convert TTAC sample times to min */
238 dftTimeunitConversion(&tac, TUNIT_MIN);
239 if(verbose>3) dftPrint(&tac);
240 }
241 /* Check that PET data is image */
242 if(img.type!=IMG_TYPE_IMAGE) {
243 fprintf(stderr, "Error: %s is not an image.\n", petfile);
244 imgEmpty(&img); dftEmpty(&tac); return(3);
245 }
246
247
248
249 /*
250 * Calculate the reference region AUC in time range
251 */
252 {
253 if(verbose>1) printf("calculating TTAC AUC\n");
254 double t[2], auc[2];
255 t[0]=tstart; t[1]=tstop;
256 ret=interpolate(tac.x, tac.voi[0].y, tac.frameNr, t, NULL, auc, NULL, 2);
257 if(ret) {
258 fprintf(stderr, "Error in integration of reference region TAC.\n");
259 if(verbose>1) printf("ret := %d\n", ret);
260 imgEmpty(&img); dftEmpty(&tac); return(4);
261 }
262 aucref=auc[1]-auc[0];
263 if(verbose>1) {
264 printf("ref_AUC1 := %g\n", auc[0]);
265 printf("ref_AUC2 := %g\n", auc[1]);
266 }
267 if(verbose>0) printf("ref_AUC := %g\n", aucref);
268 if(aucref<=1.0E-10) {
269 fprintf(stderr, "Error: invalid reference region AUC; check the data.\n");
270 imgEmpty(&img); dftEmpty(&tac); return(5);
271 }
272 }
273
274
275 /*
276 * Allocate IMG for ratio image and fill the header info fields
277 */
278 if(verbose>1) printf("allocating memory for parametric image\n");
279 IMG rout;
280 imgInit(&rout);
281 ret=imgAllocateWithHeader(&rout, img.dimz, img.dimy, img.dimx, 1, &img);
282 if(ret) {
283 fprintf(stderr, "Error: cannot allocate IMG data.\n");
284 if(verbose>1) fprintf(stderr, "ret := %d\n", ret);
285 imgEmpty(&img); dftEmpty(&tac); return(6);
286 }
287 /* Set the frame time */
288 rout.start[0]=60.0*tstart; rout.end[0]=60.0*tstop;
289 /* and set the units */
290 rout.unit=CUNIT_UNITLESS;
291
292
293 /*
294 * Compute pixel-by-pixel
295 */
296 {
297 /* Determine the threshold (AUC unit = sec x concentration) */
298 float threshold=calcThreshold*tac.voi[0].y2[tac.frameNr-1];
299 if(verbose>2) {
300 printf("ref_AUC = %g\n", tac.voi[0].y2[tac.frameNr-1]);
301 printf("threshold x AUC = %g\n", threshold);
302 }
303 if(verbose>0) printf("computing pixel-by-pixel\n");
304 long long okNr=0;
305 int zi, yi, xi, fi;
306 float peti[img.dimt];
307 float t[2], auc[2], aucroi;
308 t[0]=60.0*tstart; t[1]=60.0*tstop;
309 for(zi=0; zi<img.dimz; zi++) {
310 if(verbose>5) printf("computing plane %d\n", img.planeNumber[zi]);
311 else if(verbose>0 && img.dimz>2) {fprintf(stdout, "."); fflush(stdout);}
312 for(yi=0; yi<img.dimy; yi++) for(xi=0; xi<img.dimx; xi++) {
313 /* Set results to zero */
314 rout.m[zi][yi][xi][0]=0.0;
315 /* Check the threshold */
316 ret=fpetintegral(img.start, img.end, img.m[zi][yi][xi], img.dimt, peti, NULL);
317 /* if AUC at the end is less than threshold value, then
318 do nothing with this pixel */
319 if(peti[img.dimt-1]<threshold) continue;
320 /* Subtract reference TTAC, if required */
321 if(b_per_r!=0)
322 for(fi=0; fi<img.dimt; fi++)
323 img.m[zi][yi][xi][fi]-=tac.voi[0].y[fi];
324 /* Calculate PET TAC integrals at time range start and end */
325 ret=finterpolate(img.mid, img.m[zi][yi][xi], img.dimt, t, NULL, auc, NULL, 2);
326 auc[0]/=60.0; auc[1]/=60.0;
327 if(ret) aucroi=0.0; else aucroi=auc[1]-auc[0];
328 /* Calculate the ratio */
329 rout.m[zi][yi][xi][0]=aucroi/aucref;
330 if(verbose>4 && zi==img.dimz/2 && yi==img.dimy/3 && xi==img.dimx/3) {
331 printf("\nVoxel [%d,%d,%d] AUC: %g - %g = %g\n", zi, yi, xi, auc[1], auc[0], aucroi);
332 printf("ratio := %g\n", aucroi/aucref);
333 }
334 /* Prepare for next pixel */
335 okNr++;
336 } /* next pixel on this plane */
337 } /* next image plane */
338 if(verbose>2) printf("okNr := %lld\n", okNr);
339 }
340
341 /* Remove pixel values that are higher than the user-defined limit */
342 if(upperLimit>0.0) {
343 if(verbose>0) fprintf(stdout, "filtering out ratio values exceeding %g\n", upperLimit);
344 imgCutoff(&rout, upperLimit, 0);
345 }
346 /* Set negative BP values to zero, if required */
347 if(nonnegativity_constraint!=0) {
348 if(verbose>1) printf("setting negative ratio values to zero\n");
349 imgCutoff(&rout, 0.0, 1);
350 }
351
352
353 /*
354 * Save the ratio image
355 */
356 if(verbose>1) printf("writing image %s\n", ratfile);
357 ret=imgWrite(ratfile, &rout);
358 if(ret) {
359 fprintf(stderr, "Error: %s\n", rout.statmsg);
360 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&rout); return(11);
361 }
362 if(verbose==1) printf("Ratio image saved: %s\n", ratfile);
363
364 if(rout._fileFormat==IMG_E7 || rout._fileFormat==IMG_E7_2D) {
365 if(verbose>1) printf("copying header information\n");
366 ret=ecat7CopyHeadersNoQuant(petfile, ratfile, verbose-1);
367 if(verbose>0 && ret!=0) printf("copying headers not successful (%d).\n", ret);
368 }
369
370 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&rout);
371 if(verbose>0) printf("done.\n");
372 return(0);
373}
374/*****************************************************************************/
375
376/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
void dftInit(DFT *data)
Definition dft.c:38
void dftEmpty(DFT *data)
Definition dft.c:20
void dftPrint(DFT *data)
Definition dftio.c:538
int dftTimeunitConversion(DFT *dft, int tunit)
Definition dftunit.c:119
void ehdrEmpty(ECAT_HEADERS *ehdr)
Definition ecat7ift.c:47
int ecat7WriteHeaders(const char *fname, ECAT_HEADERS *ehdr, int verbose)
Definition ecat7ift.c:755
void ehdrInitiate(ECAT_HEADERS *ehdr)
Definition ecat7ift.c:21
int ecat7ReadHeaders(const char *fname, ECAT_HEADERS *ehdr, int verbose)
Definition ecat7ift.c:687
int iftDeleteItem(IFT *ift, int item, int verbose)
Definition ift.c:169
int iftGet(IFT *ift, char *key, int verbose)
Definition iftsrch.c:15
unsigned long long imgNaNs(IMG *img, int fix)
Definition img.c:658
int imgAllocateWithHeader(IMG *image, int planes, int rows, int columns, int frames, IMG *image_from)
Definition img.c:279
void imgEmpty(IMG *image)
Definition img.c:121
void imgInit(IMG *image)
Definition img.c:60
int ecat7CopyHeadersNoQuant(const char *file1, const char *file2, int verbose)
Definition imgcalc.c:86
int imgWrite(const char *fname, IMG *img)
Definition imgfile.c:136
int imgReadModelingData(char *petfile, char *siffile, char *inputfile1, char *inputfile2, char *inputfile3, double *fitdur, int *fitframeNr, IMG *img, DFT *inp, DFT *iinp, int verifypeak, FILE *loginfo, int verbose, char *status)
Definition imginput.c:24
void imgCutoff(IMG *image, float cutoff, int mode)
int fpetintegral(float *x1, float *x2, float *y, int nr, float *ie, float *iie)
Integrate PET TAC data to frame mid times. Float version of petintegral().
Definition integr.c:838
int interpolate(double *x, double *y, int nr, double *newx, double *newy, double *newyi, double *newyii, int newnr)
Linear interpolation and integration.
Definition integr.c:28
int finterpolate(float *x, float *y, int nr, float *newx, float *newy, float *newyi, float *newyii, int newnr)
float version of interpolate().
Definition integr.c:161
Header file for libtpccurveio.
Header file for libtpcimgio.
#define IMG_E7
#define IMG_E7_2D
#define IMG_TYPE_IMAGE
Header file for libtpcimgp.
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:40
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:213
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
Header file for libtpcmodel.
Header file for libtpcmodext.
Voi * voi
int frameNr
double * x
ECAT_MATRIX * m
unsigned short int dimx
char type
float **** m
char unit
int _fileFormat
unsigned short int dimt
int * planeNumber
float * start
unsigned short int dimz
unsigned short int dimy
float * end
const char * statmsg
float * mid
double * y2
double * y