TPCCLIB
Loading...
Searching...
No Matches
imgprofi.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 "libtpccurveio.h"
22/*****************************************************************************/
23
24/*****************************************************************************/
25static char *info[] = {
26 "List the x and y profiles of PET image at the pixel of maximum intensity",
27 "inside the 4D image. X and y profiles are saved separately in TAC format",
28 "files; from dynamic image the profiles from every time frame are saved.",
29 " ",
30 "Usage: @P [Options] imgfile xprofile yprofile [zprofile]",
31 " ",
32 "Options:",
33 " -tif=<TIFF filename>",
34 " Image matrix where profiles are calculated is saved as TIFF image",
35 " showing the profile lines.",
36 " -pxl=<x,y,z> or -pxlfile=<filename>",
37 " Instead of maximum, calculate profiles at pixel (x,y,z), where",
38 " x=column (starting from left, 1..width), y=row (starting from top,",
39 " 1..height), and z=plane (1..depth).",
40 " Option -pxlfile can be used to give pixel coordinates in file.",
41 " -focus",
42 " Profiles are centred on the selected pixel.",
43 " -stdoptions", // List standard options like --help, -v, etc
44 " ",
45 "Example #1:",
46 " @P us3456dy.v profilex.tac profiley.tac",
47 " ",
48 "See also: imgmaxp, imgpeak, pxl2tac, img2tif, imgthrs, imgdim, mask2pxl",
49 " ",
50 "Keywords: image, profile, max, input, aorta",
51 0};
52/*****************************************************************************/
53
54/*****************************************************************************/
55/* Turn on the globbing of the command line, since it is disabled by default in
56 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
57 In Unix&Linux wildcard command line processing is enabled by default. */
58/*
59#undef _CRT_glob
60#define _CRT_glob -1
61*/
62int _dowildcard = -1;
63/*****************************************************************************/
64
65/*****************************************************************************/
69int main(int argc, char **argv)
70{
71 int ai, help=0, version=0, verbose=1;
72 char imgfile[FILENAME_MAX], tiffile[FILENAME_MAX], pxlfile[FILENAME_MAX];
73 char prxfile[FILENAME_MAX], pryfile[FILENAME_MAX], przfile[FILENAME_MAX];
74 int focus=0; // 0=do not focus profiles to max; 1=do focus
75 IMG_PIXEL pos;
76 int ret;
77 char *cptr;
78
79
80 /*
81 * Get arguments
82 */
83 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
84 imgfile[0]=pxlfile[0]=tiffile[0]=prxfile[0]=pryfile[0]=przfile[0]=(char)0;
85 pos.x=pos.y=pos.z=pos.f=0;
86 /* Options */
87 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* options */
88 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
89 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
90 if(strncasecmp(cptr, "TIF=", 4)==0) {
91 if(strlcpy(tiffile, cptr+4, FILENAME_MAX)>1) continue;
92 } else if(strncasecmp(cptr, "PXL=", 4)==0 && strlen(cptr)>4) {
93 ret=string_to_xyz(cptr+4, &pos.x, &pos.y, &pos.z);
94 if(ret==0 && pos.x>0 && pos.y>0 && pos.z>0) continue;
95 } else if(strncasecmp(cptr, "PXLFILE=", 8)==0) {
96 if(strlcpy(pxlfile, cptr+8, FILENAME_MAX)>1) continue;
97 } else if(strcasecmp(cptr, "FOCUS")==0) {
98 focus=1; continue;
99 }
100 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
101 return(1);
102 } else break;
103
104 /* Print help or version? */
105 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
106 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
107 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
108
109 /* Process other arguments, starting from the first non-option */
110 if(ai<argc) {strlcpy(imgfile, argv[ai], FILENAME_MAX); ai++;}
111 if(ai<argc) {strlcpy(prxfile, argv[ai], FILENAME_MAX); ai++;}
112 if(ai<argc) {strlcpy(pryfile, argv[ai], FILENAME_MAX); ai++;}
113 if(ai<argc) {strlcpy(przfile, argv[ai], FILENAME_MAX); ai++;}
114 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
115
116 /* Is something missing or wrong? */
117 if(!pryfile[0]) {
118 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
119 return(1);
120 }
121 if(pxlfile[0] && pos.x>0) {
122 fprintf(stderr, "Error: do not use -pxl and -pxlfile together.\n");
123 return(1);
124 }
125
126 /* In verbose mode print options */
127 if(verbose>1) {
128 printf("imgfile := %s\n", imgfile);
129 printf("prxfile := %s\n", prxfile);
130 printf("pryfile := %s\n", pryfile);
131 if(przfile[0]) printf("przfile := %s\n", przfile);
132 if(tiffile[0]) printf("tiffile := %s\n", tiffile);
133 if(pxlfile[0]) printf("pxlfile := %s\n", pxlfile);
134 printf("focus := %d\n", focus);
135 }
136
137 /*
138 * Read pixel definition file
139 */
140 if(pxlfile[0]) {
141 if(verbose==1) printf("reading %s\n", pxlfile);
142 IMG_PIXELS pxl;
143 pxlInit(&pxl);
144 char buf[256];
145 ret=pxlRead(&pxl, pxlfile, buf);
146 if(ret) {
147 fprintf(stderr, "Error: %s\n", buf);
148 fprintf(stderr, "Error: cannot read pixel definition file.\n");
149 if(verbose>2) printf("ret := %d\n", ret);
150 return(2);
151 }
152 if(pxl.pxlNr>1) fprintf(stderr, "Warning: using only the first pixel definition.\n");
153 pos.x=pxl.p[0].x; pos.y=pxl.p[0].y; pos.z=pxl.p[0].z;
154 pxlFree(&pxl);
155 }
156 if(verbose>1) {
157 if(pos.x>0) printf("pixel := %d,%d,%d\n", pos.x, pos.y, pos.z);
158 }
159
160
161 /*
162 * Read PET data
163 */
164 if(verbose>0) printf("reading PET data %s\n", imgfile);
165 IMG img; imgInit(&img);
166 ret=imgRead(imgfile, &img);
167 if(ret) {
168 fprintf(stderr, "Error: %s\n", img.statmsg);
169 if(verbose>1) printf("ret := %d\n", ret);
170 return(3);
171 }
172 if(verbose>0) fprintf(stdout, " image contains %d frames and %d planes.\n", img.dimt, img.dimz);
173 if(przfile[0] && img.dimz<3) {
174 fprintf(stderr, "Warning: option for z profile ignored for this data.\n");
175 przfile[0]=(char)0;
176 }
177 if(imgNaNs(&img, 1)>0)
178 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
179
180
181 /*
182 * If pixel was not specified, then search for max
183 */
184 double maxv;
185 if(pos.x<1) {
186 float f;
187 if(verbose>1) fprintf(stdout, " searching for image max\n");
188 ret=imgSmoothMax(&img, &f, &pos);
189 if(ret!=0) {
190 fprintf(stderr, "Error: cannot determine maximum in image.\n");
191 imgEmpty(&img);
192 return(4);
193 }
194 maxv=f;
195 if(verbose>0) {
196 printf(" max_pixel := %d,%d,%d,%d\n", pos.x, pos.y, pos.z, pos.f);
197 printf(" max_smoothed_value := %g\n", maxv);
198 }
199 } else {
200 /* maximum value is needed anyway */
201 float f;
202 if(verbose>1) fprintf(stdout, " searching for image max value\n");
203 ret=imgSmoothMax(&img, &f, NULL);
204 if(ret!=0) {
205 fprintf(stderr, "Error: cannot determine maximum in image.\n");
206 imgEmpty(&img);
207 return(4);
208 }
209 maxv=f;
210 if(verbose>0) {printf(" max_smoothed_value := %g\n", maxv);}
211 }
212
213
214 /*
215 * Make x profile file
216 */
217 double d;
218 DFT dft; dftInit(&dft);
219 /* Create DFT */
220 if(verbose>1) fprintf(stdout, "creating x profiles\n");
221 ret=dftSetmem(&dft, img.dimx, img.dimt); /* frames as columns */
222 if(ret) {
223 fprintf(stderr, "Error: cannot allocate memory.\n");
224 imgEmpty(&img);
225 return(5);
226 }
227 /* Set DFT contents */
229 dft.frameNr=img.dimx; dft.voiNr=img.dimt;
230 /* set studynumber */
231 if(strlen(img.studyNr)>0) strcpy(dft.studynr, img.studyNr);
232 else studynr_from_fname(imgfile, dft.studynr);
233 strcpy(dft.unit, imgUnit(img.unit)); /* Set calibration unit */
234 /* set profile x values */
235 dft.timetype=DFT_TIME_MIDDLE; dft.timeunit=TUNIT_MM;
236 if(img.sizex<1.0E-10) img.sizex=1.0;
237 d=-(0.5*((double)img.dimx-1.0));
238 for(int fi=0; fi<img.dimx; fi++) {
239 dft.x[fi]=d*img.sizex; d+=1.0;
240 }
241 if(focus) {
242 double c=(((double)pos.x-1.0) - 0.5*((double)img.dimx-1.0)) * img.sizex;
243 if(verbose>2) printf("pos.x=%d cx=%g\n", pos.x, c);
244 for(int fi=0; fi<img.dimx; fi++) dft.x[fi]-=c;
245 }
246 /* set "voi" titles */
247 if(dft.voiNr>1) {
248 for(int ri=0; ri<dft.voiNr; ri++) {
249 char buf[128];
250 sprintf(buf, "Fr%04d", ri+1); strlcpy(dft.voi[ri].voiname, buf, MAX_REGIONSUBNAME_LEN);
251 snprintf(buf, 128, "%g", img.mid[ri]); buf[6]=(char)0;
252 snprintf(dft.voi[ri].hemisphere, MAX_REGIONSUBNAME_LEN+1, "%.6s", buf);
253 sprintf(buf, "Pl%04d", pos.z); strlcpy(dft.voi[ri].place, buf, MAX_REGIONSUBNAME_LEN);
254 sprintf(dft.voi[ri].name, "%s %s %s",
255 dft.voi[ri].voiname, dft.voi[ri].hemisphere, dft.voi[ri].place);
256 }
257 } else {
258 sprintf(dft.voi[0].voiname, "x%04d", pos.x);
259 sprintf(dft.voi[0].hemisphere, "y%04d", pos.y);
260 sprintf(dft.voi[0].place, "z%04d", pos.z);
261 sprintf(dft.voi[0].name, "%s %s %s",
262 dft.voi[0].voiname, dft.voi[0].hemisphere, dft.voi[0].place);
263 }
264 /* copy x profile */
265 for(int xi=0; xi<img.dimx; xi++)
266 for(int fi=0; fi<img.dimt; fi++)
267 dft.voi[fi].y[xi]=img.m[pos.z-1][pos.y-1][xi][fi];
268 /* Save DFT */
269 ret=dftWrite(&dft, prxfile);
270 if(ret) {
271 fprintf(stderr, "Error in writing '%s': %s\n", prxfile, dfterrmsg);
272 imgEmpty(&img); dftEmpty(&dft);
273 return(11);
274 }
275 if(verbose>0) fprintf(stdout, "x profile(s) written in %s\n", prxfile);
276 dftEmpty(&dft);
277
278
279 /*
280 * Make y profile file
281 */
282 /* Create DFT */
283 if(verbose>1) fprintf(stdout, "creating y profiles\n");
284 ret=dftSetmem(&dft, img.dimy, img.dimt); /* frames as columns */
285 if(ret) {
286 fprintf(stderr, "Error: cannot allocate memory.\n");
287 imgEmpty(&img);
288 return(5);
289 }
290 /* Set DFT contents */
292 dft.frameNr=img.dimy; dft.voiNr=img.dimt;
293 /* set studynumber */
294 if(strlen(img.studyNr)>0) strcpy(dft.studynr, img.studyNr);
295 else studynr_from_fname(imgfile, dft.studynr);
296 strcpy(dft.unit, imgUnit(img.unit)); /* Set calibration unit */
297 /* set profile x values */
298 dft.timetype=DFT_TIME_MIDDLE; dft.timeunit=TUNIT_MM;
299 if(img.sizey<1.0E-10) img.sizey=1.0;
300 d=-(0.5*((double)img.dimy-1.0));
301 for(int fi=0; fi<img.dimy; fi++) {
302 dft.x[fi]=d*img.sizey; d+=1.0;
303 }
304 if(focus) {
305 double c=(((double)pos.y-1.0) - 0.5*((double)img.dimx-1.0)) * img.sizex;
306 if(verbose>2) printf("pos.y=%d cy=%g\n", pos.y, c);
307 for(int fi=0; fi<img.dimy; fi++) dft.x[fi]-=c;
308 }
309 /* set "voi" titles */
310 if(dft.voiNr>1) {
311 for(int ri=0; ri<dft.voiNr; ri++) {
312 char buf[128]; sprintf(buf, "Fr%04d", ri+1); strlcpy(dft.voi[ri].voiname, buf, MAX_REGIONSUBNAME_LEN);
313 snprintf(buf, 128, "%g", img.mid[ri]); buf[6]=(char)0;
314 snprintf(dft.voi[ri].hemisphere, MAX_REGIONSUBNAME_LEN+1, "%.6s", buf);
315 sprintf(buf, "Pl%04d", pos.z); strlcpy(dft.voi[ri].place, buf, MAX_REGIONSUBNAME_LEN);
316 sprintf(dft.voi[ri].name, "%s %s %s",
317 dft.voi[ri].voiname, dft.voi[ri].hemisphere, dft.voi[ri].place);
318 }
319 } else {
320 sprintf(dft.voi[0].voiname, "x%04d", pos.x);
321 sprintf(dft.voi[0].hemisphere, "y%04d", pos.y);
322 sprintf(dft.voi[0].place, "z%04d", pos.z);
323 sprintf(dft.voi[0].name, "%s %s %s",
324 dft.voi[0].voiname, dft.voi[0].hemisphere, dft.voi[0].place);
325 }
326 /* copy y profile */
327 for(int yi=0; yi<img.dimy; yi++)
328 for(int fi=0; fi<img.dimt; fi++)
329 dft.voi[fi].y[yi]=img.m[pos.z-1][yi][pos.x-1][fi];
330 /* Save DFT */
331 ret=dftWrite(&dft, pryfile);
332 if(ret) {
333 fprintf(stderr, "Error in writing '%s': %s\n", pryfile, dfterrmsg);
334 imgEmpty(&img); dftEmpty(&dft);
335 return(12);
336 }
337 if(verbose>0)
338 fprintf(stdout, "y profile(s) written in %s\n", pryfile);
339 dftEmpty(&dft);
340
341
342 /*
343 * Make z profile file if necessary
344 */
345 if(przfile[0] && img.dimz>2) {
346 /* Create DFT */
347 if(verbose>1) fprintf(stdout, "creating z profiles\n");
348 ret=dftSetmem(&dft, img.dimz, img.dimt); /* frames as columns */
349 if(ret) {
350 fprintf(stderr, "Error: cannot allocate memory.\n");
351 imgEmpty(&img);
352 return(5);
353 }
354 /* Set DFT contents */
356 dft.frameNr=img.dimz; dft.voiNr=img.dimt;
357 /* set studynumber */
358 if(strlen(img.studyNr)>0) strcpy(dft.studynr, img.studyNr);
359 else studynr_from_fname(imgfile, dft.studynr);
360 strcpy(dft.unit, imgUnit(img.unit)); /* Set calibration unit */
361 /* set profile x values */
362 dft.timetype=DFT_TIME_MIDDLE; dft.timeunit=TUNIT_MM;
363 if(img.sizez<1.0E-10) img.sizez=1.0;
364 d=-(0.5*((double)img.dimz-1.0));
365 for(int fi=0; fi<img.dimz; fi++) {
366 dft.x[fi]=d*img.sizez; d+=1.0;
367 }
368 if(focus) {
369 double c=(((double)pos.z-1.0) - 0.5*((double)img.dimz-1.0)) * img.sizez;
370 if(verbose>2) printf("pos.z=%d cy=%g\n", pos.z, c);
371 for(int fi=0; fi<img.dimz; fi++) dft.x[fi]-=c;
372 }
373 /* set "voi" titles */
374 if(dft.voiNr>1) {
375 for(int ri=0; ri<dft.voiNr; ri++) {
376 char buf[128]; sprintf(buf, "Fr%04d", ri+1); strlcpy(dft.voi[ri].voiname, buf, MAX_REGIONSUBNAME_LEN);
377 snprintf(buf, 128, "%g", img.mid[ri]); buf[6]=(char)0;
378 snprintf(dft.voi[ri].hemisphere, MAX_REGIONSUBNAME_LEN+1, "%.6s", buf);
379 sprintf(buf, "Pl%04d", pos.z); strlcpy(dft.voi[ri].place, buf, MAX_REGIONSUBNAME_LEN);
380 sprintf(dft.voi[ri].name, "%s %s %s",
381 dft.voi[ri].voiname, dft.voi[ri].hemisphere, dft.voi[ri].place);
382 }
383 } else {
384 sprintf(dft.voi[0].voiname, "x%04d", pos.x);
385 sprintf(dft.voi[0].hemisphere, "y%04d", pos.y);
386 sprintf(dft.voi[0].place, "z%04d", pos.z);
387 sprintf(dft.voi[0].name, "%s %s %s",
388 dft.voi[0].voiname, dft.voi[0].hemisphere, dft.voi[0].place);
389 }
390 /* copy z profile */
391 for(int zi=0; zi<img.dimz; zi++)
392 for(int fi=0; fi<img.dimt; fi++)
393 dft.voi[fi].y[zi]=img.m[zi][pos.y-1][pos.x-1][fi];
394 /* Save DFT */
395 ret=dftWrite(&dft, przfile);
396 if(ret) {
397 fprintf(stderr, "Error in writing '%s': %s\n", przfile, dfterrmsg);
398 imgEmpty(&img); dftEmpty(&dft);
399 return(13);
400 }
401 if(verbose>0)
402 fprintf(stdout, "z profile(s) written in %s\n", przfile);
403 dftEmpty(&dft);
404 }
405
406 /*
407 * Create and save TIFF image if necessary.
408 * Do this as the last step since this messes with the image data.
409 */
410 if(tiffile[0]) {
411 if(verbose>1) fprintf(stdout, "creating TIFF image(s)\n");
412 char tmp[FILENAME_MAX+16], extension[FILENAME_MAX];
413 int fi, xj, yj;
414 float f;
415 for(fi=0; fi<img.dimt; fi++) { /* One frame at a time */
416 /* Add frame nr to filename, if necessary */
417 if(img.dimt>1) {
418 if(fi==0) {
419 strcpy(tmp, tiffile); cptr=strrchr(tmp, '.');
420 if(cptr!=NULL) {strcpy(extension, cptr); *cptr=(char)0;}
421 else {strcpy(extension, ".tif");}
422 }
423 snprintf(tiffile, FILENAME_MAX, "%s_f%d%s", tmp, fi+1, extension);
424 }
425 /* 'Invert' image values on profile lines */
426 for(xj=0; xj<img.dimx; xj++) {
427 if(img.m[pos.z-1][pos.y-1][xj][fi]>0.5*maxv)
428 img.m[pos.z-1][pos.y-1][xj][fi]=0.0;
429 else
430 img.m[pos.z-1][pos.y-1][xj][fi]=maxv;
431 }
432 for(yj=0; yj<img.dimy; yj++) {
433 if(img.m[pos.z-1][yj][pos.x-1][fi]>0.5*maxv)
434 img.m[pos.z-1][yj][pos.x-1][fi]=0.0;
435 else
436 img.m[pos.z-1][yj][pos.x-1][fi]=maxv;
437 }
438 f=-1.0;
439 ret=tiffWriteImg(&img, pos.z-1, fi, &f, PET_RAINBOW, tiffile,
440 0, 0, verbose-5, NULL);
441 if(ret) fprintf(stderr, "Warning: cannot write %s (%d)\n", tiffile, ret);
442 else if(verbose>0) fprintf(stdout, " %s written.\n", tiffile);
443
444 } /* next frame */
445 }
446
447 imgEmpty(&img);
448
449 return(0);
450}
451/*****************************************************************************/
452
453/*****************************************************************************/
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
unsigned long long imgNaNs(IMG *img, int fix)
Definition img.c:658
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 imgSmoothMax(IMG *img, float *maxvalue, IMG_PIXEL *p)
Definition imgminmax.c:248
int tiffWriteImg(IMG *img, int plane, int frame, float *maxvalue, int colorscale, char *fname, int matXdim, int matYdim, int verbose, char *status)
Definition imgtiff.c:15
char * imgUnit(int dunit)
Definition imgunits.c:315
Header file for libtpccurveio.
#define DFT_TIME_MIDDLE
#define DFT_FORMAT_STANDARD
Header file for libtpcimgio.
int string_to_xyz(char *str, int *x, int *y, int *z)
Definition vol.c:653
void pxlFree(IMG_PIXELS *pxl)
Definition pixel.c:28
int pxlRead(IMG_PIXELS *pxl, const char *fname, char *status)
Definition pixel.c:331
void pxlInit(IMG_PIXELS *pxl)
Definition pixel.c:14
Header file for libtpcimgp.
#define PET_RAINBOW
Definition libtpcimgp.h:36
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
int studynr_from_fname(char *fname, char *studynr)
Definition studynr.c:119
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:383
#define MAX_REGIONSUBNAME_LEN
Definition libtpcmisc.h:158
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:158
int _type
int timetype
Voi * voi
int timeunit
char studynr[MAX_STUDYNR_LEN+1]
int voiNr
int frameNr
double * x
char unit[MAX_UNITS_LEN+1]
IMG_PIXEL * p
long long int pxlNr
float sizex
unsigned short int dimx
float **** m
char unit
unsigned short int dimt
float sizey
unsigned short int dimz
unsigned short int dimy
const char * statmsg
char studyNr[MAX_STUDYNR_LEN+1]
float * mid
float sizez
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char name[MAX_REGIONNAME_LEN+1]
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char place[MAX_REGIONSUBNAME_LEN+1]