TPCCLIB
Loading...
Searching...
No Matches
libtpcidi.h File Reference

Header file for libtpcidi. More...

#include "tpcclibConfig.h"
#include "libtpcmisc.h"
#include "libtpcmodel.h"
#include "libtpcsvg.h"
#include "libtpccurveio.h"
#include "libtpcimgio.h"
#include "libtpcimgp.h"
#include "libtpcmodext.h"

Go to the source code of this file.

Functions

int imgCircleMask (IMG *img, int zi, double cx, double cy, double r, double mv, double *smv, int verbose)
int imgRingMask (IMG *img, int zi, double cx, double cy, double r1, double r2, double mv, double *smv, int verbose)
int imgSimulateRing (IMG *img, int fi, int zi, double cx, double cy, double r1, double r2, double vr, double vi, double vo, int verbose)
int simMyocDiameterCurve (DFT *dft, double t1, double t2, double hbr, double maxdiam, double mindiam)
int imgSimulateSphere (IMG *img, int fi, double cx, double cy, double cz, double r1, double r2, double vr, double vi, double vo, int verbose)
int heartRecoverySpilloverCorrectionFactors (double R, double d, double s, double Vb, double *FMM, double *FMB, double *FBM, double *FBB)
int imgMaskPixelTACs (IMG *img, IMG *mask, double thrs, DFT *dft, int verbose)
int imgGetConcWeightedPeakPos (IMG *img, float thrs, IMG_PIXEL *pos, int verbose)
double rcPeakPET (double FWHM, double R)
int idiSimulateTubeVol (VOL *vol, int zi, double cx, double cy, double r, double FWHM, double cbkg, double cblo)
int idiSimulateTubeImg (IMG *img, int zi, double cx, double cy, double r, double *cbkg, double *cblo)
int idiSimulateTubeImgPlane (int simmet, IMG *img, int zi, double cx, double cy, double r, double FWHM, double *cbkg, double *cblo)

Detailed Description

Header file for libtpcidi.

Author
Vesa Oikonen

Definition in file libtpcidi.h.

Function Documentation

◆ heartRecoverySpilloverCorrectionFactors()

int heartRecoverySpilloverCorrectionFactors ( double R,
double d,
double s,
double Vb,
double * FMM,
double * FMB,
double * FBM,
double * FBB )
extern

Calculate recovery and spillover correction coefficients.

Based on Henze E, Huang S-C, Ratib O, Hoffman E, Phelps ME, Schelbert HR. Measurements of regional tissue and blood-pool radiotracer concentrations from serial tomographic images of the heart. J Nucl Med. 1983;24:987-996.

See also
rcPeakPET, simMyocDiameterCurve, imgSimulateSphere
Returns
Returns 0 if successful, or <> 0 in case of an error.
Parameters
Rradius of cavity and circular ROI (mm).
dthickness of myocardium (mm).
sspatial resolution (mm); s = FWHM/(2*SQRT(2*LN(2))).
VbVascular volume fraction in myocardium; Henze et al assumed 0.1.
FMMPointer to resulting correction coefficient FMM, see the article.
FMBPointer to resulting correction coefficient FMB, see the article.
FBMPointer to resulting correction coefficient FBM, see the article.
FBBPointer to resulting correction coefficient FBB, see the article.

Definition at line 37 of file heartcorr.c.

54 {
55 double hp;
56
57 if(R<=0.0 || d<=0.0 || s<=0.0) return(1);
58 if(FMM==NULL || FMB==NULL || FBM==NULL || FBB==NULL) return(2);
59 if(Vb<0.0 || Vb>=1.0) return(3);
60 hp = exp(-R*R/(2.0*s*s));
61 *FMB = hp - exp(-(R+d)*(R+d)/(2.0*s*s));
62 *FMM = erf( (d/2.0) / (M_SQRT2*s) );
63 *FBB = 1.0 - hp;
64 *FBM = Vb + 0.5*(1.0 - *FMM); //0.6 - 0.5 * *FMM;
65 return(0);
66}

◆ idiSimulateTubeImg()

int idiSimulateTubeImg ( IMG * img,
int zi,
double cx,
double cy,
double r,
double * cbkg,
double * cblo )
extern

Simulate dynamic image surrounding a circular object extending across image planes (vessel).

Postcondition
Apply 2D Gaussian smoothing.
See also
imgGaussianFIRFilter, idiSimulateTubeVol, idiSimulateTubeImgPlane, imgSimulateSphere
Returns
Returns 0 if successful, or <> 0 in case of an error.
Parameters
imgPointer to allocated dynamic image; volume must contain pixel sizes and dimensions, and the same time frames as the TAC data.
ziPlane index [0..dimz-1].
cxX distance of circle centre (mm) from the upper left corner of the image.
cyY distance of circle centre (mm) from the upper left corner of the image.
rRadius of vessel (mm).
cbkgArray of background activities; size must be the same as img frame number.
cbloArray of vessel activities; can be higher or lower than background; size must be the same as img frame number.

Definition at line 81 of file vessel.c.

98 {
99 double dx1, dy1, dx2, dy2, d1, d2, d3, d4, r2;
100 int xi, yi, fi, n;
101
102 if(img->status!=IMG_STATUS_OCCUPIED) return(1);
103 if(zi<0 || zi>=img->dimz) return(2);
104 if(img->sizey<=0.0 || img->sizex<=0.0) return(3);
105
106 /* Simulate the circle */
107 r2=r*r;
108 for(yi=0; yi<img->dimy; yi++) {
109 dy1=dy2=(0.5+(double)yi)*img->sizey - cy;
110 dy1-=0.25*img->sizey; dy2+=0.25*img->sizey;
111 for(xi=0; xi<img->dimx; xi++) {
112 dx1=dx2=(0.5+(double)xi)*img->sizex - cx;
113 dx1-=0.25*img->sizex; dx2+=0.25*img->sizex;
114 d1=dx1*dx1+dy1*dy1; d2=dx1*dx1+dy2*dy2;
115 d3=dx2*dx2+dy1*dy1; d4=dx2*dx2+dy2*dy2;
116 n=0; if(d1<=r2) n++; if(d2<=r2) n++; if(d3<=r2) n++; if(d4<=r2) n++;
117 for(fi=0; fi<img->dimt; fi++)
118 img->m[zi][yi][xi][fi]=0.25*((double)n*cblo[fi]+(double)(4-n)*cbkg[fi]);
119 }
120 }
121
122 return(0);
123}
#define IMG_STATUS_OCCUPIED
float sizex
unsigned short int dimx
float **** m
char status
unsigned short int dimt
float sizey
unsigned short int dimz
unsigned short int dimy

◆ idiSimulateTubeImgPlane()

int idiSimulateTubeImgPlane ( int simmet,
IMG * img,
int zi,
double cx,
double cy,
double r,
double FWHM,
double * cbkg,
double * cblo )
extern

Simulate image surrounding a circular object extending across image planes (bar or vessel). This function applies currently two methods to simulate the spill-over and spill-in effects:

Method 1. is based on Germano et al. JNM 1992; 33: 613-620. This equation can not be used to estimate recovery coefficient or the true activity concentration inside the vessel, but only to fit the radius of the vessel (see Germano), which then can be used to calculate the RC.

Method 2. simulates just the vessel without PVE; add 2D Gaussian smoothing later.

To simulate the circular vessel correctly in 2D image matrix use the equations in Brix et al. Nuklearmedizin 2002;41:184-190 instead; however, that would require numerical solution to double integrals, which may be either slow or error-prone for fitting purposes.

See also
idiSimulateTubeVol, idiSimulateTubeImg, imgGaussianFIRFilter, imgCircleMask
Returns
Returns 0 if successful, or <> 0 in case of an error.
Parameters
simmetSimulation method: 0=Germano, -1 or 1=No PVE.
imgPointer to allocated dynamic image; volume must contain pixel sizes and dimensions, and the same time frames as the TAC data.
ziPlane index [0..dimz-1].
cxX distance of circle centre (mm) from the upper left corner of the image.
cyY distance of circle centre (mm) from the upper left corner of the image.
rRadius of vessel (mm).
FWHMFWHM (mm).
cbkgArray of background activities; size must be the same as img frame number.
cbloArray of vessel activities; can be higher or lower than background; size must be the same as img frame number.

Definition at line 143 of file vessel.c.

164 {
165 int xi, yi, fi;
166
167 if(img->status!=IMG_STATUS_OCCUPIED) return(1);
168 if(zi<0 || zi>=img->dimz) return(2);
169 if(img->sizey<=0.0 || img->sizex<=0.0) return(3);
170 if(cbkg==NULL || cblo==NULL) return(4);
171
172 double d, s=FWHM/2.354820; // 2*sqrt(2*ln(2))
173
174 if(simmet==0) { // Germano
175 double v, w1, w2, w3, w4, dy, dx;
176 for(yi=0; yi<img->dimy; yi++) {
177 dy=(0.5+(double)yi)*img->sizey - cy;
178 for(xi=0; xi<img->dimx; xi++) {
179 dx=(0.5+(double)xi)*img->sizex - cx;
180 d=hypot(dx-0.25*img->sizex, dy-0.25*img->sizey);
181 w1=0.5*( erf((d+r)/(M_SQRT2*s)) - erf((d-r)/(M_SQRT2*s)) );
182 d=hypot(dx-0.25*img->sizex, dy+0.25*img->sizey);
183 w2=0.5*( erf((d+r)/(M_SQRT2*s)) - erf((d-r)/(M_SQRT2*s)) );
184 d=hypot(dx+0.25*img->sizex, dy-0.25*img->sizey);
185 w3=0.5*( erf((d+r)/(M_SQRT2*s)) - erf((d-r)/(M_SQRT2*s)) );
186 d=hypot(dx+0.25*img->sizex, dy+0.25*img->sizey);
187 w4=0.5*( erf((d+r)/(M_SQRT2*s)) - erf((d-r)/(M_SQRT2*s)) );
188 for(fi=0; fi<img->dimt; fi++) {
189 v=cblo[fi]-cbkg[fi];
190 img->m[zi][yi][xi][fi]= 0.25*v*(w1+w2+w3+w4) + cbkg[fi];
191 }
192 }
193 }
194 } else { // Vessel without PVE
195 double dx1, dy1, dx2, dy2, d1, d2, d3, d4, r2;
196 int n;
197 /* Simulate the circle */
198 r2=r*r;
199 for(yi=0; yi<img->dimy; yi++) {
200 dy1=dy2=(0.5+(double)yi)*img->sizey - cy;
201 dy1-=0.25*img->sizey; dy2+=0.25*img->sizey;
202 for(xi=0; xi<img->dimx; xi++) {
203 dx1=dx2=(0.5+(double)xi)*img->sizex - cx;
204 dx1-=0.25*img->sizex; dx2+=0.25*img->sizex;
205 d1=dx1*dx1+dy1*dy1; d2=dx1*dx1+dy2*dy2;
206 d3=dx2*dx2+dy1*dy1; d4=dx2*dx2+dy2*dy2;
207 n=0; if(d1<=r2) n++; if(d2<=r2) n++; if(d3<=r2) n++; if(d4<=r2) n++;
208 for(fi=0; fi<img->dimt; fi++)
209 img->m[zi][yi][xi][fi]=0.25*((double)n*cblo[fi]+(double)(4-n)*cbkg[fi]);
210 }
211 }
212 }
213
214 return(0);
215}

◆ idiSimulateTubeVol()

int idiSimulateTubeVol ( VOL * vol,
int zi,
double cx,
double cy,
double r,
double FWHM,
double cbkg,
double cblo )
extern

Simulate image volume surrounding a circular object extending across image planes (bar or vessel). Based on Germano et al. JNM 1992; 33: 613-620.

This equation can not be used to estimate recovery coefficient or the true activity concentration inside the vessel, but only to fit the radius of the vessel (see Germano), which then can be used to calculate the RC.

To simulate the circular vessel correctly in 2D image matrix use the equations in Brix et al. Nuklearmedizin 2002;41:184-190 instead; however, that would require numerical solution to double integrals, which may be either slow or error-prone for fitting purposes.

In this version, the activity is calculated as an average of four samples inside the pixel.

See also
idiSimulateTubeImg, idiSimulateTubeImgPlane, imgGaussianFIRFilter, imgCircleMask
Returns
Returns 0 if successful, or <> 0 in case of an error.
Parameters
volPointer to allocated image volume; volume must contain pixel sizes and dimensions
ziPlane index [0..dimz-1].
cxX distance of circle centre (mm) from the upper left corner of the image.
cyY distance of circle centre (mm) from the upper left corner of the image.
rRadius of vessel (mm).
FWHMFWHM (mm).
cbkgBackground activity.
cbloVessel activity; can be higher or lower than background.

Definition at line 26 of file vessel.c.

43 {
44 double s, dx, dy, d, v;
45 int xi, yi;
46
47 if(vol->status!=IMG_STATUS_OCCUPIED) return(1);
48 if(zi<0 || zi>=vol->dimz) return(2);
49 if(vol->sizey<=0.0 || vol->sizex<=0.0) return(3);
50
51 s=FWHM/2.354820; // 2*sqrt(2*ln(2))
52 v=cblo-cbkg;
53 for(yi=0; yi<vol->dimy; yi++) {
54 dy=(0.5+(double)yi)*vol->sizey - cy;
55 for(xi=0; xi<vol->dimx; xi++) {
56 dx=(0.5+(double)xi)*vol->sizex - cx;
57 vol->v[zi][yi][xi]=0.0;
58 d=hypot(dx-0.25*vol->sizex, dy-0.25*vol->sizey);
59 vol->v[zi][yi][xi]+=(v/2.0)*( erf((d+r)/(M_SQRT2*s)) - erf((d-r)/(M_SQRT2*s)) );
60 d=hypot(dx-0.25*vol->sizex, dy+0.25*vol->sizey);
61 vol->v[zi][yi][xi]+=(v/2.0)*( erf((d+r)/(M_SQRT2*s)) - erf((d-r)/(M_SQRT2*s)) );
62 d=hypot(dx+0.25*vol->sizex, dy-0.25*vol->sizey);
63 vol->v[zi][yi][xi]+=(v/2.0)*( erf((d+r)/(M_SQRT2*s)) - erf((d-r)/(M_SQRT2*s)) );
64 d=hypot(dx+0.25*vol->sizex, dy+0.25*vol->sizey);
65 vol->v[zi][yi][xi]+=(v/2.0)*( erf((d+r)/(M_SQRT2*s)) - erf((d-r)/(M_SQRT2*s)) );
66 vol->v[zi][yi][xi]*=0.25;
67 vol->v[zi][yi][xi]+= cbkg;
68 }
69 }
70
71 return(0);
72}
char status
unsigned short int dimx
unsigned short int dimy
unsigned short int dimz
float sizex
float *** v
float sizey

◆ imgCircleMask()

int imgCircleMask ( IMG * img,
int zi,
double cx,
double cy,
double r,
double mv,
double * smv,
int verbose )
extern

Simulate a mask image of circle with specified radius.

The applied method is only approximate at pixel borders (pixel is divided into 5x5 subpixels).

See also
imgRingMask, imgSimulateSphere, idiSimulateTubeVol, imgMaskInvert
Returns
Returns 0 if successful.
Parameters
imgPointer to allocated static or dynamic image; image must contain pixel sizes and dimensions; mask values are added to pixel values, thus you may need to set pixel values to zero before calling this function.
ziPlane index [0..dimz-1].
cxX distance of circle centre (mm) from the upper left corner of the image.
cyY distance of circle centre (mm) from the upper left corner of the image.
rRadius of circle (mm).
mvMask value; this value is added to each pixel value that fits inside the radius; the pixels that are partially inside the radius will get fraction of mask value.
smvPointer to value where the sum of added mask pixel values is written; enter NULL if not needed. Use this to validate the results.
verboseVerbose level; set to <=0 to prevent all prints to stdout.

Definition at line 16 of file circle.c.

37 {
38 if(verbose>0) printf("%s(img, %d, %g, %g, %g, %g, ...)\n", __func__, zi, cx, cy, r, mv);
39
40 int n, xi, yi, fi, i, j;
41 double dx[5], dy[5], r2, v;
42
43 if(img->status<IMG_STATUS_OCCUPIED) return(1);
44 if(zi<0 || zi>=img->dimz) return(2);
45 if(img->sizey<=0.0 || img->sizex<=0.0) return(3);
46 if(img->sizey!=img->sizex) return(4);
47 if(img->dimt<1) return(5);
48
49 if(smv!=NULL) *smv=0.0;
50 /* Compare r^2 to sum of squared distances instead of square root */
51 r2=r*r;
52 for(yi=0; yi<img->dimy; yi++) {
53 dy[0]=(0.1+(double)yi)*img->sizey - cy;
54 for(j=1; j<5; j++) dy[j]=dy[j-1]+0.2*img->sizey;
55 for(xi=0; xi<img->dimx; xi++) {
56 dx[0]=(0.1+(double)xi)*img->sizex - cx;
57 for(i=1; i<5; i++) dx[i]=dx[i-1]+0.2*img->sizex;
58 for(i=0, n=0; i<5; i++) for(j=0; j<5; j++) if((dx[i]*dx[i]+dy[j]*dy[j])<r2) n++;
59 if(n==0) continue;
60 v=(double)n*mv/25.0;
61 for(fi=0; fi<img->dimt; fi++) img->m[zi][yi][xi][fi]+=v;
62 if(smv!=NULL) *smv+=v;
63 }
64 }
65
66 return(0);
67}

Referenced by imgRingMask().

◆ imgGetConcWeightedPeakPos()

int imgGetConcWeightedPeakPos ( IMG * img,
float thrs,
IMG_PIXEL * pos,
int verbose )
extern

Calculates concentration weighted peak position from a sum image.

See also
imgMaskPixelTACs, imgCircleMask, idiSimulateTubeVol
Returns
Returns 0 if successful.
Parameters
imgPointer to allocated image from which the peak position is searched. If IMG struct contains more than one times frame, then only the first one is used.
thrsThreshold fraction (0<thrs<1) between image min and max.
posPointer to pixel position structure.
verboseVerbose level; set to <=0 to prevent all prints to stdout and stderr.

Definition at line 14 of file peak.c.

24 {
25 if(verbose>0) printf("%s(img, %g, ...)\n", __func__, thrs);
26
27 int xi, yi, zi, fi=0;
28 float d, fmax, fmin, thrslev;
29 float px, py, pz, fsum;
30
31 if(img->status<IMG_STATUS_OCCUPIED) return(1);
32 if(img->dimz<1 || img->dimx<2 || img->dimy<2) return(2);
33 if(img->dimt<1) return(3);
34 if(thrs<=0.0 || thrs>=1.0) return(4);
35 if(pos==NULL) return(5);
36
37
38 /* Search min and max value inside the image volume */
39 zi=yi=xi=0; fmax=fmin=img->m[zi][yi][xi][fi];
40 for(zi=0; zi<img->dimz; zi++)
41 for(yi=0; yi<img->dimy; yi++)
42 for(xi=0; xi<img->dimx; xi++) {
43 if(img->m[zi][yi][xi][fi] > fmax) fmax=img->m[zi][yi][xi][fi];
44 else if(img->m[zi][yi][xi][fi] < fmin) fmin=img->m[zi][yi][xi][fi];
45 }
46 if(verbose>1) printf("fmin := %g\nfmax := %g\n", fmin, fmax);
47
48 /* Calculate threshold level from min and max */
49 d=fmax-fmin; if(d<=0.0) return(10);
50 thrslev=d*thrs+fmin; if(verbose>1) printf("thrslev := %g\n", thrslev);
51
52 /* Calculate concentration weighted peak position */
53 px=py=pz=0.0; fsum=0.0;
54 for(zi=0; zi<img->dimz; zi++)
55 for(yi=0; yi<img->dimy; yi++)
56 for(xi=0; xi<img->dimx; xi++) {
57 d=img->m[zi][yi][xi][fi]-thrslev;
58 if(d>0.0) {
59 px+=(float)(xi+1)*d;
60 py+=(float)(yi+1)*d;
61 pz+=(float)(zi+1)*d;
62 fsum+=d;
63 }
64 }
65 if(fsum<=0.0) return 5;
66 px/=fsum; py/=fsum; pz/=fsum;
67 if(verbose>1) printf("peak_pos := (%g,%g,%g)\n", px, py, pz);
68 pos->x=roundf(px); pos->y=roundf(py); pos->z=roundf(pz); pos->f=1;
69
70 return(0);
71}

◆ imgMaskPixelTACs()

int imgMaskPixelTACs ( IMG * img,
IMG * mask,
double thrs,
DFT * dft,
int verbose )
extern

Extract TACs of every image voxel which has a value > thrs in the mask image.

Mask value is saved as region 'size' in DFT. Mainly for testing IDI methods.

See also
imgGetConcWeightedPeakPos, imgCircleMask, imgSimulateSphere
Returns
Returns 0 if successful.
Parameters
imgPointer to allocated image from which the weighted TAC is calculated.
maskPointer to mask image; x, y, and z dimensions must be the same as in the image to which the mask is applied.
thrsMask threshold: pixels with mask values above this are included in TACs.
dftPointer to initiated DFT struct where pixel TACs will be written; any previous contents are deleted.
verboseVerbose level; set to <=0 to prevent all prints to stdout .

Definition at line 17 of file idimask.c.

30 {
31 if(verbose>0) printf("%s()\n", __func__);
32
33 int xi, yi, zi, fi, ri, ret;
34
35 if(img->status<IMG_STATUS_OCCUPIED) return(1);
36 if(mask->status<IMG_STATUS_OCCUPIED) return(2);
37 if(mask->dimz!=img->dimz) return(3);
38 if(mask->dimy!=img->dimy) return(4);
39 if(mask->dimx!=img->dimx) return(5);
40 if(img->dimt<1 || mask->dimt<1) return(6);
41 if(dft==NULL) return(7);
42
43 /* Delete any previous TAC data; do it first so that caller can check
44 the nr of extracted TACs inside DFT */
45 dftEmpty(dft);
46
47 /* Calculate the nr of voxels to extract */
48 long long nr=0;
49 for(zi=0; zi<mask->dimz; zi++)
50 for(yi=0; yi<mask->dimy; yi++)
51 for(xi=0; xi<mask->dimx; xi++)
52 if(mask->m[zi][yi][xi][0]>thrs) nr++;
53 if(verbose>1) printf("mask_pixel_nr := %lld\n", nr);
54 /* Return, if no voxels were marked in mask image */
55 if(nr==0) return(0);
56
57 /* Allocate memory for pixel TACs */
58 ret=dftAllocateWithIMG(dft, nr, img);
59 if(ret!=0) {
60 if(verbose>0) fprintf(stderr, "Error: cannot allocate memory for %lld pixel TACs.\n", nr);
61 return(10);
62 }
63 strcpy(dft->studynr, img->studyNr);
64
65 /* Save the pixel TACs in DFT */
66 ri=0;
67 for(zi=0; zi<mask->dimz; zi++)
68 for(yi=0; yi<mask->dimy; yi++)
69 for(xi=0; xi<mask->dimx; xi++) if(mask->m[zi][yi][xi][0]>thrs)
70 {
71 sprintf(dft->voi[ri].voiname, "%d", 1+xi);
72 sprintf(dft->voi[ri].hemisphere, "%d", 1+yi);
73 sprintf(dft->voi[ri].place, "%d", 1+zi);
74 sprintf(dft->voi[ri].name, "%d %d %d", 1+xi, 1+yi, 1+zi);
75 for(fi=0; fi<img->dimt; fi++) dft->voi[ri].y[fi]=img->m[zi][yi][xi][fi];
76 dft->voi[ri].size=mask->m[zi][yi][xi][0];
77 ri++;
78 }
79 dft->voiNr=ri;
80
81 return(0);
82}
void dftEmpty(DFT *data)
Definition dft.c:20
int dftAllocateWithIMG(DFT *dft, int tacNr, IMG *img)
Definition misc_model.c:296
Voi * voi
char studynr[MAX_STUDYNR_LEN+1]
int voiNr
char studyNr[MAX_STUDYNR_LEN+1]
double size
char voiname[MAX_REGIONSUBNAME_LEN+1]
double * y
char name[MAX_REGIONNAME_LEN+1]
char hemisphere[MAX_REGIONSUBNAME_LEN+1]
char place[MAX_REGIONSUBNAME_LEN+1]

◆ imgRingMask()

int imgRingMask ( IMG * img,
int zi,
double cx,
double cy,
double r1,
double r2,
double mv,
double * smv,
int verbose )
extern

Simulate a mask image of ring with specified inner and outer radius.

The applied method is only approximate at pixel borders (pixel is divided into 5x5 subpixels).

See also
imgCircleMask, imgSimulateRing, imgSimulateSphere, imgMaskInvert
Returns
Returns 0 if successful.
Parameters
imgPointer to allocated static or dynamic image; image must contain pixel sizes and dimensions; mask values are added to pixel values, thus you may need to set pixel values to zero before calling this function.
ziPlane index [0..dimz-1].
cxX distance of circle centre (mm) from the upper left corner of the image.
cyY distance of circle centre (mm) from the upper left corner of the image.
r1Inner radius of circle (mm).
r2Outer radius of circle (mm).
mvMask value; this value is added to each pixel value that fits inside the radius; the pixels that are partially inside the radius will get fraction of mask value.
smvPointer to value where the sum of added mask pixel values is written; enter NULL if not needed. Use this to validate the results.
verboseVerbose level; set to <=0 to prevent all prints to stdout.

Definition at line 77 of file circle.c.

100 {
101 int ret;
102 double mv1, mv2, d;
103
104 if(verbose>0) printf("%s(img, %d, %g, %g, %g, %g, %g, ...)\n", __func__, zi, cx, cy, r1, r2, mv);
105 if(r1>=r2 || r1<0.0) {
106 if(verbose>0) fprintf(stderr, "Error: invalid radius.\n");
107 return(1);
108 }
109
110 /* Simulate circle with the larger radius */
111 ret=imgCircleMask(img, zi, cx, cy, r2, mv, &mv1, verbose);
112 if(ret!=0) {
113 if(verbose>0) fprintf(stderr, "Error: cannot simulate circle 1.\n");
114 return(ret);
115 }
116 /* Subtract circle with the smaller radius */
117 ret=imgCircleMask(img, zi, cx, cy, r1, -mv, &mv2, verbose);
118 if(ret!=0) {
119 if(verbose>0) fprintf(stderr, "Error: cannot simulate circle 2.\n");
120 return(ret);
121 }
122 /* Calculate the sum of mask pixel values */
123 d=mv1+mv2; if(smv!=NULL) *smv=d;
124 if(d==0.0 && verbose>0) {fprintf(stderr, "Warning: empty mask image created.\n"); fflush(stderr);}
125 return(0);
126}
int imgCircleMask(IMG *img, int zi, double cx, double cy, double r, double mv, double *smv, int verbose)
Definition circle.c:16

◆ imgSimulateRing()

int imgSimulateRing ( IMG * img,
int fi,
int zi,
double cx,
double cy,
double r1,
double r2,
double vr,
double vi,
double vo,
int verbose )
extern

Simulate an image of ring with specified inner and outer radius and activity in the ring and inside and outside of it. The applied method is only approximate at pixel borders (pixel is divided into 5x5 subpixels). PET resolution effects are not simulated.

See also
imgRingMask, imgSimulateSphere, imgGaussianFIRFilter, idiSimulateTubeVol
Returns
Returns 0 if successful.
Parameters
imgPointer to allocated static or dynamic image; image must contain pixel sizes and dimensions; values are added to any existing pixel values, thus you may need to set pixel values to zero before calling this function.
fiFrame index [0..dimt-1].
ziPlane index [0..dimz-1].
cxX distance of circle centre (mm) from the upper left corner of the image.
cyY distance of circle centre (mm) from the upper left corner of the image.
r1Inner radius of circle (mm).
r2Outer radius of circle (mm).
vrRing value; this value is added to each pixel value that fits inside the radius's; the pixels that are partially inside the ring will get fraction of the value.
viInside value; this value is added to each pixel value that fits inside the inner radius; the pixels that are partially inside the radius will get fraction of the value.
voOutside value; this value is added to each pixel value that fits outside the outer radius; the pixels that are partially outside the radius will get fraction of the value.
verboseVerbose level; set to <=0 to prevent all prints to stdout.

Definition at line 17 of file heart.c.

45 {
46 int nr, ni, no, xi, yi, i, j;
47 double dx[5], dy[5], v, d;
48 double ri2, ro2;
49
50 if(verbose>0)
51 printf("%s(img, %d, %d, %g, %g, %g, %g, %g, %g, %g, %d)\n",
52 __func__, fi, zi, cx, cy, r1, r2, vr, vi, vo, verbose);
53 if(r1>=r2 || r1<0.0) {
54 if(verbose>0) fprintf(stderr, "Error: invalid radius.\n");
55 return(1);
56 }
57
58 if(img->status<IMG_STATUS_OCCUPIED) return(1);
59 if(zi<0 || zi>=img->dimz) return(2);
60 if(img->sizey<=0.0 || img->sizex<=0.0) return(3);
61 if(img->sizey!=img->sizex) return(4);
62 if(img->dimt<1 || fi>=img->dimt) return(5);
63 if(r1<0.0 || r2<r1) return(6);
64
65 /* Compare radius ^2 to sum of squared distances instead of square roots */
66 ri2=r1*r1; ro2=r2*r2;
67 for(yi=0; yi<img->dimy; yi++) {
68 dy[0]=(0.1+(double)yi)*img->sizey - cy;
69 for(j=1; j<5; j++) dy[j]=dy[j-1]+0.2*img->sizey;
70 for(xi=0; xi<img->dimx; xi++) {
71 dx[0]=(0.1+(double)xi)*img->sizex - cx;
72 for(i=1; i<5; i++) dx[i]=dx[i-1]+0.2*img->sizex;
73 nr=ni=no=0;
74 for(i=0; i<5; i++) for(j=0; j<5; j++) {
75 d=dx[i]*dx[i]+dy[j]*dy[j];
76 if(d<ri2) ni++; else if(d<ro2) nr++; else no++;
77 }
78 v=(double)nr*vr/25.0;
79 v+=(double)ni*vi/25.0;
80 v+=(double)no*vo/25.0;
81 img->m[zi][yi][xi][fi]+=v;
82 }
83 }
84 return(0);
85}

◆ imgSimulateSphere()

int imgSimulateSphere ( IMG * img,
int fi,
double cx,
double cy,
double cz,
double r1,
double r2,
double vr,
double vi,
double vo,
int verbose )
extern

Simulate a 3D image of circle with specified inner and outer radius and activity in the circle and inside and outside of it.

The applied method is only approximate at pixel borders (pixel is divided into 5x5 subpixels). PET resolution effects are not simulated.

See also
imgRingMask, imgCircleMask, imgGaussianFIRFilter, idiSimulateTubeVol
Returns
Returns 0 if successful.
Parameters
imgPointer to allocated static or dynamic image; image must contain pixel sizes and dimensions; values are added to any existing pixel values, thus you may need to set pixel values to zero before calling this function.
fiFrame index [0..dimt-1].
cxX distance of circle centre (mm) from the upper left corner of the image.
cyY distance of circle centre (mm) from the upper left corner of the image.
czZ distance of circle centre (mm) from the upper left corner of the image.
r1Inner radius of circle (mm).
r2Outer radius of circle (mm).
vrSphere wall value; this value is added to each pixel value that fits inside the radius's; the pixels that are partially inside the wall will get fraction of the value.
viInside value; this value is added to each pixel value that fits inside the inner radius; the pixels that are partially inside the radius will get fraction of the value.
voOutside value; this value is added to each pixel value that fits outside the outer radius; the pixels that are partially outside the radius will get fraction of the value.
verboseVerbose level; set to <=0 to prevent all prints to stdout.

Definition at line 154 of file heart.c.

182 {
183 int nr, ni, no, xi, yi, zi, i, j, k;
184 double dx[5], dy[5], dz[5], v, d;
185 double ri2, ro2;
186
187 if(verbose>0)
188 printf("%s(img, %d, %g, %g, %g, %g, %g, %g, %g, %g, %d)\n",
189 __func__, fi, cx, cy, cz, r1, r2, vr, vi, vo, verbose);
190 if(r1>=r2 || r1<0.0) {
191 if(verbose>0) fprintf(stderr, "Error: invalid radius.\n");
192 return(1);
193 }
194
195 if(img->status<IMG_STATUS_OCCUPIED) return(1);
196 if(img->sizez<=0.0 || img->sizey<=0.0 || img->sizex<=0.0) return(2);
197 if(img->sizey!=img->sizex || img->sizez!=img->sizex) return(3);
198 if(img->dimt<1 || fi>=img->dimt) return(4);
199 if(r1<0.0 || r2<r1) return(5);
200
201 /* Compare radius ^2 to sum of squared distances instead of square roots */
202 ri2=r1*r1; ro2=r2*r2;
203 for(zi=0; zi<img->dimz; zi++) {
204 dz[0]=(0.1+(double)zi)*img->sizez - cz;
205 for(k=1; k<5; k++) dz[k]=dz[k-1]+0.2*img->sizez;
206 for(yi=0; yi<img->dimy; yi++) {
207 dy[0]=(0.1+(double)yi)*img->sizey - cy;
208 for(j=1; j<5; j++) dy[j]=dy[j-1]+0.2*img->sizey;
209 for(xi=0; xi<img->dimx; xi++) {
210 dx[0]=(0.1+(double)xi)*img->sizex - cx;
211 for(i=1; i<5; i++) dx[i]=dx[i-1]+0.2*img->sizex;
212 nr=ni=no=0;
213 for(i=0; i<5; i++) for(j=0; j<5; j++) for(k=0; k<5; k++) {
214 d=dx[i]*dx[i]+dy[j]*dy[j]+dz[k]*dz[k];
215 if(d<ri2) ni++; else if(d<ro2) nr++; else no++;
216 }
217 v=(double)nr*vr/125.0;
218 v+=(double)ni*vi/125.0;
219 v+=(double)no*vo/125.0;
220 img->m[zi][yi][xi][fi]+=v;
221 }
222 }
223 }
224 return(0);
225}
float sizez

◆ rcPeakPET()

double rcPeakPET ( double FWHM,
double R )
extern

Calculate the traditional recovery coefficient (RC) of peak value of a circular radioactive object in 2D PET image, assuming that the object length in 3D is relatively long, and assuming that activity of background is zero.

True object activity A0 can be calculated using RC, background activity Abkg, and measured peak activity Aexp using equation A0 = Abkg + (Aexp - Abkg)/RC , or if Abkg=0, A0 = Aexp/RC.

References: Germano et al. JNM 1992; 33: 613-620 and Brix et al. Nuklearmedizin 2002;41:184-190.

See also
idiSimulateTubeVol, heartRecoverySpilloverCorrectionFactors
Returns
Returns the recovery coefficient [0-1].
Parameters
FWHMFull-width half-maximum value.
RRadius of the object.

Definition at line 24 of file recovery.c.

29 {
30 double s, rc;
31 s=FWHM/2.354820; // 2*sqrt(2*ln(2))
32 rc=1.0-exp(-R*R/(2.0*s*s));
33 return(rc);
34}

◆ simMyocDiameterCurve()

int simMyocDiameterCurve ( DFT * dft,
double t1,
double t2,
double hbr,
double maxdiam,
double mindiam )
extern

Calculate the inner LV cavity diameter as a function of time for simulations.

10 samples per heart beat will be calculated. Fractional increase/decrease rate is fixed and coded in here.

See also
imgSimulateRing, imgRingMask, idiSimulateTubeVol
Returns
Returns 0 if successful.
Parameters
dftPointer to initiated DFT struct where diameter curve will be written.
t1Start time (s).
t2Stop time (s).
hbrHeart rate (beats/min).
maxdiamMaximum inner diameter (mm).
mindiamMinimum inner diameter (mm).

Definition at line 96 of file heart.c.

109 {
110 int n, i, ret;
111 double s;
112 double rfract[10]={1.0, 0.6, 0.25, 0.0, 0.1, 0.25, 0.6, 0.8, 0.9, 0.95};
113
114 /* check input */
115 if(dft==NULL) return(1);
116 if(t2<t1) return(1);
117 if(maxdiam<mindiam) return(1);
118
119 /* delete any previous curve contents */
120 dftEmpty(dft);
121
122 /* convert heart rate to per sec */
123 if(hbr>0.0) hbr/=60.0; else hbr=0.0;
124
125 /* calculate the nr of samples */
126 if(hbr>0.0 && (t2-t1)>0.0) n=10.0*(t2-t1)/hbr; else n=1;
127
128 /* Set up curve struct */
129 ret=dftSetmem(dft, n, 1); if(ret!=0) return(3);
130 dft->frameNr=n; dft->voiNr=1; dft->timetype=DFT_TIME_STARTEND;
131 dft->timeunit=TUNIT_SEC;
132
133 /* Fill curve */
134 dft->x1[0]=t1; if(hbr>0.0) s=0.1*hbr; else s=t2-t1;
135 for(i=n=0; i<dft->frameNr; i++) {
136 if(i>0) dft->x1[i]=dft->x2[i-1];
137 dft->x2[i]=dft->x1[i]+s; dft->x[i]=0.5*(dft->x1[i]+dft->x2[i]);
138 dft->voi[0].y[i]=mindiam+rfract[n]*(maxdiam-mindiam); n++; if(n==10) n=0;
139 }
140
141 return 0;
142}
int dftSetmem(DFT *data, int frameNr, int voiNr)
Definition dft.c:57
#define DFT_TIME_STARTEND
int timetype
int timeunit
double * x1
double * x2
int frameNr
double * x