TPCCLIB
Loading...
Searching...
No Matches
imgcbvp.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 <math.h>
14#include <string.h>
15#include <unistd.h>
16#include <time.h>
17/*****************************************************************************/
18#include "libtpcmisc.h"
19#include "libtpcimgio.h"
20#include "libtpcimgp.h"
21#include "libtpcmodel.h"
22#include "libtpcmodext.h"
23/*****************************************************************************/
24
25/*****************************************************************************/
26static char *info[] = {
27 "Estimate Vb and (1-Vb)*Ct based on arterial blood curve (BTAC), assuming",
28 "that at BTAC peak tissue concentration is zero, thus Vb=Cpet/Cb",
29 "Vb is then reduced to assure that other TACs remain non-negative.",
30 " ",
31 "Do not use this oversimplified method for quantitative analyses!",
32 " ",
33 "Usage: @P [Options] imgfile btacfile ctimgfile",
34 " ",
35 "Data in image and BTAC file must be stored in the same units.",
36 " ",
37 "Options:",
38 " -vbfile=<filename>",
39 " Save image file containing Vb as pixel values.",
40 " -LV | -RV",
41 " Correct either arterial Vb or BTAC in injection veins, or",
42 " by default, both.",
43 " -stdoptions", // List standard options like --help, -v, etc
44 " ",
45 "See also: imgcbv, taccbvp, imgpeak, imgcalc, imgthrs",
46 " ",
47 "Keywords: image, peak, vascular fraction",
48 0};
49/*****************************************************************************/
50
51/*****************************************************************************/
52/* Turn on the globbing of the command line, since it is disabled by default in
53 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
54 In Unix&Linux wildcard command line processing is enabled by default. */
55/*
56#undef _CRT_glob
57#define _CRT_glob -1
58*/
59int _dowildcard = -1;
60/*****************************************************************************/
61
62/*****************************************************************************/
66int main(int argc, char **argv)
67{
68 int ai, help=0, version=0, verbose=1;
69 char petfile[FILENAME_MAX], btacfile[FILENAME_MAX], vbfile[FILENAME_MAX], ctfile[FILENAME_MAX];
70 int corrmode=3; // 0=no correction, 1=LV, 2=RV, or 3=both
71
72
73 /*
74 * Get arguments
75 */
76 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
77 petfile[0]=btacfile[0]=ctfile[0]=vbfile[0]=(char)0;
78 /* Get options */
79 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
80 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
81 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
82 if(strncasecmp(cptr, "VB=", 3)==0) {
83 strlcpy(vbfile, cptr+3, FILENAME_MAX); continue;
84 } else if(strcasecmp(cptr, "LV")==0) {
85 corrmode=1; continue;
86 } else if(strcasecmp(cptr, "RV")==0) {
87 corrmode=2; continue;
88 }
89 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
90 return(1);
91 } else break;
92
93 /* Print help or version? */
94 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
95 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
96 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
97
98 /* Process other arguments, starting from the first non-option */
99 if(ai<argc) {strlcpy(petfile, argv[ai], FILENAME_MAX); ai++;}
100 if(ai<argc) {strlcpy(btacfile, argv[ai], FILENAME_MAX); ai++;}
101 if(ai<argc) {strlcpy(ctfile, argv[ai], FILENAME_MAX); ai++;}
102 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
103
104
105 /* Did we get all the information that we need? */
106 if(!ctfile[0]) {
107 fprintf(stderr, "Error: missing command-line argument; try %s --help\n", argv[0]);
108 return(1);
109 }
110
111 /* In verbose mode print arguments and options */
112 if(verbose>1) {
113 printf("petfile := %s\n", petfile);
114 printf("btacfile := %s\n", btacfile);
115 printf("ctfile := %s\n", ctfile);
116 if(vbfile[0]) printf("vbfile := %s\n", vbfile);
117 printf("corrmode := %d\n", corrmode);
118 fflush(stdout);
119 }
120
121
122 /*
123 * Read PET image and blood TAC
124 */
125 if(verbose>1) printf("reading data files\n");
126 DFT btac;
127 IMG img, vbimg;
128 imgInit(&img); imgInit(&vbimg); dftInit(&btac);
129 double endtime=-1.0;
130 char tmp[256];
131 int ret=imgReadModelingData(
132 petfile, NULL, btacfile, NULL, NULL, &endtime, &ai, &img,
133 &btac, NULL, 0, stdout, verbose-1, tmp);
134 if(ret!=0) {
135 fprintf(stderr, "Error in reading data: %s.\n", tmp);
136 if(verbose>1) printf(" ret := %d\n", ret);
137 return(2);
138 }
139 if(imgNaNs(&img, 1)>0)
140 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
141 if(verbose>2) printf("endtime := %g min\n", endtime);
142 if(verbose>10) dftPrint(&btac);
143
144 /* Get the range of pixel values in image */
145 float imgmin, imgmax;
146 if(imgMinMax(&img, &imgmin, &imgmax)) {
147 fprintf(stderr, "Error: invalid image contents.\n");
148 imgEmpty(&img); return(3);
149 }
150 if(verbose>1) {
151 printf("image_min := %g\n", imgmin);
152 printf("image_max := %g\n", imgmax);
153 fflush(stdout);
154 }
155
156
157 /*
158 * Search BTAC peak
159 */
160 if(verbose>1) printf("finding BTAC peak\n");
161 double bpeak=btac.voi[0].y[0];
162 int ipeak=0;
163 for(int i=1; i<btac.frameNr; i++)
164 if(btac.voi[0].y[i]>bpeak) {bpeak=btac.voi[0].y[i]; ipeak=i;}
165 if(verbose>1) {
166 printf(" btac_maxv := %g\n", bpeak);
167 printf(" btac_maxx := %g\n", btac.x[ipeak]);
168 }
169 /* If peak is not the first sample, then add previous sample */
170 if(ipeak>0) bpeak+=btac.voi[0].y[ipeak-1];
171 if(verbose>2) {
172 printf(" bpeak := %g\n", bpeak);
173 }
174
175
176 /*
177 * Allocate memory for Vb image
178 */
179 ret=imgAllocateWithHeader(&vbimg, img.dimz, img.dimy, img.dimx, 1, &img);
180 if(ret) {
181 fprintf(stderr, "Error: cannot allocate memory.\n");
182 dftEmpty(&btac); imgEmpty(&img); return(4);
183 }
184 vbimg.unit=CUNIT_UNITLESS;
185
186
187 /* Check if correction for the venous injection activity is needed */
188 double rvtac[img.dimt];
189 if(corrmode==3 || corrmode==2) {
190
191 /* Find pixels where TTAC peak is somewhat higher than BTAC peak,
192 and calculate mean TAC of those */
193 int nrv=0;
194 for(int zi=0; zi<img.dimz; zi++) {
195 for(int yi=0; yi<img.dimy; yi++) {
196 for(int xi=0; xi<img.dimx; xi++) {
197 float tpeak=img.m[zi][yi][xi][ipeak];
198 if(ipeak>0) tpeak+=img.m[zi][yi][xi][ipeak-1];
199 if(tpeak/bpeak>2.0) {
200 for(int ti=0; ti<img.dimt; ti++) rvtac[ti]+=img.m[zi][yi][xi][ti];
201 nrv++;
202 }
203 }
204 }
205 }
206 if(verbose>2) printf("nrv := %d\n", nrv);
207 if(nrv>0) for(int ti=0; ti<img.dimt; ti++) rvtac[ti]/=(double)nrv;
208 else for(int ti=0; ti<img.dimt; ti++) rvtac[ti]=0.0;
209
210 if(nrv==0) { // No injection vena evident
211 if(verbose>0) printf("RV correction not applied.\n");
212 if(corrmode==3) corrmode=1; // from both to only arterial Vb correction
213 else if(corrmode==2) corrmode=0; // from venous to none
214 }
215 }
216
217 if(corrmode==0) {
218 fprintf(stderr, "Warning: no corrections applied, no files written.\n");
219 dftEmpty(&btac); imgEmpty(&img); imgEmpty(&vbimg);
220 return(0);
221 }
222
223
224 /* Correct for the venous injection activity */
225 if(corrmode==0 || corrmode==2) {
226
227 /* Find peak of injection venous curve */
228 double ymaxrv, xmaxrv; int imaxrv;
229 ymaxrv=rvtac[0];
230 xmaxrv=img.mid[0];
231 imaxrv=0;
232 for(int ti=1; ti<img.dimt; ti++) if(rvtac[ti]>ymaxrv) {
233 ymaxrv=rvtac[ti];
234 xmaxrv=img.mid[ti];
235 imaxrv=ti;
236 }
237 if(verbose>1) {
238 printf(" rv_maxv := %g\n", ymaxrv);
239 printf(" rv_maxx := %g\n", xmaxrv);
240 }
241
242 /* Correct the image data for RV TAC */
243 for(int zi=0; zi<img.dimz; zi++) {
244 for(int yi=0; yi<img.dimy; yi++) {
245 for(int xi=0; xi<img.dimx; xi++) {
246
247 /* Calculate the maximum of Vb that is possible in this pixel from T/B ratio */
248 float vb=img.m[zi][yi][xi][imaxrv]/ymaxrv;
249 if(vb>=1.0) { // this pixel must be mostly blood
250 for(int ti=0; ti<img.dimt; ti++) img.m[zi][yi][xi][ti]=0.0;
251 vbimg.m[zi][yi][xi][0]=vb;
252 continue;
253 }
254
255 /* Make initial BV corrected TTAC */
256 float ct[img.dimt], ctmin=0.0; int ictmin=0;
257 for(int ti=0; ti<img.dimt; ti++) {
258 if(img.m[zi][yi][xi][ti]>0.0) {
259 ct[ti]=img.m[zi][yi][xi][ti]-vb*rvtac[ti];
260 if(ct[ti]<ctmin) {ctmin=ct[ti]; ictmin=ti;}
261 } else ct[ti]=0.0;
262 }
263 /* Make Vb smaller to prevent negative TAC values and correct again */
264 if(ctmin<0.0) {
265 vb+=ctmin/rvtac[ictmin];
266 for(int ti=0; ti<img.dimt; ti++) {
267 if(img.m[zi][yi][xi][ti]>0.0) {
268 ct[ti]=img.m[zi][yi][xi][ti]-vb*rvtac[ti];
269 }
270 if(ct[ti]<0.0) ct[ti]=0.0;
271 }
272 }
273 /* Put correct TAC in place */
274 for(int ti=0; ti<img.dimt; ti++) img.m[zi][yi][xi][ti]=ct[ti];
275 /* Store the Vb */
276 vbimg.m[zi][yi][xi][0]=vb;
277 }
278 }
279 }
280 }
281
282
283 /* Correct for the arterial BTAC */
284 if(corrmode==3 || corrmode==1) {
285
286 for(int zi=0; zi<img.dimz; zi++) {
287 for(int yi=0; yi<img.dimy; yi++) {
288 for(int xi=0; xi<img.dimx; xi++) {
289
290 /* Calculate the maximum of Vb that is possible in this pixel from T/B ratio */
291 float tpeak=img.m[zi][yi][xi][ipeak];
292 if(ipeak>0) tpeak+=img.m[zi][yi][xi][ipeak-1];
293 float vb=tpeak/bpeak;
294 if(vb>=1.0) { // this pixel must be mostly blood
295 for(int ti=0; ti<img.dimt; ti++) img.m[zi][yi][xi][ti]=0.0;
296 vbimg.m[zi][yi][xi][0]+=vb; //1.0;
297 continue;
298 }
299
300 /* Make initial BV corrected TTAC */
301 float ct[img.dimt], ctmin=0.0; int ictmin=0;
302 for(int ti=0; ti<img.dimt; ti++) {
303 if(img.m[zi][yi][xi][ti]>0.0) {
304 ct[ti]=img.m[zi][yi][xi][ti]-vb*btac.voi[0].y[ti];
305 if(ct[ti]<ctmin) {ctmin=ct[ti]; ictmin=ti;}
306 } else ct[ti]=0.0;
307 }
308 /* Make Vb smaller to prevent negative TAC values and correct again */
309 if(ctmin<0.0) {
310 vb+=ctmin/btac.voi[0].y[ictmin];
311 for(int ti=0; ti<img.dimt; ti++) {
312 if(img.m[zi][yi][xi][ti]>0.0) {
313 ct[ti]=img.m[zi][yi][xi][ti]-vb*btac.voi[0].y[ti];
314 }
315 if(ct[ti]<0.0) ct[ti]=0.0;
316 }
317 }
318 /* Put correct TAC in place */
319 for(int ti=0; ti<img.dimt; ti++) img.m[zi][yi][xi][ti]=ct[ti];
320 /* Store the Vb */
321 vbimg.m[zi][yi][xi][0]+=vb;
322 }
323 }
324 }
325 }
326
327
328 /* If requested, save (1-Vb)Ct image */
329 if(ctfile[0]) {
330 if(verbose>1) fprintf(stdout, "writing %s\n", ctfile);
331 ret=imgWrite(ctfile, &img);
332 if(ret) {
333 fprintf(stderr, "Error: %s\n", img.statmsg);
334 if(verbose>1) printf("ret=%d\n", ret);
335 dftEmpty(&btac); imgEmpty(&img); imgEmpty(&vbimg);
336 return(11);
337 }
338 if(verbose>0) printf("Written %s\n", ctfile);
339 }
340
341 /* If requested, save Vb image */
342 if(vbfile[0]) {
343 if(verbose>1) fprintf(stdout, "writing %s\n", vbfile);
344 ret=imgWrite(vbfile, &vbimg);
345 if(ret) {
346 fprintf(stderr, "Error: %s\n", vbimg.statmsg);
347 if(verbose>1) printf("ret=%d\n", ret);
348 dftEmpty(&btac); imgEmpty(&img); imgEmpty(&vbimg);
349 return(11);
350 }
351 if(verbose>0) printf("Written %s\n", vbfile);
352 }
353
354
355 dftEmpty(&btac); imgEmpty(&img); imgEmpty(&vbimg);
356 return(0);
357}
358/*****************************************************************************/
359
360/*****************************************************************************/
void dftInit(DFT *data)
Definition dft.c:38
void dftEmpty(DFT *data)
Definition dft.c:20
void dftPrint(DFT *data)
Definition dftio.c:538
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 imgMinMax(IMG *img, float *minvalue, float *maxvalue)
Definition imgminmax.c:154
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.
Header file for libtpcmodext.
Voi * voi
int frameNr
double * x
unsigned short int dimx
float **** m
char unit
unsigned short int dimt
unsigned short int dimz
unsigned short int dimy
const char * statmsg
float * mid
double * y