TPCCLIB
Loading...
Searching...
No Matches
imgpeak.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 <math.h>
15#include <string.h>
16#include <unistd.h>
17#include <time.h>
18/*****************************************************************************/
19#include "libtpcmisc.h"
20#include "libtpcmodel.h"
21#include "libtpccurveio.h"
22#include "libtpcimgio.h"
23#include "libtpcimgp.h"
24/*****************************************************************************/
25
26/*****************************************************************************/
27static char *info[] = {
28 "Find peak value and time in dynamic PET image.",
29 "Static image containing the peak value of each pixel TAC is written.",
30 " ",
31 "Usage: @P [Options] imgfile [peakfile]",
32 " ",
33 "Options:",
34 " -frame=<filename>",
35 " Save a template image containing the frame numbers (1..frame_nr)",
36 " where the maximum pixel values were found.",
37 " -mpt=<filename>",
38 " Save TAC file, containing the frame times (sec) on x-axis, and on",
39 " y-axis the means (and mean-SD and mean+SD) of the peak values of",
40 " each pixel that had its peak at this frame time.",
41 " -time=<filename>",
42 " Save the peak time (sec) of each pixel (middle time of peak frame).",
43 " -wt=<filename>",
44 " Save the peak time (sec) of each pixel, calculated as weighted",
45 " average of 3 or 5 subsequent frames.",
46 " -ct=<filename>",
47 " Save the value-weighted mean time (sec) of all frames.",
48 " Mean residence time (MRT) in PK for PTACs uses the same equation.",
49 " -thr=<threshold%>",
50 " Use only pixels with peak value above (threshold/100 x max peak);",
51 " default is 5%.",
52 " -norm[alize]",
53 " Maximum pixel values are divided by the frame average.",
54 " -stdoptions", // List standard options like --help, -v, etc
55 " ",
56 "See also: tacpeak, imgmax, imgaumc, imgmask, imgthrs, imgfrsmo, imgdelfr",
57 " ",
58 "Keywords: image, peak, max, time, mask",
59 0};
60/*****************************************************************************/
61
62/*****************************************************************************/
63/* Turn on the globbing of the command line, since it is disabled by default in
64 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
65 In Unix&Linux wildcard command line processing is enabled by default. */
66/*
67#undef _CRT_glob
68#define _CRT_glob -1
69*/
70int _dowildcard = -1;
71/*****************************************************************************/
72
73/*****************************************************************************/
77int main(int argc, char **argv)
78{
79 int ai, help=0, version=0, verbose=1;
80 char imgfile[FILENAME_MAX], peakfile[FILENAME_MAX], framefile[FILENAME_MAX],
81 mptfile[FILENAME_MAX], timefile[FILENAME_MAX], wtfile[FILENAME_MAX], ctfile[FILENAME_MAX];
82 int max_normalized=0;
83 float calcThreshold=0.05;
84
85
86 /*
87 * Get arguments
88 */
89 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
90 imgfile[0]=peakfile[0]=framefile[0]=mptfile[0]=timefile[0]=wtfile[0]=ctfile[0]=(char)0;
91 /* Options */
92 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* options */
93 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
94 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
95 if(strncasecmp(cptr, "FRAME=", 6)==0) {
96 if(strlcpy(framefile, cptr+6, FILENAME_MAX)>1) continue;
97 } else if(strncasecmp(cptr, "MPT=", 4)==0) {
98 if(strlcpy(mptfile, cptr+4, FILENAME_MAX)>1) continue;
99 } else if(strncasecmp(cptr, "TIME=", 5)==0) {
100 if(strlcpy(timefile, cptr+5, FILENAME_MAX)>1) continue;
101 } else if(strncasecmp(cptr, "WT=", 3)==0) {
102 if(strlcpy(wtfile, cptr+3, FILENAME_MAX)>1) continue;
103 } else if(strncasecmp(cptr, "CT=", 3)==0) {
104 if(strlcpy(ctfile, cptr+3, FILENAME_MAX)>1) continue;
105 } else if(strncasecmp(cptr, "NORMALIZED", 4)==0) {
106 max_normalized=1; continue;
107 } else if(strncasecmp(cptr, "THR=", 4)==0) {
108 double v;
109 if(!atof_with_check(cptr+4, &v) && v<100.0) {calcThreshold=(float)(0.01*v); continue;}
110 }
111 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
112 return(1);
113 } else break;
114
115 /* Print help or version? */
116 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
117 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
118 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
119
120 /* Process other arguments, starting from the first non-option */
121 if(ai<argc) {strlcpy(imgfile, argv[ai], FILENAME_MAX); ai++;}
122 if(ai<argc) {strlcpy(peakfile, argv[ai], FILENAME_MAX); ai++;}
123 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
124
125 /* Is something missing or wrong? */
126 if(!imgfile[0]) {
127 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
128 return(1);
129 }
130
131 /* In verbose mode print arguments and options */
132 if(verbose>1) {
133 printf("imgfile := %s\n", imgfile);
134 if(peakfile[0]) printf("peakfile := %s\n", peakfile);
135 if(timefile[0]) printf("timefile := %s\n", timefile);
136 if(wtfile[0]) printf("wtfile := %s\n", wtfile);
137 if(ctfile[0]) printf("ctfile := %s\n", ctfile);
138 if(mptfile[0]) printf("mptfile := %s\n", mptfile);
139 if(framefile[0]) printf("framefile := %s\n", framefile);
140 printf("max_normalized := %d\n", max_normalized);
141 printf("threshold_ratio := %g\n", calcThreshold);
142 }
143
144
145 /*
146 * Read dynamic image
147 */
148 if(verbose>0) printf("reading dynamic image %s\n", imgfile);
149 IMG img; imgInit(&img);
150 if(imgRead(imgfile, &img)) {
151 fprintf(stderr, "Error: %s\n", img.statmsg);
152 return(2);
153 }
154 if(verbose>1) {
155 printf("img_dimx := %d\n", img.dimx);
156 printf("img_dimy := %d\n", img.dimy);
157 printf("img_dimz := %d\n", img.dimz);
158 printf("img_dimt := %d\n", img.dimt);
159 }
160 if(img.dimt<2) {
161 fprintf(stderr, "Error: %s contains only 1 time frame.\n", imgfile);
162 imgEmpty(&img); return(2);
163 }
164 if(imgNaNs(&img, 1)>0)
165 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
166
167 /* Check if times are needed, and if yes, then check that times are available */
168 int timesNeeded=0;
169 if(timefile[0] || wtfile[0] || ctfile[0]) timesNeeded=1;
170 if(timesNeeded && imgExistentTimes(&img)==0) {
171 fprintf(stderr, "Error: image does not contain frame times.\n");
172 imgEmpty(&img); return(2);
173 }
174
175
176 /*
177 * Find the peak frame for each pixel
178 */
179 if(verbose>0) printf("searching for peak frames\n");
180 IMG pfimg; imgInit(&pfimg);
181 if(imgGetMaxFrame(&img, &pfimg, verbose-1)!=0) {
182 fprintf(stderr, "Error: cannot search for peaks.\n");
183 imgEmpty(&img); imgEmpty(&pfimg);
184 return(3);
185 }
186
187 /*
188 * Peak value image
189 */
190 if(verbose>0) printf("making peak value image\n");
191 IMG pvimg; imgInit(&pvimg);
192 if(imgDup(&pfimg, &pvimg)) {
193 fprintf(stderr, "Error: cannot allocate memory.\n");
194 imgEmpty(&img); imgEmpty(&pfimg);
195 return(4);
196 }
197 for(int zi=0; zi<img.dimz; zi++) {
198 for(int yi=0; yi<img.dimy; yi++) {
199 for(int xi=0; xi<img.dimx; xi++) {
200 int fi=(int)roundf(pfimg.m[zi][yi][xi][0]);
201 if(fi>0) pvimg.m[zi][yi][xi][0]=img.m[zi][yi][xi][fi-1];
202 else pvimg.m[zi][yi][xi][0]=0.0;
203 }
204 }
205 }
206 /* Calculate max peak value */
207 if(verbose>1) printf("making thresholding mask\n");
208 float maxPeak=0.0;
209 if(imgMax(&pvimg, &maxPeak)) {
210 fprintf(stderr, "Error: cannot find maximum peak value.\n");
211 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&pvimg);
212 return(4);
213 }
214 if(verbose>0) printf("max_peak_value := %g\n", maxPeak);
215
216 /* Use it to make a thresholding template */
217 IMG thrimg; imgInit(&thrimg);
218 long long thrNr=0;
219 if(imgThresholdMaskCount(&pvimg, calcThreshold*maxPeak, 1.0E+20, &thrimg, &thrNr)) {
220 fprintf(stderr, "Error: cannot create thresholding mask image.\n");
221 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&pvimg);
222 return(4);
223 }
224 if(verbose>1) printf("%lld pixels are over threshold limit.\n", thrNr);
225 if(thrNr==0) {
226 fprintf(stderr, "Error: no pixels above threshold level.\n");
227 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&pvimg); imgEmpty(&thrimg);
228 return(4);
229 }
230
231 /* Apply the thresholding mask to the image data */
232 if(verbose>1) printf("thresholding\n");
233 imgThresholdByMask(&img, &thrimg, 0.0);
234 imgThresholdByMask(&pfimg, &thrimg, 0.0);
235 imgThresholdByMask(&pvimg, &thrimg, 0.0);
236
237 /*
238 * Save the peak frame data, if requested
239 */
240 if(framefile[0]) {
241 if(verbose>1) printf("writing peak frames\n");
242 if(imgWrite(framefile, &pfimg)) {
243 fprintf(stderr, "Error: %s\n", pfimg.statmsg);
244 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&pvimg); imgEmpty(&thrimg);
245 return(11);
246 }
247 if(verbose>0) fprintf(stdout, "Image %s saved.\n", framefile);
248 }
249
250 /*
251 * Save the peak value data, if requested
252 */
253 if(peakfile[0] && max_normalized) {
254 if(verbose>1) fprintf(stdout, "computing mean of pixels\n");
255 if(imgAverageMaskTAC(&img, &thrimg, img.sd)!=0) {
256 fprintf(stderr, "Error: cannot calculate average TAC.\n");
257 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&pvimg); imgEmpty(&thrimg);
258 return(5);
259 }
260 if(verbose>3) {
261 printf("Mean TAC:\n");
262 for(int i=0; i<img.dimt; i++)
263 printf("\t%g\t%g\n", img.mid[i], img.sd[i]);
264 }
265 if(verbose>1) printf("normalizing peak values\n");
266 for(int zi=0; zi<img.dimz; zi++) {
267 for(int yi=0; yi<img.dimy; yi++) {
268 for(int xi=0; xi<img.dimx; xi++) {
269 int fi=(int)roundf(pfimg.m[zi][yi][xi][0]);
270 if(fi>0 && img.sd[fi-1]>1.0E-010) pvimg.m[zi][yi][xi][0]/=img.sd[fi-1];
271 }
272 }
273 }
274 }
275 if(peakfile[0]) {
276 if(verbose>1) printf("writing peak values\n");
277 if(imgWrite(peakfile, &pvimg)) {
278 fprintf(stderr, "Error: %s\n", pvimg.statmsg);
279 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&pvimg); imgEmpty(&thrimg);
280 return(12);
281 }
282 if(verbose>0) fprintf(stdout, "Image %s saved.\n", peakfile);
283 }
284 imgEmpty(&pvimg); imgEmpty(&thrimg);
285
286
287
288 /*
289 * Optional peak frame time (the simple one)
290 */
291 if(timefile[0]) {
292 if(verbose>0) printf("searching for peak times\n");
293 IMG timg; imgInit(&timg);
294 if(imgGetMaxTime(&img, &timg, 0, verbose-1)!=0) {
295 fprintf(stderr, "Error: cannot search for peaks.\n");
296 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&timg);
297 return(6);
298 }
299 if(verbose>1) printf("writing peak times\n");
300 if(imgWrite(timefile, &timg)) {
301 fprintf(stderr, "Error: %s\n", timg.statmsg);
302 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&timg);
303 return(13);
304 }
305 if(verbose>0) fprintf(stdout, "Image %s saved.\n", timefile);
306 imgEmpty(&timg);
307 }
308
309
310 /*
311 * Weighted mean of all frame times
312 */
313 if(ctfile[0]) {
314 if(verbose>0) printf("computing weighted time\n");
315 IMG timg; imgInit(&timg);
316 if(imgGetMaxTime(&img, &timg, 1, verbose-1)!=0) {
317 fprintf(stderr, "Error: cannot search for peaks.\n");
318 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&timg);
319 return(7);
320 }
321 if(verbose>1) printf("writing weighted times\n");
322 if(imgWrite(ctfile, &timg)) {
323 fprintf(stderr, "Error: %s\n", timg.statmsg);
324 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&timg);
325 return(14);
326 }
327 if(verbose>0) fprintf(stdout, "Image %s saved.\n", ctfile);
328 imgEmpty(&timg);
329 }
330
331
332 /*
333 * Weighted mean of frame times around the peak
334 */
335 if(wtfile[0]) {
336 if(verbose>0) printf("computing weighted time\n");
337 IMG timg; imgInit(&timg);
338 if(imgGetMaxTime(&img, &timg, 2, verbose-1)!=0) {
339 fprintf(stderr, "Error: cannot search for peaks.\n");
340 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&timg);
341 return(8);
342 }
343 if(verbose>1) printf("writing weighted peak times\n");
344 if(imgWrite(wtfile, &timg)) {
345 fprintf(stderr, "Error: %s\n", timg.statmsg);
346 imgEmpty(&img); imgEmpty(&pfimg); imgEmpty(&timg);
347 return(15);
348 }
349 if(verbose>0) fprintf(stdout, "Image %s saved.\n", wtfile);
350 imgEmpty(&timg);
351 }
352
353
354
355 /*
356 * If requested, compute and save mean TAC of peak values versus peak times
357 */
358 if(mptfile[0]) {
359 if(verbose>1) fprintf(stdout, "calculating mean TAC of peak value versus peak time\n");
360 /* Allocate memory for the mean TAC */
361 DFT dft; dftInit(&dft);
362 if(dftSetmem(&dft, img.dimt, 3)) {
363 fprintf(stderr, "Error: cannot allocate memory.\n");
364 imgEmpty(&img); imgEmpty(&pfimg);
365 return(9);
366 }
367 /* Set TAC contents */
369 dft.frameNr=0; dft.voiNr=3;
370 strcpy(dft.unit, imgUnit(img.unit)); /* Set calibration unit */
371 dft.timeunit=TUNIT_SEC;
373 /* set TAC curve titles */
374 strcpy(dft.voi[0].voiname, "Mean"); strcpy(dft.voi[0].name, dft.voi[0].voiname);
375 strcpy(dft.voi[1].voiname, "-SD"); strcpy(dft.voi[1].name, dft.voi[1].voiname);
376 strcpy(dft.voi[2].voiname, "+SD"); strcpy(dft.voi[2].name, dft.voi[2].voiname);
377 /* Allocate list for peak values */
378 double *peaks=(double*)malloc(img.dimz*img.dimy*img.dimx*sizeof(double));
379 if(peaks==NULL) {
380 fprintf(stderr, "Error: out of memory.\n");
381 imgEmpty(&img); imgEmpty(&pfimg); dftEmpty(&dft);
382 return(9);
383 }
384 /* Go through each image frame */
385 for(int fi=0; fi<img.dimt; fi++) {
386 if(verbose>3) printf("frame %d\n", 1+fi);
387 int pn=0;
388 for(int zi=0; zi<pfimg.dimz; zi++) {
389 for(int yi=0; yi<pfimg.dimy; yi++) {
390 for(int xi=0; xi<pfimg.dimx; xi++) {
391 if((int)roundf(pfimg.m[zi][yi][xi][0])!=(fi+1)) continue;
392 /* this voxel has its peak at this frame */
393 peaks[pn++]=img.m[zi][yi][xi][fi];
394 }
395 }
396 }
397 /* Continue with this frame only if at least one voxel has its peak here */
398 if(verbose>3) printf(" %d peaks on this frame\n", pn);
399 if(pn==0) continue;
400 double msd;
401 double mmean=dmean(peaks, pn, &msd);
402 if(verbose>3) printf(" %g +- %g\n", mmean, msd);
403 /* Put mean, mean-sd, and mean+sd into TAC struct */
404 dft.x1[dft.frameNr]=img.start[fi]; dft.x2[dft.frameNr]=img.end[fi];
405 dft.x[dft.frameNr]=img.mid[fi];
406 dft.voi[0].y[dft.frameNr]=mmean;
407 dft.voi[1].y[dft.frameNr]=mmean-msd;
408 dft.voi[2].y[dft.frameNr]=mmean+msd;
409 dft.frameNr++;
410 }
411 /* Save TAC */
412 if(dftWrite(&dft, mptfile)!=0) {
413 fprintf(stderr, "Error in writing '%s': %s\n", mptfile, dfterrmsg);
414 imgEmpty(&img); imgEmpty(&pfimg); dftEmpty(&dft); free(peaks);
415 return(16);
416 }
417 if(verbose>0) fprintf(stdout, "peak TAC written in %s\n", mptfile);
418 free(peaks); dftEmpty(&dft);
419 }
420
421
422 imgEmpty(&img); imgEmpty(&pfimg);
423 return(0);
424}
425/*****************************************************************************/
426
427/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
void dftInit(DFT *data)
Definition dft.c:38
char dfterrmsg[64]
Definition dft.c:6
int dftSetmem(DFT *data, int frameNr, int voiNr)
Definition dft.c:57
void dftEmpty(DFT *data)
Definition dft.c:20
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
int imgExistentTimes(IMG *img)
Definition img.c:613
unsigned long long imgNaNs(IMG *img, int fix)
Definition img.c:658
int imgDup(IMG *img1, IMG *img2)
Definition img.c:304
void imgEmpty(IMG *image)
Definition img.c:121
void imgInit(IMG *image)
Definition img.c:60
int imgAverageMaskTAC(IMG *img, IMG *timg, float *tac)
Definition imgeval.c:34
int imgRead(const char *fname, IMG *img)
Definition imgfile.c:26
int imgWrite(const char *fname, IMG *img)
Definition imgfile.c:136
int imgGetMaxTime(IMG *img, IMG *mimg, const int w, int verbose)
Definition imgminmax.c:345
int imgGetMaxFrame(IMG *img, IMG *mimg, int verbose)
Definition imgminmax.c:454
int imgMax(IMG *img, float *maxvalue)
Definition imgminmax.c:15
int imgThresholdMaskCount(IMG *img, float minValue, float maxValue, IMG *timg, long long *count)
int imgThresholdByMask(IMG *img, IMG *templt, float thrValue)
char * imgUnit(int dunit)
Definition imgunits.c:315
Header file for libtpccurveio.
#define DFT_FORMAT_PMOD
#define DFT_TIME_MIDDLE
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.
double dmean(double *data, int n, double *sd)
Definition median.c:73
int _type
int timetype
Voi * voi
int timeunit
double * x1
int voiNr
double * x2
int frameNr
double * x
char unit[MAX_UNITS_LEN+1]
unsigned short int dimx
float * sd
float **** m
char unit
unsigned short int dimt
float * start
unsigned short int dimz
unsigned short int dimy
float * end
const char * statmsg
float * mid
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char name[MAX_REGIONNAME_LEN+1]