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

Functions for processing mask images. More...

#include "libtpcimgp.h"

Go to the source code of this file.

Functions

long long imgMaskCount (IMG *img)
int imgMaskErode (IMG *img, IMG *se)
int imgMaskDilate (IMG *img, IMG *se)
int imgStructuringElement (IMG *img, const int structuring_element, int verbose)
void imgMaskInvert (IMG *img)
int imgMaskConjunction (IMG *mask1, IMG *mask2)
int imgMaskRegionLabeling (IMG *mask1, IMG *mask2, int *n, int verbose)
int imgMaskFloodFill (IMG *m, int sz, int sy, int sx, int label, long long *n, int verbose)
int imgMaskCloak (IMG *img, int dim, float id)

Detailed Description

Functions for processing mask images.

Author
Vesa Oikonen

Definition in file mask.c.

Function Documentation

◆ imgMaskCloak()

int imgMaskCloak ( IMG * img,
int dim,
float id )

Cloak mask.

See also
imgMaskDilate, imgMaskErode
Returns
Returns 0 when successful.
Parameters
imgPointer to 2D/3D mask image.
dimCloak the existing mask in xy (2) or xyz (3) dimensions.
idId number for the cloak mask. Should be different from existing IDs.

Definition at line 429 of file mask.c.

436 {
437 if(img==NULL) return(1);
438 int dimx=img->dimx, dimy=img->dimy, dimz=img->dimz;
439 if(dimx<1 || dimy<1 || dimz<1) return(2);
440
441 for(int z=0; z<dimz; z++) {
442 for(int y=0; y<dimy; y++) {
443 for(int x=0; x<dimx; x++) if(!(img->m[z][y][x][0]<0.5) && img->m[z][y][x][0]!=id) {
444 int x1=x, x2=x, y1=y, y2=y, z1=z, z2=z;
445 if(x>0) x1=x-1;
446 if(x<dimx-1) x2=x+1;
447 if(y>0) y1=y-1;
448 if(y<dimy-1) y2=y+1;
449 if(dim==3) {
450 if(z>0) z1=z-1;
451 if(z<dimz-1) z2=z+1;
452 }
453 for(int nz=z1; nz<=z2; nz++)
454 for(int ny=y1; ny<=y2; ny++)
455 for(int nx=x1; nx<=x2; nx++)
456 if(z!=nz || y!=ny || x!=nx)
457 if(img->m[nz][ny][nx][0]<0.5)
458 img->m[nz][ny][nx][0]=id;
459 }
460 }
461 }
462
463 return(0);
464}
unsigned short int dimx
float **** m
unsigned short int dimz
unsigned short int dimy

◆ imgMaskConjunction()

int imgMaskConjunction ( IMG * mask1,
IMG * mask2 )

Conjunction (AND, wedge) for two 3D mask images.

See also
imgMaskInv, imgMaskDilate, imgMaskCount, imgMaskFloodFill
Returns
Returns 0 when successful.
Parameters
mask1Pointer to IMG structure containing the first mask image; will be overwritten by the conjunction mask.
mask2Pointer to IMG structure containing the second mask image; not modified.

Definition at line 238 of file mask.c.

244 {
245 if(mask1==NULL || mask2==NULL) return(1);
246 if(mask1->dimx<1 || mask1->dimy<1 || mask1->dimz<1) return(2);
247 if(mask1->dimx!=mask2->dimx) return(3);
248 if(mask1->dimy!=mask2->dimy) return(4);
249 if(mask1->dimz!=mask2->dimz) return(5);
250
251 int zi, yi, xi;
252 for(zi=0; zi<mask1->dimz; zi++)
253 for(yi=0; yi<mask1->dimy; yi++)
254 for(xi=0; xi<mask1->dimx; xi++) {
255 if(fabs(mask1->m[zi][yi][xi][0])<1.0E-12 ||
256 fabs(mask2->m[zi][yi][xi][0])<1.0E-12)
257 {
258 mask1->m[zi][yi][xi][0]=0.0;
259 } else {
260 mask1->m[zi][yi][xi][0]=1.0;
261 }
262 }
263
264 return(0);
265}

◆ imgMaskCount()

long long imgMaskCount ( IMG * img)

Count the nr of positive values inside 3D mask image.

See also
imgMaskRoiNr, imgThresholdMask, imgMaskInvert, imgMaskFloodFill
Returns
Returns the number of positive voxels.
Parameters
imgPointer to mask IMG structure.

Definition at line 15 of file mask.c.

18 {
19 long long n=0;
20 int zi, yi, xi;
21 for(zi=0; zi<img->dimz; zi++)
22 for(yi=0; yi<img->dimy; yi++)
23 for(xi=0; xi<img->dimx; xi++)
24 if(img->m[zi][yi][xi][0]>0.0) n++;
25 return(n);
26}

◆ imgMaskDilate()

int imgMaskDilate ( IMG * img,
IMG * se )

Dilate the 3D mask image.

See also
imgStructuringElement, imgMaskErode, imgMaskCloak, imgMaskCount, imgMaskFloodFill, imgSwell
Returns
Returns the number of dilated voxels, or <0 in case of an error.
Parameters
imgPointer to IMG structure containing the mask image.
sePointer to IMG structure containing the structuring element; all dimensions must be odd numbers.

Definition at line 80 of file mask.c.

86 {
87 if(img==NULL || se==NULL) return(-1);
88 if(img->dimx<1 || img->dimy<1 || img->dimz<1) return(-2);
89 if(se->dimx<1 || se->dimy<1 || se->dimz<1) return(-3);
90 if(se->dimx%2==0 || se->dimy%2==0 || se->dimz%2==0) return(-4);
91
92
93 /* make a copy of original data */
94 IMG orig; imgInit(&orig);
95 if(imgDup(img, &orig)!=0) return(-5);
96 long long n=0;
97 int zi, yi, xi, zj, yj, xj;
98 for(zi=0; zi<orig.dimz; zi++)
99 for(yi=0; yi<orig.dimy; yi++)
100 for(xi=0; xi<orig.dimx; xi++)
101 if(orig.m[zi][yi][xi][0]==0.0) {
102 int zs, ys, xs;
103 float mav=-1.0E+20;
104 for(zs=0; zs<se->dimz; zs++)
105 for(ys=0; ys<se->dimy; ys++)
106 for(xs=0; xs<se->dimx; xs++)
107 if(se->m[zs][ys][xs][0]>0.0) {
108 zj=zi+(zs-se->dimz/2); if(zj<0 || zj>=orig.dimz) continue;
109 yj=yi+(ys-se->dimy/2); if(yj<0 || yj>=orig.dimy) continue;
110 xj=xi+(xs-se->dimx/2); if(xj<0 || xj>=orig.dimx) continue;
111 if(orig.m[zj][yj][xj][0]>mav) mav=orig.m[zj][yj][xj][0];
112 }
113 if(mav>0.0) {img->m[zi][yi][xi][0]=mav; n++;}
114 }
115 imgEmpty(&orig);
116
117 return(n);
118}
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

◆ imgMaskErode()

int imgMaskErode ( IMG * img,
IMG * se )

Erode the 3D mask image.

See also
imgStructuringElement, imgMaskDilate, imgMaskCount, imgShrink
Returns
Returns the number of eroded voxels, or <0 in case of an error.
Parameters
imgPointer to IMG structure containing the mask image.
sePointer to IMG structure containing the structuring element; all dimensions must be odd numbers.

Definition at line 34 of file mask.c.

40 {
41 if(img==NULL || se==NULL) return(-1);
42 if(img->dimx<1 || img->dimy<1 || img->dimz<1) return(-2);
43 if(se->dimx<1 || se->dimy<1 || se->dimz<1) return(-3);
44 if(se->dimx%2==0 || se->dimy%2==0 || se->dimz%2==0) return(-4);
45
46
47 /* make a copy of original data */
48 IMG orig; imgInit(&orig);
49 if(imgDup(img, &orig)!=0) return(-5);
50 long long n=0;
51 int zi, yi, xi, zj, yj, xj;
52 for(zi=0; zi<orig.dimz; zi++)
53 for(yi=0; yi<orig.dimy; yi++)
54 for(xi=0; xi<orig.dimx; xi++)
55 if(orig.m[zi][yi][xi][0]>0.0) {
56 int zs, ys, xs;
57 float miv=+1.0E+20;
58 for(zs=0; zs<se->dimz; zs++)
59 for(ys=0; ys<se->dimy; ys++)
60 for(xs=0; xs<se->dimx; xs++)
61 if(se->m[zs][ys][xs][0]>0.0) {
62 zj=zi+(zs-se->dimz/2); if(zj<0 || zj>=orig.dimz) continue;
63 yj=yi+(ys-se->dimy/2); if(yj<0 || yj>=orig.dimy) continue;
64 xj=xi+(xs-se->dimx/2); if(xj<0 || xj>=orig.dimx) continue;
65 if(orig.m[zj][yj][xj][0]<miv) miv=orig.m[zj][yj][xj][0];
66 }
67 if(!(miv>1.0E-20)) {img->m[zi][yi][xi][0]=0.0; n++;}
68 }
69 imgEmpty(&orig);
70
71 return(n);
72}

◆ imgMaskFloodFill()

int imgMaskFloodFill ( IMG * m,
int sz,
int sy,
int sx,
int label,
long long * n,
int verbose )

Flood filling for the Region labelling.

Processes only the first frame, even if several do exist.

Based on Burger W and Burge MJ: Principles of Digital Image Processing - Core Algorithms, Springer, 2009, DOI 10.1007/978-1-84800-195-4.

See also
imgMaskRegionLabeling, imgMaskErode, imgMaskCount, imgMaskConjunction, imgMaskRoiNr
Returns
Returns 0 when successful.
Parameters
mPointer to IMG structure containing the mask image to be flood filled. Pixels with value 1 are flood filled with label, pixels with value <1 are considered as background, and pixels with values >1 are considered to belong to another already labelled region.
szZ coordinate of the starting point [0..dimz-1].
syY coordinate of the starting point [0..dimy-1].
sxX coordinate of the starting point [0..dimx-1].
labelThe label to be assigned to the region; at least 2.
nThe number of pixels that got labelled; enter NULL, if not needed.
verboseVerbose level; if zero, then nothing is printed into stdout or stderr.

Definition at line 352 of file mask.c.

370 {
371 if(verbose>0) {
372 printf("%s(mask, %d, %d, %d, %d)\n", __func__, sz, sy, sx, label);
373 fflush(stdout);
374 }
375 if(m==NULL || m->status!=IMG_STATUS_OCCUPIED) return(1);
376 if(m->dimx<1 || m->dimy<1 || m->dimz<1) return(2);
377 if(sx<0 || sy<0 || sz<0 || sx>=m->dimx || sy>=m->dimy || sz>=m->dimz) return(3);
378 if(label<2) return(4);
379 if(n!=NULL) *n=0;
380
381 /* Create empty stack of pixel coordinates */
382 IMG_PIXELS pxls; pxlInit(&pxls);
383
384 /* Put the start coordinate into the stack */
385 IMG_PIXEL pxl; pxl.x=sx; pxl.y=sy; pxl.z=sz;
386 if(pxlAdd(&pxls, &pxl)!=0) {
387 if(verbose>0) fprintf(stderr, "Error: cannot add seed pixel to stack.\n");
388 pxlFree(&pxls); return(11);
389 }
390
391 /* Process the stack until empty */
392 unsigned long long int pxlNr=0;
393 while(pxls.pxlNr>0) {
394 /* Take the last pixel from the list */
395 if(pxlGet(&pxls, pxls.pxlNr-1, &pxl)!=0) break;
396 pxls.pxlNr--;
397 /* Should this pixel be labelled? */
398 if(verbose>100) printf(" m[%d][%d][%d] := %g\n", pxl.z, pxl.y, pxl.x, m->m[pxl.z][pxl.y][pxl.x][0]);
399 if(pxl.z<0 || pxl.z>=m->dimz || pxl.y<0 || pxl.y>=m->dimy || pxl.x<0 || pxl.x>=m->dimx)
400 continue; // certainly not since outside of the image
401 if(m->m[pxl.z][pxl.y][pxl.x][0]!=1.0) continue; // no since labelled or part of background
402 m->m[pxl.z][pxl.y][pxl.x][0]=(float)label; // yes
403 if(verbose>100) printf(" -> m[%d][%d][%d] := %g\n", pxl.z, pxl.y, pxl.x, m->m[pxl.z][pxl.y][pxl.x][0]);
404 pxlNr++;
405 /* Add the 26 neighbours to the beginning of the stack */
406 if(pxlMakeRoom(&pxls, 0, 26)!=0) break;
407 if(pxls.pxlNr==0) pxls.pxlNr=26;
408 if(verbose>100) printf(" pxls.pxlNr := %lld\n", pxls.pxlNr);
409 unsigned long long int i=0;
410 for(int dz=-1; dz<2; dz++) for(int dy=-1; dy<2; dy++) for(int dx=-1; dx<2; dx++) {
411 if(dz==0 && dy==0 && dx==0) continue;
412 pxls.p[i].z=pxl.z+dz; pxls.p[i].y=pxl.y+dy; pxls.p[i].x=pxl.x+dx;
413 i++;
414 }
415 }
416 pxlFree(&pxls);
417 if(verbose>1) printf(" %lld pixels labelled.\n", pxlNr);
418 if(n!=NULL) *n=pxlNr;
419 if(pxlNr==0) return(21);
420 return(0);
421}
int pxlMakeRoom(IMG_PIXELS *list, long long int i, long long int n)
Definition pixel.c:110
void pxlFree(IMG_PIXELS *pxl)
Definition pixel.c:28
#define IMG_STATUS_OCCUPIED
int pxlGet(IMG_PIXELS *list, long long int i, IMG_PIXEL *pxl)
Definition pixel.c:163
int pxlAdd(IMG_PIXELS *list, IMG_PIXEL *pxl)
Definition pixel.c:139
void pxlInit(IMG_PIXELS *pxl)
Definition pixel.c:14
IMG_PIXEL * p
long long int pxlNr
char status

Referenced by imgMaskRegionLabeling().

◆ imgMaskInvert()

void imgMaskInvert ( IMG * img)

Invert the 3D mask image, setting zeroes to ones, and non-zeroes to zeroes.

Processes only the first frame, even if several do exist.

See also
imgMaskCount, imgMaskRoiNr, imgThresholdMask, imgMaskFloodFill
Parameters
imgPointer to mask IMG structure.

Definition at line 216 of file mask.c.

219 {
220 if(img==NULL) return;
221 int zi, yi, xi;
222 for(zi=0; zi<img->dimz; zi++)
223 for(yi=0; yi<img->dimy; yi++)
224 for(xi=0; xi<img->dimx; xi++)
225 if(fabs(img->m[zi][yi][xi][0])>1.0E-12)
226 img->m[zi][yi][xi][0]=0.0;
227 else
228 img->m[zi][yi][xi][0]=1.0;
229 return;
230}

◆ imgMaskRegionLabeling()

int imgMaskRegionLabeling ( IMG * mask1,
IMG * mask2,
int * n,
int verbose )

Region labelling with flood filling.

Processes only the first frame, even if several do exist.

Based on Burger W and Burge MJ: Principles of Digital Image Processing - Core Algorithms, Springer, 2009, DOI 10.1007/978-1-84800-195-4.

Returns
Returns 0 when successful.
See also
imgMaskFloodFill
Parameters
mask1Pointer to IMG structure containing the mask image to be region labelled; not modified. All pixels with value < 0.1 are considered to belong to background, others to foreground.
mask2Pointer to an empty but initiated IMG structure for the output, the region labelled mask image.
nThe number of regions that were found; enter NULL, if not needed.
verboseVerbose level; if zero, then nothing is printed into stdout or stderr

Definition at line 279 of file mask.c.

291 {
292 if(verbose>0) {printf("%s()\n", __func__); fflush(stdout);}
293 if(mask1==NULL || mask2==NULL || mask1==mask2) return(1);
294 if(mask1->status!=IMG_STATUS_OCCUPIED) return(2);
295 if(mask1->dimx<1 || mask1->dimy<1 || mask1->dimz<1) return(3);
296 if(verbose>1) printf("mask dimensions := %d x %d x %d\n", mask1->dimx, mask1->dimy, mask1->dimz);
297 if(n!=NULL) *n=0;
298
299 /* Make a copy of the mask */
300 imgEmpty(mask2);
301 long long nr;
302 if(imgThresholdMaskCount(mask1, 0.1, 1.0E+22, mask2, &nr)!=0) {
303 if(verbose>0) fprintf(stderr, "Error: cannot make initial copy of mask.\n");
304 return(11);
305 }
306 if(nr==0) {
307 if(verbose>0) fprintf(stderr, "Warning: empty mask.\n");
308 return(0);
309 }
310 if(verbose>1) printf("mask contains %lld foreground pixels.\n", nr);
311 if(verbose>80) {
312 for(int zi=0; zi<mask2->dimz; zi++)
313 for(int yi=0; yi<mask2->dimy; yi++)
314 for(int xi=0; xi<mask2->dimx; xi++)
315 if(mask2->m[zi][yi][xi][0]!=0.0)
316 printf(" %d,%d,%d\n", zi, yi, xi);
317 }
318
319 /* Label regions */
320 int ret=0, nextLabel=2;
321 for(int zi=0; zi<mask2->dimz; zi++)
322 for(int yi=0; yi<mask2->dimy; yi++)
323 for(int xi=0; xi<mask2->dimx; xi++)
324 if(mask2->m[zi][yi][xi][0]==1.0) {
325 ret=imgMaskFloodFill(mask2, zi, yi, xi, nextLabel, &nr, verbose);
326 if(ret!=0) break;
327 if(verbose>2) printf("%lld pixels labelled as %d\n", nr, nextLabel);
328 nextLabel++;
329 }
330 if(ret!=0) {
331 if(verbose>0) fprintf(stderr, "Error: Flood fill failed.\n");
332 imgEmpty(mask2); return(21);
333 }
334 if(verbose>0) printf("%d regions labelled.\n", nextLabel-2);
335 if(n!=NULL) *n=nextLabel-2;
336
337 return(0);
338}
int imgThresholdMaskCount(IMG *img, float minValue, float maxValue, IMG *timg, long long *count)
int imgMaskFloodFill(IMG *m, int sz, int sy, int sx, int label, long long *n, int verbose)
Definition mask.c:352

◆ imgStructuringElement()

int imgStructuringElement ( IMG * img,
const int structuring_element,
int verbose )

Make 3D structuring element for eroding and dilation.

See also
imgMaskDilate, imgMaskErode
Returns
Returns 0 when successful.
Parameters
imgPointer to empty IMG struct for the element.
structuring_elementStructuring element:
  1. 3x3x3 cube
  2. rounded 3x3x3 cube (23 voxels)
  3. cube on its corner (star, consisting of 7 voxels).
verboseVerbose level; if zero, then only warnings are printed into stderr

Definition at line 126 of file mask.c.

137 {
138 if(img==NULL) return(1);
139 imgEmpty(img);
140
141 int ret=0;
142 if(structuring_element==1) {
143 if(verbose>0) printf("making cube as the structuring element\n");
144 ret=imgAllocate(img, 3, 3, 3, 1);
145 } else if(structuring_element==2) {
146 if(verbose>0) printf("making rounded cube as the structuring element\n");
147 ret=imgAllocate(img, 3, 3, 3, 1);
148 } else if(structuring_element==3) {
149 if(verbose>0) printf("making star as the structuring element\n");
150 ret=imgAllocate(img, 3, 3, 3, 1);
151 } else {
152 fprintf(stderr, "Error: unsupported structuring element.\n");
153 return(2);
154 }
155 if(verbose>0) {fflush(stdout);}
156 if(ret) {
157 fprintf(stderr, "Error: cannot allocate memory.\n");
158 imgEmpty(img);
159 return(3);
160 }
161
162 int z, y, x, n;
163
164 if(structuring_element==1) { // 3x3x3 cube
165 for(z=0; z<3; z++)
166 for(y=0; y<3; y++)
167 for(x=0; x<3; x++)
168 img->m[z][y][x][0]=1.0;
169 } else if(structuring_element==2) { // rounded 3x3x3 cube
170 for(z=0; z<3; z++)
171 for(y=0; y<3; y++)
172 for(x=0; x<3; x++)
173 if(z==1 || y==1 || x==1)
174 img->m[z][y][x][0]=1.0;
175 else
176 img->m[z][y][x][0]=0.0;
177 } else if(structuring_element==3) { // 7-voxel star
178 for(z=0; z<3; z++)
179 for(y=0; y<3; y++)
180 for(x=0; x<3; x++) {
181 n=0;
182 if(z==1) n++;
183 if(y==1) n++;
184 if(x==1) n++;
185 if(n>1)
186 img->m[z][y][x][0]=1.0;
187 else
188 img->m[z][y][x][0]=0.0;
189 }
190 }
191
192 if(verbose>3) {
193 int z, y, x;
194 printf("\nplanes 1-3\n");
195 for(x=0; x<3; x++) {
196 for(z=0; z<3; z++) {
197 for(y=0; y<3; y++)
198 printf(" %g", img->m[z][y][x][0]);
199 printf(" ");
200 }
201 printf("\n");
202 }
203 printf("\n");
204 }
205 return(0);
206}
int imgAllocate(IMG *image, int planes, int rows, int columns, int frames)
Definition img.c:194