TPCCLIB
Loading...
Searching...
No Matches
imgfiltg.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <math.h>
13#include <string.h>
14#include <unistd.h>
15#include <time.h>
16/*****************************************************************************/
17#include "libtpcmisc.h"
18#include "libtpcimgio.h"
19#include "libtpcimgp.h"
20#include "libtpcmodext.h"
21/*****************************************************************************/
22
23/*****************************************************************************/
24static char *info[] = {
25 "Applying Gaussian filter for a static or dynamic PET image in ECAT, NIfTI,",
26 "or Analyze format. Filtering can be applied to x,y,z-volume (3D) by",
27 "specifying the SDs of Gaussian filter for x,y- and z-dimensions, or only",
28 "to the x,y-planes by giving the SD only for x,y-dimensions.",
29 "SDs are assumed to be in pixels, if units are not given.",
30 "SD=FWHM/2.355.",
31 " ",
32 "Usage: @P [Options] imgfile outputfile SDxy [SDz]",
33 " ",
34 "Options:",
35 " -FWHM",
36 " FWHM value(s) are given instead of SDs.",
37 " -method=<<FIR>|<AM>>",
38 " Specify the Gaussian filtering method; default is the finite impulse",
39 " response method (FIR); Alvarez-Mazorra approximate Gaussian image",
40 " filtering method (AM) is less accurate but may be faster.",
41 " -tol=<tolerance>",
42 " Default tolerance can be changed with this option.",
43 " -steps=<nr>",
44 " More steps provides better accuracy but longer execution time;",
45 " default is 4. Applies only to AM method.",
46 " -xysize=<pixel size>",
47 " Set image pixel x,y size (mm), if missing or wrong in image data.",
48 " -zsize=<pixel size>",
49 " Set image pixel z size (mm), if missing or wrong in image data.",
50 " -stdoptions", // List standard options like --help, -v, etc
51 " ",
52 "Example #1: 3D filtering with Gaussian SDs given in mm",
53 " @P s5998dy1.v s5998dy1_filt.v 3.4mm 4.1mm",
54 " ",
55 "Example #2: 2D filtering with Gaussian SDs given in pixels",
56 " @P s5998dy1.v s5998dy1_filt.v 4pxl",
57 " ",
58 "Example #3: 3D filtering with FWHMs given in mm",
59 " @P -fwhm s5998dy1.v s5998dy1_filt.v 8mm 9.66mm",
60 " ",
61 "See also: imgdysmo, imgfsegm, imgthrs, imgbkgrm, fvar4img, imgprofi",
62 " ",
63 "Keywords: image, smoothing, gaussian, FWHM",
64 0};
65/*****************************************************************************/
66
67/*****************************************************************************/
68/* Turn on the globbing of the command line, since it is disabled by default in
69 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
70 In Unix&Linux wildcard command line processing is enabled by default. */
71/*
72#undef _CRT_glob
73#define _CRT_glob -1
74*/
75int _dowildcard = -1;
76/*****************************************************************************/
77
78/*****************************************************************************/
82int main(int argc, char **argv)
83{
84 int ai, help=0, version=0, verbose=1;
85 char petfile[FILENAME_MAX], outfile[FILENAME_MAX];
86 int gaussian_method=1; // 1= FIR; 2=Alvarez-Mazorra; 3=EBox
87 double xsize=nan(""), ysize=nan(""), zsize=nan("");
88 int useSD=1; // 0=FWHM; 1=SD
89 double SDx=nan(""), SDy=nan(""), SDz=nan("");
90 int SDxUnit, SDyUnit, SDzUnit; // 0=pixels, 1=mm, 2=cm
91 double tolerance=1.0E-04;
92 int stepNr=4;
93
94
95 /*
96 * Get arguments
97 */
98 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
99 petfile[0]=outfile[0]=(char)0;
100 SDxUnit=SDyUnit=SDzUnit=0;
101 /* Get options */
102 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
103 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
104 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
105 if(strncasecmp(cptr, "METHOD=", 7)==0 && strlen(cptr)>7) {
106 cptr+=7;
107 if(strcasecmp(cptr, "FIR")==0) {gaussian_method=1; continue;}
108 if(strcasecmp(cptr, "AM")==0) {gaussian_method=2; continue;}
109 if(strcasecmp(cptr, "EBOX")==0) {gaussian_method=3; continue;}
110 } else if(strcasecmp(cptr, "SD")==0) {
111 useSD=1; continue;
112 } else if(strcasecmp(cptr, "FWHM")==0) {
113 useSD=0; continue;
114 } else if(strncasecmp(cptr, "STEPS=", 6)==0) {
115 stepNr=atoi(cptr+6); if(stepNr>0) continue;
116 } else if(strncasecmp(cptr, "XYSIZE=", 7)==0) {
117 xsize=ysize=atof_dpi(cptr+7); if(xsize>0.0) continue;
118 } else if(strncasecmp(cptr, "ZSIZE=", 6)==0) {
119 zsize=atof_dpi(cptr+6); if(zsize>0.0) continue;
120 } else if(strncasecmp(cptr, "TOL=", 4)==0) {
121 tolerance=atof_dpi(cptr+4); if(tolerance>0.0) continue;
122 } else if(strncasecmp(cptr, "TOLERANCE=", 10)==0) {
123 tolerance=atof_dpi(cptr+10); if(tolerance>0.0) continue;
124 }
125 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
126 return(1);
127 } else break;
128
129 /* Print help or version? */
130 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
131 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
132 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
133
134 /* Process other arguments, starting from the first non-option */
135 if(ai<argc) {strlcpy(petfile, argv[ai++], FILENAME_MAX);}
136 if(ai<argc) {
137 strlcpy(outfile, argv[ai++], FILENAME_MAX);
138 double v; // check that user did not forget file name
139 if(atof_with_check(outfile, &v)==0) {
140 fprintf(stderr, "Error: invalid output file name '%s'\n", outfile);
141 return(1);
142 }
143 }
144 if(ai<argc) {
145 double v;
146 int ret=atof_with_check(argv[ai], &v);
147 if(ret==0 && v>=0.0) {
148 SDx=SDy=(float)v;
149 /* Check if unit was specified too */
150 if(strcasestr(argv[ai], "pxl")!=NULL) SDxUnit=SDyUnit=0;
151 if(strcasestr(argv[ai], "mm")!=NULL) SDxUnit=SDyUnit=1;
152 if(strcasestr(argv[ai], "cm")!=NULL) SDxUnit=SDyUnit=2;
153 ai++;
154 } else {
155 fprintf(stderr, "Error: invalid filter S.D.\n");
156 return(1);
157 }
158 }
159 if(ai<argc) {
160 double v;
161 int ret=atof_with_check(argv[ai], &v);
162 if(ret==0 && v>=0.0) {
163 SDz=(float)v;
164 /* Check if unit was specified too */
165 if(strcasestr(argv[ai], "pxl")!=NULL) SDzUnit=0;
166 if(strcasestr(argv[ai], "mm")!=NULL) SDzUnit=1;
167 if(strcasestr(argv[ai], "cm")!=NULL) SDzUnit=2;
168 ai++;
169 } else {
170 fprintf(stderr, "Error: invalid filter S.D.\n");
171 return(1);
172 }
173 }
174 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
175
176 /* Did we get all the information that we need? */
177 if(!outfile[0] || !(SDx>=0.0)) {
178 fprintf(stderr, "Error: missing command-line argument; try %s --help\n", argv[0]);
179 return(1);
180 }
181 if(strcasecmp(outfile, petfile)==0) {
182 fprintf(stderr, "Error: check the output file name.\n");
183 return(1);
184 }
185 if(!(SDx>0.0) && !(SDy>0.0) && !(SDz>0.0)) {
186 fprintf(stderr, "Warning: with given SD no filtering is applied.\n");
187 fflush(stderr);
188 }
189
190
191 /* Convert FWHM to SD, if necessary */
192 if(!useSD) {SDx/=2.355; SDy/=2.355; if(SDz>0.0) SDz/=2.355;}
193
194 /* In verbose mode print arguments and options */
195 if(verbose>1) {
196 printf("petfile := %s\n", petfile);
197 printf("outfile := %s\n", outfile);
198 if(!isnan(xsize)) printf("pixel_xysize := %g mm\n", xsize);
199 if(!isnan(zsize)) printf("pixel_zsize := %g mm\n", zsize);
200 printf("gaussian_method := %d\n", gaussian_method);
201 printf("stepNr := %d\n", stepNr);
202 fflush(stdout);
203 }
204
205
206 /*
207 * Read the contents of the PET file to img data structure
208 */
209 IMG img; imgInit(&img);
210 if(verbose>0) printf("reading %s\n", petfile);
211 {
212 int ret=imgRead(petfile, &img);
213 if(ret) {
214 fprintf(stderr, "Error: %s\n", img.statmsg);
215 if(verbose>1) printf("ret=%d\n", ret);
216 imgEmpty(&img); return(2);
217 }
218 /* Check if PET data is raw or image */
219 if(img.type!=IMG_TYPE_IMAGE) {
220 fprintf(stderr, "Error: %s is not an image.\n", petfile);
221 imgEmpty(&img); return(2);
222 }
223 if(imgNaNs(&img, 1)>0)
224 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
225 }
226
227 /* Set or check pixel sizes */
228 if(xsize>0.0) img.sizex=xsize;
229 if(ysize>0.0) img.sizey=ysize;
230 if(zsize>0.0) img.sizez=zsize;
231 if(verbose>1) printf("image_xyz_sizes := %g %g %g\n", img.sizex, img.sizey, img.sizez);
232 if(!isnan(xsize) || !isnan(ysize)) {
233 if(img.sizex!=img.sizey) {
234 fprintf(stderr, "Warning: different pixel x and y size.\n");
235 fflush(stderr);
236 }
237 }
238 if(verbose>1)
239 printf("image_xyzf_dimensions := %d %d %d %d\n", img.dimx, img.dimy, img.dimz, img.dimt);
240
241 /* Check that image size in smoothing dimension is at least 4 */
242 if(SDz>0 && img.dimz<4) {
243 fprintf(stderr, "Error: invalid Z dimension for 3D filtering.\n");
244 imgEmpty(&img); return(3);
245 }
246 if((SDx>0 && img.dimx<4) || (SDy>0 && img.dimy<4)) {
247 fprintf(stderr, "Error: invalid x,y dimensions for filtering.\n");
248 imgEmpty(&img); return(3);
249 }
250
251
252 /*
253 * Set Gaussian SD in units of pixels
254 */
255 if((SDxUnit!=0 && !(img.sizex>0.0)) || (SDyUnit!=0 && !(img.sizey>0.0)) ||
256 (SDzUnit!=0 && !(img.sizez>0.0)))
257 {
258 fprintf(stderr, "Error: unknown image pixel size.\n");
259 imgEmpty(&img); return(3);
260 }
261 /* Convert cm -> mm */
262 if(SDxUnit==2) {SDx*=10.0; SDxUnit=1;}
263 if(SDyUnit==2) {SDy*=10.0; SDyUnit=1;}
264 if(SDzUnit==2) {SDz*=10.0; SDzUnit=1;}
265 /* Convert mm -> pixels */
266 if(SDxUnit==1) {SDx/=img.sizex; SDxUnit=0;}
267 if(SDyUnit==1) {SDy/=img.sizey; SDyUnit=0;}
268 if(SDzUnit==1) {SDz/=img.sizez; SDzUnit=0;}
269 if(verbose>1) {
270 printf("gaussian_sdx := %g pxl\n", SDx);
271 printf("gaussian_sdy := %g pxl\n", SDy);
272 printf("gaussian_sdz := %g pxl\n", SDz);
273 }
274
275
276 /*
277 * Gaussian smoothing
278 */
279 int ret=0;
280 if(gaussian_method==1) {
281 if(verbose>0) fprintf(stdout, "Gaussian FIR filtering\n");
282 ret=imgGaussianFIRFilter(&img, SDx, SDy, SDz, tolerance, verbose-2);
283 } else if(gaussian_method==2) {
284 if(verbose>0) fprintf(stdout, "Gaussian AM filtering\n");
285 ret=imgGaussianAMFilter(&img, SDx, SDy, SDz, stepNr, tolerance, verbose);
286 } else { // EBox
287 if(verbose>0) fprintf(stdout, "Gaussian Ebox filtering\n");
288 ret=imgGaussianEBoxFilter(&img, SDx, SDy, SDz, stepNr, verbose);
289 }
290 if(ret!=0) {
291 fprintf(stderr, "Error: cannot filter the image.\n");
292 if(verbose>1) fprintf(stderr, "ret := %d\n", ret);
293 imgEmpty(&img); return(7);
294 }
295
296
297 /*
298 * Save filtered image
299 */
300 if(verbose>2) fprintf(stdout, "writing %s\n", outfile);
301 if(imgWrite(outfile, &img)) {
302 fprintf(stderr, "Error: %s\n", img.statmsg);
303 imgEmpty(&img);
304 return(11);
305 }
306 if(verbose>0) printf("Written %s\n", outfile);
307 imgEmpty(&img);
308
309 return(0);
310}
311/*****************************************************************************/
312
313/*****************************************************************************/
int atof_with_check(char *double_as_string, double *result_value)
Definition decpoint.c:107
double atof_dpi(char *str)
Definition decpoint.c:59
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 imgWrite(const char *fname, IMG *img)
Definition imgfile.c:136
int imgGaussianEBoxFilter(IMG *img, float xsd, float ysd, float zsd, int passNr, int verbose)
Definition imgfilter.c:408
int imgGaussianFIRFilter(IMG *img, float xsd, float ysd, float zsd, double tolerance, int verbose)
Definition imgfilter.c:18
int imgGaussianAMFilter(IMG *img, float xsd, float ysd, float zsd, int passNr, double tolerance, int verbose)
Definition imgfilter.c:173
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
char * strcasestr(const char *haystack, const char *needle)
Definition strext.c:279
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.
float sizex
unsigned short int dimx
char type
unsigned short int dimt
float sizey
unsigned short int dimz
unsigned short int dimy
const char * statmsg
float sizez