TPCCLIB
Loading...
Searching...
No Matches
imgafind.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/*****************************************************************************/
22
23/*****************************************************************************/
24static char *info[] = {
25 "Trial program to find the locations of arteries in dynamic PET image.",
26 " ",
27 "Usage: @P [Options] imgfile template",
28 " ",
29 "Options:",
30 " -peak=<filename>",
31 " Pixel peak values are saved as image.",
32 " -time=<filename>",
33 " Pixel peak times (1/peaktime) are saved as image.",
34 " -ratio=<filename>",
35 " Pixel peak value/time ratios are saved as image.",
36 " -lthr=<percentage value>",
37 " Lower threshold value as percentage of maximum.",
38 " -uthr=<percentage value>",
39 " Upper threshold value as percentage of maximum.",
40 " -maxpeaktime=<time in sec>",
41 " Pixel TAC values after given time are ignored when finding peak.",
42 " -minpeaktime=<time in sec>",
43 " Pixel TAC values before given time are ignored when finding peak.",
44 " -stdoptions", // List standard options like --help, -v, etc
45 " ",
46 "See also: eabaort, imgprofi, imgthrs, imgfsegm, imgdysmo, imgmax, img2tif",
47 " ",
48 "Keywords: image, input, blood, aorta",
49 0};
50/*****************************************************************************/
51
52/*****************************************************************************/
53/* Turn on the globbing of the command line, since it is disabled by default in
54 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
55 In Unix&Linux wildcard command line processing is enabled by default. */
56/*
57#undef _CRT_glob
58#define _CRT_glob -1
59*/
60int _dowildcard = -1;
61/*****************************************************************************/
62
63/*****************************************************************************/
67int main(int argc, char **argv)
68{
69 int ai, help=0, version=0, verbose=1;
70 int ret, fi, fj, zi, yi, xi;
71 long long m, n;
72 char *cptr, imgfile[FILENAME_MAX];
73 char peakfile[FILENAME_MAX], timefile[FILENAME_MAX],
74 ratiofile[FILENAME_MAX], templfile[FILENAME_MAX];
75 float lower_threshold=0.0, upper_threshold=1.0;
76 float max_peak_time=0.0;
77 float min_peak_time=0.0;
78 float local_mean, best_mean, f1, f2, best_two_mean,
79 peak_time, peak_value_per_time;
80 int best_frame;
81 IMG img, template_img, peak_img, time_img, ratio_img;
82
83
84 /*
85 * Get arguments
86 */
87 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
88 imgfile[0]=(char)0;
89 peakfile[0]=timefile[0]=ratiofile[0]=templfile[0]=(char)0;
90 /* Options */
91 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* options */
92 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
93 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
94 if(strncasecmp(cptr, "PEAK=", 5)==0) {
95 strlcpy(peakfile, cptr+5, FILENAME_MAX); continue;
96 } else if(strncasecmp(cptr, "TIME=", 5)==0) {
97 strlcpy(timefile, cptr+5, FILENAME_MAX); continue;
98 } else if(strncasecmp(cptr, "RATIO=", 6)==0) {
99 strlcpy(ratiofile, cptr+6, FILENAME_MAX); continue;
100 } else if(strncasecmp(cptr, "LTHR=", 5)==0) {
101 double v;
102 if(atof_with_check(cptr+5, &v)==0) {
103 if(v>=0.0 && v<100.0) {lower_threshold=0.01*v; continue;}
104 }
105 } else if(strncasecmp(cptr, "UTHR=", 5)==0) {
106 double v;
107 if(atof_with_check(cptr+5, &v)==0) {
108 if(v>0.0 && v<=100.0) {upper_threshold=0.01*v; continue;}
109 }
110 } else if(strncasecmp(cptr, "MAXPEAKTIME=", 12)==0) {
111 double v;
112 if(atof_with_check(cptr+12, &v)==0) {
113 if(v>0.0) {max_peak_time=v; continue;}
114 }
115 } else if(strncasecmp(cptr, "MINPEAKTIME=", 12)==0) {
116 double v;
117 if(atof_with_check(cptr+12, &v)==0) {
118 if(v>0.0) {min_peak_time=v; continue;}
119 }
120 }
121 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
122 return(1);
123 } else break;
124
125 /* Print help or version? */
126 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
127 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
128 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
129
130 /* Process other arguments, starting from the first non-option */
131 if(ai<argc) {strlcpy(imgfile, argv[ai], FILENAME_MAX); ai++;}
132 if(ai<argc) {strlcpy(templfile, argv[ai], FILENAME_MAX); ai++;}
133 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
134
135 /* Is something missing or wrong? */
136 if(!templfile[0]) {
137 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
138 return(1);
139 }
140 if(lower_threshold>=upper_threshold) {
141 fprintf(stderr, "Error: invalid thresholds.\n");
142 return(1);
143 }
144 if(strcasecmp(imgfile, templfile)==0) {
145 fprintf(stderr, "Error: check the output filename.\n");
146 return(1);
147 }
148
149 /* In verbose mode print arguments and options */
150 if(verbose>1) {
151 printf("imgfile := %s\n", imgfile);
152 printf("peakfile := %s\n", peakfile);
153 printf("timefile := %s\n", timefile);
154 printf("ratiofile := %s\n", ratiofile);
155 printf("templfile := %s\n", templfile);
156 printf("lower_threshold := %g\n", lower_threshold);
157 printf("upper_threshold := %g\n", upper_threshold);
158 printf("max_peak_time := %g s\n", max_peak_time);
159 printf("min_peak_time := %g s\n", min_peak_time);
160 }
161
162
163 /*
164 * Read dynamic image
165 */
166 if(verbose>0) fprintf(stdout, "reading dynamic image %s\n", imgfile);
167 imgInit(&img);
168 ret=imgRead(imgfile, &img);
169 if(ret) {
170 fprintf(stderr, "Error: %s\n", img.statmsg);
171 if(verbose>1) printf("ret := %d\n", ret);
172 return(2);
173 }
174 /* Check if PET data is raw or image */
175 if(img.type!=IMG_TYPE_IMAGE) {
176 fprintf(stderr, "Error: %s is not an image.\n", imgfile);
177 imgEmpty(&img); return(2);
178 }
179 if(img.dimt<4) {
180 fprintf(stderr, "Error: %s contains only %d time frame(s).\n", imgfile, img.dimt);
181 imgEmpty(&img); return(2);
182 }
183 if(verbose>0) fprintf(stdout, " image contains %d frames and %d planes.\n", img.dimt, img.dimz);
184 if(imgNaNs(&img, 1)>0)
185 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
186
187
188 /*
189 * Allocate result images
190 */
191 if(verbose>1) fprintf(stdout, "allocating memory for parametric images\n");
192 imgInit(&peak_img); imgInit(&time_img); imgInit(&ratio_img);
193 ret=0;
194 if(ret==0 && peakfile[0])
195 ret=imgAllocateWithHeader(&peak_img, img.dimz, img.dimy, img.dimx, 1, &img);
196 if(ret==0 && timefile[0])
197 ret=imgAllocateWithHeader(&time_img, img.dimz, img.dimy, img.dimx, 1, &img);
198 if(ret==0 /* && ratiofile[0]*/) // needed even if not saved
199 ret=imgAllocateWithHeader(&ratio_img, img.dimz, img.dimy, img.dimx, 1, &img);
200 if(ret) {
201 fprintf(stderr, "Error: out of memory.\n");
202 imgEmpty(&img);
203 imgEmpty(&peak_img); imgEmpty(&time_img); imgEmpty(&ratio_img);
204 return(4);
205 }
206 /* and set the units */
207 if(timefile[0]) time_img.unit=IMGUNIT_UNITLESS; //IMGUNIT_PER_MIN;
208 /*if(ratiofile[0])*/ ratio_img.unit=IMGUNIT_UNITLESS;
209 /* and frame times */
210 ratio_img.start[0]=0.0; ratio_img.end[0]=1.0;
211
212
213 /* Remove outlier pixels */
214 n=imgOutlierFilter(&img, 10.0);
215 if(verbose>0) {
216 printf("%lld pixel(s) filtered out as outliers from dynamic image.\n", n);
217 }
218
219
220 /*
221 * Thresholding
222 */
223 if(verbose>1 || (verbose>0 && (lower_threshold>0.0 || upper_threshold<1.0)))
224 fprintf(stdout, "thresholding with limits %g-%g%% of AUC max.\n",
225 100.*lower_threshold, 100.*upper_threshold);
226 imgInit(&template_img);
227 ret=imgThresholdingLowHigh(&img, lower_threshold, upper_threshold,
228 &template_img, &n, &m);
229 if(ret)
230 fprintf(stderr, "Warning: error %d in thresholding.\n", ret);
231 else if(verbose>0 && (n>0 || m>0)) {
232 fprintf(stdout, " %lld pixels below threshold\n", n);
233 fprintf(stdout, " %lld pixels above threshold\n", m);
234 }
235 /*ret=imgThresholdByTemplate(&img, &template_img, 0.0);
236 if(ret)
237 fprintf(stderr, "Warning: error %d in thresholding.\n", ret);*/
238
239
240 /*
241 * Compute pixel-by-pixel
242 */
243 if(verbose>0) fprintf(stdout, "computing pixel-by-pixel\n");
244 for(zi=0; zi<img.dimz; zi++) {
245 if(img.dimz>1 && verbose==1) {fprintf(stdout, "."); fflush(stdout);}
246 else if(verbose>1) printf("processing plane %d\n", 1+zi);
247 for(yi=0; yi<img.dimy; yi++) {
248 for(xi=0; xi<img.dimx; xi++) {
249
250 ratio_img.m[zi][yi][xi][0]=0.0;
251 if(template_img.m[zi][yi][xi][0]<=0.0) continue;
252
253 /* Search the four consecutive time frames which have the highest mean */
254 best_mean=0.0; best_frame=0;
255 for(fj=3; fj<img.dimt; fj++) {
256 if(img.mid[fj-2]<min_peak_time) continue;
257 local_mean=0.0;
258 for(fi=fj-3; fi<=fj; fi++) {
259 local_mean+=img.m[zi][yi][xi][fi];
260 //printf(" %d", fi);
261 }
262 if(local_mean>best_mean) {
263 best_mean=local_mean;
264 best_frame=fj-3;
265 }
266 //printf(" -> %f\n", local_mean/4.0);
267 }
268 best_mean/=4.0;
269 //printf("best_mean=%f\n", best_mean);
270 //printf("best_mean_frames=%d-%d\n", best_frame, best_frame+2);
271
272 /* Which two means is higher in this range? */
273 f1=img.m[zi][yi][xi][best_frame]+img.m[zi][yi][xi][best_frame+1];
274 f2=img.m[zi][yi][xi][best_frame+1]+img.m[zi][yi][xi][best_frame+2];
275 if(f1>f2) best_two_mean=f1; else best_two_mean=f2;
276 best_two_mean*=0.5;
277 //printf("best_two_mean=%f\n", best_two_mean);
278 if(peakfile[0]) peak_img.m[zi][yi][xi][0]=best_two_mean;
279
280 /* Calculate value-weighted mean of peak mid-frame times */
281 peak_time=0.0;
282 for(fi=best_frame; fi<=best_frame+3; fi++)
283 peak_time+=img.m[zi][yi][xi][fi]*img.mid[fi];
284 if(best_mean>0.0) peak_time/=(4.0*best_mean); else peak_time=0.0;
285 //printf("peak_time=%f\n", peak_time);
286 if(timefile[0]) {
287 //time_img.m[zi][yi][xi][0]=best_frame+1;
288 if(peak_time>0) time_img.m[zi][yi][xi][0]=1.0/peak_time;
289 else time_img.m[zi][yi][xi][0]=0.0;
290 }
291
292 /* If max peak time was set, and limit is met, then remove pixel
293 from template and result images */
294 if(max_peak_time>0.0 && peak_time>max_peak_time) {
295 template_img.m[zi][yi][xi][0]=0;
296 if(peakfile[0]) peak_img.m[zi][yi][xi][0]=0.0;
297 if(timefile[0]) time_img.m[zi][yi][xi][0]=0.0;
298 continue;
299 }
300
301 /* Calculate peak value/time ratio */
302 if(peak_time>0.0 && best_two_mean>0.0) {
303 peak_value_per_time=(best_two_mean)/(peak_time);
304 } else peak_value_per_time=0.0;
305 //printf("peak_value_per_time=%f\n", peak_value_per_time);
306 /*if(ratiofile[0])*/ ratio_img.m[zi][yi][xi][0]=peak_value_per_time;
307 } // next column
308 } // next row
309 } // next plane
310 if(verbose==1) fprintf(stdout, "\ndone.\n");
311
312 /* Leave only very peaky pixels into the template */
313 ret=imgThresholdingLowHigh(&ratio_img, 0.50, 1.0,
314 &template_img, &n, &m);
315 if(ret)
316 fprintf(stderr, "Warning: error %d in thresholding.\n", ret);
317 else if(verbose>0 && (n>0 || m>0)) {
318 fprintf(stdout, " %lld pixels below threshold\n", n);
319 fprintf(stdout, " %lld pixels above threshold\n", m);
320 }
321
322
323 /* Region growing and erode boundaries */
324
325 /* Calculate TACs from final regions */
326
327 /* If required, save 4D image where arterial regions are set to zero */
328
329
330 /*
331 * Save result image(s)
332 */
333 if(verbose>1) printf("writing result image(s)\n");
334 if(templfile[0]) {
335 ret=imgWrite(templfile, &template_img);
336 if(ret) {
337 fprintf(stderr, "Error: %s\n", template_img.statmsg);
338 imgEmpty(&img); imgEmpty(&template_img);
339 imgEmpty(&peak_img); imgEmpty(&time_img); imgEmpty(&ratio_img);
340 return(11);
341 }
342 if(verbose>0) fprintf(stdout, "Template image %s saved.\n", templfile);
343 }
344 if(peakfile[0]) {
345 ret=imgWrite(peakfile, &peak_img);
346 if(ret) {
347 fprintf(stderr, "Error: %s\n", peak_img.statmsg);
348 imgEmpty(&img); imgEmpty(&template_img);
349 imgEmpty(&peak_img); imgEmpty(&time_img); imgEmpty(&ratio_img);
350 return(21);
351 }
352 if(verbose>0) fprintf(stdout, "Peak value image %s saved.\n", peakfile);
353 }
354 if(timefile[0]) {
355 ret=imgWrite(timefile, &time_img);
356 if(ret) {
357 fprintf(stderr, "Error: %s\n", time_img.statmsg);
358 imgEmpty(&img); imgEmpty(&template_img);
359 imgEmpty(&peak_img); imgEmpty(&time_img); imgEmpty(&ratio_img);
360 return(22);
361 }
362 if(verbose>0) fprintf(stdout, "Peak time image %s saved.\n", timefile);
363 }
364 if(ratiofile[0]) {
365 ret=imgWrite(ratiofile, &ratio_img);
366 if(ret) {
367 fprintf(stderr, "Error: %s\n", ratio_img.statmsg);
368 imgEmpty(&img); imgEmpty(&template_img);
369 imgEmpty(&peak_img); imgEmpty(&time_img); imgEmpty(&ratio_img);
370 return(23);
371 }
372 if(verbose>0) fprintf(stdout, "Peak value/time image %s saved.\n", ratiofile);
373 }
374
375
376 imgEmpty(&img); imgEmpty(&template_img);
377 imgEmpty(&peak_img); imgEmpty(&time_img); imgEmpty(&ratio_img);
378 if(verbose>0) printf("done.\n");
379 return(0);
380}
381/*****************************************************************************/
382
383/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
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 imgRead(const char *fname, IMG *img)
Definition imgfile.c:26
int imgWrite(const char *fname, IMG *img)
Definition imgfile.c:136
int imgOutlierFilter(IMG *img, float limit)
int imgThresholdingLowHigh(IMG *img, float lower_threshold_level, float upper_threshold_level, IMG *timg, long long *lower_thr_nr, long long *upper_thr_nr)
Header file for libtpcimgio.
#define IMG_TYPE_IMAGE
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
unsigned short int dimx
char type
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