TPCCLIB
Loading...
Searching...
No Matches
imgthbcv.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 <time.h>
18/*****************************************************************************/
19#include "libtpcmisc.h"
20#include "libtpcimgio.h"
21#include "libtpcimgp.h"
22#include "libtpcmodel.h"
23#include "libtpcmodext.h"
24/*****************************************************************************/
25/* Local functions */
26double bcvfunc(double p, void*);
27/*****************************************************************************/
28
29/*****************************************************************************/
30static char *info[] = {
31 "Based on given absolute threshold, calculate between-class variance from",
32 "static PET image file in ECAT, NIfTI, or Analyze format.",
33 "If threshold is not given, threshold that gives the highest between-class",
34 "variance is estimated.",
35 "Between-class variance is calculated using formula by Cao et al. 2018",
36 "doi: 10.1109/ACCESS.2018.2889013",
37 " ",
38 "Usage: @P [Options] imgfile [threshold]",
39 " ",
40 "Options:",
41 " -mask=<filename>",
42 " Save mask file containing pixel values 1 (above threshold) and",
43 " 0 (under the threshold).",
44 " -stdoptions", // List standard options like --help, -v, etc
45 " ",
46 "See also: imgthrs, imgmask, imgqntls, imginteg, imgslim, imgcutof",
47 " ",
48 "Keywords: image, threshold",
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/*****************************************************************************/
65
73 IMG *img,
76 const int fi,
78 float threshold,
80 int verbose
81) {
82 if(verbose>0) {printf("%s(IMG, %d, %f, ...)\n", __func__, fi, threshold); fflush(stdout);}
83 double bcv=nan("");
84 if(img==NULL || img->dimz<1 || img->dimy<1 || img->dimx<1 || img->dimt<1) return(bcv);
85 if(fi<1 || fi>img->dimt) return(bcv);
86
87 if(verbose>1) fprintf(stdout, "thresholding\n");
88 unsigned int p0=0, p1=0;
89 double s0=0.0, s1=0.0;
90 for(int zi=0; zi<img->dimz; zi++) {
91 for(int yi=0; yi<img->dimy; yi++) {
92 for(int xi=0; xi<img->dimx; xi++) {
93 if(img->m[zi][yi][xi][fi-1]<threshold) {
94 p0++; s0+=img->m[zi][yi][xi][fi-1];
95 } else if(img->m[zi][yi][xi][fi-1]>=threshold) {
96 p1++; s1+=img->m[zi][yi][xi][fi-1];
97 } // NaNs are left out with if else if
98 }
99 }
100 }
101 if(verbose>1) {
102 printf("p0=%u\n", p0);
103 printf("p1=%u\n", p1);
104 }
105 /* If no pixels in either of classes, between-class variance is 0 */
106 if(p0==0 || p1==0) {
107 bcv=0.0;
108 } else { // otherwise calculate means, and the between-class variance
109
110 /* Calculate means */
111 double mu0, mu1, mu;
112 mu0=s0/(double)p0;
113 mu1=s1/(double)p1;
114 mu=(s0+s1)/(double)(p0+p1);
115 if(verbose>1) {
116 printf("mu0=%g\n", mu0);
117 printf("mu1=%g\n", mu1);
118 printf("mu=%g\n", mu);
119 }
120
121 /* Calculate between-class variance */
122 bcv=(double)p0*(double)p1*( (mu0-mu1)*(mu0-mu1) + (mu0-mu)*(mu0-mu) + (mu1-mu)*(mu1-mu) );
123 }
124
125 if(verbose>1) {printf("BCV := %g\n", bcv); fflush(stdout);}
126 return(bcv);
127}
128/*****************************************************************************/
129
130/*****************************************************************************/
132/*****************************************************************************/
133
134/*****************************************************************************/
138int main(int argc, char **argv)
139{
140 int ai, help=0, version=0, verbose=1;
141 char petfile[FILENAME_MAX], maskfile[FILENAME_MAX];
142 float threshold=nanf("");
143
144
145 /*
146 * Get arguments
147 */
148 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
149 petfile[0]=maskfile[0]=(char)0;
150 /* Get options */
151 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
152 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
153 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
154 if(strncasecmp(cptr, "MASK=", 5)==0) {
155 strlcpy(maskfile, cptr+5, FILENAME_MAX); continue;
156 }
157 fprintf(stderr, "Error: invalid option '%s'.\n", argv[ai]);
158 return(1);
159 } else break;
160
161 /* Print help or version? */
162 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
163 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
164 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
165
166 /* Process other arguments, starting from the first non-option */
167 if(ai<argc) {strlcpy(petfile, argv[ai], FILENAME_MAX); ai++;}
168 if(ai<argc) {
169 double v;
170 if(atof_with_check(argv[ai], &v)!=0) {
171 fprintf(stderr, "Error: invalid threshold '%s'.\n", argv[ai]);
172 return(1);
173 }
174 threshold=v;
175 ai++;
176 }
177 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
178
179
180 /* Did we get all the information that we need? */
181 if(!petfile[0]) {
182 fprintf(stderr, "Error: missing command-line argument; try %s --help\n", argv[0]);
183 return(1);
184 }
185
186
187 /* In verbose mode print arguments and options */
188 if(verbose>1) {
189 printf("petfile := %s\n", petfile);
190 if(!isnan(threshold)) printf("threshold := %g\n", threshold);
191 if(maskfile[0]) printf("maskfile := %s\n", maskfile);
192 fflush(stdout);
193 }
194
195
196 /*
197 * Read the contents of the PET file to img data structure
198 */
199 IMG img; imgInit(&img);
200 if(verbose>1) {printf("reading %s\n", petfile); fflush(stdout);}
201 if(imgRead(petfile, &img)) {
202 fprintf(stderr, "Error: %s\n", img.statmsg);
203 imgEmpty(&img); return(2);
204 }
205 if(imgNaNs(&img, 1)>0)
206 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
207 /* Check that image is static */
208 if(img.dimt>1) {
209 fprintf(stderr, "Error: do not use for dynamic image.\n");
210 imgEmpty(&img); return(2);
211 }
212 /* Get the range of pixel values in image */
213 float imin, imax;
214 if(imgMinMax(&img, &imin, &imax)) {
215 fprintf(stderr, "Error: invalid image contents.\n");
216 imgEmpty(&img); return(3);
217 }
218 if(verbose>1) {
219 printf("image_min := %g\n", imin);
220 printf("image_max := %g\n", imax);
221 fflush(stdout);
222 }
223
224 double bcv=0.0;
225 if(!isnan(threshold)) {
226 if(threshold<=imin || threshold>=imax) {
227 fprintf(stdout, "Image pixel value range: %g - %g\n", imin, imax); fflush(stdout);
228 fprintf(stderr, "Error: invalid threshold %g.\n", threshold);
229 imgEmpty(&img); return(4);
230 }
231 /* Calculate between-class variance, print it, and quit */
232 bcv=imgBetween2ClassesVariance(&img, 1, threshold, verbose-2);
233 } else {
234 /* Find the threshold that gives the largest between-class variance */
235 if(verbose>1) {printf("finding optimal threshold...\n"); fflush(stdout);}
236 double p, fv;
237 int ret=nlopt1D(bcvfunc, &img, 0.5*(imin+imax), imin, imax, 0.1*(imax-imin),
238 0.000001*(imax-imin), 1000, &p, &fv, verbose-2);
239 if(ret!=0) {
240 fprintf(stderr, "Error: invalid image contents.\n");
241 imgEmpty(&img); return(4);
242 }
243 threshold=p;
244 bcv=-fv;
245 printf("threshold := %g\n", threshold);
246 fflush(stdout);
247 }
248 printf("BCV := %g\n", bcv);
249 fflush(stdout);
250
251
252 /* If requested, make a mask file based on threshold */
253 if(maskfile[0]) {
254 IMG mask; imgInit(&mask);
255 int ret=imgThresholdMask(&img, threshold, imax+1.0, &mask);
256 if(ret) {
257 fprintf(stderr, "Error: cannot threshold.\n");
258 if(verbose>1) printf("ret=%d\n", ret);
259 imgEmpty(&img); imgEmpty(&mask);
260 return(6);
261 }
262 if(verbose>1) fprintf(stdout, "writing %s\n", maskfile);
263 ret=imgWrite(maskfile, &mask);
264 if(ret) {
265 fprintf(stderr, "Error: %s\n", img.statmsg);
266 if(verbose>1) printf("ret=%d\n", ret);
267 imgEmpty(&img); imgEmpty(&mask);
268 return(11);
269 }
270 if(verbose>0) printf("Written %s\n", maskfile);
271 imgEmpty(&mask);
272 }
273
274
275 imgEmpty(&img);
276 return(0);
277}
278/*****************************************************************************/
279
280/*****************************************************************************
281 *
282 * Functions to be minimized
283 *
284 *****************************************************************************/
285double bcvfunc(double p, void *fdata)
286{
287 return(-imgBetween2ClassesVariance(fdata, 1, p, 0));
288}
289/*****************************************************************************/
290
291/*****************************************************************************/
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
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 imgMinMax(IMG *img, float *minvalue, float *maxvalue)
Definition imgminmax.c:154
double imgBetween2ClassesVariance(IMG *img, const int fi, float threshold, int verbose)
Definition imgthbcv.c:71
int imgThresholdMask(IMG *img, float minValue, float maxValue, IMG *timg)
Header file for libtpcimgio.
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
Header file for libtpcmodel.
int nlopt1D(double(*_fun)(double, void *), void *_fundata, double x, double xl, double xu, double delta, double tol, const int maxeval, double *nx, double *nf, int verbose)
Definition nlopt1d.c:14
Header file for libtpcmodext.
unsigned short int dimx
float **** m
unsigned short int dimt
unsigned short int dimz
unsigned short int dimy
const char * statmsg