TPCCLIB
Loading...
Searching...
No Matches
imgflowb.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <math.h>
15/*****************************************************************************/
16#include "tpcextensions.h"
17#include "tpcift.h"
18#include "tpccsv.h"
19#include "tpctac.h"
20#include "tpcimage.h"
21#include "tpcli.h"
22#include "tpclinopt.h"
23#include "tpctacmod.h"
24#include "tpctacimg.h"
25/*****************************************************************************/
26
27/*****************************************************************************/
28static char *info[] = {
29 "Make a map of cerebral blood flow from dynamic radiowater PET image,.",
30 "correcting for the PVE (Iida et al., 2000).",
31 " ",
32 "Currently only NIfTI format is supported.",
33 "Radioactivity concentrations in image and blood data must be in same units.",
34 "Maps of grey matter blood flow and alpha (PTF) are saved.",
35 " ",
36 "Usage: @P [options] imgfile btacfile fgmap agmap",
37 " ",
38 "Options:",
39 " -end=<Fit end time (sec)>",
40 " Use data from 0 to end time; by default, 300 s.",
41 " -thr=<threshold%>",
42 " Pixels with AUC less than (threshold/100 x BTAC AUC) are set to zero.",
43 " Default is 1%.",
44 " -aW=<filename>",
45 " Map of white matter alpha (PTF).",
46 " -Va=<filename | 0>",
47 " Va map is saved in units mL blood/mL PET volume, or, Va is fixed to 0.",
48 " -dT=<filename | delay>",
49 " Time delay map is saved, or, delay is fixed to given time in sec.",
50 " -stdoptions", // List standard options like --help, -v, etc
51 " ",
52 "See also: imgflow, imgdelay",
53 " ",
54 "Keywords: image, blood flow, radiowater, brain",
55 0};
56/*****************************************************************************/
57
58/*****************************************************************************/
59/* Turn on the globbing of the command line, since it is disabled by default in
60 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
61 In Unix&Linux wildcard command line processing is enabled by default. */
62/*
63#undef _CRT_glob
64#define _CRT_glob -1
65*/
66int _dowildcard = -1;
67/*****************************************************************************/
68
69/*****************************************************************************/
76int tacInputForLLSQ(
78 TAC *btac,
81 TAC *ttac,
83 double dtmin,
85 double dtmax,
87 double dtstep,
89 TAC *b1,
91 TAC *b2,
93 TAC *b3,
95 TPCSTATUS *status
96) {
97 int verbose=0; if(status!=NULL) verbose=status->verbose;
98 if(verbose>2) {printf("%s(inp, tis, %g, %g, %g, ...)\n", __func__, dtmin, dtmax, dtstep); fflush(stdout);}
99
100 /* Check function input */
101 if(btac==NULL || ttac==NULL || btac->sampleNr<1 || ttac->sampleNr<1 || btac->tacNr<1 || ttac->tacNr<1 ) {
102 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
103 return(TPCERROR_FAIL);
104 }
105 if(verbose>3) {
106 printf(" %d BTAC ", btac->sampleNr); if(btac->isframe) printf("frames\n"); else printf("samples\n");
107 printf(" %d TTAC ", ttac->sampleNr); if(ttac->isframe) printf("frames\n"); else printf("samples\n");
108 }
109 if(btac->sampleNr<5 || ttac->sampleNr<5) {
110 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_TOO_FEW);
111 return(TPCERROR_TOO_FEW);
112 }
113 double brange[2], trange[2];
114 if(tacXRange(ttac, &trange[0], &trange[1])!=0 || tacXRange(btac, &brange[0], &brange[1])!=0) {
115 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
117 }
118 if(verbose>3) {
119 printf(" TTAC range := %g - %g\n BTAC range := %g - %g\n",
120 trange[0], trange[1], brange[0], brange[1]);
121 }
122 int dtNr=1;
123 if(isfinite(dtstep) && dtstep>0.0) {
124 double r=dtmax-dtmin;
125 if(!(r>5.0*dtstep)) {
126 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
127 return(TPCERROR_FAIL);
128 }
129 dtNr=1+r/dtstep;
130 if(dtNr>5000) {
131 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
132 return(TPCERROR_FAIL);
133 }
134 /* Check that input curve is long enough */
135 if((brange[1]+dtmin)<0.95*trange[1]) {
136 if(verbose>2) printf("BTAC tmax=%g TTAC tmax=%g dtmin=%g\n", brange[1], trange[1], dtmin);
137 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_XRANGE);
139 }
140 }
141
142 /* Check if there is anything to do */
143 if(b1==NULL && b2==NULL && b3==NULL) {
144 if(verbose>2) {printf(" no output required\n"); fflush(stdout);}
145 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
146 return(TPCERROR_OK);
147 }
148
149 /* Integrate BTAC */
150 double bi[btac->sampleNr], bii[btac->sampleNr], *ix;
151 int ret=0;
152 if(btac->isframe==0) {
153 if(verbose>3) {printf(" integrating BTAC samples\n"); fflush(stdout);}
154 ret=liIntegrate(btac->x, btac->c[0].y, btac->sampleNr, bi, 3, 0);
155 if(!ret) liIntegrate(btac->x, bi, btac->sampleNr, bii, 3, 0);
156 ix=btac->x;
157 } else {
158 if(verbose>3) {printf(" integrating BTAC frames\n"); fflush(stdout);}
159 ret=liIntegrateFE(btac->x1, btac->x2, btac->c[0].y, btac->sampleNr, bi, bii, 0);
160 ix=btac->x2;
161 }
162 if(ret) {
163 if(verbose>2) {printf(" -> returns %d\n", ret); fflush(stdout);}
164 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_VALUE);
166 }
167
168 /* Set space for result BTACs */
169 if(verbose>3) {printf(" room for output\n"); fflush(stdout);}
170 if(b1!=NULL) tacFree(b1);
171 if(b2!=NULL) tacFree(b2);
172 if(b3!=NULL) tacFree(b3);
173 if(b1!=NULL) ret=tacDuplicate(ttac, b1);
174 if(b2!=NULL && !ret) ret=tacDuplicate(ttac, b2);
175 if(b3!=NULL && !ret) ret=tacDuplicate(ttac, b3);
176 if(ret!=TPCERROR_OK) {statusSet(status, __func__, __FILE__, __LINE__, ret); return(ret);}
177 if(dtNr>1) {
178 if(b1!=NULL) {ret=tacAllocateMore(b1, dtNr); b1->tacNr=dtNr;}
179 if(b2!=NULL && !ret) {ret=tacAllocateMore(b2, dtNr); b2->tacNr=dtNr;}
180 if(b3!=NULL && !ret) {ret=tacAllocateMore(b3, dtNr); b3->tacNr=dtNr;}
181 if(ret!=TPCERROR_OK) {statusSet(status, __func__, __FILE__, __LINE__, ret); return(ret);}
182 }
183
184 /* Interpolate to TTAC times */
185 if(b1!=NULL) {
186 if(verbose>3) {printf(" interpolating BTAC\n"); fflush(stdout);}
187 double dx[btac->sampleNr];
188 for(int ci=0; ci<b1->tacNr; ci++) {
189 double dt=0.0; if(dtNr>1) dt=dtmin+dtstep*(double)ci;
190 b1->c[ci].size=dt;
191 for(int ti=0; ti<btac->sampleNr; ti++) dx[ti]=btac->x[ti]+dt;
192 if(ttac->isframe==0)
193 ret=liInterpolate(dx, btac->c[0].y, btac->sampleNr, b1->x, b1->c[ci].y,
194 NULL, NULL, b1->sampleNr, 3, 1, 0);
195 else
196 ret=liInterpolateForPET(dx, btac->c[0].y, btac->sampleNr, b1->x1, b1->x2, b1->c[ci].y,
197 NULL, NULL, b1->sampleNr, 3, 1, 0);
198 if(ret) break;
199 }
200 }
201 if(b2!=NULL && !ret) {
202 if(verbose>3) {printf(" interpolating BTAC integral\n"); fflush(stdout);}
203 double dx[btac->sampleNr];
204 for(int ci=0; ci<b2->tacNr; ci++) {
205 double dt=0.0; if(dtNr>1) dt=dtmin+dtstep*(double)ci;
206 b2->c[ci].size=dt;
207 for(int ti=0; ti<btac->sampleNr; ti++) dx[ti]=ix[ti]+dt;
208 if(ttac->isframe==0)
209 ret=liInterpolate(dx, bi, btac->sampleNr, b2->x, b2->c[ci].y,
210 NULL, NULL, b2->sampleNr, 3, 1, 0);
211 else
212 ret=liInterpolateForPET(dx, bi, btac->sampleNr, b2->x1, b2->x2, b2->c[ci].y,
213 NULL, NULL, b2->sampleNr, 3, 1, 0);
214 if(ret) break;
215 }
216 }
217 if(b3!=NULL && !ret) {
218 if(verbose>3) {printf(" interpolating BTAC 2nd integral\n"); fflush(stdout);}
219 double dx[btac->sampleNr];
220 for(int ci=0; ci<b3->tacNr; ci++) {
221 double dt=0.0; if(dtNr>1) dt=dtmin+dtstep*(double)ci;
222 b3->c[ci].size=dt;
223 for(int ti=0; ti<btac->sampleNr; ti++) dx[ti]=ix[ti]+dt;
224 if(ttac->isframe==0)
225 ret=liInterpolate(dx, bii, btac->sampleNr, b3->x, b3->c[ci].y,
226 NULL, NULL, b3->sampleNr, 3, 1, 0);
227 else
228 ret=liInterpolateForPET(dx, bii, btac->sampleNr, b3->x1, b3->x2, b3->c[ci].y,
229 NULL, NULL, b3->sampleNr, 3, 1, 0);
230 if(ret) break;
231 }
232 }
233 if(ret) {
234 if(verbose>2) {printf(" -> returns %d\n", ret); fflush(stdout);}
235 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_VALUE);
237 }
238
239 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
240 return(TPCERROR_OK);
241}
242/*****************************************************************************/
243
244/*****************************************************************************/
248int main(int argc, char **argv)
249{
250 int ai, help=0, version=0, verbose=1;
251 int ret;
252 char imgfile[FILENAME_MAX], btacfile[FILENAME_MAX];
253 char fgfile[FILENAME_MAX], agfile[FILENAME_MAX], fwfile[FILENAME_MAX], awfile[FILENAME_MAX];
254 char vafile[FILENAME_MAX], dtfile[FILENAME_MAX], ssfile[FILENAME_MAX];
255 char llsqfile[FILENAME_MAX]; // Results from LLSQ: p0-4, dT, sum-of-squares
256 char kmapfile[FILENAME_MAX]; // Results converted to CM: Va, K1a, k2a, K1b, k2b, dT, SS; 1/min
257 double fixedVa=nan("");
258 double fixeddT=nan("");
259 double endtime=300.0; // fit end time in seconds
260 double endtimemin=120.0; // shortest fit end time allowed
261 double dtrange[2]={-10.,+50.};
262 double dtstep=1.0;
263 float calcThreshold=0.01;
264
265 double pg=1.03;
266 double pw=0.86;
267
268
269 /*
270 * Get arguments
271 */
272 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
273 imgfile[0]=btacfile[0]=(char)0;
274 fgfile[0]=agfile[0]=vafile[0]=awfile[0]=fwfile[0]=dtfile[0]=ssfile[0]=(char)0;
275 llsqfile[0]=kmapfile[0]=(char)0;
276 /* Options */
277 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
278 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
279 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
280 if(strncasecmp(cptr, "END=", 4)==0) {
281 ret=atofCheck(cptr+4, &endtime); if(!ret && endtime>0.0) continue;
282 } else if(strncasecmp(cptr, "MIN=", 4)==0) {
283 ret=atofCheck(cptr+4, &dtrange[0]); if(!ret && isfinite(dtrange[0])) continue;
284 } else if(strncasecmp(cptr, "MAX=", 4)==0) {
285 ret=atofCheck(cptr+4, &dtrange[1]); if(!ret && isfinite(dtrange[1])) continue;
286 } else if(strncasecmp(cptr, "THR=", 4)==0) {
287 double v; ret=atofCheck(cptr+4, &v);
288 if(!ret && v<100.0) {calcThreshold=(float)(0.01*v); continue;}
289 } else if(strncasecmp(cptr, "AW=", 3)==0) {
290 strlcpy(awfile, cptr+3, FILENAME_MAX); if(strlen(awfile)) continue;
291 } else if(strncasecmp(cptr, "FW=", 3)==0) {
292 strlcpy(fwfile, cptr+3, FILENAME_MAX); if(strlen(fwfile)) continue;
293 } else if(strcasecmp(cptr, "VA=0")==0) {
294 fixedVa=0.0; continue;
295 } else if(strncasecmp(cptr, "VA=", 3)==0) {
296 strlcpy(vafile, cptr+3, FILENAME_MAX); if(strlen(vafile)) continue;
297 } else if(strncasecmp(cptr, "DT=", 3)==0) {
298 double v; ret=atofCheck(cptr+3, &v);
299 if(!ret && v>=-50.0 && v<=50.0) {fixeddT=v; continue;}
300 strlcpy(dtfile, cptr+3, FILENAME_MAX); if(strlen(dtfile)) continue;
301 } else if(strncasecmp(cptr, "SS=", 3)==0) {
302 strlcpy(ssfile, cptr+3, FILENAME_MAX); if(strlen(ssfile)) continue;
303 } else if(strncasecmp(cptr, "LLSQ=", 5)==0) {
304 strlcpy(llsqfile, cptr+5, FILENAME_MAX); if(strlen(llsqfile)) continue;
305 } else if(strncasecmp(cptr, "KMAP=", 5)==0) {
306 strlcpy(kmapfile, cptr+5, FILENAME_MAX); if(strlen(kmapfile)) continue;
307 }
308 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
309 return(1);
310 } else break;
311
312 /* Print help or version? */
313 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
314 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
315 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
316
317 /* Process other arguments, starting from the first non-option */
318 if(ai<argc) strlcpy(imgfile, argv[ai++], FILENAME_MAX);
319 if(ai<argc) strlcpy(btacfile, argv[ai++], FILENAME_MAX);
320 if(ai<argc) strlcpy(fgfile, argv[ai++], FILENAME_MAX);
321 if(ai<argc) strlcpy(agfile, argv[ai++], FILENAME_MAX);
322 if(ai<argc) {fprintf(stderr, "Error: too many arguments: '%s'.\n", argv[ai]); return(1);}
323 /* Is something missing? */
324 if(!agfile[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
325
326 /* Check options */
327 if(endtime<endtimemin) {
328 fprintf(stderr, "Error: too short fit time set with option -end.\n");
329 return(1);
330 }
331 if(isfinite(fixeddT)) {
332 dtrange[0]=dtrange[1]=fixeddT;
333 dtstep=nan("");
334 } else {
335 if(dtrange[0]>dtrange[1]) {int i=dtrange[0]; dtrange[0]=dtrange[1]; dtrange[1]=i;}
336 if((dtrange[1]-dtrange[0])>180.) {
337 fprintf(stderr, "Error: too wide delay range.\n");
338 return(1);
339 } else if((dtrange[1]-dtrange[0])>120.) {
340 fprintf(stderr, "Warning: large delay range.\n");
341 } else if((dtrange[1]-dtrange[0])<4.) {
342 fprintf(stderr, "Error: too short delay range.\n");
343 return(1);
344 }
345 }
346
347 /* In verbose mode print arguments and options */
348 if(verbose>1) {
349 printf("imgfile := %s\n", imgfile);
350 printf("btacfile := %s\n", btacfile);
351 printf("fgfile := %s\n", fgfile);
352 printf("agfile := %s\n", agfile);
353 printf("endtime := %g s\n", endtime);
354 printf("delay_range := %g - %g s\n", dtrange[0], dtrange[1]);
355 printf("delay_step_size := %g s\n", dtstep);
356 printf("threshold := %g\n", calcThreshold);
357 if(awfile[0]) printf("awfile := %s\n", awfile);
358 if(fwfile[0]) printf("fwfile := %s\n", fwfile);
359 if(vafile[0]) printf("vafile := %s\n", vafile);
360 if(isfinite(fixedVa)) printf("fixed_Va := %g\n", fixedVa);
361 if(dtfile[0]) printf("dtfile := %s\n", dtfile);
362 if(isfinite(fixeddT)) printf("fixed_dT := %g\n", fixeddT);
363 if(ssfile[0]) printf("ssfile := %s\n", ssfile);
364 if(llsqfile[0]) printf("llsqfile := %s\n", llsqfile);
365 if(kmapfile[0]) printf("kmapfile := %s\n", kmapfile);
366 fflush(stdout);
367 }
368
369 TPCSTATUS status; statusInit(&status);
370 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
371 status.verbose=verbose-1;
372
373
374 /*
375 * Read BTAC
376 */
377 if(verbose>1) printf("reading %s\n", btacfile);
378 TAC btac; tacInit(&btac);
379 ret=tacRead(&btac, btacfile, &status);
380 if(ret!=TPCERROR_OK) {
381 fprintf(stderr, "Error: %s (%s)\n", errorMsg(status.error), btacfile);
382 tacFree(&btac); return(2);
383 }
384 if(verbose>2) {
385 printf("fileformat := %s\n", tacFormattxt(btac.format));
386 printf("tacNr := %d\n", btac.tacNr);
387 printf("sampleNr := %d\n", btac.sampleNr);
388 printf("xunit := %s\n", unitName(btac.tunit));
389 printf("yunit := %s\n", unitName(btac.cunit));
390 printf("isframe := %d\n", btac.isframe);
391 fflush(stdout);
392 }
393 /* Make sure that BTAC frame mid times are set */
394 tacSetX(&btac, NULL);
395
396
397 /*
398 * Read image data
399 */
400 if(verbose>1) {printf("reading %s\n", imgfile); fflush(stdout);}
401 IMG img; imgInit(&img);
402 ret=imgRead(&img, imgfile, &status);
403 if(ret!=TPCERROR_OK) { // error
404 tacFree(&btac); imgFree(&img);
405 fprintf(stderr, "Error: %s (%s)\n", errorMsg(status.error), imgfile); fflush(stderr);
406 return(2);
407 }
408 if(imgNaNs(&img, 1)>0)
409 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
410 if(verbose>2) imgContents(&img, stdout);
411 double ixmin, ixmax;
412 if(imgXRange(&img, &ixmin, &ixmax)!=TPCERROR_OK) {
413 fprintf(stderr, "Error: invalid sample times in %s\n", imgfile); fflush(stderr);
414 tacFree(&btac); imgFree(&img); return(2);
415 }
416 if(verbose>1) printf("Image range: %g - %g\n", ixmin, ixmax);
417 /* Refine fit end time */
418 if(ixmax<endtimemin) {
419 fprintf(stderr, "Error: image time range is too short.\n");
420 tacFree(&btac); imgFree(&img); return(2);
421 }
422 if(ixmax<endtime) endtime=ixmax;
423
424 /* If BTAC has no frame start and end times, check if those can be obtained from image */
425 if(tacimgXMatch(&btac, &img)) tacimgXCopy(&btac, &img);
426
427 /* Convert BTAC time units to same as in the image */
428 if(btac.tunit==UNIT_UNKNOWN) {
429 if(verbose>0) fprintf(stderr, "Warning: missing BTAC time units.\n");
430 double bxmin, bxmax;
431 if(tacXRange(&btac, &bxmin, &bxmax)!=TPCERROR_OK) {
432 fprintf(stderr, "Error: invalid sample times in %s\n", btacfile); fflush(stderr);
433 tacFree(&btac); imgFree(&img); return(2);
434 }
435 unit guessedUnit=img.tunit;
436 if(img.tunit==UNIT_SEC && bxmax<0.2*ixmax) guessedUnit=UNIT_MIN;
437 if(img.tunit==UNIT_MIN && bxmax>20.*ixmax) guessedUnit=UNIT_SEC;
438 fprintf(stderr, "Warning: assuming BTAC sample times are in units %s.\n", unitName(guessedUnit));
439 btac.tunit=guessedUnit;
440 }
441 if(tacXUnitConvert(&btac, img.tunit, &status)!=TPCERROR_OK) {
442 fprintf(stderr, "Error: %s (%s)\n", errorMsg(status.error), btacfile); fflush(stderr);
443 tacFree(&btac); imgFree(&img); return(2);
444 }
445 /* If times are in minutes, convert to sec */
446 if(btac.tunit==UNIT_MIN) {
447 tacXUnitConvert(&btac, UNIT_SEC, NULL);
449 }
450 double bxmin, bxmax;
451 if(tacXRange(&btac, &bxmin, &bxmax)!=TPCERROR_OK) {
452 fprintf(stderr, "Error: invalid sample times in %s\n", btacfile); fflush(stderr);
453 tacFree(&btac); imgFree(&img); return(2);
454 }
455 if(verbose>1) printf("BTAC range: %g - %g\n", bxmin, bxmax);
456
457 /* Check that concentration units match in image and BTAC */
458 if(img.cunit==UNIT_UNKNOWN) {
459 if(btac.cunit!=UNIT_UNKNOWN) {
460 img.cunit=btac.cunit;
461 fprintf(stderr, "Warning: assuming image concentrations are in units %s.\n", unitName(img.cunit));
462 }
463 } else if(btac.cunit==UNIT_UNKNOWN) {
464 btac.cunit=img.cunit;
465 fprintf(stderr, "Warning: assuming BTAC concentrations are in units %s.\n", unitName(img.cunit));
466 } else {
467 if(tacYUnitConvert(&btac, img.cunit, &status)) {
468 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
469 tacFree(&btac); imgFree(&img); return(2);
470 }
471 }
472
473
474 /*
475 * Check time ranges
476 */
477 if(verbose>1) {printf("checking time range\n"); fflush(stdout);}
478 ret=0;
479 if(btac.sampleNr<5) {fprintf(stderr, "Error: BTAC has too few samples.\n"); ret++;}
480 if(img.dimt<5) {fprintf(stderr, "Error: image has too few frames.\n"); ret++;}
481 if(bxmax<endtimemin) {fprintf(stderr, "Error: BTAC time range is too short.\n"); ret++;}
482 if(ixmax<endtimemin) {fprintf(stderr, "Error: image time range is too short.\n"); ret++;}
483 if(dtrange[0]<0.0 && bxmax<(endtime+dtrange[0])) {
484 endtime+=dtrange[0];
485 if(endtime<endtimemin) {
486 fprintf(stderr, "Error: BTAC does not extend to required end time.\n"); ret++;}
487 }
488 int frameNr=0;
489 for(int i=0; i<img.dimt; i++) if(img.x[i]<=endtime) frameNr++;
490 if(frameNr<5) {fprintf(stderr, "Error: image has too few frames in fit time range.\n"); ret++;}
491 if(ret>0) {tacFree(&btac); imgFree(&img); return(2);}
492
493 /* Make room for TTAC integrals, used also to pass frame information to BTAC interpolation */
494 TAC ttac; tacInit(&ttac);
495 ret=tacAllocateWithIMG(&ttac, &img, 3);
496 if(ret) {
497 fprintf(stderr, "Error: %s\n", errorMsg(ret));
498 tacFree(&btac); imgFree(&img); return(3);
499 }
500 ttac.sampleNr=frameNr;
501 ttac.tacNr=3;
502
503 /* Make delayed BTACs and integrals, matching image frames, for LLSQ fitting */
504 TAC inp, inp2, inp3; tacInit(&inp); tacInit(&inp2); tacInit(&inp3);
505 if(tacInputForLLSQ(&btac, &ttac, dtrange[0], dtrange[1], dtstep, &inp, &inp2, &inp3, &status)) {
506 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
507 tacFree(&btac); imgFree(&img); tacFree(&ttac); tacFree(&inp); tacFree(&inp2); tacFree(&inp3);
508 return(4);
509 }
510 if(verbose>4) {
511 printf("writing delayed, interpolated, and integrated BTACs\n");
512 FILE *fp=fopen("imgflowb_input1.tac", "w");
513 if(fp!=NULL) tacWrite(&inp, fp, TAC_FORMAT_PMOD, 0, NULL);
514 fclose(fp);
515 fp=fopen("imgflowb_input2.tac", "w");
516 if(fp!=NULL) tacWrite(&inp2, fp, TAC_FORMAT_PMOD, 0, NULL);
517 fclose(fp);
518 fp=fopen("imgflowb_input3.tac", "w");
519 if(fp!=NULL) tacWrite(&inp3, fp, TAC_FORMAT_PMOD, 0, NULL);
520 fclose(fp);
521 }
522
523
524 /* Allocate matrices for LLSQ */
525 if(verbose>1) {printf("allocating memory for LLSQ\n"); fflush(stdout);}
526 int llsq_m=ttac.sampleNr;
527 int llsq_n=5;
528 double **llsq_a=(double**)malloc(llsq_n*sizeof(double*));
529 double *llsq_mat=(double*)malloc((llsq_n*llsq_m)*sizeof(double));
530 if(llsq_a==NULL || llsq_mat==NULL) {
531 fprintf(stderr, "Error: cannot allocate memory for LLSQ.\n");
532 tacFree(&btac); imgFree(&img); tacFree(&ttac); tacFree(&inp); tacFree(&inp2); tacFree(&inp3);
533 return(5);
534 }
535 for(int ni=0; ni<llsq_n; ni++) llsq_a[ni]=llsq_mat+ni*llsq_m;
536 double llsq_b[llsq_m], llsq_x[llsq_n], llsq_wp[llsq_n], llsq_zz[llsq_m];
537 int indexp[llsq_n];
538
539
540 /*
541 * Allocate memory for LLSQ parameter images (llsq_n & delay & SS)
542 */
543 if(verbose>1) {printf("preparing LLSQ parameter map\n"); fflush(stdout);}
544 IMG map; imgInit(&map);
545 if(imgAllocate(&map, img.dimz, img.dimy, img.dimx, llsq_n+2, &status)!=TPCERROR_OK) {
546 fprintf(stderr, "Error: cannot allocate memory\n"); fflush(stderr);
547 tacFree(&btac); imgFree(&img); tacFree(&ttac); tacFree(&inp); tacFree(&inp2); tacFree(&inp3);
548 free(llsq_a); free(llsq_mat);
549 return(6);
550 }
551 imgCopyHeader(&img, &map);
553
554
555 /* Calculate threshold value */
556 double thrs=tacAUC(&btac, 0, 0.0, img.x2[frameNr-1], NULL);
557 thrs*=calcThreshold;
558
559 /*
560 * Pixel-by-pixel LLSQ
561 */
562 long long pxlNr=img.dimx*img.dimy*img.dimz;
563 long long okNr=0;
564 if(verbose>0) {printf("processing %llu image pixels\n", pxlNr); fflush(stdout);}
565 for(int zi=0; zi<img.dimz; zi++) {
566 if(img.dimz>2 && verbose>0) {fprintf(stdout, "."); fflush(stdout);}
567 for(int yi=0; yi<img.dimy; yi++) for(int xi=0; xi<img.dimx; xi++) {
568 for(int pi=0; pi<map.dimt; pi++) map.m[zi][yi][xi][pi]=0.0;
569 for(int mi=0; mi<llsq_m; mi++) ttac.c[0].y[mi]=img.m[zi][yi][xi][mi];
570// if(liIntegrateFE(ttac.x1, ttac.x2, ttac.c[0].y, llsq_m, ttac.c[1].y, ttac.c[2].y, 0)!=0) continue;
571 if(liIntegratePET(ttac.x1, ttac.x2, ttac.c[0].y, llsq_m, ttac.c[1].y, ttac.c[2].y, 0)!=0) continue;
572
573 if(ttac.c[1].y[llsq_m-1]<thrs) continue;
574 /* Try with each delayed BTAC */
575 int diBest=-1;
576 double r2Best=nan("");
577 for(int di=0; di<inp.tacNr; di++) {
578 /* Setup data matrix A and vector B */
579 for(int mi=0; mi<llsq_m; mi++)
580 llsq_b[mi]=img.m[zi][yi][xi][mi]; // TTAC
581 for(int mi=0; mi<llsq_m; mi++) {
582 if(isfinite(fixedVa))
583 llsq_mat[mi]=0.0;
584 else
585 llsq_mat[mi]=inp.c[di].y[mi]; // BTAC
586 llsq_mat[mi+1*llsq_m]=inp2.c[di].y[mi]; // BTAC integral
587 llsq_mat[mi+2*llsq_m]=-ttac.c[1].y[mi]; // TTAC integral
588 llsq_mat[mi+3*llsq_m]=inp3.c[di].y[mi]; // BTAC 2nd integral
589 llsq_mat[mi+4*llsq_m]=-ttac.c[2].y[mi]; // TTAC 2nd integral
590 }
591 /* Compute NNLS */
592 double r2=nan("");
593 int ret=nnls(llsq_a, llsq_m, llsq_n, llsq_b, llsq_x, &r2, llsq_wp, llsq_zz, indexp);
594 if(ret>1) continue;
595 if((isfinite(r2) && !isfinite(r2Best)) || r2<r2Best) {
596 r2Best=r2;
597 diBest=di;
598 for(int pi=0; pi<llsq_n; pi++) map.m[zi][yi][xi][pi]=llsq_x[pi];
599 map.m[zi][yi][xi][llsq_n]=inp.c[di].size; // delay time was stored there
600 map.m[zi][yi][xi][llsq_n+1]=r2;
601 }
602 } // next delay
603 if(diBest>=0) okNr++;
604 }
605 }
606 if(img.dimz>2 && verbose>0) {fprintf(stdout, "\n"); fflush(stdout);}
607 free(llsq_a); free(llsq_mat); /* Free NNLS matrix data */
608 if(okNr==0) {
609 fprintf(stderr, "Error: no pixels fitted successfully\n"); fflush(stderr);
610 tacFree(&btac); imgFree(&img); tacFree(&ttac); tacFree(&inp); tacFree(&inp2); tacFree(&inp3);
611 imgFree(&map);
612 return(7);
613 }
614 if(verbose>0) printf(" LLSQ successful in %lld/%lld pixels\n", okNr, pxlNr);
615 /* Free original data */
616 tacFree(&btac); imgFree(&img); tacFree(&ttac); tacFree(&inp); tacFree(&inp2); tacFree(&inp3);
617
618 /*
619 * Write requested output images
620 */
621 if(llsqfile[0]) {
622 if(verbose>1) printf(" writing %s\n", llsqfile);
623 if(imgWrite(&map, llsqfile, &status)!=TPCERROR_OK) {
624 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
625 imgFree(&map);
626 return(11);
627 }
628 if(verbose>0) {printf(" %s written.\n", llsqfile); fflush(stdout);}
629 }
630 IMG pimg; imgInit(&pimg); // one-frame image for one outcome parameter
631 if(imgAllocate(&pimg, map.dimz, map.dimy, map.dimx, 1, &status)!=TPCERROR_OK) {
632 fprintf(stderr, "Error: cannot allocate memory\n"); fflush(stderr);
633 return(12);
634 }
635 imgCopyHeader(&map, &pimg);
636 if(dtfile[0]) {
637 if(verbose>1) printf(" writing %s\n", dtfile);
638 pimg.cunit=UNIT_SEC;
639 for(int zi=0; zi<pimg.dimz; zi++) for(int yi=0; yi<pimg.dimy; yi++) for(int xi=0; xi<pimg.dimx; xi++) {
640 pimg.m[zi][yi][xi][0]=map.m[zi][yi][xi][map.dimt-2];
641 }
642 if(imgWrite(&pimg, dtfile, &status)!=TPCERROR_OK) {
643 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
644 imgFree(&map); imgFree(&pimg);
645 return(13);
646 }
647 if(verbose>0) {printf(" %s written.\n", dtfile); fflush(stdout);}
648 }
649 if(ssfile[0]) {
650 if(verbose>1) printf(" writing %s\n", ssfile);
651 pimg.cunit=UNIT_UNKNOWN;
652 for(int zi=0; zi<pimg.dimz; zi++) for(int yi=0; yi<pimg.dimy; yi++) for(int xi=0; xi<pimg.dimx; xi++) {
653 pimg.m[zi][yi][xi][0]=map.m[zi][yi][xi][map.dimt-1];
654 }
655 if(imgWrite(&pimg, ssfile, &status)!=TPCERROR_OK) {
656 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
657 imgFree(&map); imgFree(&pimg);
658 return(14);
659 }
660 if(verbose>0) {printf(" %s written.\n", ssfile); fflush(stdout);}
661 }
662 if(vafile[0]) {
663 if(verbose>1) printf(" writing %s\n", vafile);
665 for(int zi=0; zi<pimg.dimz; zi++) for(int yi=0; yi<pimg.dimy; yi++) for(int xi=0; xi<pimg.dimx; xi++) {
666 pimg.m[zi][yi][xi][0]=map.m[zi][yi][xi][0];
667 }
668 if(imgWrite(&pimg, vafile, &status)!=TPCERROR_OK) {
669 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
670 imgFree(&map); imgFree(&pimg);
671 return(15);
672 }
673 if(verbose>0) {printf(" %s written.\n", vafile); fflush(stdout);}
674 }
675
676 /* Convert LLSQ parameters into parameters K1a, k2a, K1b, and k2b */
677 {
678 for(int zi=0; zi<pimg.dimz; zi++) for(int yi=0; yi<pimg.dimy; yi++) for(int xi=0; xi<pimg.dimx; xi++) {
679 double p[llsq_n]; for(int i=0; i<llsq_n; i++) p[i]=map.m[zi][yi][xi][i];
680 double k2a=(p[2]+sqrt(p[2]*p[2] - 4.0*p[4]))/2.0;
681 double k2b=(p[2]-sqrt(p[2]*p[2] - 4.0*p[4]))/2.0;
682 double K1a=(k2a*(p[1]-p[0]*p[2]) - p[3] + p[0]*p[4])/sqrt(p[2]*p[2]-4.0*p[4]);
683 double K1b=(p[3] - p[0]*p[4] - k2b*(p[1]-p[0]*p[2]))/sqrt(p[2]*p[2]-4.0*p[4]);
684//printf("p[] = %g %g %g %g %g\n", p[0], p[1], p[2], p[3], p[4]);
685//printf("K1a=%g k2a=%g K1b=%g k2b=%g\n", K1a, k2a, K1b, k2b);
686 map.m[zi][yi][xi][1]=60.*K1a;
687 map.m[zi][yi][xi][2]=60.*k2a;
688 map.m[zi][yi][xi][3]=60.*K1b;
689 map.m[zi][yi][xi][4]=60.*k2b;
690 }
691 }
692 if(kmapfile[0]) {
693 if(verbose>1) printf(" writing %s\n", kmapfile);
694 if(imgWrite(&map, kmapfile, &status)!=TPCERROR_OK) {
695 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
696 imgFree(&map); imgFree(&pimg);
697 return(21);
698 }
699 if(verbose>0) {printf(" %s written.\n", kmapfile); fflush(stdout);}
700 }
701
702
703 if(fgfile[0]) {
704 if(verbose>1) printf(" writing %s\n", fgfile);
706 for(int zi=0; zi<pimg.dimz; zi++) for(int yi=0; yi<pimg.dimy; yi++) for(int xi=0; xi<pimg.dimx; xi++) {
707 pimg.m[zi][yi][xi][0]=pg*map.m[zi][yi][xi][2];
708 if(pimg.m[zi][yi][xi][0]>1.0) pimg.m[zi][yi][xi][0]=1.0;
709 }
710 if(imgWrite(&pimg, fgfile, &status)!=TPCERROR_OK) {
711 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
712 imgFree(&map); imgFree(&pimg);
713 return(31);
714 }
715 if(verbose>0) {printf(" %s written.\n", fgfile); fflush(stdout);}
716 }
717 if(fwfile[0]) {
718 if(verbose>1) printf(" writing %s\n", fwfile);
720 for(int zi=0; zi<pimg.dimz; zi++) for(int yi=0; yi<pimg.dimy; yi++) for(int xi=0; xi<pimg.dimx; xi++) {
721 pimg.m[zi][yi][xi][0]=pw*map.m[zi][yi][xi][4];
722 if(pimg.m[zi][yi][xi][0]>1.0) pimg.m[zi][yi][xi][0]=1.0;
723 }
724 if(imgWrite(&pimg, fwfile, &status)!=TPCERROR_OK) {
725 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
726 imgFree(&map); imgFree(&pimg);
727 return(32);
728 }
729 if(verbose>0) {printf(" %s written.\n", fwfile); fflush(stdout);}
730 }
731
732 if(agfile[0]) {
733 if(verbose>1) printf(" writing %s\n", agfile);
735 for(int zi=0; zi<pimg.dimz; zi++) for(int yi=0; yi<pimg.dimy; yi++) for(int xi=0; xi<pimg.dimx; xi++) {
736 pimg.m[zi][yi][xi][0]=(map.m[zi][yi][xi][1]/map.m[zi][yi][xi][2])/pg;
737 if(!isfinite(pimg.m[zi][yi][xi][0])) pimg.m[zi][yi][xi][0]=0.0;
738 if(pimg.m[zi][yi][xi][0]<0.0) pimg.m[zi][yi][xi][0]=0.0;
739 if(pimg.m[zi][yi][xi][0]>1.0) pimg.m[zi][yi][xi][0]=1.0;
740 }
741 if(imgWrite(&pimg, agfile, &status)!=TPCERROR_OK) {
742 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
743 imgFree(&map); imgFree(&pimg);
744 return(41);
745 }
746 if(verbose>0) {printf(" %s written.\n", agfile); fflush(stdout);}
747 }
748 if(awfile[0]) {
749 if(verbose>1) printf(" writing %s\n", awfile);
751 for(int zi=0; zi<pimg.dimz; zi++) for(int yi=0; yi<pimg.dimy; yi++) for(int xi=0; xi<pimg.dimx; xi++) {
752 pimg.m[zi][yi][xi][0]=(map.m[zi][yi][xi][3]/map.m[zi][yi][xi][4])/pw;
753 if(!isfinite(pimg.m[zi][yi][xi][0])) pimg.m[zi][yi][xi][0]=0.0;
754 if(pimg.m[zi][yi][xi][0]<0.0) pimg.m[zi][yi][xi][0]=0.0;
755 if(pimg.m[zi][yi][xi][0]>1.0) pimg.m[zi][yi][xi][0]=1.0;
756 }
757 if(imgWrite(&pimg, awfile, &status)!=TPCERROR_OK) {
758 fprintf(stderr, "Error: %s\n", errorMsg(status.error)); fflush(stderr);
759 imgFree(&map); imgFree(&pimg);
760 return(42);
761 }
762 if(verbose>0) {printf(" %s written.\n", awfile); fflush(stdout);}
763 }
764
765
766 imgFree(&map); imgFree(&pimg);
767 return(0);
768}
769/*****************************************************************************/
770
771/*****************************************************************************/
int atofCheck(const char *s, double *v)
Definition decpoint.c:94
int imgXUnitConvert(IMG *img, const int u)
Definition image.c:462
void imgContents(IMG *img, FILE *fp)
Definition image.c:293
void imgFree(IMG *img)
Definition image.c:107
unsigned long long imgNaNs(IMG *img, int fix)
Definition image.c:373
void imgInit(IMG *img)
Definition image.c:64
int imgAllocate(IMG *img, const unsigned int dimz, const unsigned int dimy, const unsigned int dimx, const unsigned int dimt, TPCSTATUS *status)
Definition image.c:126
int imgXRange(IMG *img, double *xmin, double *xmax)
Definition image.c:430
int imgCopyHeader(IMG *img1, IMG *img2)
Definition imageheader.c:18
int imgRead(IMG *img, const char *fname, TPCSTATUS *status)
Definition imageio.c:82
int imgWrite(IMG *img, const char *fname, TPCSTATUS *status)
Definition imageio.c:214
int liIntegrateFE(double *x1, double *x2, double *y, int nr, double *ie, double *iie, const int verbose)
Linear integration of PET TAC to frame end times.
Definition integrate.c:219
int liIntegrate(double *x, double *y, const int nr, double *yi, const int se, const int verbose)
Linear integration of TAC with trapezoidal method.
Definition integrate.c:33
int liIntegratePET(double *x1, double *x2, double *y, int nr, double *ie, double *iie, const int verbose)
Calculate PET TAC AUC from start to each time frame, as averages during each frame.
Definition integrate.c:120
int liInterpolate(double *x, double *y, const int nr, double *newx, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear interpolation and/or integration with trapezoidal method.
int liInterpolateForPET(double *x, double *y, const int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, const int newnr, const int se, const int ee, const int verbose)
Linear TAC interpolation and/or integration to PET frames.
double tacAUC(TAC *tac, int ti, double t1, double t2, TPCSTATUS *status)
Calculates TAC AUC from t1 to t2.
Definition litac.c:486
int tacAllocateWithIMG(TAC *tac, IMG *img, int tacNr)
Allocate TAC based on data in IMG.
Definition misc.c:16
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *wp, double *zzp, int *indexp)
Definition nnls.c:48
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
Definition tpcimage.h:82
unsigned short int dimx
Definition tpcimage.h:112
unit cunit
Definition tpcimage.h:203
float **** m
Definition tpcimage.h:161
float * x2
Definition tpcimage.h:182
unsigned short int dimt
Definition tpcimage.h:110
unsigned short int dimz
Definition tpcimage.h:116
unsigned short int dimy
Definition tpcimage.h:114
float * x
Definition tpcimage.h:184
unit tunit
Definition tpcimage.h:205
double * y
Definition tpctac.h:75
double size
Definition tpctac.h:71
Definition tpctac.h:87
double * x
Definition tpctac.h:97
unit cunit
Definition tpctac.h:105
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
double * x2
Definition tpctac.h:101
unit tunit
Definition tpctac.h:109
double * x1
Definition tpctac.h:99
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
void tacFree(TAC *tac)
Definition tac.c:106
int tacDuplicate(TAC *tac1, TAC *tac2)
Make a duplicate of TAC structure.
Definition tac.c:356
void tacInit(TAC *tac)
Definition tac.c:24
int tacAllocateMore(TAC *tac, int tacNr)
Definition tac.c:178
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacYUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:72
int tacXUnitConvert(TAC *tac, const int u, TPCSTATUS *status)
Definition tacunits.c:23
int tacSetX(TAC *d, TPCSTATUS *status)
Set TAC x values based on x1 and x2 values, or guess x1 and x2 values based on x values.
Definition tacx.c:653
int tacXRange(TAC *d, double *xmin, double *xmax)
Get the range of x values (times) in TAC structure.
Definition tacx.c:124
Header file for library libtpccsv.
Header file for library libtpcextensions.
unit
@ UNIT_MIN
minutes
@ UNIT_ML_PER_ML
mL/mL
@ UNIT_ML_PER_ML_MIN
mL/(mL*min)
@ UNIT_UNKNOWN
Unknown unit.
@ UNIT_SEC
seconds
@ TPCERROR_INVALID_XRANGE
Invalid sample time range.
@ TPCERROR_INVALID_VALUE
Invalid value.
@ TPCERROR_FAIL
General error.
@ TPCERROR_OK
No error.
@ TPCERROR_TOO_FEW
File contains too few samples.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
Header file for libtpcimage.
Header file for libtpcli.
Header file for libtpclinopt.
Header file for library libtpctac.
@ TAC_FORMAT_PMOD
PMOD TAC format.
Definition tpctac.h:33
Header file for libtpctacimg.
int tacimgXMatch(TAC *tac, IMG *img)
Definition x.c:17
int tacimgXCopy(TAC *tac, IMG *img)
Definition x.c:74
Header file for libtpctacmod.