stensor_kernels.h
1 /*#############################################################################
2  *
3  * Copyright 2011 by Henrik Skibbe and Marco Reisert
4  *
5 
6  * This file is part of the STA-ImageAnalysisToolbox
7  *
8  * STA-ImageAnalysisToolbox is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * STA-ImageAnalysisToolbox is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with STA-ImageAnalysisToolbox.
20  * If not, see <http://www.gnu.org/licenses/>.
21  *
22  *
23 *#############################################################################*/
24 
25 #ifndef STA_STENSOR_KERNELS_H
26 #define STA_STENSOR_KERNELS_H
27 
28 #include "stensor.h"
29 #include <string>
30 #include <complex>
31 #include <limits>
32 
33 
34 namespace hanalysis
35 {
36 
37 
38 enum STA_CONVOLUTION_KERNELS {
39  STA_CONV_KERNEL_UNKNOWN=-1,
40  STA_CONV_KERNEL_GAUSS_BESSEL=0,
41  STA_CONV_KERNEL_GAUSS_LAGUERRE=1,
42  STA_CONV_KERNEL_GAUSS=2,
43  STA_CONV_KERNEL_SH=3,
44  STA_CONV_KERNEL_FOURIER=4
45 } ;
46 
47 
48 template<typename T>
49 class Kernel
50 {
51 protected:
52 public:
53 
54  Kernel()
55  {
56 
57  }
58  virtual std::complex<T> get(T rsqr, T theta, T phi,int l,int m)=0;
59  virtual std::complex<T> get(T rsqr)=0;
60  virtual std::string getName()=0;
61  virtual STA_CONVOLUTION_KERNELS getID()=0;
62  virtual bool radialComplex()=0;
63  virtual std::complex<T> weight()=0;
64  virtual ~Kernel(){};
65 };
66 
67 template<typename T> class GaussLaguerre;
68 template<typename T> class Gauss;
69 template<typename T> class GaussBessel;
70 template<typename T> class SH;
71 template<typename T> class Fourier;
72 
73 
74 template<typename T,typename S>
75 int renderKernel(
76  //std::complex<T> * & kernel,
77  std::complex<T> * kernel,
78  const std::size_t shape[],
79  Kernel<S> * kfp,
80  int L=0,
81  int m=0,
82  bool centered=false,
84  const S v_size[]=NULL,
85  int stride = -1)
86 {
87  if (std::abs(m)>L)
88  return -1;
89  if (L<0)
90  return -1;
91 
92 
93  bool zero_order=(L==0);
94 
95  if (stride==-1)
96  {
97  if (field_property==STA_FIELD_STORAGE_C)
98  stride=2*L+1;
99  else
100  stride=L+1;
101  }
102 
103  S voxel_size[3];
104  voxel_size[0]=voxel_size[1]=voxel_size[2]=T ( 1 );
105  if ( v_size!=NULL )
106  {
107  voxel_size[0]*=v_size[0]; // Zdir
108  voxel_size[1]*=v_size[1]; // Ydir
109  voxel_size[2]*=v_size[2]; // Xdir
110  }
111 
112 
113  printf("%f %f %f\n",voxel_size[0],voxel_size[1],voxel_size[2]);
114 
115 
116  Kernel<S> & kf=*kfp;
117 
118  std::complex<double> norm=kf.weight();
119 
120 
121 
122  int z2=shape[0]/2;
123  int y2=shape[1]/2;
124  int x2=shape[2]/2;
125 
126  std::size_t jumpZ=shape[2]*shape[1];
127 
128 
129  int shape_[3];
130  shape_[0]=shape[0];
131  shape_[1]=shape[1];
132  shape_[2]=shape[2];
133 
134 // int shape2[3];
135 // shape2[0]=shape_[0]/2;
136 // shape2[1]=shape_[1]/2;
137 // shape2[2]=shape_[2]/2;
138 
139 
140  if (centered)
141  {
142 #pragma omp parallel for num_threads(get_numCPUs())
143  for (int z=0;z<shape_[0];z++)
144  {
145  T vec[3];
146  T vecq[3];
147  std::complex<T> * K=kernel+z*jumpZ*stride;
148  T Z=(T(z-z2))* voxel_size[0];
149  vec[0] = Z ;
150  vecq[0] = vec[0]*vec[0];
151 
152  for (int y=0;y<shape_[1];y++)
153  {
154  T Y=(T(y-y2))* voxel_size[1];
155  vec[1] = Y ;
156  vecq[1] = vec[1]*vec[1];
157  for (int x=0;x<shape_[2];x++)
158  {
159  T X=(T(x-x2)) * voxel_size[2];
160  vec[2] = X;
161  vecq[2] = vec[2]*vec[2];
162  T sum = vecq[0]+vecq[1]+vecq[2];
163  if (zero_order)
164  {
165  std::complex<T> & current=(*K);
166  current=kf.get(sum);
167  current*=norm;
168  }
169  else
170  {
171  std::complex<T> & current=K[L+m];
172  T length=std::sqrt(sum);
173  T theta=0;
174  if (length>0)
175  theta=std::acos( Z/length);
176  T phi=std::atan2( Y, X);
177  current=kf.get(sum,-theta,-phi,L,m);
178  current*=norm;
179  }
180  K+=stride;
181  }
182  }
183  }
184  } else
185  {
186 #pragma omp parallel for num_threads(get_numCPUs())
187  for (int z=0;z<shape_[0];z++)
188  {
189  T vec[3];
190  T vecq[3];
191  std::complex<T> * K=kernel+z*jumpZ*stride;
192 
193  T Z=(T(z));
194  if (z>z2) Z=-(shape[0]-Z);
195  Z*= voxel_size[0];
196 
197  vec[0] = Z ;
198  vecq[0] = vec[0]*vec[0];
199 
200  for (int y=0;y<shape_[1];y++)
201  {
202  T Y=(T(y));
203  if (y>y2) Y=-(shape[1]-Y);
204  Y*= voxel_size[1];
205 
206  vec[1] = Y ;
207  vecq[1] = vec[1]*vec[1];
208  for (int x=0;x<shape_[2];x++)
209  {
210  T X=(T(x));
211  if (x>x2) X=-(shape[2]-X);
212  X*=voxel_size[2];
213 
214 
215  vec[2] = X;
216  vecq[2] = vec[2]*vec[2];
217  T sum = vecq[0]+vecq[1]+vecq[2];
218  if (zero_order)
219  {
220  std::complex<T> & current=(*K);
221  current=kf.get(sum);
222  current*=norm;
223  }
224  else
225  {
226  std::complex<T> & current=K[L+m];
227  T length=std::sqrt(sum);
228  T theta=0;
229  if (length>0)
230  theta=std::acos( Z/length);
231  T phi=std::atan2( Y, X);
232  current=kf.get(sum,-theta,-phi,L,m);
233  current*=norm;
234  }
235  K+=stride;
236  }
237  }
238  }
239  }
240  return 0;
241 }
242 
243 
244 
248 template<typename T>
249 class Gauss: public Kernel<T>
250 {
251 private:
252  std::complex<T> imag;
253  T t;
254 public:
255  std::string getName() {
256  return std::string("Gauss");
257  };
258  STA_CONVOLUTION_KERNELS getID() {
259  return STA_CONV_KERNEL_GAUSS;
260  }
261  bool radialComplex() {
262  return false;
263  };
264 
265  ~Gauss(){};
266 
267  Gauss() : Kernel<T>()
268  {
269  t=1;
270  imag = std::complex<T>(0,1);
271 
272  }
273  void setSigma(T s) {
274 
275  t=s*s;
276  if (t==0)
277  printf("sigma has been set to 0!!!\n");
278  }
279 
280  std::complex<T> weight()
281  {
282  return std::complex<T>(T(1.0)/std::pow(T(t*2*M_PI),T(3.0/2.0)));
283  };
284 
285 
286  std::complex<T> get(T rsqr, T theta, T phi,int l=0,int m=0)
287  {
288  T r=std::sqrt(rsqr);
289  std::complex<T> tmp=1;
290  //tmp*=std::exp(-rsqr/(T(2.0)*t))/std::pow(t,T(l+0.5));
291  tmp*=std::exp(-rsqr/(T(2.0)*t));
292  if (l>0)
293  {
294  tmp*=hanalysis::basis_SphericalHarmonicsSemiSchmidt(l,m,(double)theta,(double)phi);
295  tmp*=std::pow(r,l);
296  }
297  return tmp;
298  };
299 
300  std::complex<T> get(T rsqr)
301  {
302  std::complex<T> tmp=1;
303  tmp*=std::exp(-rsqr/(T(2.0)*t));
304  return tmp;
305  };
306 
307 };
308 
309 
313 template<typename T>
314 class GaussLaguerre: public Kernel<T>
315 {
316 private:
317  int degree;
318  T t;
319  std::complex<double> imag;
320 
321 public:
322 
323  ~GaussLaguerre(){};
324 
325  std::string getName() {
326  return std::string("GaussLaguerre");
327  };
328  STA_CONVOLUTION_KERNELS getID() {
329  return STA_CONV_KERNEL_GAUSS_LAGUERRE;
330  }
331  bool radialComplex() {
332  return false;
333  };
334 
335  GaussLaguerre() : Kernel<T>()
336  {
337  imag = std::complex<T>(0,1);
338  degree=0;
339  t=1;
340  }
341  void setDegree(int d) {
342  degree=d;
343  }
344  void setSigma(T s) {
345 
346  t=s*s;
347  if (t==0)
348  printf("sigma has been set to 0!!!\n");
349  }
350 
351 
352  std::complex<T> weight()
353  {
354  return std::complex<T>(1);
355  //return std::complex<double>(std::pow(double(t*2*M_PI),3.0/2.0)/(std::pow((double)2,(double)degree)*gsl_sf_fact(degree)));
356  //return std::complex<double>(std::pow(t,l-degree)*gsl_sf_doublefact(l)*std::pow(double(t*2*M_PI),3.0/2.0)/(std::pow((double)2,(double)degree)*gsl_sf_fact(degree)));
357  };
358 
359  std::complex<T> get(T rsqr, T theta, T phi,int l=0,int m=0)
360  {
361  T r=std::sqrt(rsqr);
362  std::complex<T> tmp=1;
363  //tmp*=std::exp(-rsqr/(2.0*t))/std::pow(t,l+0.5);
364  tmp*=std::exp(-rsqr/(T(2.0)*t));
365  tmp*=gsl_sf_laguerre_n ((double)degree,l+0.5,rsqr/(2.0*t));
366  if (l>0)
367  {
368  tmp*=hanalysis::basis_SphericalHarmonicsSemiSchmidt(l,m,(double)theta,(double)phi);
369  tmp*=std::pow(r,l);
370  }
371  return tmp;
372  };
373 
374  std::complex<T> get(T rsqr)
375  {
376  //T r=std::sqrt(rsqr);
377  std::complex<T> tmp=1;
378  tmp*=std::exp(-rsqr/(T(2.0)*t));
379  tmp*=gsl_sf_laguerre_n ((double)degree,0.5,rsqr/(2.0*t));
380  return tmp;
381  };
382 };
383 
384 
385 
389 template<typename T>
390 class GaussBessel: public Kernel<T>
391 {
392 private:
393  T freq;
394  T s;
395  T t;
396  T sqrtt;
397 public:
398  ~GaussBessel(){};
399 
400  std::string getName() {
401  return std::string("GaussBessel");
402  };
403  STA_CONVOLUTION_KERNELS getID() {
404  return STA_CONV_KERNEL_GAUSS_BESSEL;
405  }
406  bool radialComplex() {
407  return false;
408  };
409  GaussBessel() : Kernel<T>()
410  {
411  freq=1.0;
412  t=1;
413  sqrtt=std::sqrt(t);
414  s=1;
415  // scale=1.0;
416  }
417  void setFreq(T f) {
418  freq=f;
419  }
420  void setSigma(T s) {
421  t=s*s;
422  sqrtt=s;
423  if (t==0)
424  printf("sigma has been set to 0!!!\n");
425  }
426  void setGauss(T s) {
427  this->s=s;
428  if (t==0)
429  printf("sigma has been set to 0!!!\n");
430  }
431 
432  std::complex<T> weight()
433  {
434  return 1;
435  //std::complex<T>(std::pow(T(t*2*M_PI),T(3.0/2.0)));
436  };
437 
438  std::complex<T> get(T rsqr, T theta, T phi,int l=0,int m=0)
439  {
440  T r=std::sqrt(rsqr);
441  std::complex<T> tmp=1;
442  tmp*=std::exp(-rsqr/(T(2.0)*s*t));
443 
444  if (l>0)
445  {
446  tmp*=hanalysis::basis_SphericalHarmonicsSemiSchmidt(l,m,(double)theta,(double)phi);
447  // tmp*=std::pow(-1.0,l);
448  double tmp2=0;
449  for (int i=0;i<=l;i++)
450  {
451  double fact=gsl_sf_fact(l)/(gsl_sf_fact(i)*gsl_sf_fact(l-i));
452  tmp2+=fact*std::pow(1.0/(s*t),l-i)*std::pow(freq/(sqrtt),i)*std::pow(r,l-i)*gsl_sf_bessel_jl (i,freq*r/sqrtt);
453  }
454  tmp*=tmp2;
455  } else
456  {
457  tmp*=gsl_sf_bessel_j0 (freq*r/sqrtt);
458  }
459  return tmp;
460  };
461 
462  std::complex<T> get(T rsqr)
463  {
464  T r=std::sqrt(rsqr);
465  std::complex<T> tmp=1;
466  //j_0 = sinx/x
467  tmp*=gsl_sf_bessel_j0 (freq*r/sqrtt);
468  tmp*=std::exp(-rsqr/(2.0*s*t));
469  return tmp;
470  };
471 
472 };
473 
474 
475 
476 
477 
478 
479 
480 
481 template<typename T>
482 class SH: public Kernel<T>
483 {
484 private:
485  T freq;
486  T s;
487 public:
488  ~SH(){};
489 
490  std::string getName() {
491  return std::string("SH");
492  };
493  STA_CONVOLUTION_KERNELS getID() {
494  return STA_CONV_KERNEL_SH;
495  }
496  bool radialComplex() {
497  return false;
498  };
499  SH() : Kernel<T>()
500  {
501  freq=1.0;
502  s=1;
503  }
504  void setRadius(T f) {
505  freq=f;
506  }
507  void setSmooth(T s) {
508  this->s=s;
509  if (s==0)
510  printf("sigma has been set to 0!!!\n");
511  }
512 
513  std::complex<T> weight()
514  {
515  //return std::complex<T>(1.0/(freq+std::numeric_limits<T>::epsilon()));
516  return std::complex<T>(1.0/(freq+0.1));
517  };
518 
519  std::complex<T> get(T rsqr, T theta, T phi,int l=0,int m=0)
520  {
521  T r=std::sqrt(rsqr);
522  std::complex<T> tmp=1;
523 
524  r=((r-freq)*(r-freq)/(s*s*2));
525 // if (r<(T)0.01) // faster
526 // //if (r<std::numeric_limits<T>::epsilon())
527 // {
528 // tmp=0;
529 // return tmp;
530 // };
531  tmp*=std::exp(-r);
532 
533  if (l>0)
534  {
535  tmp*=hanalysis::basis_SphericalHarmonicsSemiSchmidt(l,m,(double)theta,(double)phi);
536  tmp*=sqrt((2*l+1)/(4*M_PI));
537  }
538  return tmp;
539  };
540 
541  std::complex<T> get(T rsqr)
542  {
543  T r=std::sqrt(rsqr);
544  std::complex<T> tmp=1;
545  tmp*=std::exp(-((r-freq)*(r-freq)/(s*s*2)));
546  return tmp;
547  };
548 
549 };
550 
551 
552 
553 
554 template<typename T>
555 class Fourier: public Kernel<T>
556 {
557 private:
558  int currentl;
559  int currentn;
560  double kln;
561  double Nln;
562  double a;
563 public:
564  ~Fourier(){};
565 
566  std::string getName() {
567  return std::string("Fourier");
568  };
569  STA_CONVOLUTION_KERNELS getID() {
570  return STA_CONV_KERNEL_FOURIER;
571  }
572  bool radialComplex() {
573  return false;
574  };
575  Fourier() : Kernel<T>()
576  {
577  currentl=0;
578  currentn=1;
579  a=1;
580  getFourierFreqAndNorm(a,currentl,currentn,kln, Nln);
581  }
582  void setRadius(T a) {
583  this->a=a;
584  //sta_assert(a>0);
585  getFourierFreqAndNorm(a,currentl,currentn,kln, Nln);
586  }
587 
588  void setRadFunc(int n){
589  this->currentn=n;
590  getFourierFreqAndNorm(a,currentl,currentn,kln, Nln);
591  }
592 
593  std::complex<T> weight()
594  {
595  //return std::complex<T>(1.0/(freq+std::numeric_limits<T>::epsilon()));
596 
597  return std::complex<T>(1.0);
598  };
599 
600  std::complex<T> get(T rsqr, T theta, T phi,int l=0,int m=0)
601  {
602  if (l!=currentl)
603  {
604  currentl=l;
605  getFourierFreqAndNorm(a,currentl,currentn,kln, Nln);
606  }
607 
608  T r=std::sqrt(rsqr);
609  if (r>=a+9)
610  return 0.0;
611 
612  std::complex<T> tmp=Nln;
613 
614  if (r>=a)
615  tmp*=std::exp(-rsqr/2);
616 
617  if (l>0)
618  {
619  tmp*=hanalysis::basis_SphericalHarmonicsSemiSchmidt(l,m,(double)theta,(double)phi);
620  tmp*=sqrt((2*l+1)/(4*M_PI));
621  }
622  tmp*=gsl_sf_bessel_jl (l,kln *r);
623  return tmp;
624  };
625 
626  std::complex<T> get(T rsqr)
627  {
628  if (0!=currentl)
629  {
630  currentl=0;
631  getFourierFreqAndNorm(a,currentl,currentn,kln, Nln);
632  }
633 
634  T r=std::sqrt(rsqr);
635  if (r>=a+9)
636  return T(0.0);
637 
638  std::complex<T> tmp=Nln;
639 
640  if (r>=a)
641  tmp*=std::exp(-rsqr/2);
642 
643  tmp*=gsl_sf_bessel_jl (0,kln *r);
644  return tmp;
645  };
646 
647 };
648 
649 
650 }
651 
652 #endif
STA_FIELD_STORAGE
tensor field data storage
Definition: stensor.h:5163
Definition: stensor_kernels.h:70
Definition: stensor_kernels.h:69
Definition: stensor_kernels.h:67
Definition: stensor_kernels.h:68
Definition: stensor.h:5167
Definition: stensor_kernels.h:71
The STA-ImageAnalysisToolkit namespace.
Definition: stafield.h:55
Definition: stensor_kernels.h:49
Definition: stensor.h:5170