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