| Bsoft 1.9 Bernard's software package

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
img_nad.cpp
Go to the documentation of this file.
1
10 #include "img_nad.h"
11 #include "Matrix.h"
12 #include "utilities.h"
13
14 // Declaration of global variables
15 extern int verbose; // Level of output to the screen
16
17 /*
18 Calculates a structure tensor for a 3D volume.
19 */
20 Bimage* img_structure_tensor(Bimage* p, long zs, long zw)
21 {
22 long i, k, xx, yy, zz, zf;
23 long nxy = p->sizeX()*p->sizeY();
24 double dx, dy, dz;
25
26 // Padding for the top and bottom slices
27 if ( zs > 0 ) zw++;
28 if ( zs+zw < p->sizeZ() ) zw++;
29
30 Bimage* pd = new Bimage(Float, 6, p->sizeX(), p->sizeY(), zw, 1);
31 pd->image->origin(p->image->origin());
32 pd->sampling(p->sampling());
33
34 // Start point for the first slice
35 if ( zs > 0 ) {
36 pd->image->origin(0,0,1);
37 zs--;
38 }
39
40 for ( zz=zs, zf=zs+zw, k=0, i=nxy*zs; zz<zf; zz++ ) {
41 for ( yy=0; yy<p->sizeY(); yy++ ) {
42 for ( xx=0; xx<p->sizeX(); xx++, i++ ) {
43 dx = dy = dz = -p->average();
44 if ( xx > 0 ) dx = -(*p)[i-1];
45 if ( xx < p->sizeX()-1 ) dx += (*p)[i+1];
46 else dx += p->average();
47 if ( yy > 0 ) dy = -(*p)[i-p->sizeX()];
48 if ( yy < p->sizeY()-1 ) dy += (*p)[i+p->sizeX()];
49 else dy += p->average();
50 if ( zz > 0 ) dz = -(*p)[i-nxy];
51 if ( zz < p->sizeZ()-1 ) dz += (*p)[i+nxy];
52 else dz += p->average();
53 dx /= 2;
54 dy /= 2;
55 dz /= 2;
56 pd->set(k++, dx*dx);
57 pd->set(k++, dx*dy);
58 pd->set(k++, dx*dz);
59 pd->set(k++, dy*dy);
60 pd->set(k++, dy*dz);
61 pd->set(k++, dz*dz);
62 // cout << xx << tab << yy << tab << zz << tab << dx << tab << dy << tab << dz << endl;
63 }
64 }
65 }
66
67 return pd;
68 }
69
70 /*
71 Calculates the diffusion tensor of EED or CED using the structure tensor.
72 Principal axis backtransformation of a symmetric 3x3 matrix.
73 A = U * diag(lam[0], lam[1], lam[2]) * U_transpose with U = (v1 | v2 | v3)
74 */
75 int img_diffusion_tensor(Bimage* pd, double lambda, double C, double alpha)
76 {
77 long i, j, imgsize = pd->sizeX()*pd->sizeY()*pd->sizeZ();
78 double lam[3] = {1,1,1}; /* eigenvalues of diffusion tensor */
79 double* d; /* vector with unordered eigenvalues */
80 Matrix a(3,3); /* real tensor matrix */
81 double beta = 1 - alpha; /* time saver */
82 double thexp = 16, grd, gol, denom;
83
84 for ( i=0; i<imgsize; i++ ) {
85 j = i*pd->channels();
86 a[0][0] = (*pd)[j++];
87 a[0][1] = a[1][0] = (*pd)[j++];
88 a[0][2] = a[2][0] = (*pd)[j++];
89 a[1][1] = (*pd)[j++];
90 a[1][2] = a[2][1] = (*pd)[j++];
91 a[2][2] = (*pd)[j++];
92 // cout << i << tab << a[0] << tab << a[1] << tab << a[2] << tab << a[4] << tab << a[5] << tab << a[8] << endl;
93
94 /* calculate third eigenvalue */
95 grd = a[0][0] + a[1][1] + a[2][2];
96 d = a.jacobi_rotation();
97 a.eigen_sort(d);
98
99 if ( C ) {
100 // for plane-like structures, calculate the second eigenvalue
101 lam[0] = lam[1] = lam[2] = alpha;
102 denom = d[0] - d[1];
103 if ( denom && denom > d[2] && ( denom > d[1] - d[2] ) )
104 lam[1] += beta * exp (- C / (denom*denom));
105 /* calculate third eigenvalue */
106 denom = d[0] - d[2];
107 if ( denom ) lam[2] += beta * exp (- C / (denom*denom));
108 } else {
109 if ( grd > 0.0) {
110 gol = sqrt(grd)/lambda;
111 lam[0] = lam[1] = 1.0 - exp (-3.31488 / pow(gol, thexp));
112 } else {
113 lam[0] = lam[1] = 1;
114 }
115 }
116
117 delete[] d;
118
119 /* principal axis backtransformation */
120 j = i*pd->channels();
121 pd->set(j++, lam[0]*a[0][0]*a[0][0] + lam[1]*a[0][1]*a[0][1] + lam[2]*a[0][2]*a[0][2]);
122 pd->set(j++, lam[0]*a[0][0]*a[1][0] + lam[1]*a[0][1]*a[1][1] + lam[2]*a[0][2]*a[1][2]);
123 pd->set(j++, lam[0]*a[0][0]*a[2][0] + lam[1]*a[0][1]*a[2][1] + lam[2]*a[0][2]*a[2][2]);
124 pd->set(j++, lam[0]*a[1][0]*a[1][0] + lam[1]*a[1][1]*a[1][1] + lam[2]*a[1][2]*a[1][2]);
125 pd->set(j++, lam[0]*a[1][0]*a[2][0] + lam[1]*a[1][1]*a[2][1] + lam[2]*a[1][2]*a[2][2]);
126 pd->set(j++, lam[0]*a[2][0]*a[2][0] + lam[1]*a[2][1]*a[2][1] + lam[2]*a[2][2]*a[2][2]);
127
128 // cout << i;
129 // for ( int k=0; k<6; k++ ) cout << tab << (*pd)[j++];
130 // cout << endl;
131 }
132
133 return 0;
134 }
135
136 int img_diffuse(Bimage* p, Bimage* pdn, Bimage* pd, double ht, long zs)
137 {
138 long i, k, xx, yy, zz, zf, ii, ik;
139 long iw, xw, yw, zw, ix, iy, iz, zs1, xf1, yf1, zf1;
140 long nxy = p->sizeX()*p->sizeY();
141 double w[27], v;
142 double r = ht/4;
143
144 if ( verbose & VERB_FULL )
145 cout << "Calculating the new image chunk" << endl;
146
147 xf1 = pd->sizeX() - 1;
148 yf1 = pd->sizeY() - 1;
149 zs1 = zs;
150 ik = 0;
151 if ( zs > 0 ) { // The diffusion tensor reference starts one slice in
152 ik = nxy;
153 zs1 = zs - 1;
154 }
155 zf = zs1 + pd->sizeZ();
156 zf1 = zf - 1;
157 if ( zf < p->sizeZ() ) zf -= 1;
158 if ( zf > p->sizeZ() ) zf = p->sizeZ();
159
160 if ( verbose & VERB_DEBUG )
161 cout << "pd->sizeZ()=" << pd->sizeZ() << " zs=" << zs << " zs1=" << zs1 << " zf=" << zf << " zf1=" << zf1 << endl;
162
163 for ( zz=zs, i=nxy*zs; zz<zf; zz++ ) {
164 for ( yy=0; yy<p->sizeY(); yy++ ) {
165 for ( xx=0; xx<p->sizeX(); xx++, i++, ik++ ) {
166 for ( iw=0; iw<27; iw++ ) w[iw] = 0;
167
168 k = pd->channels()*ik;
169 w[12] = w[14] = 2*(*pd)[k] - fabs((*pd)[k+1]) - fabs((*pd)[k+2]);
170 w[10] = w[16] = 2*(*pd)[k+3] - fabs((*pd)[k+1]) - fabs((*pd)[k+4]);
171 w[4] = w[22] = 2*(*pd)[k+5] - fabs((*pd)[k+4]) - fabs((*pd)[k+2]);
172
173 w[9] = w[17] = (*pd)[k+1] + fabs((*pd)[k+1]);
174 w[15] = w[11] = -(*pd)[k+1] + fabs((*pd)[k+1]);
175
176 w[3] = w[23] = (*pd)[k+2] + fabs((*pd)[k+2]);
177 w[5] = w[21] = -(*pd)[k+2] + fabs((*pd)[k+2]);
178
179 w[1] = w[25] = (*pd)[k+4] + fabs((*pd)[k+4]);
180 w[7] = w[19] = -(*pd)[k+4] + fabs((*pd)[k+4]);
181
182 if ( xx > 0 ) {
183 k = pd->channels()*(ik - 1);
184 w[12] += 2*(*pd)[k] - fabs((*pd)[k+1]) - fabs((*pd)[k+2]);
185 }
186 if ( xx < xf1 ) {
187 k = pd->channels()*(ik + 1);
188 w[14] += 2*(*pd)[k] - fabs((*pd)[k+1]) - fabs((*pd)[k+2]);
189 }
190
191 if ( yy > 0 ) {
192 k = pd->channels()*(ik - pd->sizeX());
193 w[10] += 2*(*pd)[k+3] - fabs((*pd)[k+1]) - fabs((*pd)[k+4]);
194 }
195 if ( yy < yf1 ) {
196 k = pd->channels()*(ik + pd->sizeX());
197 w[16] += 2*(*pd)[k+3] - fabs((*pd)[k+1]) - fabs((*pd)[k+4]);
198 }
199
200 if ( zz > zs1 ) {
201 k = pd->channels()*(ik - nxy);
202 w[4] += 2*(*pd)[k+5] - fabs((*pd)[k+4]) - fabs((*pd)[k+2]);
203 }
204 if ( zz < zf1 ) {
205 k = pd->channels()*(ik + nxy);
206 w[22] += 2*(*pd)[k+5] - fabs((*pd)[k+4]) - fabs((*pd)[k+2]);
207 }
208
209 if ( xx > 0 && yy > 0 ) {
210 k = pd->channels()*(ik - pd->sizeX() - 1) + 1;
211 w[9] += (*pd)[k] + fabs((*pd)[k]);
212 }
213 if ( xx < xf1 && yy > 0 ) {
214 k = pd->channels()*(ik - pd->sizeX() + 1) + 1;
215 w[11] += -(*pd)[k] + fabs((*pd)[k]);
216 }
217 if ( xx > 0 && yy < yf1 ) {
218 k = pd->channels()*(ik + pd->sizeX() - 1) + 1;
219 w[15] += -(*pd)[k] + fabs((*pd)[k]);
220 }
221 if ( xx < xf1 && yy < yf1 ) {
222 k = pd->channels()*(ik + pd->sizeX() + 1) + 1;
223 w[17] += (*pd)[k] + fabs((*pd)[k]);
224 }
225
226 if ( xx > 0 && zz > zs1 ) {
227 k = pd->channels()*(ik - nxy - 1) + 2;
228 w[3] += (*pd)[k] + fabs((*pd)[k]);
229 }
230 if ( xx < xf1 && zz > zs1 ) {
231 k = pd->channels()*(ik - nxy + 1) + 2;
232 w[5] += -(*pd)[k] + fabs((*pd)[k]);
233 }
234 if ( xx > 0 && zz < zf1 ) {
235 k = pd->channels()*(ik + nxy - 1) + 2;
236 w[21] += -(*pd)[k] + fabs((*pd)[k]);
237 }
238 if ( xx < xf1 && zz < zf1 ) {
239 k = pd->channels()*(ik + nxy + 1) + 2;
240 w[23] += (*pd)[k] + fabs((*pd)[k]);
241 }
242
243 if ( yy > 0 && zz > zs1 ) {
244 k = pd->channels()*(ik - pd->sizeX() - nxy) + 4;
245 w[1] += (*pd)[k] + fabs((*pd)[k]);
246 }
247 if ( yy < yf1 && zz > zs1 ) {
248 k = pd->channels()*(ik + pd->sizeX() - nxy) + 4;
249 w[7] += -(*pd)[k] + fabs((*pd)[k]);
250 }
251 if ( yy > 0 && zz < zf1 ) {
252 k = pd->channels()*(ik - pd->sizeX() + nxy) + 4;
253 w[19] += -(*pd)[k] + fabs((*pd)[k]);
254 }
255 if ( yy < yf1 && zz < zf1 ) {
256 k = pd->channels()*(ik + pd->sizeX() + nxy) + 4;
257 w[25] += (*pd)[k] + fabs((*pd)[k]);
258 }
259
260 /* modify weights to prevent flux across boundaries */
261 if ( xx==0 ) w[15] = w[12] = w[9] = w[3] = w[21] = 0.0;
262 if ( xx==p->sizeX()-1 ) w[11] = w[14] = w[17] = w[5] =w[23] = 0.0;
263 if ( yy==0 ) w[9] = w[10] = w[11] = w[1] = w[19] = 0.0;
264 if ( yy==p->sizeY()-1 ) w[17] = w[16] = w[15] = w[7] = w[25] = 0.0;
265 if ( zz==0 ) w[7] = w[4] = w[1] = w[5] = w[3] = 0.0;
266 if ( zz==p->sizeZ()-1 ) w[23] = w[22] = w[21] = w[1] =w[25] = 0.0;
267
268 // cout << xx << tab << yy << tab << zz;
269 // for ( iw=0; iw<27; iw++ ) cout << tab << w[iw]*r;
270 // cout << endl;
271
272 /* evolution */
273 v = (*p)[i];
274 for ( zw=0; zw<3; zw++ ) {
275 iz = zz + zw - 1;
276 if ( iz >= 0 && iz < p->sizeZ() ) for ( yw=0; yw<3; yw++ ) {
277 iy = yy + yw - 1;
278 if ( iy >= 0 && iy < p->sizeY() ) for ( xw=0; xw<3; xw++ ) {
279 ix = xx + xw - 1;
280 if ( ix >= 0 && ix < p->sizeX() ) {
281 iw = 9*zw + 3*yw + xw;
282 if ( w[iw] ) {
283 ii = (iz*p->sizeY() + iy)*p->sizeX() + ix;
284 v += w[iw]*r*((*p)[ii] - (*p)[i]);
285 }
286 }
287 }
288 }
289 }
290 pdn->set(i, v);
291 }
292 }
293 }
294
295 return 0;
296 }
297
298 int img_nad_chunk(Bimage* p, Bimage* pdn, double lambda, double C, double alpha, double ht, long zs, long zw)
299 {
300 if ( zs+zw > p->sizeZ() ) zw = p->sizeZ() - zs;
301
302 if ( verbose & VERB_DEBUG )
303 cout << "DEBUG img_nad_chunk: Chunk start = " << zs << " and size = " << zw << endl;
304
305 Bimage* pd = img_structure_tensor(p, zs, zw);
306
307 img_diffusion_tensor(pd, lambda, C, alpha);
308
309 img_diffuse(p, pdn, pd, ht, zs);
310
311 delete pd;
312
313 return 0;
314 }
315
330 Bimage* img_nad(Bimage* p, double ht, long zw, double lambda, double C, double alpha)
331 {
332 p->change_type(Float);
333
334 Bimage* pdn = p->copy();
335
336 #ifdef HAVE_GCD
337 dispatch_apply((p->sizeZ() - 1)/zw + 1, dispatch_get_global_queue(0, 0), ^(size_t zz){
338 img_nad_chunk(p, pdn, lambda, C, alpha, ht, zz*zw, zw);
339 });
340 #else
341 #pragma omp parallel for
342 for ( long zz=0; zz<p->sizeZ(); zz+=zw )
343 img_nad_chunk(p, pdn, lambda, C, alpha, ht, zz, zw);
344 #endif
345
346 return pdn;
347 }
348
349
Bimage::change_type
void change_type(char letter)
Get the data type indicated by a single letter code.
Definition: Bimage.cpp:1544
Bimage::sizeZ
void sizeZ(size_t nz)
Definition: Bimage.h:332
img_diffusion_tensor
int img_diffusion_tensor(Bimage *pd, double lambda, double C, double alpha)
Definition: img_nad.cpp:75
img_nad.h
Header file for denoising by nonlinear anisotropic diffusion: Coherence and edge enhancing diffusion...
img_structure_tensor
Bimage * img_structure_tensor(Bimage *p, long zs, long zw)
Definition: img_nad.cpp:20
utilities.h
Header file for general utilities.
VERB_DEBUG
#define VERB_DEBUG
Definition: utilities.h:106
Matrix.h
Generalized matrix class.
Bimage::average
double average(size_t cc, double xf, double yf, double zf, size_t nn, double iscale)
Averages in the xy plane when scaling is less than 1.
Definition: Bimage.cpp:1209
Float
Definition: utilities.h:151
verbose
int verbose
Bimage
General image parameter class.
Definition: Bimage.h:152
Bimage::channels
size_t channels()
Definition: Bimage.h:325
Bimage::sampling
void sampling(double s)
Definition: Bimage.h:440
Bsub_image::origin
void origin(double x, double y, double z)
Definition: Bimage.h:132
Bimage::set
void set(size_t j, double v)
Sets a single value at the given index.
Definition: Bimage.cpp:977
img_diffuse
int img_diffuse(Bimage *p, Bimage *pdn, Bimage *pd, double ht, long zs)
Definition: img_nad.cpp:136
Matrix
Definition: Matrix.h:21
Bimage::copy
Bimage * copy()
Copies the header information and data of an image into a new image structure.
Definition: Bimage.cpp:2414
Bimage::sizeX
void sizeX(size_t nx)
Definition: Bimage.h:330
Bimage::sizeY
void sizeY(size_t ny)
Definition: Bimage.h:331
img_nad
Bimage * img_nad(Bimage *p, double ht, long zw, double lambda, double C, double alpha)
Denoises a 3D density map by non-linear anisotropic diffusion.
Definition: img_nad.cpp:330
img_nad_chunk
int img_nad_chunk(Bimage *p, Bimage *pdn, double lambda, double C, double alpha, double ht, long zs, long zw)
Definition: img_nad.cpp:298
VERB_FULL
#define VERB_FULL
Definition: utilities.h:103
Matrix::jacobi_rotation
double * jacobi_rotation()
Computes all eigenvalues and eigenvectors of a real symmetric matrix.
Definition: matrix.cpp:401
Bimage::image
Bsub_image * image
Definition: Bimage.h:183