TPCCLIB
Loading...
Searching...
No Matches
imgaafind.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <math.h>
14#include <string.h>
15#include <unistd.h>
16#include <time.h>
17/*****************************************************************************/
18#include "libtpcmisc.h"
19#include "libtpcimgio.h"
20#include "libtpcimgp.h"
21/*****************************************************************************/
22
23/*****************************************************************************/
24static char *info[] = {
25 "Trial program to find the location of abdominal aorta in dynamic PET image.",
26 " ",
27 "Usage: @P [Options] imgfile maskfile",
28 " ",
29 "Options:",
30 " -peak=<filename>",
31 " Image containing possible peak pixels.",
32 " -zmask=<filename>",
33 " TIFF showing initial mask for all image planes.",
34 " -stdoptions", // List standard options like --help, -v, etc
35 " ",
36 "See also: eabaort, imgprofi, imgthrs, imgfsegm, imgzavg, imgmax, img2tif",
37 " ",
38 "Keywords: image, input, blood, aorta, mask",
39 0};
40/*****************************************************************************/
41
42/*****************************************************************************/
43/* Turn on the globbing of the command line, since it is disabled by default in
44 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
45 In Unix&Linux wildcard command line processing is enabled by default. */
46/*
47#undef _CRT_glob
48#define _CRT_glob -1
49*/
50int _dowildcard = -1;
51/*****************************************************************************/
52
53/*****************************************************************************/
57int main(int argc, char **argv)
58{
59 int ai, help=0, version=0, verbose=1;
60 int ret;
61 char *cptr, imgfile[FILENAME_MAX], maskfile[FILENAME_MAX];
62 char peakfile[FILENAME_MAX], zmaskfile[FILENAME_MAX];
63
64
65 /*
66 * Get arguments
67 */
68 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
69 imgfile[0]=maskfile[0]=(char)0;
70 peakfile[0]=(char)0;
71 /* Options */
72 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') { /* options */
73 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(cptr==NULL) continue;
74 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
75 if(strncasecmp(cptr, "PEAK=", 5)==0) {
76 strlcpy(peakfile, cptr+5, FILENAME_MAX); continue;
77 } else if(strncasecmp(cptr, "ZMASK=", 6)==0) {
78 strlcpy(zmaskfile, cptr+6, FILENAME_MAX); continue;
79 }
80 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
81 return(1);
82 } else break;
83
84 /* Print help or version? */
85 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
86 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
87 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
88
89 /* Process other arguments, starting from the first non-option */
90 if(ai<argc) {strlcpy(imgfile, argv[ai], FILENAME_MAX); ai++;}
91 if(ai<argc) {strlcpy(maskfile, argv[ai], FILENAME_MAX); ai++;}
92 if(ai<argc) {fprintf(stderr, "Error: too many arguments.\n"); return(1);}
93
94 /* Is something missing or wrong? */
95 if(!maskfile[0]) {
96 fprintf(stderr, "Error: missing command-line argument; use option --help\n");
97 return(1);
98 }
99 if(strncasecmp(filenameGetExtension(zmaskfile), ".TIFF", 4)!=0) {
100 fprintf(stderr, "Error: invalid file name for TIF.\n");
101 return(1);
102 }
103
104 /* In verbose mode print arguments and options */
105 if(verbose>1) {
106 printf("imgfile := %s\n", imgfile);
107 printf("maskfile := %s\n", maskfile);
108 printf("zmaskfile := %s\n", zmaskfile);
109 if(peakfile[0]) printf("peakfile := %s\n", peakfile);
110 }
111
112
113 /*
114 * Read dynamic image
115 */
116 if(verbose>0) fprintf(stdout, "reading dynamic image %s\n", imgfile);
117 IMG img; imgInit(&img);
118 ret=imgRead(imgfile, &img);
119 if(ret) {
120 fprintf(stderr, "Error: %s\n", img.statmsg);
121 if(verbose>1) printf("ret := %d\n", ret);
122 return(2);
123 }
124 if(imgNaNs(&img, 1)>0)
125 if(verbose>0) fprintf(stderr, "Warning: missing pixel values.\n");
126 /* Check if PET data is raw or image */
127 if(img.type!=IMG_TYPE_IMAGE) {
128 fprintf(stderr, "Error: %s is not an image.\n", imgfile);
129 imgEmpty(&img); return(2);
130 }
131 int dimt, dimz, dimy, dimx;
132 dimt=img.dimt; dimz=img.dimz; dimy=img.dimy; dimx=img.dimx;
133 if(verbose>0) fprintf(stdout, " dim[x,y,z,t] := %d, %d, %d, %d\n", dimx, dimy, dimz, dimt);
134
135
136 /*
137 * Filter in x,y dimension and in z dimension
138 */
139 IMG xyfilt; imgInit(&xyfilt);
140 IMG zfilt; imgInit(&zfilt);
141 ret=imgDup(&img, &xyfilt);
142 if(ret==0) ret=imgDup(&img, &zfilt);
143 if(ret) {
144 fprintf(stderr, "Error: cannot setup IMG data.\n");
145 if(verbose>1) fprintf(stderr, "ret := %d\n", ret);
146 imgEmpty(&img); imgEmpty(&xyfilt); imgEmpty(&zfilt); return(3);
147 }
148 ret=imgMeanFilter(&xyfilt, 5, 5, 0, 0, verbose-4);
149 if(ret==0) ret=imgMeanFilter(&zfilt, 0, 0, 5, 0, verbose-4);
150 if(ret!=0) {
151 fprintf(stderr, "Error: cannot filter the image.\n");
152 if(verbose>1) fprintf(stderr, "ret := %d\n", ret);
153 imgEmpty(&img); imgEmpty(&xyfilt); imgEmpty(&zfilt); return(4);
154 }
155
156
157 /*
158 * Subtract filtered images at peak time
159 */
160 IMG peak; imgInit(&peak);
161 ret=imgAllocateWithHeader(&peak, dimz, dimy, dimx, 1, &img);
162 if(ret) {
163 fprintf(stderr, "Error: out of memory.\n");
164 imgEmpty(&img); imgEmpty(&xyfilt); imgEmpty(&zfilt); imgEmpty(&peak);
165 return(5);
166 }
167 for(int z=0; z<dimz; z++)
168 for(int y=0; y<dimy; y++)
169 for(int x=0; x<dimx; x++) {
170 /* Find highest pixel value in t dimension */
171 float maxv=0.0;
172 int maxt=0;
173 for(int t=0; t<dimt; t++) {
174 if(xyfilt.m[z][y][x][t]>maxv) {maxt=t; maxv=xyfilt.m[z][y][x][t];}
175 }
176 peak.m[z][y][x][0]=zfilt.m[z][y][x][maxt]-xyfilt.m[z][y][x][maxt];
177 if(peak.m[z][y][x][0]<0.0) peak.m[z][y][x][0]=0.0;
178 /* divide by peak 'time' */
179 if(maxt>0) peak.m[z][y][x][0]/=(float)maxt;
180 }
181
182 /* Divide by distance from the image centre */
183 for(int y=0; y<dimy; y++) {
184 for(int x=0; x<dimx; x++) {
185 float d=1.0+hypotf((float)x-dimx/2, (float)y-dimy/2); // always >= 1
186 for(int z=0; z<dimz; z++)
187 peak.m[z][y][x][0]/=d;
188 }
189 }
190
191 /* Write peak file */
192 if(peakfile[0]) {
193 if(verbose>1) printf("writing peak image...\n");
194 ret=imgWrite(peakfile, &peak);
195 if(ret) {
196 fprintf(stderr, "Error: %s\n", peak.statmsg);
197 imgEmpty(&img); imgEmpty(&xyfilt); imgEmpty(&zfilt); imgEmpty(&peak);
198 return(11);
199 }
200 if(verbose>0) fprintf(stdout, "Peak image %s saved.\n", peakfile);
201 }
202
203 /* Free filter images */
204 imgEmpty(&xyfilt); imgEmpty(&zfilt);
205
206
207 /*
208 * Make mask
209 */
210 IMG mask; imgInit(&mask);
211 ret=imgAllocateWithHeader(&mask, dimz, dimy, dimx, 1, &img);
212 if(ret) {
213 fprintf(stderr, "Error: out of memory.\n");
214 imgEmpty(&img); imgEmpty(&peak);
215 return(6);
216 }
217
218 {
219 /* Mean over image planes */
220 IMG zimg; imgInit(&zimg);
221 if(imgMeanZ(&peak, &zimg)) {
222 fprintf(stderr, "Error: cannot calculate mean over z dimension.\n");
223 imgEmpty(&img); imgEmpty(&peak); imgEmpty(&mask); imgEmpty(&zimg);
224 return(6);
225 }
226
227 /* Get peak position from that (omitting image border) */
228 int px=1, py=1;
229 float pmax=zimg.m[0][1][1][0];
230 for(int y=1; y<dimy-1; y++) for(int x=1; x<dimx-1; x++) if(zimg.m[0][y][x][0]>pmax) {
231 pmax=zimg.m[0][y][x][0]; px=x; py=y;
232 }
233 if(verbose>1) printf("estimated x,y position is %d,%d\n", 1+px, 1+py);
234
235 /* Grow it */
236 IMG zmask; imgInit(&zmask);
237 imgAllocateWithHeader(&zmask, 1, dimy, dimx, 1, &zimg);
238 imgRegionGrowingByThreshold(&zimg, 0, py, px, 0.25*pmax, 100.*pmax, &zmask, verbose-4);
239 /* Save as TIFF */
240 if(zmaskfile[0]) {
241 if(verbose>1) printf("writing zmask as TIFF...\n");
242 float mv=-1.0;
243 ret=tiffWriteImg(&zmask, -1, -1, &mv, PET_GRAYSCALE, zmaskfile, 0, 0, 0, NULL);
244 if(ret) {
245 fprintf(stderr, "Error: cannot write %s\n", zmaskfile);
246 imgEmpty(&img); imgEmpty(&peak); imgEmpty(&mask); imgEmpty(&zmask);
247 return(12);
248 }
249 if(verbose>0) fprintf(stdout, "Mask image %s saved.\n", maskfile);
250 }
251
252 /* Inside that mask find max pixel in each image plane */
253 /* Overwrite peak IMG structure with peak values from original dynamic image */
254 float zmax[dimz];
255 int xpos[dimz], ypos[dimz];
256 if(verbose>2) printf("peakpos(z,y,x) max\n");
257 for(int z=0; z<dimz; z++) {
258 zmax[z]=0.0;
259 int py=0, px=0, pt=0;
260 for(int y=0; y<dimy; y++) for(int x=0; x<dimx; x++) {
261 if(zmask.m[0][y][x][0]>0.5) {
262 for(int t=0; t<dimt; t++)
263 if(img.m[z][y][x][t]>zmax[z]) {
264 py=y; px=x; pt=t; zmax[z]=img.m[z][y][x][t];
265 }
266 peak.m[z][y][x][0]=img.m[z][y][x][pt];
267 } else {
268 peak.m[z][y][x][0]=0.0;
269 }
270 }
271 xpos[z]=px; ypos[z]=py;
272 if(verbose>2) printf("%d,%d,%d %g\n", 1+z, ypos[z], xpos[z], zmax[z]);
273 }
274/*
275 int py=0, px=0;
276 for(int y=0; y<dimy; y++) for(int x=0; x<dimx; x++)
277 if(zmask.m[0][y][x][0]>0.5 && peak.m[z][y][x][0]>zmax[z]) {
278 py=y; px=x; zmax[z]=peak.m[z][y][x][0];
279 }
280 //mask.m[z][py][px][0]=1.0;
281 xpos[z]=px; ypos[z]=py;
282 if(verbose>2) printf("%d,%d,%d %g\n", 1+z, ypos[z], xpos[z], zmax[z]);
283 }
284*/
285
286 /* Median of plane max values */
287 float m=fmedian(zmax, dimz);
288 if(verbose>2) printf("peakmaxmedian := %g\n", m);
289 /* Grow regions starting from the max of each plane */
290 if(verbose>1) printf("growing from max of each plane\n");
291 for(int z=0; z<dimz; z++) {
292 imgRegionGrowingByThreshold(&peak, z, ypos[z], xpos[z], 0.95*m, 100.*m, &mask, verbose-4);
293 }
294
295 imgEmpty(&zimg); imgEmpty(&zmask);
296 }
297
298 /* Write file */
299 if(maskfile[0]) {
300 if(verbose>1) printf("writing mask image...\n");
301 ret=imgWrite(maskfile, &mask);
302 if(ret) {
303 fprintf(stderr, "Error: %s\n", mask.statmsg);
304 imgEmpty(&img); imgEmpty(&peak); imgEmpty(&mask);
305 return(13);
306 }
307 if(verbose>0) fprintf(stdout, "Mask image %s saved.\n", maskfile);
308 }
309
310 imgEmpty(&img); imgEmpty(&peak); imgEmpty(&mask);
311 if(verbose>0) printf("done.\n");
312 return(0);
313}
314/*****************************************************************************/
315
316/*****************************************************************************/
char * filenameGetExtension(char *s)
Get the last extension of a filename.
Definition filename.c:139
unsigned long long imgNaNs(IMG *img, int fix)
Definition img.c:658
int imgAllocateWithHeader(IMG *image, int planes, int rows, int columns, int frames, IMG *image_from)
Definition img.c:279
int imgDup(IMG *img1, IMG *img2)
Definition img.c:304
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 imgMeanFilter(IMG *img, int xn, int yn, int zn, int tn, int verbose)
Definition imgfilter.c:624
int imgMeanZ(IMG *img1, IMG *img2)
Definition imgflips.c:157
float fmedian(float *data, long long int n)
Definition imgminmax.c:593
int imgRegionGrowingByThreshold(IMG *img, const int sz, const int sy, const int sx, float lthr, float uthr, IMG *mask, int verbose)
int tiffWriteImg(IMG *img, int plane, int frame, float *maxvalue, int colorscale, char *fname, int matXdim, int matYdim, int verbose, char *status)
Definition imgtiff.c:15
Header file for libtpcimgio.
#define IMG_TYPE_IMAGE
Header file for libtpcimgp.
#define PET_GRAYSCALE
Definition libtpcimgp.h:32
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
unsigned short int dimx
char type
float **** m
unsigned short int dimt
unsigned short int dimz
unsigned short int dimy
const char * statmsg