TPCCLIB
Loading...
Searching...
No Matches
imgbkgrm.c File Reference

Set pixels in dynamic PET image to zero if their TACs seem to contain only noise. More...

Go to the source code of this file.

Functions

int imgBorderAverageTAC (IMG *img, float *tac, float *sd, float *med)
 
int imgNoiseTemplate (IMG *img, int keepNegat, int border, IMG *timg, int verbose, char *status)
 

Detailed Description

Set pixels in dynamic PET image to zero if their TACs seem to contain only noise.

Remarks
Application name was previously ebkgrm.
Author
Vesa Oikonen

Definition in file imgbkgrm.c.

Function Documentation

◆ imgBorderAverageTAC()

int imgBorderAverageTAC ( IMG * img,
float * tac,
float * sd,
float * med )

Calculates an average time-activity curve of all pixels at the x,y-border in the specified IMG data.

Border values can often be assumed to consist of background noise only. Z-borders are not included because imaging target usually extends over z-borders.

See also
imgAverageTAC, imgAverageMaskTAC
Returns
Returns 0, if ok.
Parameters
imgPointer to the image data.
tacPointer to an array, allocated for the size of img->dimt, where border pixel mean values will be written; enter NULL if not needed.
sdPointer to an array, allocated for the size of img->dimt, where border pixel s.d. values will be written; enter NULL if not needed.
medPointer to an array, allocated for the size of img->dimt, where border pixel median values will be written; enter NULL if not needed.

Definition at line 85 of file imgbkgrm.c.

97 {
98 if(img==NULL || img->status<IMG_STATUS_OCCUPIED) return(1);
99 if(tac==NULL && sd==NULL && med==NULL) return(0);
100
101 /* compute the TAC */
102 int pxlNr=img->dimz*(2*img->dimx+2*(img->dimy-2));
103 float a[pxlNr], fm, fs;
104 for(int fi=0; fi<img->dimt; fi++) {
105 int i=0;
106 for(int zi=0; zi<img->dimz; zi++) {
107 int yi, xi;
108 yi=0;
109 for(xi=0; xi<img->dimx; xi++) a[i++]=img->m[zi][yi][xi][fi];
110 yi=img->dimy-1;
111 for(xi=0; xi<img->dimx; xi++) a[i++]=img->m[zi][yi][xi][fi];
112 xi=0;
113 for(yi=1; yi<img->dimy-1; yi++) a[i++]=img->m[zi][yi][xi][fi];
114 xi=img->dimx-1;
115 for(yi=1; yi<img->dimy-1; yi++) a[i++]=img->m[zi][yi][xi][fi];
116 }
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;
121 }
122 if(med!=NULL) med[fi]=fmedian(a, pxlNr);
123 }
124 return(0);
125}
float fmean(float *data, long long int n, float *sd)
Definition imgminmax.c:618
float fmedian(float *data, long long int n)
Definition imgminmax.c:593
#define IMG_STATUS_OCCUPIED
unsigned short int dimx
float **** m
char status
unsigned short int dimt
unsigned short int dimz
unsigned short int dimy

Referenced by imgNoiseTemplate().

◆ imgNoiseTemplate()

int imgNoiseTemplate ( IMG * img,
int keepNegat,
int border,
IMG * timg,
int verbose,
char * status )

Creates a mask (template) image based on whether pixel TAC is closer to scaled mean TAC of the image data than to the zero, based on AICs.

Pixel considered as noise will lead to mask value 0, otherwise 1.

See also
imgThresholdByMask, imgRawCountsPerTime
Returns
Returns 0 if ok.
Parameters
imgOriginal dynamic image; if sinogram data, then divide by frame lengths first. If data does not contain frame times, then equal frame times are assumed.
keepNegatProcess pixels with AUC<0 normally (1), or consider as noise (0).
borderSet to 0 to compare pixels TACs to zero, or set to <>0 to compare to background TAC calculated as median of image x,y-border pixels.
timgMask image; if empty, then it will be allocated here; if pre-allocated, then mask pixel value changed to 0 when necessary, but 0 is never changed to 1.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.
statusPointer to a string (allocated for at least 64 chars) where error message or other execution status will be written; enter NULL, if not needed.

Definition at line 137 of file imgbkgrm.c.

154 {
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");
158 if(img==NULL || img->status!=IMG_STATUS_OCCUPIED) return(1);
159 if(timg==NULL) return(1);
160 if(timg->status==IMG_STATUS_OCCUPIED) {
161 if(img->dimx!=timg->dimx) return(2);
162 if(img->dimy!=timg->dimy) return(2);
163 if(img->dimz!=timg->dimz) return(2);
164 }
165 if(img->dimt<2) {
166 if(status!=NULL) strcpy(status, "method works only for dynamic data");
167 return(3);
168 }
169
170 int ret, n;
171
172 /*
173 * Compute the mean TAC of all pixels
174 */
175 n=img->dimt;
176 float fdur[n], meany[n], bkgtac[n];
177
178 if(verbose>1) fprintf(stdout, "computing mean of pixels\n");
179 if(imgExistentTimes(img)) {
180 for(int i=0; i<n; i++) fdur[i]=img->end[i]-img->start[i];
181 } else {
182 for(int i=0; i<n; i++) fdur[i]=1.0;
183 }
184 ret=imgAverageTAC(img, meany);
185 if(ret) {
186 if(status!=NULL) strcpy(status, "cannot calculate average TAC");
187 if(verbose>1) printf("ret := %d\n", ret);
188 return(4);
189 }
190
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");
197 return(4);
198 }
199
200 /* If requested, compute the background TAC as the mean of x,y-border pixels */
201 double bkg_tac_auc=0.0;
202 if(border==0) {
203 /* or just zeroes */
204 for(int i=0; i<n; i++) bkgtac[i]=0.0;
205 } else {
206 if(verbose>1) fprintf(stdout, "computing background from border pixels\n");
207 if(imgBorderAverageTAC(img, NULL, NULL, bkgtac)!=0) {
208 if(status!=NULL) strcpy(status, "cannot calculate background TAC");
209 return(5);
210 }
211 /* Compute AUC for background TAC */
212 for(int i=0; i<n; i++) bkg_tac_auc+=fdur[i]*bkgtac[i];
213 }
214 if(verbose>2) printf("bkg_tac_auc := %g\n", bkg_tac_auc);
215
216 /*
217 * Allocate the mask image, if not allocated already
218 */
219 int maskExisted=0;
220 if(timg->status==IMG_STATUS_OCCUPIED) {
221 /* Pre-existing mask contents are used later */
222 maskExisted=1;
223 } else {
224 ret=imgAllocateWithHeader(timg, img->dimz, img->dimy, img->dimx, 1, img);
225 if(ret) {
226 if(status!=NULL) strcpy(status, "cannot allocate memory for mask data");
227 return(6);
228 }
229 }
230
231 /*
232 * Go through all the pixels
233 */
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);
236 int zi, yi, xi;
237 for(zi=0; zi<img->dimz; zi++) {
238 for(yi=0; yi<img->dimy; yi++) {
239 for(xi=0; xi<img->dimx; xi++) {
240 /* If pixel was already masked out, then keep it that way */
241 if(maskExisted && timg->m[zi][yi][xi][0]<0.1) {
242 timg->m[zi][yi][xi][0]=0.0; continue;
243 }
244 /* Compute AUC for this pixel */
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];
247 /* If tacAUC<AUCbkg and user did not want to keep negatives, then remove it */
248 if(keepNegat==0 && pxl_tac_auc<=bkg_tac_auc) {
249 timg->m[zi][yi][xi][0]=0.0; continue;
250 }
251
252 /* Calculate WSS between this TAC and zero */
253 double wss0=0.0;
254 for(int i=0; i<n; i++) {
255 double g=img->m[zi][yi][xi][i];
256 wss0+=fdur[i]*g*g;
257 }
258
259 /* Calculate WSS between this TAC and background TAC */
260 double wss1=0.0;
261 for(int i=0; i<n; i++) {
262 double g=img->m[zi][yi][xi][i]-bkgtac[i];
263 wss1+=fdur[i]*g*g;
264 }
265
266 /* Calculate WSS between this TAC and scaled background TAC */
267 double wss2=0.0; double sf2=1.0;
268 if(bkg_tac_auc>1.0E-10) sf2=pxl_tac_auc/bkg_tac_auc;
269 if(sf2>2.0) sf2=2.0; // Limit for the scale
270 for(int i=0; i<n; i++) {
271 double g=img->m[zi][yi][xi][i]-sf2*bkgtac[i];
272 wss2+=fdur[i]*g*g;
273 }
274
275 /* Calculate WSS between this TAC and scaled mean TAC */
276 double wss3=0.0; double sf3=pxl_tac_auc/mean_tac_auc;
277 if(sf3<0.5) sf3=0.5; // Limit for the scale
278 for(int i=0; i<n; i++) {
279 double g=img->m[zi][yi][xi][i]-sf3*meany[i];
280 wss3+=fdur[i]*g*g;
281 }
282
283 /* Compute AICs */
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);
288 /* Conserve pixel value if aic3 is better than others */
289 if(aic3<aic0 && aic3<aic1 && aic3<aic2) {
290 timg->m[zi][yi][xi][0]=1.0;
291 } else {
292 timg->m[zi][yi][xi][0]=0.0;
293 }
294 if(verbose>10) {
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]);
303 }
304 }
305 }
306 } // next zi
307 if(verbose>1) fprintf(stdout, "... done.\n");
308
309
310 if(status!=NULL) strcpy(status, "ok");
311 return(0);
312}
double aicSS(double ss, const int n, const int k)
Definition aic.c:20
int imgExistentTimes(IMG *img)
Definition img.c:613
int imgAllocateWithHeader(IMG *image, int planes, int rows, int columns, int frames, IMG *image_from)
Definition img.c:279
int imgBorderAverageTAC(IMG *img, float *tac, float *sd, float *med)
Definition imgbkgrm.c:85
int imgAverageTAC(IMG *img, float *tac)
Definition imgeval.c:15
float * start
float * end