| Bsoft 2.0.5 Bernard's software package

Bimage_filter.cpp
Go to the documentation of this file.
1
9 #include "Bimage.h"
10 #include "matrix_linear.h"
11 #include "math_util.h"
12 #include "utilities.h"
13
14 // Declaration of global variables
15 extern int verbose; // Level of output to the screen
16
17 long kmin(long i, long hk)
18 {
19 return (i < hk)? hk - i: 0;
20 }
21
22 long kmax(long i, long km, long m)
23 {
24 long hk = km/2;
25 return (i + km < m + hk)? km: m + hk - i;
26 }
27
34 int Bimage::kernel_gaussian(double sigma, double max)
35 {
36 if ( sigma < 0.001 ) sigma = 1;
37 if ( fabs(max) < 1e-10 ) max = 1;
38
39 if ( verbose & VERB_PROCESS ) {
40 cout << "Generating a gaussian kernel:" << endl;
41 cout << "Size: " << size() << endl;
42 cout << "Sigma: " << sigma << endl;
43 cout << "Maximum: " << max << endl << endl;
44 }
45
46 Vector3<double> h(size()/2);
47 origin(h);
48
49 long i, xx, yy, zz;
50 double x2, y2, z2, s2;
51 double invsigma2(-0.5/(sigma*sigma));
52
53 for ( i=zz=0; zz<z; zz++ ) {
54 z2 = zz - h[2];
55 z2 *= z2;
56 for ( yy=0; yy<y; yy++ ) {
57 y2 = yy - h[1];
58 y2 *= y2;
59 for ( xx=0; xx<x; xx++, i++ ) {
60 x2 = xx - h[0];
61 x2 *= x2;
62 s2 = x2 + y2 + z2;
63 set(i, max*exp(s2*invsigma2));
64 }
65 }
66 }
67
68 return 0;
69 }
70
77 int Bimage::kernel_laplacian_of_gaussian(double sigma, double max)
78 {
79 if ( sigma < 0.001 ) sigma = 1;
80 if ( max < 1e-10 ) max = 1;
81
82 if ( verbose & VERB_PROCESS ) {
83 cout << "Generating a laplacian-of-gaussian kernel:" << endl;
84 cout << "Size: " << size() << endl;
85 cout << "Sigma: " << sigma << endl;
86 cout << "Maximum: " << max << endl << endl;
87 }
88
89 Vector3<double> h(size()/2);
90 origin(h);
91
92 long i, xx, yy, zz, ndim(0);
93 if ( x > 1 ) ndim++;
94 if ( y > 1 ) ndim++;
95 if ( z > 1 ) ndim++;
96 double x2, y2, z2, s2;
97 double invsigma2 = 1/(sigma*sigma);
98 double invsigma4 = invsigma2*invsigma2;
99 double scale = max/(ndim*invsigma2);
100
101 for ( i=zz=0; zz<z; zz++ ) {
102 z2 = zz - h[2];
103 z2 *= z2;
104 for ( yy=0; yy<y; yy++ ) {
105 y2 = yy - h[1];
106 y2 *= y2;
107 for ( xx=0; xx<x; xx++, i++ ) {
108 x2 = xx - h[0];
109 x2 *= x2;
110 s2 = x2 + y2 + z2;
111 set(i, scale*(s2*invsigma4 - ndim*invsigma2)*exp(-0.5*s2*invsigma2));
112 }
113 }
114 }
115
116 return 0;
117 }
118
119
120 int Bimage::average_line_sum(long nn, long i, long ik, long nk)
121 {
122 if ( size()[ik] < 2 ) return 0;
123
124 long ii(i*x), j, j1, j2, jc, cc, inc(1);
125 long nl(size()[ik]), ll(nl*c), hk(nk/2), nv(0);
126 vector<double> s(c,0);
127 // for ( cc=0; cc<c; cc++ ) s[cc] = 0;
128
129 if ( ik == 1 ) {
130 ii = (i%x) + (i/x) * x * y;
131 inc = x;
132 } else if ( ik == 2 ) {
133 ii = i;
134 inc = x * y;
135 }
136
137 ii += nn * x * y * z;
138
139 double step = inc*hk;
140 vector<double> v(ll);
141
142 // cout << ii << tab << ll << tab << hk << tab << inc << tab << s[0] << endl;
143 // Initial sum
144 for ( j=ii, j1=0; j1<hk; j+=inc, j1++, nv++ )
145 for ( cc=0, jc=j*c; cc<c; cc++, jc++ )
146 s[cc] += (*this)[jc];
147 // cout << "---" << endl;
148 // Main sums
149 for ( j=ii, j1=0; j1<nl; j+=inc, j1++ ) {
150 if ( j1 < nl-hk ) { // Add the leading values
151 j2 = j + (long) step;
152 for ( cc=0, jc=j2*c; cc<c; cc++, jc++ )
153 s[cc] += (*this)[jc];
154 nv++;
155 }
156 for ( cc=0, jc=j1*c; cc<c; cc++, jc++ )
157 v[jc] = s[cc]/nv;
158 if ( j1 >= hk ) { // Subtract the trailing values
159 j2 = j - (long) step;
160 for ( cc=0, jc=j2*c; cc<c; cc++, jc++ )
161 s[cc] -= (*this)[jc];
162 nv--;
163 }
164 }
165
166 for ( j=ii, j1=0; j1<ll; j+=inc )
167 for ( cc=0, jc=j*c; cc<c; cc++, jc++, j1++ )
168 set(jc, v[j1]);
169
170 return 0;
171 }
172
173 int Bimage::average_line_sums(long nn, long ik, long nk)
174 {
175 if ( size()[ik] < 2 ) return 0;
176
177 long i, nls(1);
178
179 // Count the number of lines
180 for ( i=0; i<3; i++ ) if ( i != ik ) nls *= size()[i];
181
182 if ( verbose & VERB_PROCESS )
183 cout << tab << "Axis " << ik << " of size " << nls << endl;
184
185 // Do each line
186 #ifdef HAVE_GCD
187 dispatch_apply(nls, dispatch_get_global_queue(0, 0), ^(size_t i){
188 average_line_sum(nn, i, ik, nk);
189 });
190 #else
191 #pragma omp parallel for
192 for ( i=0; i<nls; i++ )
193 average_line_sum(nn, i, ik, nk);
194 #endif
195
196 return 0;
197 }
198
208 int Bimage::filter_average(long kernel_size)
209 {
210 Vector3<long> ksize(kernel_size, kernel_size, kernel_size);
211 return filter_average(ksize);
212 }
213
214 int Bimage::filter_average(Vector3<long> k)
215 {
216 change_type(Float);
217
218 if ( k[0]%2 == 0 ) k[0] += 1;
219 if ( k[1]%2 == 0 ) k[1] += 1;
220 if ( k[2]%2 == 0 ) k[2] += 1;
221
222 k = k.min(size());
223
224 if ( verbose & VERB_LABEL ) {
225 cout << "Applying an averaging filter:" << endl;
226 cout << "Kernel size: " << k << " (" << k.volume() << ")" << endl << endl;
227 }
228
229 long i, nn;
230
231 for ( nn=0; nn<n; nn++ ) {
232 if ( verbose & VERB_PROCESS )
233 cout << "Image " << nn << endl;
234 for ( i=0; i<3; i++ )
235 average_line_sums(nn, i, k[i]);
236 }
237
238 if ( verbose & VERB_PROCESS ) cout << endl;
239
240 statistics();
241
242 return 0;
243 }
244
245 int Bimage::gaussian_line_sum(long nn, long i, long ik, Bimage* pk)
246 {
247 if ( size()[ik] < 2 ) return 0;
248
249 long ii(i*x), j, j1, j2, jm, jc, ji, cc, inc(1), nl(size()[ik]), ll(nl*c), hk(pk->x/2);
250 double w;
251
252 if ( ik == 1 ) {
253 ii = (i%x) + (i/x) * x * y;
254 inc = x;
255 } else if ( ik == 2 ) {
256 ii = i;
257 inc = x * y;
258 }
259
260 ii += nn * x * y * z;
261 jm = ii + nl*inc;
262
263 vector<double> v(ll);
264
265 // Main sums
266 for ( j1=0; j1<nl; j1++ ) {
267 j2 = ( j1 < hk )? hk - j1: 0;
268 j = ii;
269 if ( j2 < 1 ) j += (j1 - hk)*inc;
270 for ( cc=0, jc=j1*c; cc<c; cc++, jc++ )
271 v[jc] = 0;
272 for ( w=0; j2<pk->x && j<jm; j+=inc, j2++ ) {
273 for ( cc=0, jc=j1*c, ji=j*c; cc<c; cc++, jc++, ji++ )
274 v[jc] += (*pk)[j2] * (*this)[ji];
275 w += (*pk)[j2];
276 }
277 for ( cc=0, jc=j1*c; cc<c; cc++, jc++ )
278 v[jc] /= w;
279 }
280
281 // Transfer back
282 for ( j=ii, j1=0; j1<ll; j+=inc )
283 for ( cc=0, jc=j*c; cc<c; cc++, jc++, j1++ )
284 set(jc, v[j1]);
285
286 return 0;
287 }
288
289 int Bimage::gaussian_line_sums(long nn, long ik, Bimage* pk)
290 {
291 if ( size()[ik] < 2 ) return 0;
292
293 long i, nls(1);
294
295 // Count the number of lines
296 for ( i=0; i<3; i++ ) if ( i != ik ) nls *= size()[i];
297
298 if ( verbose & VERB_PROCESS )
299 cout << tab << "Axis " << ik << " of size " << nls << endl;
300
301 // Do each line
302 #ifdef HAVE_GCD
303 dispatch_apply(nls, dispatch_get_global_queue(0, 0), ^(size_t i){
304 gaussian_line_sum(nn, i, ik, pk);
305 });
306 #else
307 #pragma omp parallel for
308 for ( i=0; i<nls; i++ )
309 gaussian_line_sum(nn, i, ik, pk);
310 #endif
311
312 return 0;
313 }
314
325 int Bimage::filter_gaussian(long kernel_size, double sigma)
326 {
327 change_type(Float);
328
329 if ( kernel_size%2 == 0 ) kernel_size += 1;
330
331 Bimage* pk = new Bimage(Float, TSimple, kernel_size, 1, 1, 1);
332 pk->kernel_gaussian(sigma, 1);
333
334 if ( verbose & VERB_PROCESS ) {
335 cout << "Applying a gaussian filter:" << endl;
336 cout << "Kernel size: " << pk->x << endl;
337 cout << "Sigma: " << sigma << endl << endl;
338 }
339
340 long i, nn;
341
342 for ( nn=0; nn<n; nn++ ) {
343 if ( verbose & VERB_PROCESS )
344 cout << "Image " << nn << endl;
345 for ( i=0; i<3; i++ )
346 gaussian_line_sums(nn, i, pk);
347 }
348
349 if ( verbose & VERB_PROCESS ) cout << endl;
350
351 delete pk;
352
353 statistics();
354
355 return 0;
356 }
357
366 int Bimage::filter_sinc()
367 {
368 long i, xx, yy, zz;
369 double r, w;
370 Vector3<double> d;
371
372 if ( verbose )
373 cout << "Weighing with a sinc function" << endl << endl;
374
375 for ( i=zz=0; zz<z; zz++ ) {
376 d[2] = (-image->origin()[2] + zz)/z;
377 for ( yy=0; yy<y; yy++ ) {
378 d[1] = (-image->origin()[1] + yy)/y;
379 for ( xx=0; xx<x; xx++, i++ ) {
380 d[0] = (-image->origin()[0] + xx)/x;
381 r = M_PI*d.length();
382 if ( r ) {
383 w = r/sin(r);
384 set(i, w * w * (*this)[i]);
385 }
386 }
387 }
388 }
389
390 return 0;
391 }
392
393 int Bimage::convolve_chunk(Bimage* pkernel, float* nudata, long i, long len)
394 {
395 long ic, j, jy, jz, jn, m, nn, xx, yy, zz, cc, kx, ky, kz, ix, iy, iz;
396 Vector3<long> hk(pkernel->image->origin());
397 long xmin, ymin, zmin, xmax, ymax, zmax;
398 double v, w;
399
400 coordinates(i, cc, xx, yy, zz, nn);
401
402 if ( cc != 0 )
403 cerr << "Warning: chunk not on channel boundary! (" << i << ")" << endl;
404
405 if ( verbose & VERB_DEBUG )
406 cout << "DEBUG Bimage::convolve_chunk: " << i << tab << cc << tab << xx
407 << tab << yy << tab << zz << tab << nn << endl;
408
409 xmin = kmin(xx, hk[0]);
410 xmax = kmax(xx, pkernel->x, x);
411 ymin = kmin(yy, hk[1]);
412 ymax = kmax(yy, pkernel->y, y);
413 zmin = kmin(zz, hk[2]);
414 zmax = kmax(zz, pkernel->z, z);
415
416 m = i+len;
417 if ( m > datasize ) m = datasize;
418
419 for ( ; i<m; xx++, i+=c ) {
420 if ( xx >= x ) {
421 xx = 0;
422 yy++;
423 if ( yy >= y ) {
424 yy = 0;
425 zz++;
426 if ( zz >= z ) {
427 zz = 0;
428 nn++;
429 }
430 zmin = kmin(zz, hk[2]);
431 zmax = kmax(zz, pkernel->z, z);
432 }
433 ymin = kmin(yy, hk[1]);
434 ymax = kmax(yy, pkernel->y, y);
435 }
436 xmin = kmin(xx, hk[0]);
437 xmax = kmax(xx, pkernel->x, x);
438 for ( cc=0, ic=i; cc<c; cc++, ic++ ) nudata[ic] = 0;
439 w = 0;
440 jn = nn*z;
441 for ( kz=zmin; kz<zmax; kz++ ) {
442 jz = (jn + zz + kz - hk[2])*y;
443 iz = kz*pkernel->y;
444 for ( ky=ymin; ky<ymax; ky++ ) {
445 jy = (jz + yy + ky - hk[1])*x;
446 iy = (iz + ky)*pkernel->x;
447 for ( kx=xmin; kx<xmax; kx++ ) {
448 j = (jy + xx + kx - hk[0])*c;
449 ix = iy + kx;
450 v = (*pkernel)[ix];
451 for ( cc=0, ic=i; cc<c; cc++, ic++, j++ )
452 nudata[ic] += (*this)[j]*v;
453 w += v;
454 }
455 }
456 }
457 if ( w ) for ( cc=0, ic=i; cc<c; cc++, ic++ )
458 nudata[ic] /= w;
459 }
460
461 return 0;
462 }
463
474 int Bimage::convolve(Bimage* pkernel)
475 {
476 if ( !pkernel || !pkernel->data_pointer() ) {
477 cerr << "Error in Bimage::convolve: No kernel specified!" << endl << endl;
478 return -1;
479 }
480
481 if ( pkernel->sizeX() > x || pkernel->sizeY() > y || pkernel->sizeZ() > z ) {
482 error_show("Error in Bimage::convolve", __FILE__, __LINE__);
483 cerr << "Error: Kernel size does not fit the image size:" << endl;
484 cerr << " Kernel size = " << pkernel->size() << endl;
485 cerr << " Image size = " << size() << endl;
486 return -1;
487 }
488
489 change_type(Float);
490 pkernel->change_type(Float);
491
492 if ( verbose & VERB_PROCESS ) {
493 cout << "Convolving with a kernel: " << pkernel->file_name() << endl;
494 cout << "Kernel size: " << pkernel->size() << endl << endl;
495 }
496
497 long i, xx, yy, chunk_size(get_chunk_size(datasize, c));
498
499 float* nudata = new float[datasize];
500
501 // if ( verbose & VERB_FULL ) {
502 cout << "Kernel:" << endl;
503 for ( i=yy=0; yy<pkernel->sizeY()*pkernel->sizeZ(); yy++ ) {
504 for ( xx=0; xx<pkernel->sizeX(); xx++, i++ )
505 cout << tab << (*pkernel)[i];
506 cout << endl;
507 }
508 cout << endl;
509 // }
510
511 #ifdef HAVE_GCD
512 dispatch_apply((datasize - 1)/chunk_size + 1, dispatch_get_global_queue(0, 0), ^(size_t i){
513 convolve_chunk(pkernel, nudata, i*chunk_size, chunk_size);
514 });
515 #else
516 #pragma omp parallel for
517 for ( long i=0; i<datasize; i+=chunk_size )
518 convolve_chunk(pkernel, nudata, i, chunk_size);
519 #endif
520
521 data_assign((unsigned char *) nudata);
522
523 statistics();
524
525 return 0;
526 }
527
545 int Bimage::filter_ortho(int type)
546 {
547 change_type(Float);
548
549 long i, xx, yy, zz, nn;
550 double value;
551 long slicesize(x*y*c);
552 float* nudata = new float[datasize];
553 long ksize(1);
554 if ( x > 1 ) ksize += 2;
555 if ( y > 1 ) ksize += 2;
556 if ( z > 1 ) ksize += 2;
557 vector<double> kernel(ksize);
558
559 if ( type == 0 ) {
560 kernel[0] = 0;
561 for ( i=1; i<7; i+=2 )
562 if ( ksize > i ) {
563 kernel[i] = -1;
564 kernel[i+1] = 1;
565 }
566 } else if ( type == 1 ) {
567 kernel[0] = 0;
568 for ( i=1; i<7; i+=2 )
569 if ( ksize > i ) {
570 kernel[0] -= 2;
571 kernel[i] = 1;
572 kernel[i+1] = 1;
573 }
574 }
575
576 if ( verbose & VERB_PROCESS ) {
577 cout << "Convolving with an orthogonal kernel:" << endl;
578 cout << "Kernel type: ";
579 switch ( type ) {
580 case 0: cout << "gradient"; break;
581 case 1: cout << "laplacian"; break;
582 default: break;
583 }
584 cout << endl << endl;
585 }
586
587 for ( i=nn=0; nn<n; nn++ ) {
588 for ( zz=0; zz<z; zz++ ) {
589 for ( yy=0; yy<y; yy++ ) {
590 for ( xx=0; xx<x; xx++, i++ ) {
591 value = kernel[0]*(*this)[i];
592 if ( x > 1 ) {
593 if ( xx > 0 ) value += kernel[1]*(*this)[i-1];
594 else value += kernel[1]*(*this)[i+x-1];
595 if ( xx < x - 1 ) value += kernel[2]*(*this)[i+1];
596 else value += kernel[2]*(*this)[i+1-x];
597 if ( type == 0 ) {
598 nudata[i] = value*value;
599 value = 0;
600 }
601 }
602 if ( y > 1 ) {
603 if ( yy > 0 ) value += kernel[3]*(*this)[i-x];
604 else value += kernel[3]*(*this)[i+slicesize-x];
605 if ( yy < y - 1 ) value += kernel[4]*(*this)[i+x];
606 else value += kernel[4]*(*this)[i+x-slicesize];
607 if ( type == 0 ) {
608 nudata[i] += value*value;
609 value = 0;
610 }
611 }
612 if ( z > 1 ) {
613 if ( zz > 0 ) value += kernel[5]*(*this)[i-slicesize];
614 else value += kernel[5]*(*this)[i+datasize-slicesize];
615 if ( zz < z - 1 ) value += kernel[6]*(*this)[i+slicesize];
616 else value += kernel[6]*(*this)[i+slicesize-datasize];
617 if ( type == 0 ) {
618 nudata[i] += value*value;
619 value = 0;
620 }
621 }
622 if ( type == 1 ) nudata[i] = value;
623 else nudata[i] = sqrt(nudata[i]);
624 }
625 }
626 }
627 }
628
629 data_assign((unsigned char *) nudata);
630
631 statistics();
632
633 return 0;
634 }
635
642 int Bimage::filter_dog(double sigma1, double sigma2)
643 {
644 if ( sigma1 > sigma2 ) swap(sigma1, sigma2);
645
646 long k(long(6*sigma2+1));
647 Vector3<long> ksize(k, k, k);
648 ksize = ksize.min(size());
649
650 double m1(1/(sqrt(TWOPI)*sigma1));
651 double m2(1/(sqrt(TWOPI)*sigma2));
652
653 Bimage* pk = new Bimage(Float, TSimple, ksize, 1);
654 Bimage* pk2 = new Bimage(Float, TSimple, ksize, 1);
655
656 pk->kernel_gaussian(sigma1, m1);
657 pk2->kernel_gaussian(sigma2, m2);
658 pk->subtract(pk2);
659
660 delete pk2;
661
662 convolve(pk);
663
664 delete pk;
665
666 statistics();
667
668 return 0;
669 }
670
671 int Bimage::filter_bilateral_chunk(Bimage* pkernel, double sigma2,
672 int kernel_type, float* nudata, long i, long len, int first)
673 {
674 long nn, xx, yy, zz, cc;
675 long ic, j, jy, jz, jn, m, kx, ky, kz, ix, iy, iz, cnt(0);
676 Vector3<long> hk(pkernel->image->origin());
677 long xmin, ymin, zmin, xmax, ymax, zmax;
678
679 double diff2, f, ref, acc, acc_num, acc_denom;
680 double gauss_neginv2sig2(0), lorentz_invsig2(0), tukey_invsig2(0);
681 if ( kernel_type == 1) gauss_neginv2sig2 = -0.5/(sigma2*sigma2);
682 else if ( kernel_type == 2) lorentz_invsig2 = 1./(sigma2*sigma2);
683 else if ( kernel_type == 3) tukey_invsig2 = 0.2/(sigma2*sigma2);
684
685 coordinates(i, cc, xx, yy, zz, nn);
686
687 if ( cc != 0 )
688 cerr << "Warning: chunk not on channel boundary! (" << i << ")" << endl;
689
690 if ( verbose & VERB_DEBUG )
691 cout << "DEBUG Bimage::filter_bilateral_chunk: " << i << tab << cc << tab << xx
692 << tab << yy << tab << zz << tab << nn << endl;
693
694 xmin = kmin(xx, hk[0]);
695 xmax = kmax(xx, pkernel->x, x);
696 ymin = kmin(yy, hk[1]);
697 ymax = kmax(yy, pkernel->y, y);
698 zmin = kmin(zz, hk[2]);
699 zmax = kmax(zz, pkernel->z, z);
700
701 m = i+len;
702 if ( m > datasize ) m = datasize;
703
704 for ( ; i<m; xx++, i+=c ) {
705 if ( xx >= x ) {
706 xx = 0;
707 yy++;
708 if ( yy >= y ) {
709 yy = 0;
710 zz++;
711 if ( zz >= z ) {
712 zz = 0;
713 nn++;
714 }
715 zmin = kmin(zz, hk[2]);
716 zmax = kmax(zz, pkernel->z, z);
717 }
718 ymin = kmin(yy, hk[1]);
719 ymax = kmax(yy, pkernel->y, y);
720 }
721 xmin = kmin(xx, hk[0]);
722 xmax = kmax(xx, pkernel->x, x);
723 for ( cc=0, ic=i; cc<c; cc++, ic++ ) nudata[ic] = 0;
724 ref = (*this)[i];
725 acc_num = acc_denom = 0.0;
726 jn = nn*z;
727 for ( kz=zmin; kz<zmax; kz++ ) {
728 jz = (jn + zz + kz - hk[2])*y;
729 iz = kz*pkernel->y;
730 for ( ky=ymin; ky<ymax; ky++ ) {
731 jy = (jz + yy + ky - hk[1])*x;
732 iy = (iz + ky)*pkernel->x;
733 for ( kx=xmin; kx<xmax; kx++ ) {
734 j = (jy + xx + kx - hk[0])*c;
735 ix = iy + kx;
736 diff2 = ref - (*this)[j];
737 diff2 *= diff2;
738 acc = 0;
739 switch (kernel_type) {
740 case 1: // gaussian
741 acc = exp(gauss_neginv2sig2*diff2);
742 break;
743 case 2: // lorentz
744 acc = 1/(1+lorentz_invsig2*diff2);
745 break;
746 case 3: // tukey
747 if (diff2 <= tukey_invsig2) {
748 f = 1 - tukey_invsig2*diff2;
749 acc = 0.5*f*f;
750 };
751 break;
752 }
753 acc *= (*pkernel)[ix];
754 acc_num += acc*(*this)[j];
755 acc_denom += acc;
756 }
757 }
758 }
759 for ( cc=0, ic=i; cc<c; cc++, ic++ )
760 if (acc_denom > 0) nudata[ic] = acc_num/acc_denom;
761 if ( first && ( verbose & ( VERB_TIME | VERB_PROCESS | VERB_RESULT ) ) )
762 cerr << "Complete: " << setprecision(3)
763 << (++cnt)*100.0/len << " % \r" << flush;
764 }
765
766 return 0;
767 }
768
784 int Bimage::filter_bilateral(double sigma1, double sigma2,
785 int kernel_type, long kernel_radius)
786 {
787 // Initialize parameters
788 if ( sigma1 <= 0 ) sigma1 = 1;
789 if ( kernel_radius <= 0 ) kernel_radius = (long) (sigma1*3);
790 if ( sigma2 <= 0 ) sigma2 = std;
791
792 Vector3<long> ksize(kernel_radius*2+1, kernel_radius*2+1, kernel_radius*2+1);
793 ksize = ksize.min(size());
794
795 Bimage* pkernel = new Bimage(Double, TSimple, ksize, 1);
796 pkernel->kernel_gaussian(sigma1, 1);
797
798 change_type(Float);
799
800 if ( verbose & VERB_LABEL ) {
801 cout << "Denoising with a bilateral kernel:" << endl;
802 cout << "Sigma values: " << sigma1 << " " << sigma2 << endl;
803 cout << "Kernel type: " << kernel_type << endl;
804 cout << "Kernel size: " << ksize << endl << endl;
805 }
806
807 long chunk_size(get_chunk_size(datasize, c));
808
809 float* nudata = new float[datasize];
810
811 #ifdef HAVE_GCD
812 dispatch_apply((datasize - 1)/chunk_size + 1, dispatch_get_global_queue(0, 0), ^(size_t i){
813 filter_bilateral_chunk(pkernel, sigma2, kernel_type, nudata, i*chunk_size, chunk_size, i==0);
814 });
815 #else
816 #pragma omp parallel for
817 for ( long i=0; i<datasize; i+=chunk_size )
818 filter_bilateral_chunk(pkernel, sigma2, kernel_type, nudata, i, chunk_size, i==0);
819 #endif
820
821 delete pkernel;
822
823 data_assign((unsigned char *) nudata);
824
825 statistics();
826
827 return 0;
828 }
829
836 int Bimage::filter_rolling_ball(long radius, double scale)
837 {
838 if ( radius < 1 ) radius = 1;
839 if ( fabs(scale) < 1e-30 ) scale = 1;
840
841 long i, xx, yy, zz, nn, kx, ky, kz;
842 long ix, iy, iz, jx, jy, jz;
843 double r2(radius*radius);
844 double dx2, dy2, dz2, diff, bcenter;
845
846 Vector3<long> ksize(radius*2+1, radius*2+1, radius*2+1);
847 ksize = ksize.min(size());
848 Vector3<long> hk(ksize/2);
849 Vector3<long> lo, hi;
850
851 long ball_size = (long) ksize.volume();
852 vector<double> ball(ball_size);
853
854 for ( i=zz=0; zz<ksize[2]; zz++ ) {
855 dz2 = (double)zz - hk[2];
856 dz2 *= dz2;
857 for ( yy=0; yy<ksize[1]; yy++ ) {
858 dy2 = (double)yy - hk[1];
859 dy2 *= dy2;
860 for ( xx=0; xx<ksize[0]; xx++, i++ ) {
861 dx2 = (double)xx - hk[0];
862 dx2 *= dx2;
863 diff = r2 - dx2 - dy2 - dz2;
864 if ( diff > 0 ) ball[i] = sqrt(diff)/scale;
865 else ball[i] = 0;
866 }
867 }
868 }
869
870 change_type(Float);
871
872 if ( verbose & VERB_PROCESS ) {
873 cout << "Rolling ball filter:" << endl;
874 cout << "Radius: " << radius << endl;
875 cout << "Scaling: " << scale << endl << endl;
876 }
877
878 vector<float> back(datasize);
879 for ( i=0; i<datasize; i++ ) back[i] = (*this)[i];
880
881 for ( i=nn=0; nn<n; nn++ ) {
882 for ( zz=0; zz<z; zz++ ) {
883 lo[2] = kmin(zz, hk[2]);
884 hi[2] = kmax(zz, ksize[2], z);
885 for ( yy=0; yy<y; yy++ ) {
886 lo[1] = kmin(yy, hk[1]);
887 hi[1] = kmax(yy, ksize[1], y);
888 for ( xx=0; xx<x; xx++, i++ ) {
889 lo[0] = kmin(xx, hk[0]);
890 hi[0] = kmax(xx, ksize[0], x);
891 if ( scale > 0 ) bcenter = max;
892 else bcenter = min;
893 for ( kz=lo[2]; kz<hi[2]; kz++ ) {
894 iz = (nn*z + zz + kz - hk[2])*y;
895 jz = kz*ksize[1];
896 for ( ky=lo[1]; ky<hi[1]; ky++ ) {
897 iy = (iz + yy + ky - hk[1])*x;
898 jy = (jz + ky)*ksize[0];
899 for ( kx=lo[0]; kx<hi[0]; kx++ ) {
900 ix = iy + xx + kx - hk[0];
901 jx = jy + kx;
902 diff = (*this)[ix] - (bcenter + ball[jx]);
903 if ( ball[jx] > 0 ) {
904 if ( diff < 0 ) bcenter += diff; // Moving the ball down
905 } else if ( ball[jx] < 0 ) {
906 if ( diff > 0 ) bcenter += diff; // Moving the ball up
907 }
908 }
909 }
910 }
911 for ( kz=lo[2]; kz<hi[2]; kz++ ) {
912 iz = (nn*z + zz + kz - hk[2])*y;
913 jz = kz*ksize[1];
914 for ( ky=lo[1]; ky<hi[1]; ky++ ) {
915 iy = (iz + yy + ky - hk[1])*x;
916 jy = (jz + ky)*ksize[0];
917 for ( kx=lo[0]; kx<hi[0]; kx++ ) {
918 ix = iy + xx + kx - hk[0];
919 jx = jy + kx;
920 diff = bcenter + ball[jx];
921 if ( ball[jx] > 0 ) {
922 if ( back[ix] > diff ) back[ix] = diff; // Assigning the background
923 } else if ( ball[jx] < 0 ) {
924 if ( back[ix] < diff ) back[ix] = diff; // Assigning the background
925 }
926 }
927 }
928 }
929 }
930 }
931 }
932 }
933
934 for ( i=0; i<datasize; i++ ) set(i, (*this)[i] - back[i]);
935
936 statistics();
937
938 return 0;
939 }
940
941 int Bimage::filter_rank_chunk(long kernel_size, double rank, float* nudata, long i, long len)
942 {
943 Vector3<long> blocksize(kernel_size, kernel_size, kernel_size);
944 blocksize = blocksize.min(size());
945 Vector3<long> hk(blocksize/2);
946 long blocktotalsize = (long) blocksize.volume();
947 vector<double> block(blocktotalsize);
948
949 long nn, xx, yy, zz, cc;
950 long j, jy, jz, jn, m, kx, ky, kz;
951 long xmin, ymin, zmin, xmax, ymax, zmax;
952 long nblock, imed;
953
954 coordinates(i, cc, xx, yy, zz, nn);
955
956 if ( cc != 0 )
957 cerr << "Warning: chunk not on channel boundary! (" << i << ")" << endl;
958
959 if ( verbose & VERB_DEBUG )
960 cout << "DEBUG Bimage::filter_rank_chunk: " << i << tab << cc << tab << xx
961 << tab << yy << tab << zz << tab << nn << endl;
962
963 xmin = kmin(xx, hk[0]);
964 xmax = kmax(xx, blocksize[0], x);
965 ymin = kmin(yy, hk[1]);
966 ymax = kmax(yy, blocksize[1], y);
967 zmin = kmin(zz, hk[2]);
968 zmax = kmax(zz, blocksize[2], z);
969
970 m = i+len;
971 if ( m > datasize ) m = datasize;
972
973 for ( ; i<m; xx++, i+=c ) {
974 if ( xx >= x ) {
975 xx = 0;
976 yy++;
977 if ( yy >= y ) {
978 yy = 0;
979 zz++;
980 if ( zz >= z ) {
981 zz = 0;
982 nn++;
983 }
984 zmin = kmin(zz, hk[2]);
985 zmax = kmax(zz, blocksize[2], z);
986 }
987 ymin = kmin(yy, hk[1]);
988 ymax = kmax(yy, blocksize[1], y);
989 }
990 xmin = kmin(xx, hk[0]);
991 xmax = kmax(xx, blocksize[0], x);
992 nblock = 0;
993 jn = nn*z;
994 for ( kz=zmin; kz<zmax; kz++ ) {
995 jz = (jn + zz + kz - hk[2])*y;
996 for ( ky=ymin; ky<ymax; ky++ ) {
997 jy = (jz + yy + ky - hk[1])*x;
998 for ( kx=xmin; kx<xmax; kx++ ) {
999 j = (jy + xx + kx - hk[0])*c;
1000 block[nblock++] = (*this)[j];
1001 }
1002 }
1003 }
1004 imed = nblock*rank;
1005 partition(block, nblock, imed);
1006 nudata[i] = block[imed];
1007 }
1008
1009 return 0;
1010 }
1011
1022 int Bimage::filter_rank(long kernel_size, double rank)
1023 {
1024 if ( compoundtype != TSimple ) {
1025 cerr << "Error: The rank filter only operates on single value images!" << endl << endl;
1026 return -1;
1027 }
1028
1029 if ( kernel_size%2 == 0 ) kernel_size += 1;
1030
1031 // long i, j, jz, jy, nn, xx, yy, zz, kx, ky, kz;
1032 Vector3<long> blocksize(kernel_size, kernel_size, kernel_size);
1033 blocksize = blocksize.min(size());
1034 long blocktotalsize = (long) blocksize.volume();
1035
1036 if ( verbose & VERB_PROCESS ) {
1037 cout << "Applying a rank filter:" << endl;
1038 cout << "Rank: " << (long)(rank*blocktotalsize) << endl;
1039 cout << "Kernel size: " << blocksize << " (" << blocksize.volume() << ")" << endl << endl;
1040 }
1041
1042 long i, chunk_size(get_chunk_size(datasize, c));
1043 float* nudata = new float[datasize];
1044
1045 #ifdef HAVE_GCD
1046 dispatch_apply((datasize - 1)/chunk_size + 1, dispatch_get_global_queue(0, 0), ^(size_t i){
1047 filter_rank_chunk(kernel_size, rank, nudata, i*chunk_size, chunk_size);
1048 });
1049 #else
1050 #pragma omp parallel for
1051 for ( long i=0; i<datasize; i+=chunk_size )
1052 filter_rank_chunk(kernel_size, rank, nudata, i, chunk_size);
1053 #endif
1054
1055 for ( i=0; i<datasize; i++ ) set(i, nudata[i]);
1056
1057 if ( verbose & VERB_DEBUG )
1058 cout << "DEBUG Bimage::filter_rank: Done" << endl;
1059
1060 delete[] nudata;
1061
1062 statistics();
1063
1064 return 0;
1065 }
1066
1076 Bimage* Bimage::filter_peak(long kernel_size)
1077 {
1078 if ( compoundtype != TSimple ) {
1079 cerr << "Error: The average filter only operates on single value images!" << endl << endl;
1080 return NULL;
1081 }
1082
1083 if ( kernel_size%2 == 0 ) kernel_size += 1;
1084 if ( kernel_size < 3 ) kernel_size = 3;
1085
1086 long i, j, nn, xx, yy, zz, kx, ky, kz;
1087 long zlo, zhi, ylo, yhi, xlo, xhi;
1088 Vector3<long> blocksize(kernel_size, kernel_size, kernel_size);
1089 blocksize = blocksize.min(size());
1090 Vector3<long> h(blocksize/2);
1091 long blocktotalsize = (long) blocksize.volume();
1092 double bkg, v, v2;
1093
1094 Bimage* ppeak = copy();
1095
1096 if ( verbose & VERB_PROCESS ) {
1097 cout << "Applying a peak filter:" << endl;
1098 cout << "Block size: " << blocksize << " (" << blocktotalsize << ")" << endl << endl;
1099 }
1100
1101 // Do the peak filtering
1102 for ( i=nn=0; nn<n; nn++ ) {
1103 bkg = background(nn);
1104 for ( zz=0; zz<z; zz++ ) {
1105 zlo = (zz > h[2])? zz - h[2]: 0;
1106 zhi = zz + h[2];
1107 if ( zhi >= z ) zhi = z - 1;
1108 for ( yy=0; yy<y; yy++ ) {
1109 ylo = (yy > h[1])? yy - h[1]: 0;
1110 yhi = yy + h[1];
1111 if ( yhi >= y ) yhi = y - 1;
1112 for ( xx=0; xx<x; xx++, i++ ) {
1113 xlo = (xx > h[0])? xx - h[0]: 0;
1114 xhi = xx + h[0];
1115 if ( xhi >= x ) xhi = x - 1;
1116 v = (*this)[i];
1117 for ( kz=zlo; kz<=zhi; kz++ ) {
1118 for ( ky=ylo; ky<=yhi; ky++ ) {
1119 for ( kx=xlo; kx<=xhi; kx++ ) {
1120 j = index(kx, ky, kz, nn);
1121 v2 = (*this)[j];
1122 if ( v < v2 ) v = bkg;
1123 }
1124 }
1125 }
1126 ppeak->set(i, v);
1127 }
1128 }
1129 }
1130 }
1131
1132 if ( verbose & VERB_DEBUG )
1133 cout << "DEBUG Bimage::filter_peak: Done" << endl;
1134
1135 ppeak->statistics();
1136
1137 return ppeak;
1138 }
1139
1145 Bimage* Bimage::periodic_averaging(Vector3<double> period)
1146 {
1147 change_type(Float);
1148
1149 period = period.min(size());
1150
1151 Bimage* pnu = copy_header();
1152 pnu->size(period);
1153 pnu->page_size(period);
1154 pnu->data_alloc();
1155 vector<float> w(pnu->image_size());
1156
1157 long i, j, k, xo, yo, zo, nn, xx, yy, zz, cc;
1158
1159 if ( verbose ) {
1160 cout << "Calculating a periodic average:" << endl;
1161 cout << "Period: " << period << endl << endl;
1162 }
1163
1164 for ( i=nn=0; nn<n; nn++ ) {
1165 for ( k=0; k<pnu->image_size(); k++ ) w[k] = 0;
1166 for ( zo=zz=0; zo<z; zo++, zz++ ) {
1167 if ( zz >= pnu->sizeZ() ) zz = 0;
1168 for ( yo=yy=0; yo<y; yo++, yy++ ) {
1169 if ( yy >= pnu->sizeY() ) yy = 0;
1170 for ( xo=xx=0; xo<x; xo++, xx++ ) {
1171 if ( xx >= pnu->sizeX() ) xx = 0;
1172 k = pnu->index(xx, yy, zz);
1173 w[k] += 1;
1174 j = pnu->index(0, xx, yy, zz, nn);
1175 for ( cc=0; cc<c; cc++, j++, i++ )
1176 pnu->add(j, (*this)[i]);
1177 }
1178 }
1179 }
1180 for ( k=0, j=nn*c*pnu->image_size(); k<pnu->image_size(); k++ )
1181 if ( w[k] ) for ( cc=0; cc<c; cc++, j++ )
1182 pnu->set(j, (*pnu)[j]/w[k]);
1183 }
1184
1185 pnu->origin(Vector3<long>(period/2));
1186
1187 return pnu;
1188 }
1189
1190
1191
Bimage::change_type
void change_type(char letter)
Get the data type indicated by a single letter code.
Definition: Bimage.cpp:1743
Bimage::filter_rank_chunk
int filter_rank_chunk(long kernel_size, double rank, float *nudata, long i, long len)
Definition: Bimage_filter.cpp:941
Bimage::copy_header
Bimage * copy_header()
Definition: Bimage.h:650
Bimage::filter_sinc
int filter_sinc()
Weighs an image with a sinc function.
Definition: Bimage_filter.cpp:366
Bimage.h
Header file for image class.
Vector3::length
double length()
Definition: Vector3.h:222
Bimage::convolve_chunk
int convolve_chunk(Bimage *pkernel, float *nudata, long i, long len)
Definition: Bimage_filter.cpp:393
Bimage::add
void add(long j, double v)
Definition: Bimage.h:308
Bimage::image_size
long image_size()
Definition: Bimage.h:267
utilities.h
Header file for general utilities.
VERB_DEBUG
#define VERB_DEBUG
Definition: utilities.h:112
Bimage::index
long index(long nx, long ny) const
Definition: Bimage.h:383
Bimage::filter_rolling_ball
int filter_rolling_ball(long radius, double scale)
Apply a rolling ball filter.
Definition: Bimage_filter.cpp:836
get_chunk_size
size_t get_chunk_size(size_t datasize)
Returns the chunk size per thread.
Definition: utilities.cpp:645
VERB_PROCESS
#define VERB_PROCESS
Definition: utilities.h:107
Bimage::filter_bilateral
int filter_bilateral(double sigma1, double sigma2, int kernel_type, long kernel_radius)
Denoise an image with combined gaussian distance and density difference kernel.
Definition: Bimage_filter.cpp:784
Bimage::periodic_averaging
Bimage * periodic_averaging(Vector3< double > period)
Calculates an average within a periodic frame.
Definition: Bimage_filter.cpp:1145
Bimage::file_name
void file_name(string s)
Definition: Bimage.h:230
Bimage::Bimage
Bimage()
Initializes an image.
Definition: Bimage.cpp:44
TSimple
Definition: Bimage.h:58
Float
Definition: utilities.h:157
Bimage
General image parameter class.
Definition: Bimage.h:163
Bimage::filter_gaussian
int filter_gaussian(long kernel_size, double sigma)
Applies a gaussian filter to an image.
Definition: Bimage_filter.cpp:325
Bimage::data_alloc
unsigned char * data_alloc()
Definition: Bimage.h:256
M_PI
#define M_PI
Definition: utilities.h:59
Bimage::filter_average
int filter_average(long kernel_size)
Applies an averaging filter to an image.
Definition: Bimage_filter.cpp:208
Double
Definition: utilities.h:158
Bimage::statistics
long statistics()
Calculates the statistics for an image.
Definition: Bimage_stats.cpp:22
Bimage::data_assign
unsigned char * data_assign(unsigned char *nudata)
Assign image data.
Definition: Bimage.cpp:852
VERB_TIME
#define VERB_TIME
Definition: utilities.h:110
Bimage::kernel_laplacian_of_gaussian
int kernel_laplacian_of_gaussian(double sigma, double max)
Generates a laplacian-of-gaussian kernel.
Definition: Bimage_filter.cpp:77
Bimage::size
Vector3< long > size() const
Definition: Bimage.h:373
verbose
int verbose
Bimage::filter_ortho
int filter_ortho(int type)
Convolves the image with an orthogonal kernel with wrapping.
Definition: Bimage_filter.cpp:545
Bsub_image::origin
void origin(double x, double y, double z)
Definition: Bimage.h:127
Bimage::filter_rank
int filter_rank(long kernel_size, double rank)
Applies a median filter to an image.
Definition: Bimage_filter.cpp:1022
Bimage::set
void set(long j, double v)
Sets a single value at the given index.
Definition: Bimage.cpp:1096
VERB_RESULT
#define VERB_RESULT
Definition: utilities.h:105
Bimage::convolve
int convolve(Bimage *pkernel)
Convolves an image with an arbitrary size convolution filter.
Definition: Bimage_filter.cpp:474
Bimage::filter_bilateral_chunk
int filter_bilateral_chunk(Bimage *pkernel, double sigma2, int kernel_type, float *nudata, long i, long len, int first)
Definition: Bimage_filter.cpp:671
Bimage::filter_peak
Bimage * filter_peak(long kernel_size)
Finds the peaks in an image.
Definition: Bimage_filter.cpp:1076
Bimage::data_pointer
unsigned char * data_pointer()
Definition: Bimage.h:261
Bimage::copy
Bimage * copy()
Copies the header information and data of an image into a new image structure.
Definition: Bimage.cpp:2695
Bimage::sizeX
void sizeX(long nx)
Definition: Bimage.h:377
kmin
long kmin(long i, long hk)
Definition: Bimage_filter.cpp:17
matrix_linear.h
Header file for matrix functions.
kmax
long kmax(long i, long km, long m)
Definition: Bimage_filter.cpp:22
Bimage::sizeZ
void sizeZ(long nz)
Definition: Bimage.h:379
Vector3< double >
Bimage::filter_dog
int filter_dog(double sigma1, double sigma2)
Convolves the image with a difference of gausians kernel.
Definition: Bimage_filter.cpp:642
Vector3::min
Type min()
Definition: Vector3.h:169
partition
int partition(vector< double > &a, int n, int k)
Determines the index k'th value in the array.
Definition: math_util.cpp:123
kernel
Definition: kernlut.h:13
Bimage::page_size
Vector3< long > page_size()
Definition: Bimage.h:480
Bimage::coordinates
void coordinates(long i, long &nx, long &ny, long &nz)
Definition: Bimage.h:416
Vector3::volume
double volume()
Definition: Vector3.h:235
Bimage::subtract
void subtract(Bimage *p)
Subtracts another image from an image.
Definition: Bimage.cpp:3403
Bimage::background
double background(long nn)
Definition: Bimage.h:542
Bimage::kernel_gaussian
int kernel_gaussian(double sigma, double max)
Generates a gaussian kernel image.
Definition: Bimage_filter.cpp:34
Bimage::sizeY
void sizeY(long ny)
Definition: Bimage.h:378
VERB_LABEL
#define VERB_LABEL
Definition: utilities.h:106
TWOPI
#define TWOPI
Definition: utilities.h:68
error_show
int error_show(string message, string file, int line)
Displays the error with file and line reference.
Definition: utilities.cpp:755
tab
ostream & tab(ostream &out)
Definition: utilities.cpp:21
Bimage::image
Bsub_image * image
Definition: Bimage.h:188
Bimage::origin
void origin(double ox, double oy, double oz)
Definition: Bimage.h:563
math_util.h
Header file for general utilities.