10#include "tpcclibConfig.h"
28static char *info[] = {
29 "Threshold dynamic PET image file in ECAT, NIfTI, or Analyze format.",
30 "AIC is used to determine whether the TAC of a single pixel consists of",
31 "noise only, or if it resembles the scaled mean of all image pixels.",
32 "If no significant signal is found, that pixel is set to zero.",
33 "After this operation, PET data can usually be compressed to about",
34 "one-third of the original file size.",
36 "If file name for mask file is given, then original image file is not",
37 "modified but a mask file is written, with 0 marking the noise pixels and",
38 "1 marking the pixels with signal. Otherwise the original image file is",
41 "Usage: @P [Options] imgfile [maskfile]",
45 " By default, all pixels with AUC<0 are set to zero; with this option",
46 " those are tested as usual.",
47 " -bkg=<zero|border>",
48 " Use zero values as background (zero, default), or mean of pixels at",
49 " image x,y-border (border).",
50 " -bordertac=<filename>",
51 " Save TAC of average pixel values at image x,y-borders.",
57 "See also: imgmask, imgthrs, imginteg, imgposv, imgslim",
59 "Keywords: image, threshold, mask, noise",
99 if(tac==NULL && sd==NULL && med==NULL)
return(0);
103 float a[pxlNr], fm, fs;
104 for(
int fi=0; fi<img->
dimt; fi++) {
106 for(
int zi=0; zi<img->
dimz; zi++) {
109 for(xi=0; xi<img->
dimx; xi++) a[i++]=img->
m[zi][yi][xi][fi];
111 for(xi=0; xi<img->
dimx; xi++) a[i++]=img->
m[zi][yi][xi][fi];
113 for(yi=1; yi<img->
dimy-1; yi++) a[i++]=img->
m[zi][yi][xi][fi];
115 for(yi=1; yi<img->
dimy-1; yi++) a[i++]=img->
m[zi][yi][xi][fi];
117 if(tac!=NULL || sd!=NULL) {
118 fm=
fmean(a, pxlNr, &fs);
119 if(tac!=NULL) tac[fi]=fm;
120 if(sd!=NULL) sd[fi]=fs;
122 if(med!=NULL) med[fi]=
fmedian(a, pxlNr);
155 if(verbose>0) printf(
"imgNoiseTemplate(*img, %d, %d, *timg, %d, status)\n",
156 keepNegat, border, verbose);
157 if(status!=NULL) strcpy(status,
"fault in calling routine");
159 if(timg==NULL)
return(1);
161 if(img->
dimx!=timg->
dimx)
return(2);
162 if(img->
dimy!=timg->
dimy)
return(2);
163 if(img->
dimz!=timg->
dimz)
return(2);
166 if(status!=NULL) strcpy(status,
"method works only for dynamic data");
176 float fdur[n], meany[n], bkgtac[n];
178 if(verbose>1) fprintf(stdout,
"computing mean of pixels\n");
180 for(
int i=0; i<n; i++) fdur[i]=img->
end[i]-img->
start[i];
182 for(
int i=0; i<n; i++) fdur[i]=1.0;
186 if(status!=NULL) strcpy(status,
"cannot calculate average TAC");
187 if(verbose>1) printf(
"ret := %d\n", ret);
191 if(verbose>1) fprintf(stdout,
"computing AUC of the mean TAC\n");
192 float mean_tac_auc=0.0;
193 for(
int i=0; i<n; i++) mean_tac_auc+=fdur[i]*meany[i];
194 if(verbose>2) printf(
"mean_tac_auc := %g\n", mean_tac_auc);
195 if(fabs(mean_tac_auc)<1.0E-10) {
196 if(status!=NULL) strcpy(status,
"very small TAC average");
201 double bkg_tac_auc=0.0;
204 for(
int i=0; i<n; i++) bkgtac[i]=0.0;
206 if(verbose>1) fprintf(stdout,
"computing background from border pixels\n");
208 if(status!=NULL) strcpy(status,
"cannot calculate background TAC");
212 for(
int i=0; i<n; i++) bkg_tac_auc+=fdur[i]*bkgtac[i];
214 if(verbose>2) printf(
"bkg_tac_auc := %g\n", bkg_tac_auc);
226 if(status!=NULL) strcpy(status,
"cannot allocate memory for mask data");
234 if(verbose>1) fprintf(stdout,
"processing pixels...\n");
235 float wsum=0.0;
for(
int i=0; i<n; i++) wsum+=fdur[i];
if(verbose>4) printf(
"wsum=%g\n", wsum);
237 for(zi=0; zi<img->
dimz; zi++) {
238 for(yi=0; yi<img->
dimy; yi++) {
239 for(xi=0; xi<img->
dimx; xi++) {
241 if(maskExisted && timg->
m[zi][yi][xi][0]<0.1) {
242 timg->
m[zi][yi][xi][0]=0.0;
continue;
245 double pxl_tac_auc=0.0;
246 for(
int i=0; i<n; i++) pxl_tac_auc+=fdur[i]*img->
m[zi][yi][xi][i];
248 if(keepNegat==0 && pxl_tac_auc<=bkg_tac_auc) {
249 timg->
m[zi][yi][xi][0]=0.0;
continue;
254 for(
int i=0; i<n; i++) {
255 double g=img->
m[zi][yi][xi][i];
261 for(
int i=0; i<n; i++) {
262 double g=img->
m[zi][yi][xi][i]-bkgtac[i];
267 double wss2=0.0;
double sf2=1.0;
268 if(bkg_tac_auc>1.0E-10) sf2=pxl_tac_auc/bkg_tac_auc;
270 for(
int i=0; i<n; i++) {
271 double g=img->
m[zi][yi][xi][i]-sf2*bkgtac[i];
276 double wss3=0.0;
double sf3=pxl_tac_auc/mean_tac_auc;
278 for(
int i=0; i<n; i++) {
279 double g=img->
m[zi][yi][xi][i]-sf3*meany[i];
284 double aic0=
aicSS(wss0, n, 0);
285 double aic1=
aicSS(wss1, n, 0);
286 double aic2=
aicSS(wss2, n, 1);
287 double aic3=
aicSS(wss3, n, 1);
289 if(aic3<aic0 && aic3<aic1 && aic3<aic2) {
290 timg->
m[zi][yi][xi][0]=1.0;
292 timg->
m[zi][yi][xi][0]=0.0;
295 printf(
" p[%d][%d][%d]: wss0=%g wss1=%g wss2=%g wss3=%g; aic0=%g aic1=%g aic2=%g aic3=%g\n",
296 zi, yi, xi, wss0, wss1, wss2, wss3, aic0, aic1, aic2, aic3);
297 printf(
" -> %g\n", timg->
m[zi][yi][xi][0]);
298 }
else if(verbose>1 && yi==img->
dimy-1 && xi==img->
dimx-1 && timg->
m[zi][yi][xi][0]==1.0) {
299 printf(
" p[%d][%d][%d]: wss0=%g wss1=%g wss2=%g wss3=%g; aic0=%g aic1=%g aic2=%g aic3=%g\n",
300 zi, yi, xi, wss0, wss1, wss2, wss3, aic0, aic1, aic2, aic3);
301 printf(
" sf2=%g sf3=%g\n", sf2, sf3);
302 printf(
" -> %g\n", timg->
m[zi][yi][xi][0]);
307 if(verbose>1) fprintf(stdout,
"... done.\n");
310 if(status!=NULL) strcpy(status,
"ok");
320int main(
int argc,
char **argv)
322 int ai, help=0, version=0, verbose=1;
323 char petfile[FILENAME_MAX], maskfile[FILENAME_MAX], borderfile[FILENAME_MAX];
332 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
333 petfile[0]=maskfile[0]=borderfile[0]=(char)0;
335 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
337 char *cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
338 if(strncasecmp(cptr,
"KEEPNEGAT", 5)==0) {
339 keepNegat=1;
continue;
340 }
else if(strncasecmp(cptr,
"BORDERTAC=", 10)==0) {
341 strlcpy(borderfile, cptr+10, FILENAME_MAX);
if(borderfile[0])
continue;
342 }
else if(strncasecmp(cptr,
"BKG=", 4)==0) {
343 cptr+=4;
if(strncasecmp(cptr,
"ZERO", 1)==0) {bkgMethod=0;
continue;}
344 if(strncasecmp(cptr,
"BORDER", 1)==0) {bkgMethod=1;
continue;}
346 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
351 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
356 if(ai<argc) {
strlcpy(petfile, argv[ai], FILENAME_MAX); ai++;}
357 if(ai<argc) {
strlcpy(maskfile, argv[ai], FILENAME_MAX); ai++;}
358 if(ai<argc) {fprintf(stderr,
"Error: too many arguments.\n");
return(1);}
363 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
370 printf(
"petfile := %s\n", petfile);
371 if(maskfile[0]) printf(
"maskfile := %s\n", maskfile);
372 if(borderfile[0]) printf(
"borderfile := %s\n", borderfile);
373 printf(
"keepNegat := %d\n", keepNegat);
380 if(verbose>0) {printf(
"reading %s\n", petfile); fflush(stdout);}
384 fprintf(stderr,
"Error: %s\n", img.
statmsg);
385 if(verbose>1) printf(
"ret=%d\n", ret);
389 printf(
"dimt := %d\n", img.
dimt);
390 printf(
"dimx := %d\n", img.
dimx);
391 printf(
"dimy := %d\n", img.
dimy);
392 printf(
"dimz := %d\n", img.
dimz);
393 printf(
"type := %d\n", img.
type);
397 fprintf(stderr,
"Error: method works only for dynamic data.\n");
401 if(verbose>0) fprintf(stderr,
"Warning: missing pixel values.\n");
404 if(img.
dimt>1) fprintf(stderr,
"Warning: unknown frame times.\n");
410 fprintf(stderr,
"Error: cannot correct sinogram counts.\n");
411 if(verbose>1) printf(
"ret=%d\n", ret);
420 if(verbose>0) fprintf(stdout,
"calculating the TAC of border pixels\n");
423 fprintf(stderr,
"Error: cannot calculate TAC of border pixels.\n");
428 fprintf(stderr,
"Error: cannot make TAC of border pixels.\n");
431 for(
int i=0; i<dft.
frameNr; i++) dft.
voi[0].
y[i]=bv[i];
432 for(
int i=0; i<dft.
frameNr; i++) dft.
voi[1].
y[i]=bs[i];
433 for(
int i=0; i<dft.
frameNr; i++) dft.
voi[2].
y[i]=bm[i];
439 fprintf(stderr,
"Error in writing '%s': %s\n", borderfile,
dfterrmsg);
442 if(verbose>0) printf(
"TAC of border pixels written in %s\n", borderfile);
450 if(verbose>0) fprintf(stdout,
"calculating the mask\n");
455 fprintf(stderr,
"Error: %s.\n", buf);
456 if(verbose>1) printf(
"ret=%d\n", ret);
460 fprintf(stderr,
"Error: whole image would be considered as noise.\n");
470 if(verbose>1) fprintf(stdout,
"writing mask image...\n");
473 fprintf(stderr,
"Error: %s\n", mask.
statmsg);
477 if(verbose>0) printf(
"Written %s\n", maskfile);
485 if(verbose>1) fprintf(stdout,
"applying the mask\n");
489 fprintf(stderr,
"Error: cannot apply mask to PET data.\n");
492 if(verbose>1) fprintf(stdout,
"writing masked image...\n");
495 fprintf(stderr,
"Error: %s\n", img.
statmsg);
499 if(verbose>0) printf(
"Written modified %s\n", petfile);
double aicSS(double ss, const int n, const int k)
int dftWrite(DFT *data, char *filename)
int imgExistentTimes(IMG *img)
unsigned long long imgNaNs(IMG *img, int fix)
int imgAllocateWithHeader(IMG *image, int planes, int rows, int columns, int frames, IMG *image_from)
void imgEmpty(IMG *image)
int imgRawCountsPerTime(IMG *img, int operation)
int imgBorderAverageTAC(IMG *img, float *tac, float *sd, float *med)
int imgNoiseTemplate(IMG *img, int keepNegat, int border, IMG *timg, int verbose, char *status)
int imgAverageTAC(IMG *img, float *tac)
int imgRead(const char *fname, IMG *img)
int imgWrite(const char *fname, IMG *img)
float fmean(float *data, long long int n, float *sd)
float fmedian(float *data, long long int n)
int imgThresholdByMask(IMG *img, IMG *templt, float thrValue)
Header file for libtpccurveio.
Header file for libtpcimgio.
#define IMG_STATUS_OCCUPIED
Header file for libtpcimgp.
long long imgMaskCount(IMG *img)
Header file for libtpcmisc.
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
size_t strlcpy(char *dst, const char *src, size_t dstsize)
int tpcHtmlUsage(const char *program, char *text[], const char *path)
void tpcPrintBuild(const char *program, FILE *fp)
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Header file for libtpcmodel.
Header file for libtpcmodext.
int dftAllocateWithIMG(DFT *dft, int tacNr, IMG *img)
char voiname[MAX_REGIONSUBNAME_LEN+1]
char name[MAX_REGIONNAME_LEN+1]