TPCCLIB
Loading...
Searching...
No Matches
ecatmrp.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 <ctype.h>
18#include <dirent.h>
19#include <sys/stat.h>
20#include <sys/file.h>
21#include <time.h>
22/*****************************************************************************/
23#include "libtpcmisc.h"
24#include "libtpcimgio.h"
25#include "libtpcrec.h"
26/*****************************************************************************/
27
28/*****************************************************************************/
29static char *info[] = {
30 "Reconstruct PET image from attenuation and normalization corrected",
31 "2D PET sinogram using median root prior (MRP) [1,2,3].",
32 "This program does not correct image data for decay.",
33 "Image is corrected for the dead-time based on factors in the sinogram.",
34 "Image data is written in units ECAT counts per pixel per second.",
35 " ",
36 "Not for clinical use! Program is not thoroughly tested!",
37 " ",
38 "Usage: @P [Options] scnfile imgfile",
39 " ",
40 "Options:",
41 " -zoom=<value>",
42 " Set zoom factor; by default 1.0 (no zoom).",
43 " -dim=<value>",
44 " Set image x and y dimensions; by default 128.",
45 " -rot[ation]=<value>",
46 " Set image rotation in degrees, -180 - 180; by default 0 (no rotation).",
47 " -x=<value>",
48 " Set image shift in x direction (in cm); by default 0.",
49 " -y=<value>",
50 " Set image shift in y direction (in cm); by default 0.",
51 " -perv",
52 " Divide image voxel values by voxel volume (mL); by default the voxel",
53 " volume is corrected later during image calibration.",
54 " -beta=<value>",
55 " Set beta value, usually 0.1 - 0.9; by default 0.3.",
56 " -mask=<3|5>",
57 " Set mask dimension for median filter, either 3 (3x3) or 5 (5x5 without",
58 " corener pixels); by default 3.",
59 " -iter=<value>",
60 " Set maximum number of iterations; by default 150.",
61 " -skip=<value>",
62 " Set the number of iterations without prior; by default 1.",
63 " -os=<1|2|4|8|16>",
64 " Set the number of OS sets (acceleration); by default 1.",
65 " -stdoptions", // List standard options like --help, -v, etc
66 " ",
67 "Example:",
68 " @P -dim=256 a2345dy1.scn a2345dy1.img",
69 " ",
70 "References:",
71 "1. Alenius S, Ruotsalainen U. Bayesian image reconstruction for emission",
72 " tomography based on median root prior.",
73 " Eur J Nucl Med. 1997;24(3): 258-265.",
74 "2. Alenius S, Ruotsalainen U. Generalization of median root prior",
75 " reconstruction. IEEE Trans Med Imaging 2002; 21(11): 1413-1420.",
76 "3. Katoh C, Ruotsalainen U, Laine H, Alenius S, Iida H, Nuutila P, Knuuti J.",
77 " Iterative reconstruction based on median root prior in quantification of",
78 " myocardial blood flow and oxygen metabolism.",
79 " J Nucl Med. 1999;40(5):862-867.",
80 " ",
81 "See also: ecatnorm, edecay, ecalibr, atnmake, eframe, ecatfbp, img2scn",
82 " ",
83 "Keywords: ECAT, sinogram, image, reconstruction, MRP",
84 0};
85/*****************************************************************************/
86
87/*****************************************************************************/
88/* Turn on the globbing of the command line, since it is disabled by default in
89 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
90 In Unix&Linux wildcard command line processing is enabled by default. */
91/*
92#undef _CRT_glob
93#define _CRT_glob -1
94*/
95int _dowildcard = -1;
96/*****************************************************************************/
97
98/*****************************************************************************/
102int main(int argc, char **argv)
103{
104 int ai, help=0, version=0, verbose=1;
105 char scnfile[FILENAME_MAX], imgfile[FILENAME_MAX];
106 int maxIterNr=150;
107 int skipPriorNr=1;
108 float beta=0.3;
109 float rotate=0.0;
110 float zoom=1.0;
111 float shiftX=0.0, shiftY=0.0;
112 int pervol=0;
113 int imgDim=128;
114 int maskDim=3;
115 int osSetNr=1;
116 char *cptr;
117 int ret;
118
119
120 /*
121 * Get arguments
122 */
123 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
124 scnfile[0]=imgfile[0]=(char)0;
125 /* Options */
126 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* options */
127 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
128 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
129 if(strncasecmp(cptr, "ITER=", 5)==0) {
130 maxIterNr=atoi(cptr+5); if(maxIterNr>1) continue;
131 } else if(strncasecmp(cptr, "SKIP=", 5)==0) {
132 skipPriorNr=atoi(cptr+5); if(skipPriorNr>0) continue;
133 } else if(strncasecmp(cptr, "OS=", 3)==0) {
134 osSetNr=atoi(cptr+3);
135 if(osSetNr==0 || osSetNr==1 || osSetNr==2) continue;
136 if(osSetNr==4 || osSetNr==8 || osSetNr==16) continue;
137 if(osSetNr==32 || osSetNr==64 || osSetNr==128) continue;
138 } else if(strncasecmp(cptr, "DIM=", 4)==0) {
139 imgDim=atoi(cptr+4); if(imgDim>1 && imgDim<=2048) continue;
140 } else if(strncasecmp(cptr, "MASK=", 5)==0) {
141 maskDim=atoi(cptr+5); if(maskDim==3 || maskDim==5) continue;
142 } else if(strncasecmp(cptr, "ZOOM=", 5)==0) {
143 zoom=atof_dpi(cptr+5); if(zoom>0.1 && zoom<100.0) continue;
144 } else if(strncasecmp(cptr, "BETA=", 5)==0) {
145 beta=atof_dpi(cptr+5); if(beta>0.05 && beta<100.0) continue;
146 } else if(strncasecmp(cptr, "ROTATION=", 9)==0) {
147 double v;
148 ret=atof_with_check(cptr+9, &v);
149 if(v>=-180.0 && v<=180.0) {rotate=v; continue;}
150 } else if(strncasecmp(cptr, "ROT=", 4)==0) {
151 double v;
152 ret=atof_with_check(cptr+4, &v);
153 if(v>-360.0 && v<360.0) {rotate=v; continue;}
154 } else if(strncasecmp(cptr, "X=", 2)==0) {
155 double v;
156 ret=atof_with_check(cptr+2, &v);
157 if(v>-50.0 && v<50.0) {shiftX=10.0*v; continue;}
158 } else if(strncasecmp(cptr, "Y=", 2)==0) {
159 double v;
160 ret=atof_with_check(cptr+2, &v);
161 if(v>-50.0 && v<50.0) {shiftY=10.0*v; continue;}
162 }
163 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
164 return(1);
165 } else break;
166
167 /* Print help or version? */
168 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
169 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
170 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
171
172 /* Process other arguments, starting from the first non-option */
173 if(ai<argc) {strlcpy(scnfile, argv[ai++], FILENAME_MAX);}
174 if(ai<argc) {strlcpy(imgfile, argv[ai++], FILENAME_MAX);}
175 if(ai<argc) {
176 fprintf(stderr, "Error: too many arguments.\n");
177 return(1);
178 }
179
180 /* Is something missing? */
181 if(!imgfile[0]) {
182 fprintf(stderr, "Error: missing command-line argument; use --help\n");
183 return(1);
184 }
185
186 /* In verbose mode print arguments and options */
187 if(verbose>1) {
188 printf("scnfile := %s\n", scnfile);
189 printf("imgfile := %s\n", imgfile);
190 printf("Beta := %g\n", beta);
191 printf("Zoom := %g\n", zoom);
192 printf("Dimension := %d\n", imgDim);
193 printf("Mask := %d\n", maskDim);
194 printf("Rotation := %g\n", rotate);
195 printf("X_shift_mm := %g\n", shiftX);
196 printf("Y_shift_mm := %g\n", shiftY);
197 printf("volume_correction := %d\n", pervol);
198 printf("maxIterNr := %d\n", maxIterNr);
199 printf("skipPriorNr := %d\n", skipPriorNr);
200 printf("osSetNr := %d\n", osSetNr);
201 }
202
203 /* Check that input and output files do not have the same filename */
204 if(strcasecmp(imgfile, scnfile)==0) {
205 fprintf(stderr, "Error: original sinogram must not be overwritten.\n");
206 return(1);
207 }
208 /* Check that image dimension is even */
209 if(imgDim%2) {
210 fprintf(stderr, "Error: invalid image dimension.\n");
211 return(1);
212 }
213
214
215 /*
216 * Read sinogram
217 */
218 if(verbose>0) printf("reading sinogram %s\n", scnfile);
219 IMG scn; imgInit(&scn);
220 ret=imgRead(scnfile, &scn);
221 if(ret) {
222 fprintf(stderr, "Error: %s\n", scn.statmsg);
223 if(verbose>1) printf("ret := %d\n", ret);
224 return(2);
225 }
226 if(verbose>1) {
227 printf("dimx := %d\n", scn.dimx);
228 printf("dimy := %d\n", scn.dimy);
229 printf("dimz := %d\n", scn.dimz);
230 printf("dimt := %d\n", scn.dimt);
231 }
232 /* Check that we have a sinogram */
233 if(scn.type!=IMG_TYPE_RAW) {
234 fprintf(stderr, "Error: file is not a sinogram.\n");
235 imgEmpty(&scn);
236 return(2);
237 }
238
239 /*
240 * Reconstruction
241 */
242 IMG img; imgInit(&img);
243 if(verbose>0) printf("MRP reconstruction... (may take a long time)\n");
244 ret=imgMRP(&scn, &img, imgDim, zoom, shiftX, shiftY, rotate,
245 maxIterNr, skipPriorNr, beta, maskDim, osSetNr,
246 verbose);
247 if(ret) {
248 fprintf(stderr, "Error in reconstruction.\n");
249 if(verbose>1) printf("ret := %d\n", ret);
250 imgEmpty(&scn);
251 return(3);
252 }
253 /* Set header info in the output data */
254 img.zoom=zoom;
255
256 /* Pixel volume correction, if required */
257 if(pervol) {
258 if(verbose>0) printf("correcting for voxel volume\n");
259 float vol=0.001*img.sizex*img.sizey*img.sizez;
260 if(vol>0.0) {
261 int zi, yi, xi, ti;
262 for(zi=0; zi<img.dimz; zi++)
263 for(yi=0; yi<img.dimy; yi++)
264 for(xi=0; xi<img.dimx; xi++)
265 for(ti=0; ti<img.dimt; ti++)
266 img.m[zi][yi][xi][ti]/=vol;
267 } else {
268 fprintf(stderr, "Warning: cannot correct for pixel volume.\n");
269 }
270 }
271
272
273 /*
274 * Save the image */
275 if(verbose>0) printf("writing image %s\n", imgfile);
276 if(imgWrite(imgfile, &img)) {
277 fprintf(stderr, "Error: %s\n", img.statmsg);
278 imgEmpty(&img); imgEmpty(&scn);
279 return(11);
280 }
281
282 imgEmpty(&img); imgEmpty(&scn);
283 if(verbose>0) fprintf(stdout, "done.\n");
284
285 return(0);
286}
287/*****************************************************************************/
288
289/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
double atof_dpi(char *str)
Definition decpoint.c:59
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
Header file for libtpcimgio.
#define IMG_TYPE_RAW
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 libtpcrec.
int imgMRP(IMG *scn, IMG *img, int imgDim, float zoom, float shiftX, float shiftY, float rotation, int maxIterNr, int skipPriorNr, float beta, int maskDim, int osSetNr, int verbose)
Definition mrp.c:21
float sizex
unsigned short int dimx
char type
float **** m
unsigned short int dimt
float sizey
unsigned short int dimz
unsigned short int dimy
float zoom
const char * statmsg
float sizez