TPCCLIB
Loading...
Searching...
No Matches
imgmyocc.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <string.h>
16#include <math.h>
17#include <time.h>
18/*****************************************************************************/
19#include "libtpccurveio.h"
20#include "libtpcmodext.h"
21#include "libtpcmisc.h"
22#include "libtpcmodel.h"
23#include "libtpcimgio.h"
24#include "libtpcimgp.h"
25/*****************************************************************************/
26#define NNLS_N 4
27/*****************************************************************************/
28
29/*****************************************************************************/
30static char *info[] = {
31 "Estimate tissue and vascular components in dynamic myocardial PET imaging",
32 "using 1TCM and LV cavity BTAC.",
33 " ",
34 "Usage: @P [Options] bfile imgfile tcimgfile vcimgfile",
35 " ",
36 "Options:",
37 " -thr=<threshold%>",
38 " Pixels with AUC less than (threshold/100 x PTAC AUC) are set to zero;",
39 " default is 1%.",
40 " -end=<Fit end time (min)>",
41 " Use data from 0 to end time; by default, model is fitted to all frames.",
42 " -stdoptions", // List standard options like --help, -v, etc
43 " ",
44 "See also: imgpeak, imgaumc",
45 " ",
46 "Keywords: image, modelling, NNLS",
47 0};
48/*****************************************************************************/
49
50/*****************************************************************************/
51/* Turn on the globbing of the command line, since it is disabled by default in
52 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
53 In Unix&Linux wildcard command line processing is enabled by default. */
54/*
55#undef _CRT_glob
56#define _CRT_glob -1
57*/
58int _dowildcard = -1;
59/*****************************************************************************/
60
61/*****************************************************************************/
65int main(int argc, char **argv)
66{
67 int ai, help=0, version=0, verbose=1;
68 char bfile[FILENAME_MAX], petfile[FILENAME_MAX], tcfile[FILENAME_MAX];
69 char vcfile[FILENAME_MAX];
70 float calcThreshold=0.01;
71 double fittime=-1.0;
72 int ret;
73
74 /*
75 * Get arguments
76 */
77 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
78 bfile[0]=petfile[0]=tcfile[0]=vcfile[0]=(char)0;
79 /* Get options */
80 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
81 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
82 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
83 if(strncasecmp(cptr, "THR=", 4)==0) {
84 double v; ret=atof_with_check(cptr+4, &v);
85 if(!ret && v>=0.0 && v<=200.0) {calcThreshold=(float)(0.01*v); continue;}
86 } else if(strncasecmp(cptr, "END=", 4)==0) {
87 ret=atof_with_check(cptr+4, &fittime); if(!ret && fittime>0.0) continue;
88 }
89 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
90 return(1);
91 } else break;
92
93
94 /* Print help or version? */
95 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
96 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
97 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
98
99 /* Process other arguments, starting from the first non-option */
100 if(ai<argc) strlcpy(bfile, argv[ai++], FILENAME_MAX);
101 if(ai<argc) strlcpy(petfile, argv[ai++], FILENAME_MAX);
102 if(ai<argc) strlcpy(tcfile, argv[ai++], FILENAME_MAX);
103 if(ai<argc) strlcpy(vcfile, argv[ai++], FILENAME_MAX);
104 if(ai<argc) {fprintf(stderr, "Error: invalid argument '%s'.\n", argv[ai]); return(1);}
105 /* Did we get all the information that we need? */
106 if(!vcfile[0]) {
107 fprintf(stderr, "Error: missing command-line argument; use option --help\n"); return(1);}
108 /* In verbose mode print arguments and options */
109 if(verbose>1) {
110 printf("bfile := %s\n", bfile);
111 printf("petfile := %s\n", petfile);
112 printf("tcfile := %s\n", tcfile);
113 printf("vcfile := %s\n", vcfile);
114 printf("calcThreshold :=%g\n", calcThreshold);
115 if(fittime>0.0) printf("required_fittime := %g min\n", fittime);
116 }
117 if(verbose>8) IMG_TEST=verbose-8; else IMG_TEST=0;
118 if(verbose>20) ECAT63_TEST=ECAT7_TEST=verbose-20; else ECAT63_TEST=ECAT7_TEST=0;
119
120
121 /*
122 * Read PET image and input TAC
123 */
124 if(verbose>0) printf("reading data files\n");
125 DFT tac; dftInit(&tac);
126 IMG img; imgInit(&img);
127 int dataNr=0;
128 char errmsg[512];
130 petfile, NULL, bfile, NULL, NULL, &fittime, &dataNr, &img,
131 NULL, &tac, 1, stdout, verbose-2, errmsg);
132 if(ret!=0) {
133 fprintf(stderr, "Error: %s.\n", errmsg);
134 if(verbose>1) printf(" ret := %d\n", ret);
135 return(2);
136 }
137 if(imgNaNs(&img, 1)>0)
138 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
139 /* Set time unit to min, also for integrals in y2[] */
140 if(tac.timeunit==TUNIT_SEC) {
141 for(int fi=0; fi<tac.frameNr; fi++) tac.voi[0].y2[fi]/=60.0;
142 for(int fi=0; fi<tac.frameNr; fi++) tac.voi[0].y3[fi]/=3600.0;
143 }
144 ret=dftTimeunitConversion(&tac, TUNIT_MIN);
145 if(verbose>1) {
146 printf("fittimeFinal := %g min\n", fittime);
147 printf("dataNr := %d\n", dataNr);
148 }
149 /* Check that image is dynamic */
150 if(dataNr<6) {
151 fprintf(stderr, "Error: too few time frames for fitting.\n");
152 if(verbose>1) imgInfo(&img);
153 imgEmpty(&img); dftEmpty(&tac); return(2);
154 }
155
156
157 /* Add place for RV cavity and tissue TACs, too */
158 if(verbose>1) fprintf(stdout, "allocating working memory for pixel TACs\n");
159 ret=dftAddmem(&tac, 2);
160 if(ret) {
161 fprintf(stderr, "Error: cannot allocate memory.\n");
162 if(verbose>0) printf("ret := %d\n", ret);
163 imgEmpty(&img); dftEmpty(&tac); return(3);
164 }
165 strcpy(tac.voi[0].name, "LV-cavity");
166 strcpy(tac.voi[1].name, "RV-cavity");
167 strcpy(tac.voi[2].name, "tissue");
168
169
170 /* Estimate RV BTAC by moving LV BTAC to left */
171 {
172 double tmov[tac.frameNr];
173 for(int i=0; i<tac.frameNr; i++) tmov[i]=tac.x[i]-7.0/60;
174 ret=interpolate4pet(tmov, tac.voi[0].y, tac.frameNr, tac.x1, tac.x2, tac.voi[1].y, NULL, NULL, tac.frameNr);
175 }
176 if(ret) {
177 fprintf(stderr, "Error: cannot interpolate data.\n");
178 imgEmpty(&img); dftEmpty(&tac); return(2);
179 }
180
181
182 /* Determine the threshold */
183 double threshold=calcThreshold*tac.voi[0].y2[dataNr-1];
184 if(verbose>1) printf("threshold_AUC := %g\n", threshold);
185
186
187 /*
188 * Allocate result images (allocate all, even if user did not want to save those)
189 */
190 if(verbose>1) fprintf(stdout, "allocating memory for parametric image data\n");
191 IMG tcimg; imgInit(&tcimg);
192 IMG vcimg; imgInit(&vcimg);
193 ret=imgAllocateWithHeader(&tcimg, img.dimz, img.dimy, img.dimx, 1, &img);
194 if(!ret) ret=imgAllocateWithHeader(&vcimg, img.dimz, img.dimy, img.dimx, 1, &img);
195 if(ret) {
196 fprintf(stderr, "Error: cannot allocate memory for result image.\n");
197 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&tcimg); imgEmpty(&vcimg);
198 return(4);
199 }
200 /* set 'frame time' for parametric images */
201 vcimg.start[0]=tcimg.start[0]=0.0;
202 vcimg.end[0]=tcimg.end[0]=60.*fittime;
203 /* set units in parametric images */
204 tcimg.unit=CUNIT_UNITLESS;
205 vcimg.unit=CUNIT_UNITLESS;
206
207
208 /* Fitting */
209
210 int fittedNr=0, fittedokNr=0, thresholdNr=0;
211
212 /*
213 * Allocate memory required by NNLS
214 */
215 if(verbose>1) fprintf(stdout, "allocating memory for NNLS\n");
216 int nnls_n=NNLS_N;
217 int nnls_m=dataNr;
218 int n, m /*, nnls_index[nnls_n]*/;
219 double **nnls_a, nnls_b[nnls_m], nnls_zz[nnls_m], /* nnls_x[nnls_n],*/ *nnls_mat,
220 /*nnls_wp[nnls_n],*/ nnls_rnorm;
221 nnls_mat=(double*)malloc((nnls_n*nnls_m)*sizeof(double));
222 nnls_a=(double**)malloc(nnls_n*sizeof(double*));
223 if(nnls_mat==NULL || nnls_a==NULL) {
224 fprintf(stderr, "Error: cannot allocate memory for NNLS.\n");
225 imgEmpty(&img); dftEmpty(&tac); imgEmpty(&tcimg); imgEmpty(&vcimg);
226 return(4);
227 }
228 for(n=0; n<nnls_n; n++) nnls_a[n]=nnls_mat+n*nnls_m;
229
230 /*
231 * Compute pixel-by-pixel
232 */
233 if(verbose>0) fprintf(stdout, "computing NNLS pixel-by-pixel\n");
234 double *ct, *cti, *clv, *clvi, *crv;
235 clv=tac.voi[0].y; clvi=tac.voi[0].y2;
236 crv=tac.voi[1].y;
237 ct=tac.voi[2].y; cti=tac.voi[2].y2;
238 for(int pi=0; pi<img.dimz; pi++) {
239 if(verbose>0) {fprintf(stdout, "."); fflush(stdout);}
240 for(int yi=0; yi<img.dimy; yi++) {
241 for(int xi=0; xi<img.dimx; xi++) {
242 /* Set pixel results to zero */
243 tcimg.m[pi][yi][xi][0]=0.0;
244 vcimg.m[pi][yi][xi][0]=0.0;
245 /* Copy and integrate pixel curve */
246 for(int fi=0; fi<tac.frameNr; fi++) ct[fi]=img.m[pi][yi][xi][fi];
247 ret=petintegral(tac.x1, tac.x2, ct, tac.frameNr, cti, NULL);
248 if(ret) continue;
249 /* if AUC at the end is less than threshold value, then do nothing more */
250 if(cti[dataNr-1]<threshold) {thresholdNr++; continue;}
251
252 /*
253 * Estimate parameters
254 */
255
256 /* Fill the NNLS data matrix */
257 for(int m=0; m<nnls_m; m++) {
258 nnls_a[0][m]=clvi[m];
259 nnls_a[1][m]=clv[m];
260 nnls_a[2][m]=crv[m];
261 nnls_a[3][m]=-cti[m];
262 nnls_b[m]=ct[m];
263 }
264 if(/*verbose>5 &&*/ pi==img.dimz/2 && yi==img.dimy/2 && xi==img.dimx/2) {
265 printf("Matrix A Array B\n");
266 for(m=0; m<nnls_m; m++) {
267 printf("%12.3f %12.3f %12.3f %12.3f %12.3f\n",
268 nnls_a[0][m], nnls_a[1][m], nnls_a[2][m], nnls_a[3][m], nnls_b[m]);
269 }
270 }
271 /* NNLS */
272 int nnls_index[nnls_n];
273 double nnls_x[nnls_n], nnls_wp[nnls_n];
274 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm, nnls_wp, nnls_zz, nnls_index);
275 if(ret!=0) { /* no solution is possible */
276 if(verbose>3) printf("no solution possible (%d)\n", ret);
277 if(verbose>4) printf("nnls_n=%d nnls_m=%d\n", nnls_n, nnls_m);
278 for(int n=0; n<nnls_n; n++) nnls_x[n]=0.0;
279 nnls_rnorm=0.0;
280 continue;
281 }
282 fittedNr++; fittedokNr++;
283
284 /* Put results to output images */
285 vcimg.m[pi][yi][xi][0]=nnls_x[1]+0.5*nnls_x[2];
286 if(vcimg.m[pi][yi][xi][0]>2.0) vcimg.m[pi][yi][xi][0]=2.0;
287
288 tcimg.m[pi][yi][xi][0]=nnls_x[0]-nnls_x[3]*(nnls_x[1]+0.9*nnls_x[2]);;
289 double b=nnls_x[1]+0.9*nnls_x[2];
290 if(b>0.0 && b<0.67) tcimg.m[pi][yi][xi][0]/=(1.0-b);
291 if(tcimg.m[pi][yi][xi][0]>1.0) tcimg.m[pi][yi][xi][0]=1.0;
292 if(tcimg.m[pi][yi][xi][0]<0.0) tcimg.m[pi][yi][xi][0]=0.0;
293
294 } /* next column */
295 } /* next row */
296 } /* next plane */
297 if(verbose>0) {fprintf(stdout, " done.\n"); fflush(stdout);}
298 free(nnls_mat); free(nnls_a);
299 /* Show statistics on how we succeeded */
300 n=(int)img.dimx*(int)img.dimy*(int)img.dimz;
301 if(verbose>0) {
302 fprintf(stdout, "%d out of %d pixels were fitted; %d pixels ok.\n", fittedokNr, n, fittedNr);
303 fprintf(stdout, "%d pixels were thresholded.\n", thresholdNr);
304 }
305
306
307 /* No need for dynamic image any more */
308 imgEmpty(&img); dftEmpty(&tac);
309
310
311 /*
312 * Save parametric images
313 */
314
315 ret=imgWrite(tcfile, &tcimg);
316 if(!ret) ret=imgWrite(vcfile, &vcimg);
317 imgEmpty(&tcimg); imgEmpty(&vcimg);
318 if(ret) {
319 fprintf(stderr, "Error: cannot write parametric image.\n");
320 return(11);
321 }
322 if(verbose>0) fprintf(stdout, "Parametric image(s) saved.\n");
323
324 return(0);
325}
326/*****************************************************************************/
327
328/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
void dftInit(DFT *data)
Definition dft.c:38
int dftAddmem(DFT *dft, int voiNr)
Definition dft.c:107
void dftEmpty(DFT *data)
Definition dft.c:20
int dftTimeunitConversion(DFT *dft, int tunit)
Definition dftunit.c:119
int ECAT63_TEST
Definition ecat63h.c:6
int ECAT7_TEST
Definition ecat7h.c:6
int IMG_TEST
Definition img.c:6
void imgInfo(IMG *image)
Definition img.c:359
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 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
int petintegral(double *x1, double *x2, double *y, int nr, double *ie, double *iie)
Integrate PET TAC data to frame mid times.
Definition integr.c:771
int interpolate4pet(double *x, double *y, int nr, double *newx1, double *newx2, double *newy, double *newyi, double *newyii, int newnr)
Interpolate and integrate TAC to PET frames.
Definition integr.c:510
Header file for libtpccurveio.
Header file for libtpcimgio.
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.
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *w, double *zz, int *index)
Definition nnls.c:37
Header file for libtpcmodext.
Voi * voi
int timeunit
double * x1
double * x2
int frameNr
double * x
unsigned short int dimx
float **** m
char unit
float * start
unsigned short int dimz
unsigned short int dimy
float * end
double * y2
double * y
char name[MAX_REGIONNAME_LEN+1]
double * y3