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

thresholding and filtering dynamic and parametric PET images. More...

#include "libtpcimgp.h"

Go to the source code of this file.

Functions

int imgThresholding (IMG *img, float threshold_level, long long *thr_nr)
 
int imgThresholdingLowHigh (IMG *img, float lower_threshold_level, float upper_threshold_level, IMG *timg, long long *lower_thr_nr, long long *upper_thr_nr)
 
int imgThresholdMaskCount (IMG *img, float minValue, float maxValue, IMG *timg, long long *count)
 
int imgThresholdMask (IMG *img, float minValue, float maxValue, IMG *timg)
 
int imgThresholdByMask (IMG *img, IMG *templt, float thrValue)
 
void imgCutoff (IMG *image, float cutoff, int mode)
 
int imgOutlierFilter (IMG *img, float limit)
 
int imgRegionGrowingByThreshold (IMG *img, const int sz, const int sy, const int sx, float lthr, float uthr, IMG *mask, int verbose)
 

Detailed Description

thresholding and filtering dynamic and parametric PET images.

Author
Vesa Oikonen

Definition in file imgthreshold.c.

Function Documentation

◆ imgCutoff()

void imgCutoff ( IMG * image,
float cutoff,
int mode )

Pixel values that exceed or go under a user-defined limit are set to that limit value.

See also
imgFast3DGaussianFilter, imgThresholdingLowHigh, imgAverageAUC, imgsegmThreshold, imgAverageTAC, imgMinMax
Parameters
imagePointer to IMG struct which will be filtered here.
cutoffCut-off value.
modeMode of operation: 0=pixels exceeding the limit are cut off, 1=pixels which go under the limit are cut off.

Definition at line 306 of file imgthreshold.c.

314 {
315 int zi, yi, xi, ti;
316
317 if(mode==0) {
318 for(zi=0; zi<image->dimz; zi++)
319 for(yi=0; yi<image->dimy; yi++)
320 for(xi=0; xi<image->dimx; xi++)
321 for(ti=0; ti<image->dimt; ti++)
322 if(image->m[zi][yi][xi][ti]>cutoff) image->m[zi][yi][xi][ti]=cutoff;
323 } else {
324 for(zi=0; zi<image->dimz; zi++)
325 for(yi=0; yi<image->dimy; yi++)
326 for(xi=0; xi<image->dimx; xi++)
327 for(ti=0; ti<image->dimt; ti++)
328 if(image->m[zi][yi][xi][ti]<cutoff) image->m[zi][yi][xi][ti]=cutoff;
329 }
330 return;
331}
unsigned short int dimx
float **** m
unsigned short int dimt
unsigned short int dimz
unsigned short int dimy

◆ imgOutlierFilter()

int imgOutlierFilter ( IMG * img,
float limit )

Filter out pixels that are over limit x higher than their closest 8 neighbour pixels.

See also
imgFast2DGaussianFilter, imgFast3DGaussianFilter, imgThresholdingLowHigh
Returns
Returns the nr of filtered pixels, and negative value in case of an error.
Parameters
imgPointer to IMG struct which will be filtered here.
limitCut-off value.

Definition at line 339 of file imgthreshold.c.

344 {
345 int zi, yi, xi, fi;
346 long long nr=0;
347 float f;
348 IMG tmp;
349
350 if(img->status!=IMG_STATUS_OCCUPIED || img->dimt<1) return(-1);
351 imgInit(&tmp);
352 if(imgAllocate(&tmp, img->dimz, img->dimy, img->dimx, 1)!=0) return(-2);
353 /* Process one frame at a time */
354 for(fi=0; fi<img->dimt; fi++) {
355 /* Copy one frame to safety */
356 for(zi=0; zi<tmp.dimz; zi++)
357 for(yi=0; yi<tmp.dimy; yi++)
358 for(xi=0; xi<tmp.dimx; xi++)
359 tmp.m[zi][yi][xi][0]=img->m[zi][yi][xi][fi];
360 /* Go through it */
361 for(zi=0; zi<img->dimz; zi++) {
362 for(yi=1; yi<img->dimy-1; yi++) for(xi=1; xi<img->dimx-1; xi++) {
363 f=tmp.m[zi][yi][xi-1][0]+
364 tmp.m[zi][yi][xi+1][0]+
365 tmp.m[zi][yi-1][xi][0]+
366 tmp.m[zi][yi+1][xi][0]+
367 tmp.m[zi][yi+1][xi-1][0]+
368 tmp.m[zi][yi+1][xi+1][0]+
369 tmp.m[zi][yi-1][xi-1][0]+
370 tmp.m[zi][yi-1][xi+1][0];
371 f/=8.0;
372 if(img->m[zi][yi][xi][fi]>(limit*f)) {img->m[zi][yi][xi][fi]=f; nr++;}
373 }
374 } /* next plane */
375 } /* next frame */
376 imgEmpty(&tmp);
377
378 return(nr);
379}
int imgAllocate(IMG *image, int planes, int rows, int columns, int frames)
Definition img.c:194
void imgEmpty(IMG *image)
Definition img.c:121
void imgInit(IMG *image)
Definition img.c:60
#define IMG_STATUS_OCCUPIED
char status

◆ imgRegionGrowingByThreshold()

int imgRegionGrowingByThreshold ( IMG * img,
const int sz,
const int sy,
const int sx,
float lthr,
float uthr,
IMG * mask,
int verbose )

Seeded region growing based on thresholds.

Calls itself recursively until neighbouring pixels fall outside thresholds. Because of recursion, program which uses this function needs a large space for stack.

See also
imgMaskErode, imgMaskDilate, imgsegmClusterExpand
Returns
Returns 0, if seed pixel was added to mask, and 1 if not, and >1 in case of an error.
Parameters
imgPointer to static image data, to which the threshold is applied.
szSeed pixel position [z,y,x] as indices.
sySeed pixel position [z,y,x] as indices.
sxSeed pixel position [z,y,x] as indices.
lthrLower threshold as absolute value.
uthrUpper threshold as absolute value.
maskPointer to mask image; must have the same dimensions as the static image.
verboseVerbose level; if zero, then only warnings are printed into stderr.

Definition at line 394 of file imgthreshold.c.

411 {
412 if(verbose>0) {
413 printf("imgRegionGrowingByThreshold(img, %d, %d, %d, %g, %g, mask, %d)\n",
414 sz, sy, sx, lthr, uthr, verbose);
415 fflush(stdout);
416 }
417 if(img==NULL || img->status!=IMG_STATUS_OCCUPIED) return(2);
418 if(mask==NULL || mask->status!=IMG_STATUS_OCCUPIED) return(3);
419 if(img->dimz!=mask->dimz || img->dimy!=mask->dimy || img->dimx!=mask->dimx) return(4);
420 int dimz=img->dimz, dimy=img->dimy, dimx=img->dimx;
421
422 /* Check that seed pixel resides inside image volume */
423 if(sz<0 || sy<0 || sx<0 || sz>=dimz || sy>=dimy || sx>=dimx) {
424 if(verbose>1) printf("pixels does not reside inside image\n");
425 return(1);
426 }
427
428 /* Check that seed pixel is not already part of mask */
429 if(mask->m[sz][sy][sx][0]>0.5) {
430 if(verbose>1) printf("seed already belongs to mask\n");
431 return(1);
432 }
433
434 /* Threshold */
435 if(img->m[sz][sy][sx][0]<lthr || img->m[sz][sy][sx][0]>uthr) {
436 if(verbose>1) {
437 printf(" [%d][%d][%d] outside thresholds\n", sz, sy, sx);
438 fflush(stdout);
439 }
440 mask->m[sz][sy][sx][0]=0.0;
441 return(1);
442 }
443 if(verbose>1) {
444 printf(" [%d][%d][%d] added to mask\n", sz, sy, sx);
445 fflush(stdout);
446 }
447 mask->m[sz][sy][sx][0]=1.0;
448
449 /* Check the neighbouring pixels */
450 int nsz, nsy, nsx;
451 nsz=sz; nsy=sy; nsx=sx-1;
452 imgRegionGrowingByThreshold(img, nsz, nsy, nsx, lthr, uthr, mask, verbose);
453 nsz=sz; nsy=sy; nsx=sx+1;
454 imgRegionGrowingByThreshold(img, nsz, nsy, nsx, lthr, uthr, mask, verbose);
455 nsz=sz; nsy=sy-1; nsx=sx;
456 imgRegionGrowingByThreshold(img, nsz, nsy, nsx, lthr, uthr, mask, verbose);
457 nsz=sz; nsy=sy+1; nsx=sx;
458 imgRegionGrowingByThreshold(img, nsz, nsy, nsx, lthr, uthr, mask, verbose);
459 nsz=sz-1; nsy=sy; nsx=sx;
460 imgRegionGrowingByThreshold(img, nsz, nsy, nsx, lthr, uthr, mask, verbose);
461 nsz=sz+1; nsy=sy; nsx=sx;
462 imgRegionGrowingByThreshold(img, nsz, nsy, nsx, lthr, uthr, mask, verbose);
463
464 return(0);
465}
int imgRegionGrowingByThreshold(IMG *img, const int sz, const int sy, const int sx, float lthr, float uthr, IMG *mask, int verbose)

Referenced by imgRegionGrowingByThreshold().

◆ imgThresholdByMask()

int imgThresholdByMask ( IMG * img,
IMG * templt,
float thrValue )

Threshold IMG by a mask image (template).

Sets pixel values in img to thrValue, if corresponding pixel value in template is == 0. Only first frame of template is used.

See also
imgThresholdMask, imgThresholdMaskCount, imgMaskTAC
Returns
Returns 0, if ok.
Parameters
imgImage to threshold.
templtThreshold template (mask image with 1 frame) where 0=cut off.
thrValueValue which is written in cut off pixels.

Definition at line 282 of file imgthreshold.c.

289 {
290 if(img->status!=IMG_STATUS_OCCUPIED) return(1);
291 if(templt->status!=IMG_STATUS_OCCUPIED) return(2);
292 for(int zi=0; zi<img->dimz; zi++)
293 for(int yi=0; yi<img->dimy; yi++) for(int xi=0; xi<img->dimx; xi++)
294 if(templt->m[zi][yi][xi][0]==0.0) {
295 for(int fi=0; fi<img->dimt; fi++) img->m[zi][yi][xi][fi]=thrValue;
296 }
297 return(0);
298}

◆ imgThresholding()

int imgThresholding ( IMG * img,
float threshold_level,
long long * thr_nr )

Threshold dynamic or static IMG data.

Pixel time-activity curves (TACs) which have AUC less than Threshold*Max_AUC will be set to zero.

See also
imgsegmThresholdByMask, imgThresholdingLowHigh, imgFast3DGaussianFilter, imgsegmThreshold, imgMax, imgMinMax, imgFrameIntegral
Returns
Returns 0, if ok.
Parameters
imgIMG data.
threshold_levelThreshold level, e.g. 0.50 will set to zero all pixels that are less than 50% of maximum pixel.
thr_nrNumber of pixels that will fall below the threshold level; give NULL pointer, if not needed.

Definition at line 19 of file imgthreshold.c.

26 {
27 int zi, yi, xi, fi, ret;
28 long long nr=0;
29 IMG aucimg;
30 float maxauc, thr_limit;
31
32 if(img->status!=IMG_STATUS_OCCUPIED) return(1);
33 if(img->dimt>1) { // dynamic image
34 /* Calculate AUC image */
35 imgInit(&aucimg);
36 ret=imgFrameIntegral(img, 0, img->dimt-1, &aucimg, 0);
37 if(ret) return(ret);
38 /* Search the max AUC */
39 ret=imgMax(&aucimg, &maxauc); if(ret) {imgEmpty(&aucimg); return(ret);}
40 /* Calculate the limit value */
41 thr_limit=threshold_level*maxauc;
42 /* Set to zero the pixels with AUC less than this limit */
43 for(zi=0; zi<img->dimz; zi++)
44 for(yi=0; yi<img->dimy; yi++)
45 for(xi=0; xi<img->dimx; xi++)
46 if(aucimg.m[zi][yi][xi][0]<thr_limit) {
47 for(fi=0; fi<img->dimt; fi++) img->m[zi][yi][xi][fi]=0.0;
48 nr++;
49 }
50 imgEmpty(&aucimg);
51 } else { // static image
52 /* Search the max value */
53 ret=imgMax(img, &maxauc); if(ret) return(ret);
54 /* Calculate the limit value */
55 thr_limit=threshold_level*maxauc;
56 /* Set to zero the pixels with AUC less than this limit */
57 for(zi=0; zi<img->dimz; zi++)
58 for(yi=0; yi<img->dimy; yi++)
59 for(xi=0; xi<img->dimx; xi++)
60 if(img->m[zi][yi][xi][0]<thr_limit) {
61 for(fi=0; fi<img->dimt; fi++) img->m[zi][yi][xi][fi]=0.0;
62 nr++;
63 }
64 }
65 if(thr_nr!=NULL) *thr_nr=nr;
66 return(0);
67}
int imgFrameIntegral(IMG *img, int first, int last, IMG *iimg, int verbose)
Definition imgarithm.c:346
int imgMax(IMG *img, float *maxvalue)
Definition imgminmax.c:15

◆ imgThresholdingLowHigh()

int imgThresholdingLowHigh ( IMG * img,
float lower_threshold_level,
float upper_threshold_level,
IMG * timg,
long long * lower_thr_nr,
long long * upper_thr_nr )

Threshold dynamic or static IMG data.

Checks whether pixel AUCs are lower or higher than the specified threshold levels * Max_AUC. Those pixel TACs are set to zero, or alternatively, if mask IMG is given, corresponding mask image pixel is set to 0.

See also
imgsegmThresholdByMask, imgVoiMaskTAC, imgMaskTAC, imgsegmThreshold, imgFrameIntegral
Returns
Returns 0, if ok.
Parameters
img(Dynamic) IMG data.
lower_threshold_levelLower threshold level, e.g. 0.10 will set to zero all pixels that are less than 10% of maximum pixel
upper_threshold_levelUpper threshold level, e.g. 0.90 will set to zero all pixels that are over 90% of maximum pixel
timgMask image; if empty, then it will be allocated here; if pre-allocated, then mask image value changed to 0 when necessary, but 0 is never changed to 1; enter NULL, if original TACs are to be thresholded to zeroes
lower_thr_nrNumber of pixels that will fall below the lower threshold level; give NULL pointer, if not needed.
upper_thr_nrNumber of pixels rejected because above the upper threshold level; give NULL pointer, if not needed.

Definition at line 79 of file imgthreshold.c.

99 {
100 int zi, yi, xi, fi, ret;
101 long long lnr=0, unr=0;
102 IMG aucimg;
103 float maxauc, lower_thr_limit, upper_thr_limit;
104
105 if(img->status!=IMG_STATUS_OCCUPIED) return(1);
106
107 /* Check if mask image is given and if it exists */
108 if(timg!=NULL && timg->status!=IMG_STATUS_OCCUPIED) {
109 /* Allocate memory for the mask data */
110 ret=imgAllocate(timg, img->dimz, img->dimy, img->dimx, 1);
111 if(ret) return(ret);
112 /* set mask image header information */
113 imgCopyhdr(img, timg);
114 timg->start[0]=img->start[0]; timg->end[0]=img->end[img->dimt-1];
115 timg->mid[0]=(timg->start[0]+timg->end[0])/2.0;
116 /* Initiate mask to 1 */
117 for(zi=0; zi<img->dimz; zi++)
118 for(yi=0; yi<img->dimy; yi++)
119 for(xi=0; xi<img->dimx; xi++)
120 timg->m[zi][yi][xi][0]=1.0;
121 } else if(timg!=NULL) {
122 /* Check that mask dimensions are ok */
123 if(timg->dimz!=img->dimz || timg->dimy!=img->dimy || timg->dimx!=img->dimx) return 2;
124 if(timg->dimt<1) return 3;
125 }
126
127 /* Threshold */
128 if(img->dimt>1) { // dynamic image
129 /* Calculate AUC image */
130 imgInit(&aucimg);
131 ret=imgFrameIntegral(img, 0, img->dimt-1, &aucimg, 0);
132 if(ret) return(ret);
133 /* Search the max AUC */
134 ret=imgMax(&aucimg, &maxauc); if(ret) {imgEmpty(&aucimg); return(ret);}
135 /* Calculate the limit values */
136 lower_thr_limit=lower_threshold_level*maxauc;
137 upper_thr_limit=upper_threshold_level*maxauc;
138 /* Set to zero the pixels with AUC less/more than these limits */
139 for(zi=0; zi<img->dimz; zi++)
140 for(yi=0; yi<img->dimy; yi++)
141 for(xi=0; xi<img->dimx; xi++)
142 if(aucimg.m[zi][yi][xi][0]<lower_thr_limit) {
143 if(timg==NULL) for(fi=0; fi<img->dimt; fi++) img->m[zi][yi][xi][fi]=0.0;
144 else timg->m[zi][yi][xi][0]=0.0;
145 lnr++;
146 } else if(aucimg.m[zi][yi][xi][0]>upper_thr_limit) {
147 if(timg==NULL) for(fi=0; fi<img->dimt; fi++) img->m[zi][yi][xi][fi]=0.0;
148 else timg->m[zi][yi][xi][0]=0.0;
149 unr++;
150 }
151 imgEmpty(&aucimg);
152 } else { // static image
153 /* Search the max value */
154 ret=imgMax(img, &maxauc); if(ret) return(ret);
155 /* Calculate the limit values */
156 lower_thr_limit=lower_threshold_level*maxauc;
157 upper_thr_limit=upper_threshold_level*maxauc;
158 /* Set to zero the pixels with AUC less/more than these limits */
159 for(zi=0; zi<img->dimz; zi++)
160 for(yi=0; yi<img->dimy; yi++)
161 for(xi=0; xi<img->dimx; xi++)
162 if(img->m[zi][yi][xi][0]<lower_thr_limit) {
163 if(timg==NULL) for(fi=0; fi<img->dimt; fi++) img->m[zi][yi][xi][fi]=0.0;
164 else timg->m[zi][yi][xi][0]=0.0;
165 lnr++;
166 } else if(img->m[zi][yi][xi][0]>upper_thr_limit) {
167 if(timg==NULL) for(fi=0; fi<img->dimt; fi++) img->m[zi][yi][xi][fi]=0.0;
168 else timg->m[zi][yi][xi][0]=0.0;
169 unr++;
170 }
171 }
172
173 if(lower_thr_nr!=NULL) *lower_thr_nr=lnr;
174 if(upper_thr_nr!=NULL) *upper_thr_nr=unr;
175 return(0);
176}
int imgCopyhdr(IMG *image1, IMG *image2)
Definition img.c:471
float * start
float * end
float * mid

◆ imgThresholdMask()

int imgThresholdMask ( IMG * img,
float minValue,
float maxValue,
IMG * timg )

Creates a mask (template) image based on lower and upper threshold values.

This function allocates memory for the mask image. If pixel value in original image is >=minValue and <=maxValue, the corresponding mask pixel is set to 1, otherwise to 0. Only the first frame of images are used.

See also
imgThresholdMaskCount, imgsegmThresholdByMask, imgAverageMaskTAC, imgMinMax, imgMaskDilate, imgMaskErode, imgThresholdingLowHigh, imgsegmThreshold
Returns
Returns 0 if ok.
Parameters
imgOriginal image; only first frame is used here.
minValueLower threshold.
maxValueUpper threshold.
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.

Definition at line 257 of file imgthreshold.c.

268 {
269 return(imgThresholdMaskCount(img, minValue, maxValue, timg, NULL));
270}
int imgThresholdMaskCount(IMG *img, float minValue, float maxValue, IMG *timg, long long *count)

◆ imgThresholdMaskCount()

int imgThresholdMaskCount ( IMG * img,
float minValue,
float maxValue,
IMG * timg,
long long * count )

Creates a mask (template) image based on lower and upper threshold values.

This function allocates memory for the mask image. If pixel value in original image is >=minValue and <=maxValue, the corresponding mask pixel is set to 1, otherwise to 0. Only the first frame of images are used.

See also
imgThresholdMask, imgThresholdByMask, imgsegmThresholdByMask, imgMaskRoiNr, imgMaskDilate, imgMaskErode, imgMinMax
Returns
Returns 0 if ok.
Parameters
imgOriginal image; only first frame is used here.
minValueLower threshold.
maxValueUpper threshold.
timgMask image; if empty, then it will be allocated here; if pre-allocated, then template value changed to 0 when necessary, but 0 is never changed to 1.
countThe number of pixels that pass the threshold limits is written here; set to NULL if not needed.

Definition at line 191 of file imgthreshold.c.

205 {
206 int fi=0, zi, xi, yi, ret;
207
208 if(img->status!=IMG_STATUS_OCCUPIED) return(1);
209 if(count!=NULL) *count=0;
210 /* Check if mask image exists */
211 if(timg->status!=IMG_STATUS_OCCUPIED) {
212 /* Allocate memory for the template data */
213 ret=imgAllocate(timg, img->dimz, img->dimy, img->dimx, 1);
214 if(ret) return(ret);
215 /* set mask image header information */
216 imgCopyhdr(img, timg);
217 timg->start[0]=img->start[0]; timg->end[0]=img->end[img->dimt-1];
218 timg->mid[0]=(timg->start[0]+timg->end[0])/2.0;
219 /* Initiate template to 1 */
220 for(zi=0; zi<img->dimz; zi++)
221 for(yi=0; yi<img->dimy; yi++)
222 for(xi=0; xi<img->dimx; xi++)
223 timg->m[zi][yi][xi][0]=1.0;
224 } else {
225 /* Check that mask image dimensions are ok */
226 if(timg->dimz!=img->dimz || timg->dimy!=img->dimy || timg->dimx!=img->dimx)
227 return 2;
228 if(timg->dimt<1) return(3);
229 }
230 /* Set mask contents */
231 fi=0;
232 long long n=0;
233 for(zi=0; zi<img->dimz; zi++)
234 for(yi=0; yi<img->dimy; yi++)
235 for(xi=0; xi<img->dimx; xi++) {
236 /*printf("pxl=%g (%g - %g)\n", img->m[zi][yi][xi][fi], minValue, maxValue);*/
237 if(img->m[zi][yi][xi][fi]<minValue || img->m[zi][yi][xi][fi]>maxValue)
238 timg->m[zi][yi][xi][0]=0.0;
239 else n++;
240 }
241 if(count!=NULL) *count=n;
242 return(0);
243}

Referenced by imgMaskRegionLabeling(), and imgThresholdMask().