9#include "tpcclibConfig.h"
24unsigned _stklen = 16777216;
28static char *info[] = {
29 "Flexible image segmentation (clustering) for dynamic PET image (1).",
30 "This program can be used for method testing purposes only!",
31 "Default stack size on Windows may be too small, causing program to crash.",
33 "User must provide threshold percentage to exclude the background (bkgthrs),",
34 "maximal CV percentage allowed for pixels in the same cluster (maxcv),",
35 "and threshold percentage for correlation coefficient between cluster TACs",
38 "Static cluster image will contain the cluster numbers as integers, where",
39 "0 represents pixels below background threshold, and 1, 2, 3, ... represent",
40 "clusters in DECREASING order of TAC integrals.",
42 "Usage: @P [Options] image bkgthrs maxcv ccthrs clusterimage",
45 " -ctac=<filename for cluster TACs>",
46 " Cluster TACs are saved in TAC format.",
47 " -cf=<filename for correction factor image>",
48 " Save image file that will contain correction factors for individual",
49 " pixels, calculated as (AUC of cluster avg TAC)/(AUC of pixel TAC).",
50 " -sm=<filename for smoothed dynamic image>",
51 " TACs in the original dynamic image are replaced by the cluster TACs",
52 " which have been divided by the correction factors.",
56 " @P -ctac=b123cluster.dat b123dy1.v 30 5 50 b123cluster.v",
59 "1. Bentourkia M. A flexible image segmentation prior to parametric",
60 " estimation. Comput Med Imaging Graph. 2001;25:501-506.",
62 "See also: imgthrs, imgdysmo, imgfiltg, imgmask, img2tif, ecat2ana, pxl2tac",
64 "Keywords: image, smoothing, mask, threshold",
83int main(
int argc,
char **argv)
85 int ai, help=0, version=0, verbose=1;
86 char petfile[FILENAME_MAX], clufile[FILENAME_MAX],
87 tacfile[FILENAME_MAX], corfile[FILENAME_MAX],
88 smofile[FILENAME_MAX];
89 double bkgthrs, maxcv, ccthrs;
97 if(argc==1) {
tpcPrintUsage(argv[0], info, stderr);
return(1);}
98 petfile[0]=clufile[0]=tacfile[0]=corfile[0]=smofile[0]=(char)0;
100 for(ai=1; ai<argc; ai++)
if(*argv[ai]==
'-') {
102 cptr=argv[ai]+1;
if(*cptr==
'-') cptr++;
if(cptr==NULL)
continue;
103 if(strncasecmp(cptr,
"CTAC=", 5)==0) {
104 strlcpy(tacfile, cptr+5, FILENAME_MAX);
continue;
105 }
else if(strncasecmp(cptr,
"CF=", 3)==0) {
106 strlcpy(corfile, cptr+3, FILENAME_MAX);
continue;
107 }
else if(strncasecmp(cptr,
"SM=", 3)==0) {
108 strlcpy(smofile, cptr+3, FILENAME_MAX);
continue;
109 }
else if(strncasecmp(cptr,
"SMO=", 4)==0) {
110 strlcpy(smofile, cptr+4, FILENAME_MAX);
continue;
112 fprintf(stderr,
"Error: invalid option '%s'.\n", argv[ai]);
117 if(help==2) {
tpcHtmlUsage(argv[0], info,
"");
return(0);}
122 if(ai<argc) {
strlcpy(petfile, argv[ai++], FILENAME_MAX);}
125 if(ret!=0 || bkgthrs>=100.0) {
126 fprintf(stderr,
"Error: invalid background threshold.\n");
129 if(bkgthrs<0.0) bkgthrs=0.0;
else bkgthrs/=100.0;
134 if(ret!=0 || maxcv>=100.0) {
135 fprintf(stderr,
"Error: invalid CV limit.\n");
138 if(maxcv<0.0) maxcv=0.0;
else maxcv/=100.0;
143 if(ret!=0 || ccthrs>=100.0) {
144 fprintf(stderr,
"Error: invalid correlation coefficient threshold.\n");
147 if(ccthrs<0.0) ccthrs=0.0;
else ccthrs/=100.0;
150 if(ai<argc) {
strlcpy(clufile, argv[ai++], FILENAME_MAX);}
152 fprintf(stderr,
"Error: invalid argument '%s'.\n", argv[ai]);
158 fprintf(stderr,
"Error: missing command-line argument; use option --help\n");
162 if(strcasecmp(petfile, clufile)==0 || strcasecmp(petfile, tacfile)==0 ||
163 strcasecmp(petfile, corfile)==0 || strcasecmp(petfile, smofile)==0) {
164 fprintf(stderr,
"Error: same filename for input and output data.\n");
171 printf(
"petfile := %s\n", petfile);
172 printf(
"clufile := %s\n", clufile);
173 if(tacfile[0]) printf(
"tacfile:=%s\n", tacfile);
174 if(corfile[0]) printf(
"corfile:=%s\n", corfile);
175 if(smofile[0]) printf(
"smofile:=%s\n", smofile);
176 printf(
"bkgthrs := %g\n", 100.*bkgthrs);
177 printf(
"maxcv := %g\n", 100.*maxcv);
178 printf(
"ccthrs := %g\n", 100.*ccthrs);
186 if(verbose>0) fprintf(stdout,
"reading image %s\n", petfile);
190 fprintf(stderr,
"Error: %s\n", img.
statmsg);
if(verbose>1)
imgInfo(&img);
194 printf(
"image dimensions: %d %d %d\n", img.
dimz, img.
dimy, img.
dimx);
195 printf(
"image frame nr: %d\n", img.
dimt);
199 fprintf(stderr,
"Error: image is not dynamic.\n");
203 if(verbose>0) fprintf(stderr,
"Warning: missing pixel values.\n");
206 fprintf(stderr,
"Error: image does not contain frame times.\n");
212 fprintf(stderr,
"Error: cannot correct sinogram counts.\n");
213 if(verbose>1) printf(
"ret=%d\n", ret);
218 if(verbose>0) printf(
"calculating AUC image...\n");
222 fprintf(stderr,
"Error: cannot calculate AUC image.\n");
223 if(verbose>1) printf(
"ret=%d\n", ret);
227 sumimg.
unit=CUNIT_UNITLESS;
230 if(verbose>0) printf(
"searching for max AUC pixel value...\n");
232 ret=
imgMax(&sumimg, &maxauc);
234 fprintf(stderr,
"Error: cannot find maximum AUC.\n");
235 if(verbose>1) printf(
"ret=%d\n", ret);
239 if(verbose>1) printf(
"AUCmax := %g\n", maxauc);
242 float minauc=maxauc*bkgthrs;
244 printf(
"thresholding image (min=%g, max=%g)...\n", minauc, maxauc);
250 fprintf(stderr,
"Error: cannot do thresholding.\n");
251 if(verbose>1) printf(
"ret=%d\n", ret);
256 char tmp[FILENAME_MAX+20], buf[128];
257 sprintf(tmp,
"%s.templimg.tif", petfile);
261 if(ret) {fprintf(stderr,
"Error: %s\n", buf); fflush(stderr);}
265 double meanauc, CVmax, CVlim;
266 meanauc=0.5*(minauc+maxauc);
267 CVmax= ((maxauc-meanauc)*(maxauc-meanauc) +
268 (minauc-meanauc)*(minauc-meanauc)) / meanauc;
271 printf(
"CVmax :=%g\nCVlim := %g\n", CVmax, CVlim);
276 if(verbose>0) printf(
"conversion of mask to initial cluster image...\n");
281 fprintf(stderr,
"Error: cannot make cluster template.\n");
282 if(verbose>1) printf(
"ret=%d\n", ret);
288 if(verbose>0) {printf(
"searching for clusters...\n"); fflush(stdout);}
289 int pi, ri, ci, clusterID=0, clusterNr=0;;
293 printf(
"finding max pixel value for %dth cluster.\n", clusterID+2);
299 fprintf(stderr,
"Error: cannot search max AUC.\n");
300 if(verbose>1) printf(
"ret=%d\n", ret);
304 if(verbose>4) fprintf(stdout,
"All pixels included in clusters.\n");
308 printf(
"Max %g found at [%d][%d][%d] (%g)\n", maxauc, pi, ri, ci,
309 templimg.
m[pi][ri][ci][0]);
319 printf(
"All neighbours are part of clusters; this was added to %d.\n",
320 (
int)templimg.
m[pi][ri][ci][0]);
327 printf(
"At least one neighbour is free.\n"); fflush(stdout);
334 printf(
"expanding the cluster around pixel [%d][%d][%d]\n", pi, ri, ci);
338 pi, ri, ci, pi, ri, ci, CVlim, ccthrs, verbose-5);
340 fprintf(stderr,
"Error: problem in clustering.\n");
341 if(verbose>1) printf(
"ret=%d\n", ret);
346 char tmp[FILENAME_MAX+20], buf[128];
347 sprintf(tmp,
"%s.step%d.tif", petfile, clusterID);
348 printf(
"writing %s of temporary cluster situation\n", tmp);
350 float g=(float)clusterID;
353 if(ret) {fprintf(stderr,
"Error: %s\n", buf); fflush(stderr);}
355 if(verbose==1) {fprintf(stdout,
"."); fflush(stdout);}
357 if(verbose==1) {fprintf(stdout,
"\n"); fflush(stdout);}
359 if(verbose>0) {printf(
"\n%d clusters found.\n", clusterNr); fflush(stdout);}
365 if(verbose>1) printf(
"writing cluster image %s\n", clufile);
367 fprintf(stderr,
"Error: %s\n", templimg.
statmsg);
373 if(!tacfile[0] && !corfile[0] && !smofile[0]) {
375 if(verbose>0) printf(
"done.\n");
383 if(verbose>0) printf(
"calculating cluster average TACs...\n");
385 ret=
clusterTACs(&img, &templimg, clusterNr, &tac, verbose-2);
387 fprintf(stderr,
"Error: cannot calculate cluster average TACs.\n");
388 if(verbose>1) printf(
"ret=%d\n", ret);
394 if(verbose>1) printf(
"writing cluster average TACs in %s\n", tacfile);
397 fprintf(stderr,
"Error: %s\n",
dfterrmsg);
404 if(!corfile[0] && !smofile[0]) {
406 if(verbose>0) printf(
"done.\n");
414 if(verbose>0) printf(
"calculating correction image...\n");
416 if(verbose>2) printf(
"integrating cluster TACs...\n");
417 for(
int i=0; i<tac.
voiNr; i++) {
419 tac.
voi[i].
y2, NULL);
421 fprintf(stderr,
"Error: cannot integrate cluster TACs.\n");
427 if(verbose>2) printf(
"calculating image...\n");
428 for(pi=0; pi<sumimg.
dimz; pi++)
429 for(ri=0; ri<sumimg.
dimy; ri++)
430 for(ci=0; ci<sumimg.
dimx; ci++) {
431 clusterID=(int)templimg.
m[pi][ri][ci][0];
432 if(clusterID>0 && sumimg.
m[pi][ri][ci][0]>1.0E-006) {
433 sumimg.
m[pi][ri][ci][0]=
434 tac.
voi[clusterID-1].
y2[tac.
frameNr-1]/sumimg.
m[pi][ri][ci][0];
435 }
else sumimg.
m[pi][ri][ci][0]=1.0;
438 if(verbose>1) printf(
"writing correction image %s\n", corfile);
440 fprintf(stderr,
"Error: %s\n", sumimg.
statmsg);
451 if(verbose>0) printf(
"calculating smoothed dynamic image...\n");
454 for(pi=0; pi<sumimg.
dimz; pi++)
455 for(ri=0; ri<sumimg.
dimy; ri++)
456 for(ci=0; ci<sumimg.
dimx; ci++) {
457 clusterID=(int)templimg.
m[pi][ri][ci][0];
459 for(fi=0; fi<img.
dimt; fi++)
460 img.
m[pi][ri][ci][fi]=
461 tac.
voi[clusterID-1].
y[fi]/sumimg.
m[pi][ri][ci][0];
463 for(fi=0; fi<img.
dimt; fi++)
464 img.
m[pi][ri][ci][fi]=0.0;
470 fprintf(stderr,
"Error: cannot correct sinogram counts.\n");
475 if(verbose>1) printf(
"writing smoothed image %s\n", smofile);
477 fprintf(stderr,
"Error: %s\n", img.
statmsg);
486 if(verbose>0) printf(
"done.\n");
int clusterTACs(IMG *dimg, IMG *cimg, int nr, DFT *tac, int verbose)
int atof_with_check(char *double_as_string, double *result_value)
int dftWrite(DFT *data, char *filename)
int imgExistentTimes(IMG *img)
unsigned long long imgNaNs(IMG *img, int fix)
void imgEmpty(IMG *image)
int imgFrameIntegral(IMG *img, int first, int last, IMG *iimg, int verbose)
int imgRawCountsPerTime(IMG *img, int operation)
int imgRead(const char *fname, IMG *img)
int imgWrite(const char *fname, IMG *img)
int imgMax(IMG *img, float *maxvalue)
int imgsegmThresholdMask(IMG *img, float minValue, float maxValue, IMG *timg)
int imgsegmCheckNeighbours(IMG *cimg, int pi, int ri, int ci)
int imgsegmMaskToCluster(IMG *img)
int imgsegmFindBestNeighbour(IMG *dimg, IMG *cimg, int pi, int ri, int ci)
int imgsegmFindMaxOutsideClusters(IMG *sumimg, IMG *cluster, float *max, int *plane, int *row, int *col)
int imgsegmClusterExpand(IMG *cimg, IMG *simg, IMG *dimg, int clusterID, int pi, int ri, int ci, int pj, int rj, int cj, float CVlim, float CClim, int verbose)
int tiffWriteImg(IMG *img, int plane, int frame, float *maxvalue, int colorscale, char *fname, int matXdim, int matYdim, int verbose, char *status)
int petintegrate(double *x1, double *x2, double *y, int nr, double *newyi, double *newyii)
Header file for libtpccurveio.
Header file for libtpcimgio.
Header file for libtpcimgp.
#define PET_GRAYSCALE_INV
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.