TPCCLIB
Loading...
Searching...
No Matches
pxl2tac.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 "libtpccurveio.h"
21#include "libtpcimgp.h"
22#include "libtpcmodext.h"
23/*****************************************************************************/
24
25/*****************************************************************************/
26static char *info[] = {
27 "Extract the TACs of specified pixel(s) in PET image.",
28 "Pixels can be specified as mask images, volume range definition files, or",
29 "as file containing list of pixel coordinates.",
30 " ",
31 "Usage: @P [Options] imgfile tacfile pixel(s)",
32 " ",
33 "Options:",
34 " -positives",
35 " Only those pixel TACs which have values over zero are extracted.",
36 " -stdoptions", // List standard options like --help, -v, etc
37 " ",
38 "Volume range definition (vrd) file is an ASCII text file, which contains",
39 "pixel coordinates (x y z; 1..dimension) of the two opposite corners of",
40 "the extracted image volume, for example:",
41 " corner1 := 63 57 26",
42 " corner2 := 84 71 44",
43 "One or more pixel coordinates (x y z; 1..dimension) can be listed in file,",
44 "for example:",
45 " 24,52,13",
46 " 25,52,14",
47 " ",
48 "See also: imgthrs, mask2pxl, imgbox, imgmask, imghead, img2dft, imgmaxp",
49 " ",
50 "Keywords: image, pixel, TAC, software testing",
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 int ret, fileNr=0, firstfile=0;
73 char petfile[FILENAME_MAX], tacfile[FILENAME_MAX];
74 char *cptr, tmp[128], pxlfile[FILENAME_MAX];
75 int positives=0; // 0=extract all, 1=extract only pixels with value >0
76 IMG img;
77
78
79 /*
80 * Get arguments
81 */
82 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
83 petfile[0]=tacfile[0]=pxlfile[0]=(char)0;
84 /* Options */
85 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* options */
86 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
87 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
88 if(strncasecmp(cptr, "POSITIVES", 3)==0) {
89 positives=1; continue;
90 }
91 /* We should not be here */
92 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
93 return(1);
94 } else break;
95
96 /* Print help or version? */
97 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
98 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
99 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
100
101 /* Process other arguments, starting from the first non-option */
102 if(ai<argc) {strlcpy(petfile, argv[ai], FILENAME_MAX); ai++;}
103 if(ai<argc) {strlcpy(tacfile, argv[ai], FILENAME_MAX); ai++;}
104 for(; ai<argc; ai++) { // pixel def file(s)
105 if(firstfile==0) firstfile=ai;
106 fileNr++;
107 }
108
109 /* Is something missing or wrong? */
110 if(!tacfile[0] || fileNr<1) {
111 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
112 return(1);
113 }
114
115 /* In verbose mode print arguments and options */
116 if(verbose>1) {
117 printf("petfile := %s\n", petfile);
118 printf("tacfile := %s\n", tacfile);
119 printf("fileNr := %d\n", fileNr);
120 printf("positives := %d\n", positives);
121 fflush(stdout);
122 }
123
124
125 /*
126 * Read the contents of the PET file to img data structure
127 */
128 imgInit(&img);
129 if(verbose>0) printf("reading %s\n", petfile);
130 ret=imgRead(petfile, &img);
131 if(ret) {
132 fprintf(stderr, "Error: %s\n", img.statmsg);
133 if(verbose>1) printf("ret=%d\n", ret);
134 imgEmpty(&img); return(2);
135 }
136 if(verbose>0) {
137 printf("pet_dimx := %d\n", img.dimx);
138 printf("pet_dimy := %d\n", img.dimy);
139 printf("pet_dimz := %d\n", img.dimz);
140 printf("pet_dimt := %d\n", img.dimt);
141 }
142 /* Correct sinogram data for decay */
143 if(img.type==IMG_TYPE_RAW) {
144 if(verbose>0) fprintf(stdout, "correcting sinogram data for decay\n");
145 ret=imgDecayCorrection(&img, 1);
146 if(ret) {
147 fprintf(stderr, "Error %d: cannot decay correct dynamic sinogram.\n", ret);
148 if(ret==1) fprintf(stderr, " Sinogram contains no isotope.\n");
149 if(ret==2) fprintf(stderr, " Sinogram is already decay corrected.\n");
150 imgEmpty(&img);
151 return(2);
152 }
153 }
154 /* Correct sinogram data for frame lengths */
155 if(img.type==IMG_TYPE_RAW) {
156 if(verbose>0) fprintf(stdout, "correcting sinogram data for frame lengths\n");
157 ret=imgRawCountsPerTime(&img, 1);
158 if(ret) {
159 fprintf(stderr, "Error: cannot correct sinogram counts.\n");
160 if(verbose>1) printf("ret=%d\n", ret);
161 imgEmpty(&img); return(2);
162 }
163 }
164
165
166
167 /*
168 * Read pixel definitions
169 */
170 if(verbose==1) printf("reading pixel positions\n");
171 IMG_PIXELS pxl;
172 pxlInit(&pxl);
173 for(ai=firstfile; ai<argc; ai++) {
174 strlcpy(pxlfile, argv[ai], FILENAME_MAX);
175 if(verbose>1) printf("reading %s\n", pxlfile);
176 /* First, try to read file as pixel list */
177 if((ret=pxlRead(&pxl, pxlfile, tmp))==0) {
178 continue;
179 } else if(verbose>1) {
180 printf("could not read as pixel list: %s\n", tmp);
181 if(verbose>2) printf("ret := %d\n", ret);
182 }
183 /* Then try to read as Read Volume Range Definition File */
184 VOL_RANGE vol_range={0,0,0,0,0,0};
185 IMG_PIXEL p={0,0,0,0};
186 if((ret=vrdRead(pxlfile, &vol_range, tmp))==0) {
187 vrdReorder(&vol_range);
188 if(verbose>1) {
189 printf("vol_range.x := %d - %d\n", vol_range.x1, vol_range.x2);
190 printf("vol_range.y := %d - %d\n", vol_range.y1, vol_range.y2);
191 printf("vol_range.z := %d - %d\n", vol_range.z1, vol_range.z2);
192 }
193 /* Add range pixels to the list */
194 long long n=vrdVxlNr(&vol_range);
195 if(n<1) {
196 fprintf(stderr, "Warning: no pixels defined in %s\n", pxlfile);
197 } else {
198 if(pxlAllocateMore(&pxl, n)!=0) {
199 fprintf(stderr, "Error: out of memory.\n");
200 imgEmpty(&img); pxlFree(&pxl); return(3);
201 }
202 for(p.z=vol_range.z1; p.z<=vol_range.z2; p.z++)
203 for(p.x=vol_range.x1; p.x<=vol_range.x2; p.x++)
204 for(p.y=vol_range.y1; p.y<=vol_range.y2; p.y++)
205 pxlAdd(&pxl, &p);
206 }
207 continue;
208 } else if(verbose>1) {
209 printf("could not read as vrd file: %s\n", tmp);
210 if(verbose>2) printf("ret := %d\n", ret);
211 }
212 /* Then try to read as mask image */
213 if(verbose>1) printf("reading mask image %s\n", pxlfile);
214 IMG mask; imgInit(&mask);
215 ret=imgRead(pxlfile, &mask);
216 if(ret) {
217 fprintf(stderr, "Error: %s\n", mask.statmsg);
218 if(verbose>1) printf("ret := %d\n", ret);
219 imgEmpty(&img); return(4);
220 }
221 /* Check that dimensions are compatible */
222 if(img.dimx!=mask.dimx || img.dimy!=mask.dimy || img.dimz!=mask.dimz) {
223 fprintf(stderr, "Error: different image dimensions.\n");
224 if(verbose>0) {
225 printf("image := %d x %d x %d\n", img.dimx, img.dimy, img.dimz);
226 printf("mask := %d x %d x %d\n", mask.dimx, mask.dimy, mask.dimz);
227 }
228 imgEmpty(&img); imgEmpty(&mask); return(4);
229 }
230 if(pxlAddFromMask(&pxl, &mask)<1) {
231 fprintf(stderr, "Warning: no pixels defined in mask %s\n", pxlfile);
232 }
233 imgEmpty(&mask);
234 continue;
235 } // next pixel list, vrd, or mask file
236 if(pxl.pxlNr<1) {
237 fprintf(stderr, "Error: no pixels to extract.\n");
238 imgEmpty(&img); pxlFree(&pxl); return(4);
239 }
240 if(verbose>6) {
241 printf("list of pixels to extract:\n");
242 pxlWrite(&pxl, stdout, NULL);
243 }
244 /* Remove any duplicates */
245 ret=pxlRmDuplicates(&pxl);
246 if(ret>0 && verbose>0) {
247 printf("%d pixel duplicates removed.\n", ret);
248 }
249 if(verbose>1) {
250 printf("list of pixels to extract:\n");
251 pxlWrite(&pxl, stdout, NULL);
252 }
253
254 /* Check that pixels are inside image dimensions */
255 ret=0;
256 for(long long int i=0; i<pxl.pxlNr; i++) {
257 if(pxl.p[i].z<1 || pxl.p[i].z>img.dimz) {
258 fprintf(stderr, "Error: pixel outside image z dimension.\n");
259 ret++;
260 }
261 if(pxl.p[i].x<1 || pxl.p[i].x>img.dimx) {
262 fprintf(stderr, "Error: pixel outside image x dimension.\n");
263 ret++;
264 }
265 if(pxl.p[i].y<1 || pxl.p[i].y>img.dimy) {
266 fprintf(stderr, "Error: pixel outside image x dimension.\n");
267 ret++;
268 }
269 }
270 if(ret!=0) {
271 imgEmpty(&img); pxlFree(&pxl); return(4);
272 }
273
274
275 /*
276 * Prepare TAC data
277 */
278 if(verbose>0) printf("reading %llu pixel TACs.\n", pxl.pxlNr);
279 DFT dft; dftInit(&dft);
280 /* Allocate memory for TAC */
281 ret=dftAllocateWithIMG(&dft, pxl.pxlNr, &img);
282 if(ret) {
283 fprintf(stderr, "Error: cannot allocate memory for TACs.\n");
284 imgEmpty(&img); pxlFree(&pxl);
285 return(5);
286 }
287 if(verbose>13) {
288 fflush(stdout);
289 printf(" _voidataNr := %d\n", dft._voidataNr);
290 printf(" _dataSize := %d\n", dft._dataSize);
291 printf(" voiNr := %d\n", dft.voiNr);
292 printf(" frameNr := %d\n", dft.frameNr);
293 fflush(stdout);
294 }
295 /* Set DFT information */
296 /* File format based on filename */
297 {
298 char *p; p=strrchr(tacfile, '.');
299 if(strcasecmp(p, ".dft")==0) dft._type=DFT_FORMAT_STANDARD;
300 else if(strcasecmp(p, ".tac")==0) dft._type=DFT_FORMAT_PMOD;
301 else if(strcasecmp(p, ".bld")==0) dft._type=DFT_FORMAT_PMOD;
302 else if(strcasecmp(p, ".csv")==0) dft._type=DFT_FORMAT_CSV_UK;
303 else dft._type=DFT_FORMAT_PMOD;
304 }
305 /* Set studynumber */
306 if(strlen(dft.studynr)==0) studynr_from_fname2(petfile, dft.studynr, 1);
307 if(verbose>1) printf("studynr := %s\n", dft.studynr);
308 /* Set scan start time */
310 /* Radiopharmaceutical and isotope */
313 if(verbose>10) printf(" isotope := %s\n", imgIsotope(&img));
314 strcpy(dft.isotope, imgIsotope(&img));
315
316 /* Fill data */
317 if(verbose>2) printf("filling TAC data\n");
318 int n=0; // TAC
319 for(long long i=0; i<pxl.pxlNr; i++) {
320 if(verbose>11) {printf(" tac %llu\n", 1+i); fflush(stdout);}
321 for(int j=0; j<img.dimt; j++) {
322 if(verbose>30) {
323 printf("j=%d n=%d z=%d y=%d x=%d\n", j, n,
324 pxl.p[i].z-1, pxl.p[i].y-1, pxl.p[i].x-1);
325 }
326 dft.voi[n].y[j]=img.m[pxl.p[i].z-1][pxl.p[i].y-1][pxl.p[i].x-1][j];
327 }
328 /* If required, check that TAC is >0 */
329 if(positives!=0) {
330 int j;
331 for(j=0; j<img.dimt; j++) if(dft.voi[n].y[j]>1.0E-08) break;
332 if(j==img.dimt) continue; // all were <= 0
333 }
334 /* Set "voi" titles */
335 if(verbose>20) {printf(" setting ROI name\n"); fflush(stdout);}
336 sprintf(dft.voi[n].voiname, "x%04d", pxl.p[i].x);
337 sprintf(dft.voi[n].hemisphere, "y%04d", pxl.p[i].y);
338 sprintf(dft.voi[n].place, "z%04d", pxl.p[i].z);
339 sprintf(dft.voi[n].name, "%s_%s_%s",
340 dft.voi[n].voiname, dft.voi[n].hemisphere, dft.voi[n].place);
341 if(verbose>10) printf(" %s\n", dft.voi[n].voiname);
342 dft.voi[n].size=img.sizex*img.sizey*img.sizez;
343 n++;
344 } /* next pixel */
345 dft.voiNr=n; dft.frameNr=img.dimt;
346 imgEmpty(&img); pxlFree(&pxl);
347 if(n<1) {
348 fprintf(stderr, "Error: no pixels extracted.\n");
349 dftEmpty(&dft); return(9);
350 }
351 /* Convert times to minutes */
352 dftSec2min(&dft);
353
354
355 /*
356 * Write the TACs
357 */
358 if(verbose>1) fprintf(stdout, "writing TACs in %s\n", tacfile);
359 if(verbose>3) printf("dft._type := %d\n", dft._type);
360 if(verbose>30) dftPrint(&dft);
361 if(dftWrite(&dft, tacfile)) {
362 fprintf(stderr, "Error in writing '%s': %s\n", tacfile, dfterrmsg);
363 dftEmpty(&dft); return(11);
364 }
365 if(verbose>0) fprintf(stdout, "Pixel TACs written in %s\n", tacfile);
366 dftEmpty(&dft);
367
368 return(0);
369}
370/*****************************************************************************/
371
372/*****************************************************************************/
char * ctime_r_int(const time_t *t, char *buf)
Convert calendard time t into a null-terminated string of the form YYYY-MM-DD hh:mm:ss,...
Definition datetime.c:110
void dftInit(DFT *data)
Definition dft.c:38
char dfterrmsg[64]
Definition dft.c:6
void dftEmpty(DFT *data)
Definition dft.c:20
void dftPrint(DFT *data)
Definition dftio.c:538
int dftWrite(DFT *data, char *filename)
Definition dftio.c:594
void dftSec2min(DFT *dft)
Definition dftunit.c:160
void imgEmpty(IMG *image)
Definition img.c:121
void imgInit(IMG *image)
Definition img.c:60
int imgRawCountsPerTime(IMG *img, int operation)
Definition imgarithm.c:442
char * imgIsotope(IMG *img)
Definition imgdecayc.c:76
int imgDecayCorrection(IMG *image, int mode)
Definition imgdecayc.c:16
int imgRead(const char *fname, IMG *img)
Definition imgfile.c:26
Header file for libtpccurveio.
#define DFT_FORMAT_PMOD
#define DFT_FORMAT_CSV_UK
#define DFT_FORMAT_STANDARD
Header file for libtpcimgio.
#define IMG_TYPE_RAW
void pxlFree(IMG_PIXELS *pxl)
Definition pixel.c:28
int vrdReorder(VOL_RANGE *vol_range)
Definition vol.c:607
int pxlAllocateMore(IMG_PIXELS *pxl, long long int pxlNr)
Definition pixel.c:74
int vrdVxlNr(VOL_RANGE *vol_range)
Definition vol.c:634
int pxlAdd(IMG_PIXELS *list, IMG_PIXEL *pxl)
Definition pixel.c:139
int pxlWrite(IMG_PIXELS *pxl, FILE *fp, char *status)
Definition pixel.c:299
int pxlRead(IMG_PIXELS *pxl, const char *fname, char *status)
Definition pixel.c:331
long long int pxlRmDuplicates(IMG_PIXELS *list)
Definition pixel.c:273
int vrdRead(char *vdffile, VOL_RANGE *vol_range, char *status)
Definition vol.c:742
void pxlInit(IMG_PIXELS *pxl)
Definition pixel.c:14
long long int pxlAddFromMask(IMG_PIXELS *list, IMG *img)
Definition pixel.c:185
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
int studynr_from_fname2(char *fname, char *studynr, int force)
Definition studynr.c:67
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 libtpcmodext.
int dftAllocateWithIMG(DFT *dft, int tacNr, IMG *img)
Definition misc_model.c:296
char scanStartTime[20]
char decayCorrected
int _type
Voi * voi
char studynr[MAX_STUDYNR_LEN+1]
int voiNr
int frameNr
char isotope[8]
char radiopharmaceutical[32]
IMG_PIXEL * p
long long int pxlNr
float sizex
unsigned short int dimx
char type
float **** m
char decayCorrection
time_t scanStart
unsigned short int dimt
float sizey
unsigned short int dimz
unsigned short int dimy
char radiopharmaceutical[32]
const char * statmsg
float sizez
double size
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]