MeVisLab Toolbox Reference
mlKernel.h
Go to the documentation of this file.
1 /*************************************************************************************
2 **
3 ** Copyright 2007, MeVis Medical Solutions AG
4 **
5 ** The user may use this file in accordance with the license agreement provided with
6 ** the Software or, alternatively, in accordance with the terms contained in a
7 ** written agreement between the user and MeVis Medical Solutions AG.
8 **
9 ** For further information use the contact form at https://www.mevislab.de/contact
10 **
11 **************************************************************************************/
12 
13 #ifndef ML_KERNEL_H
14 #define ML_KERNEL_H
15 
16 
18 
19 // ML-includes
20 #include "mlInitSystemKernel.h"
21 #include <mlMemory.h>
22 #include <cerrno>
23 
24 ML_START_NAMESPACE
25 
26  //-------------------------------------------------------------------------------------------
72  //-------------------------------------------------------------------------------------------
73  template <typename KDATATYPE> class TKernel {
74 
75  public:
76 
77  //--------------------------------------------------------------------------------------------------------
101  //--------------------------------------------------------------------------------------------------------
103  KERN_SET = 0,
122 
123  NUM_KERN_MODIFYERS
124  };
125 
127  inline TKernel();
128 
130  inline TKernel(const TKernel &kern);
131 
133  inline virtual ~TKernel();
134 
136  const TKernel& operator=(const TKernel &kern);
137 
139  void reset();
140 
142  inline size_t getTabSize() const;
143 
150  inline const ImageVector* getCoordTab(size_t dim = 0) const;
151 
156  inline const KDATATYPE* getValueTab(size_t dim = 0) const;
157 
159  KDATATYPE getValueTabSum() const;
160 
163  KDATATYPE getMinValue() const;
164 
167  KDATATYPE getMaxValue() const;
168 
171  KDATATYPE getNegativeValueSum() const;
172 
175  KDATATYPE getPositiveValueSum() const;
176 
178  void manipulateKernelElements(KernModifier mode, KDATATYPE v);
179 
188  inline const ImageVector &getExtent() const;
189 
194  inline const ImageVector &getNegativeExtent() const;
195 
197  inline const ImageVector &getPositiveExtent() const;
198 
201  static inline MLint coordToIndex(MLint x, MLint y, MLint z, MLint c, MLint t, MLint u, const ImageVector &size);
202 
204  static inline MLint coordToIndex(const ImageVector &p, const ImageVector &size);
205 
207  static inline ImageVector indexToCoord(MLint idx, const ImageVector &ext);
208 
211 
214 
217  MLint findIndex(const ImageVector &pos) const;
218 
225  void setPartialKernel(size_t numElems, ImageVector * const coords, KDATATYPE * const values=nullptr);
226 
248  std::string getKernel(bool asLines=false, MLint fieldWidth=0, MLint precision=10) const;
249 
276  std::string setKernel(const std::string &kernString);
277 
286  void setKernel(const ImageVector &ext, const KDATATYPE * const values=nullptr, bool * const mask=nullptr);
287 
295  template <typename KDATATYPE2>
296  void setKernel(const ImageVector &ext,
297  const KDATATYPE2 * const xaxis, const KDATATYPE2 * const yaxis, const KDATATYPE2 * const zaxis,
298  const KDATATYPE2 * const caxis, const KDATATYPE2 * const taxis, const KDATATYPE2 * const uaxis,
299  bool normalize)
300  {
301  // Clear current separability members.
302  _invalidateSeparableInfos();
303 
304  MLint b=0;
305 
306  // Check for valid parameters. Return empty kernel otherwise.
307  if (!xaxis || !yaxis || !zaxis || !caxis || !taxis || !uaxis){
308  _clearTables();
309  _calculateRealKernelExt();
310  return;
311  }
312 
313  // Pointer to matrix which contains the products of the corresponding axis-values
314  KDATATYPE *valuematrix =
315  static_cast<KDATATYPE*>(Memory::allocateMemory(sizeof(KDATATYPE) * ext.compMul(), ML_FATAL_MEMORY_ERROR));
316 
317  for (MLint u=0; u<ext.u; ++u){
318  for (MLint t=0; t<ext.t; ++t){
319  for (MLint c=0; c<ext.c; ++c){
320  for (MLint z=0; z<ext.z; ++z){
321  for (MLint y=0; y<ext.y; ++y){
322  for (MLint x=0; x<ext.x; ++x){
323  valuematrix[b++] = static_cast<KDATATYPE>(xaxis[x]*yaxis[y]*zaxis[z]*caxis[c]*taxis[t]*uaxis[u]);
324  }
325  }}}}}
326 
327  setKernel(ext,valuematrix);
328 
329  Memory::freeMemory(valuematrix);
330  valuematrix=nullptr;
331 
332  // If desired then normalize all kernel elements so that their sum becomes 1.
333  if (normalize){ manipulateKernelElements(KERN_NORMALIZE, 0); }
334  }
335 
342  void setSeparableKernel(const std::vector<typename std::vector<KDATATYPE> > &separableRows);
343 
348  void resizeKernel(const ImageVector &ext, KDATATYPE newVal=0);
349 
351  void fillUndefinedElements(KDATATYPE newVal=0);
352 
357  void makeCircular();
358 
362  void mirror(int dimension=-1);
363 
367 
372  static std::vector<KDATATYPE> get1DGauss(size_t numSamples, bool normalize=true);
373 
375  void setGauss(const ImageVector &ext);
376 
377 
378  //-------------------------------------------------------------------------------------------
379  //
382  //
383  // If the kernel is interpreted as a separable kernel then the first six rows
384  // of the first slice of the kernel matrix are taken.
385  // These six rows are interpreted as the six 1-dimensional axis in x,y,z,c,t, and u
386  // dimensions which are used as 1-D filter kernels for a 6D separable filtering.
387  //
388  //
389  // For example:
390  //
391  // | 1 3 5 6 4 |
392  // | 2 7 2 |
393  // | 4 1 9 5 |
394  // | |
395  // | 3 8 3 |
396  // | |
397  //
398  // describes a separable kernel with the following axes extent:
399  // X=5, Y=3, Z=4, C=0, T=3, U=0.
400  // An extent of 0 (for example C and U dimension) is used to describe
401  // that filtering with a 1-D kernel in that dimension is not applied.
402  //
403  //-------------------------------------------------------------------------------------------
408  inline void setSeparable(bool isSeparableVal);
409 
412  inline bool isSeparable() const;
413 
418 
425 
432  size_t getSeparableDimIndex(size_t dim=0) const;
433 
436  const std::vector<ImageVector> &getSeparableCoordTab() const;
437 
439 
440  protected:
441  //-------------------------------------------------------------------------------------------
442  //
443  // Protected methods.
444  //
445  //-------------------------------------------------------------------------------------------
446 
448  void _init();
449 
451  void _clearTables();
452 
456  void _addCoordinate(const ImageVector &pos, KDATATYPE value, bool update);
457 
463 
470 
473 
474 
475 
476  private:
477  //-------------------------------------------------------------------------------------------
478  //
479  // Member variables.
480  //
481  //-------------------------------------------------------------------------------------------
482 
485  ImageVector _ext;
486 
488  ImageVector _negExt;
489 
491  ImageVector _posExt;
492 
495  size_t _tabSize;
496 
498  KDATATYPE* _valueTab;
499 
501  ImageVector* _coordTab;
502 
503 
506 
509  bool _isSeparable;
510 
514 
516  mutable bool _areSeparabilityInfosUpToDate;
517 
519  mutable ImageVector _separableDimEntries;
520 
523  mutable ImageVector _separableOneDimExt;
524 
527  mutable ImageVector _separableExt;
528 
530  mutable ImageVector _separableNegExt;
531 
533  mutable ImageVector _separablePosExt;
534 
536  mutable std::vector<ImageVector> _separableCoordTab;
538  }; // class TKernel
539 
540 
541 
542 
543 
544  //------------------------------------------------------------------------
545  // IMPLEMENTATION PART: No user specific things below.
546  //------------------------------------------------------------------------
547 
548 
549  //-------------------------------------------------------------------------------------------
551  //-------------------------------------------------------------------------------------------
552  template <typename KDATATYPE>
554  {
555  _init();
556  }
557 
558  //-------------------------------------------------------------------------------------------
560  //-------------------------------------------------------------------------------------------
561  template <typename KDATATYPE>
563  {
564  _init();
565  operator=(kern);
566  }
567 
568  //-------------------------------------------------------------------------------------------
570  //-------------------------------------------------------------------------------------------
571  template <typename KDATATYPE>
573  {
574  _clearTables();
575  }
576 
577  //-------------------------------------------------------------------------------------------
578  // Assignment operator. Sets current instance to contents of \c kern.
579  //-------------------------------------------------------------------------------------------
580  template <typename KDATATYPE>
582  {
583  // Assign kernel to this if it's not this.
584  if (&kern != this){
585  // Clean up current kernel table.
586  _clearTables();
587 
588  // Set new kernel table size, the kernel voxels and the kernel values.
589  setPartialKernel(kern._tabSize, kern._coordTab, kern._valueTab);
590 
591  // Copy mutable members for separable kernel support.
592  _isSeparable = kern._isSeparable;
593  _areSeparabilityInfosUpToDate = kern._areSeparabilityInfosUpToDate;
594  _separableDimEntries = kern._separableDimEntries;
595  _separableOneDimExt = kern._separableOneDimExt;
596  _separableExt = kern._separableExt;
597  _separableNegExt = kern._separableNegExt;
598  _separablePosExt = kern._separablePosExt;
599  _separableCoordTab = kern._separableCoordTab;
600  }
601 
602  // Return copy.
603  return *this;
604  }
605 
606  //-------------------------------------------------------------------------------------------
607  // Reset kernel to construction state.
608  //-------------------------------------------------------------------------------------------
609  template <typename KDATATYPE>
611  {
612  // Remove dynamic structures.
613  _clearTables();
614 
615  // Call constructor initialization. We can do that here, because
616  // all internal tables have been cleared.
617  _init();
618  }
619 
620  //-------------------------------------------------------------------------------------------
621  // Returns the current number of kernel elements.
622  //-------------------------------------------------------------------------------------------
623  template <typename KDATATYPE>
625  {
626  if (_isSeparable){
627  _validateSeparabilityInfos();
628  return getSeparableCoordTab().size();
629  }
630  else{
631  return _tabSize;
632  }
633  }
634 
635  //-------------------------------------------------------------------------------------------
636  // Gets a table of coordinates pointing to all kernel elements
637  // which are currently defined.
638  // The size of the returned table is given by getTabSize().
639  // In the case of separable filtering it returns those which are
640  // valid for the current pass of separable kernel filtering.
641  // It is a subset of the array given by \c getSeparableCoordTab().
642  //-------------------------------------------------------------------------------------------
643  template <typename KDATATYPE>
645  {
646  return _isSeparable ? &(getSeparableCoordTab()[getSeparableDimIndex(dim)]) : _coordTab;
647  }
648 
649  //-------------------------------------------------------------------------------------------
650  // Gets the table of kernel element values which are currently defined.
651  // The size of the returned table is given by getTabSize().
652  // In the case of separable filtering the subset of kernel elements
653  // for the pass \c dim can be requested.
654  //-------------------------------------------------------------------------------------------
655  template <typename KDATATYPE>
656  const KDATATYPE* TKernel<KDATATYPE>::getValueTab(size_t dim) const
657  {
658  return _isSeparable ? (_valueTab + getSeparableDimIndex(dim)) : _valueTab;
659  }
660 
661  //-------------------------------------------------------------------------------------------
662  // Return the sum of all kernel element values
663  //-------------------------------------------------------------------------------------------
664  template <typename KDATATYPE>
666  {
667  // Scan all elements of the value table and sum them up.
668  KDATATYPE v=0;
669  for (size_t i=0; i<_tabSize; i++){ v+=_valueTab[i]; }
670  return v;
671  }
672 
673  //-------------------------------------------------------------------------------------------
674  // Return the minimum value of all kernel element values
675  // If kernel value table is empty then 0 is returned.
676  //-------------------------------------------------------------------------------------------
677  template <typename KDATATYPE>
679  {
680  // Scan all elements of the value table and search the minimum.
681  KDATATYPE v = (_tabSize==0) ? static_cast<KDATATYPE>(0) : _valueTab[0];
682  for (size_t i=1; i<_tabSize; i++){ if (_valueTab[i] < v){ v = _valueTab[i]; } }
683  return v;
684  }
685 
686  //-------------------------------------------------------------------------------------------
687  // Return the maximum value of all kernel element values
688  // If kernel value table is empty then 1 is returned.
689  //-------------------------------------------------------------------------------------------
690  template <typename KDATATYPE>
692  {
693  // Scan all elements of the value table and search the minimum.
694  KDATATYPE v = (_tabSize==0) ? static_cast<KDATATYPE>(1) : _valueTab[0];
695  for (size_t i=1; i<_tabSize; i++){ if (_valueTab[i] > v){ v = _valueTab[i]; } }
696  return v;
697  }
698 
699 
700  //-------------------------------------------------------------------------------------------
701  // Return the sum of all negative kernel element values.
702  // If kernel value table is empty then 0 is returned.
703  //-------------------------------------------------------------------------------------------
704  template <typename KDATATYPE>
706  {
707  KDATATYPE v = 0;
708  for (size_t i=0; i<_tabSize; i++){
709  // Make checks for not "> 0" instead of "< 0" to avoid warnings on unsigned KDATATYPEs.
710  if (!(_valueTab[i] > 0)){ v += _valueTab[i]; }
711  }
712  return v;
713  }
714 
715  //-------------------------------------------------------------------------------------------
716  // Return the sum of all positive kernel element values.
717  // If kernel value table is empty then 0 is returned.
718  //-------------------------------------------------------------------------------------------
719  template <typename KDATATYPE>
721  {
722  KDATATYPE v = 0;
723  for (size_t i=0; i<_tabSize; i++){ if (_valueTab[i] > 0){ v += _valueTab[i]; } }
724  return v;
725  }
726 
727 
728  //-------------------------------------------------------------------------------------------
729  // Modify all kernel element values with the value \c v.
730  //-------------------------------------------------------------------------------------------
731  template <typename KDATATYPE>
733  {
734  // Invalidate current information for separable kernels.
735  _invalidateSeparableInfos();
736 
737  switch (mode){
738  case KERN_SET:{
739  // Set each kernel element to v.
740  for (size_t i=0; i<_tabSize; i++){ _valueTab[i] = v; }
741  }
742  break;
743 
744  case KERN_MULT:{
745  // Multiply each kernel element with v.
746  for (size_t i=0; i<_tabSize; i++){ _valueTab[i] *= v; }
747  }
748  break;
749 
750  case KERN_ADD:{
751  // Add v to each kernel element.
752  for (size_t i=0; i<_tabSize; i++){ _valueTab[i] += v; }
753  }
754  break;
755 
756  case KERN_INVDIV:{
757  // Set each kernel element to v / kernelElement. Zero kernel elements are left unchanged.
758  for (size_t i=0; i<_tabSize; i++){ if (!MLValueIs0WOM(_valueTab[i])) {_valueTab[i] = v/_valueTab[i]; } }
759  }
760  break;
761 
762  case KERN_INVSUB:{
763  // Set each kernel element by v - kernelElement.
764  for (size_t i=0; i<_tabSize; i++){ _valueTab[i] = v-_valueTab[i]; }
765  }
766  break;
767 
768  case KERN_SQR:{
769  // Compute all squares of _valueTab[i].
770  for (size_t i=0; i<_tabSize; i++){ _valueTab[i] *= _valueTab[i]; }
771  }
772  break;
773 
774  case KERN_SQRT:{
775  // Compute all square roots of _valueTab[i]. Negative kernel elements
776  // are left unchanged.
777  for (size_t i=0; i<_tabSize; i++){
778  // We do not use >= because but two comparisons to avoid warnings
779  // in case of unsigned KDATATYPE.
780  if ((_valueTab[i]>0) || (MLValueIs0WOM(_valueTab[i]))){
781  // As documented in class description we cast in case of integer KDATATYPES.
782  _valueTab[i] = static_cast<KDATATYPE>(sqrt(static_cast<double>(_valueTab[i])));
783  }
784  }
785  }
786  break;
787 
788  case KERN_POW:{
789  // Compute all _valueTab[i] raised to the power of v.
790  for (size_t i=0; i<_tabSize; i++){
791  // Linux man page says: Error on "The argument x is negative and y is not an integral value.
792  // This would result in a complex number." This then will set errno (EDOM).
793  // So we leave kernel elements unchanged in that case. We do not use >= because but
794  // two comparisons to avoid warnings in case of unsigned KDATATYPE.
795  if ( (_valueTab[i] > static_cast<KDATATYPE>(0)) || MLValueIs0WOM(_valueTab[i]) ){
796  // As documented in class description we cast in case of integer KDATATYPES.
797  errno = 0;
798  KDATATYPE buf = static_cast<KDATATYPE>(powl(_valueTab[i], v));
799  if (0 == errno){
800  _valueTab[i] = buf;
801  }
802  }
803  }
804  }
805  break;
806 
807  case KERN_LOG:{
808  // Compute logarithm of base v of all kernel elements.
809  // Do not apply operations on kernel elements which are not permitted,
810  // e.g. negative bases or negative values or base == 1. In that case
811  // leave kernel elements unchanged.
812  // For LOGv(K) we use log(K)/log(v) instead.
813  if ((v > 0) && (MLValuesDifferWOM(v, static_cast<KDATATYPE>(1))) ){
814  MLdouble invBase=1.0/log(static_cast<double>(v));
815  for (size_t i=0; i<_tabSize; i++){
816  KDATATYPE val = _valueTab[i];
817  // As documented in class description we cast in case of integer KDATATYPES.
818  if (val > 0){ _valueTab[i] = static_cast<KDATATYPE>(log(static_cast<double>(val))*invBase); }
819  }
820  }
821  }
822  break;
823 
824  case KERN_NORMALIZE:{
825  // Multiply all kernel element values with a value so that their sum is 1.
826  // If sum is zero then values are left unchanged.
827  KDATATYPE sum=getValueTabSum();
828  // As documented in class description we cast in case of integer KDATATYPES.
829  if (!MLValueIs0WOM(sum)){ manipulateKernelElements(KERN_MULT, static_cast<KDATATYPE>(1./sum)); }
830  }
831  break;
832 
833  case KERN_GAUSS:{
834  // Set all kernel elements to binomial values and normalize.
835  setGauss(_ext);
836  }
837  break;
838 
839  case KERN_SPHERE:{
840  // Throw away kernel corners to make it approximately spherical.
841  makeCircular();
842  }
843  break;
844 
845  case KERN_MIRROR:{
846  // Apply mirroring operation.
847  mirror();
848  }
849  break;
850 
851  case KERN_MIRROR_X:{
852  // Apply mirroring operation in x dimension.
853  mirror(0);
854  }
855  break;
856 
857  case KERN_MIRROR_Y:{
858  // Apply mirroring operation in y dimension.
859  mirror(1);
860  }
861  break;
862 
863  case KERN_MIRROR_Z:{
864  // Apply mirroring operation in z dimension.
865  mirror(2);
866  }
867  break;
868 
869  case KERN_MIRROR_C:{
870  // Apply mirroring operation in c dimension.
871  mirror(3);
872  }
873  break;
874 
875  case KERN_MIRROR_T:{
876  // Apply mirroring operation in t dimension.
877  mirror(4);
878  }
879  break;
880 
881  case KERN_MIRROR_U:{
882  // Apply mirroring operation in u dimension.
883  mirror(5);
884  }
885  break;
886 
887  case NUM_KERN_MODIFYERS:{
888  ML_PRINT_ERROR("TKernel<KDATATYPE>::manipulateKernelElements(mlKernModifier mode, KDATATYPE v)",
889  ML_PROGRAMMING_ERROR, "NUM_KERN_MODIFYERS is an invalid parameter. Ignoring kernel manipulation.");
890  }
891  break;
892 
893  default:{
894  ML_PRINT_ERROR("TKernel<KDATATYPE>::manipulateKernelElements(mlKernModifier mode, KDATATYPE v)",
895  ML_BAD_PARAMETER, "Invalid parameter passed. Ignoring kernel manipulation.");
896  }
897  break;
898 
899  }
900  }
901 
902  //-------------------------------------------------------------------------------------------
903  // Returns the kernel extents in 6D. It defines the rectangular region in
904  // which all coordinates returned by \c getCoordTab() are found.
905  // Note that the returned region might be larger than required
906  // e.g. after removing elements from kernel.
907  // In the case of separable filtering it returns a vector where the
908  // components 0,...,5 contain the extent of the region spanned by the
909  // 6 separated 1-D kernels. Note that components for those dimensions
910  // where no filtering takes place are set to 1.
911  //-------------------------------------------------------------------------------------------
912  template <typename KDATATYPE>
914  {
915  if (_isSeparable){
916  _validateSeparabilityInfos();
917  return _separableExt;
918  }
919  else{
920  return _ext;
921  }
922  }
923 
924  //-------------------------------------------------------------------------------------------
925  // The extent of the kernel to both sides. The sum of both +1 is the extent of the kernel.
926  // Using \c getNegativeExtent() as negative extent of an image and \c getPositiveExtent() as positive extent
927  // increment for the image then the kernel can be placed correctly on all normal image
928  // voxels without having voxel accesses out of range.
929  //-------------------------------------------------------------------------------------------
930  template <typename KDATATYPE>
932  {
933  if (_isSeparable){
934  _validateSeparabilityInfos();
935  return _separableNegExt;
936  }
937  else{
938  return _negExt;
939  }
940  }
941 
942  //-------------------------------------------------------------------------------------------
943  // See \c getNegativeExtent().
944  //-------------------------------------------------------------------------------------------
945  template <typename KDATATYPE>
947  {
948  if (_isSeparable){
949  _validateSeparabilityInfos();
950  return _separablePosExt;
951  }
952  else{
953  return _posExt;
954  }
955  }
956 
957  //-------------------------------------------------------------------------------------------
958  // Converts the coordinate (x,y,z,c,t,u) into the kernel to an index into an array
959  // with 6D extents given by \c size.
960  //-------------------------------------------------------------------------------------------
961  template <typename KDATATYPE>
963  {
964  return SubImage::coordToIndex(x,y,z,c,t,u, size);
965  }
966 
967  //-------------------------------------------------------------------------------------------
968  // Converts the coordinate \p into the kernel with extents \c size to an index.
969  //-------------------------------------------------------------------------------------------
970  template <typename KDATATYPE>
972  {
973  return SubImage::coordToIndex(p, size);
974  }
975 
976  //-------------------------------------------------------------------------------------------
977  // Converts an index into an array with extents \c ext to a coordinate.
978  //-------------------------------------------------------------------------------------------
979  template <typename KDATATYPE>
981  {
982  return SubImage::indexToCoord(idx, ext);
983  }
984 
985  //-------------------------------------------------------------------------------------------
987  //-------------------------------------------------------------------------------------------
988  template <typename KDATATYPE>
990  {
991  return ImageVector(ext.x/2, ext.y/2, ext.z/2, ext.c/2, ext.t/2, ext.u/2);
992  }
993 
994  //-------------------------------------------------------------------------------------------
996  //-------------------------------------------------------------------------------------------
997  template <typename KDATATYPE>
999  {
1000  return ImageVector(ext.x-ext.x/2-1, ext.y-ext.y/2-1, ext.z-ext.z/2-1,
1001  ext.c-ext.c/2-1, ext.t-ext.t/2-1, ext.u-ext.u/2-1);
1002  }
1003 
1004  //-------------------------------------------------------------------------------------------
1005  // Return index to kernel element if it exists; otherwise return -1.
1006  // Note that this method needs to search; so it's not very efficient.
1007  //-------------------------------------------------------------------------------------------
1008  template <typename KDATATYPE>
1010  {
1011  // Search coordinate in _coordtab.
1012  for (size_t c=0; c < _tabSize; c++){
1013  if (_coordTab[c] == pos){
1014  return c;
1015  }
1016  }
1017 
1018  return -1;
1019  }
1020 
1021  //-------------------------------------------------------------------------------------------
1022  // Defines a set of local kernel coordinates and optionally a set
1023  // of values which define the kernel elements.
1024  // \c numElems defines the number of coordinates.
1025  // If desired the corresponding set of kernel values can be passed in \c values.
1026  // Otherwise all kernel values are set to (KDATATYPE)(1.0/(KDATATYPE)_tabSize).
1027  // Note that \c coords and \c values have to contain \c numElems entries if passed.
1028  //-------------------------------------------------------------------------------------------
1029  template <typename KDATATYPE>
1030  void TKernel<KDATATYPE>::setPartialKernel(size_t numElems, ImageVector * const coords, KDATATYPE * const values)
1031  {
1032  // Clear all dynamic tables.
1033  _clearTables();
1034 
1035  // Define the new number of kernel voxels.
1036  _tabSize = numElems;
1037 
1038  // Recreate the coordinate and value tables
1039  if (_tabSize > 0) {
1040  _coordTab = new ImageVector[_tabSize];
1041 
1042  _valueTab = new KDATATYPE[_tabSize];
1043 
1044  // Copy all passed coordinates into the coordinate table.
1045  for (size_t c=0; c < _tabSize; c++){ _coordTab[c] = coords[c]; }
1046 
1047  // If we have a user defined value table then copy it.
1048  // Otherwise fill table with values 1.0/static_cast<KDATATYPE>(_tabSize).
1049  if (values){
1050  memcpy(_valueTab, values, _tabSize*sizeof(KDATATYPE));
1051  }
1052  else{
1053  // As documented in class description we cast in case of integer KDATATYPES.
1054  KDATATYPE v = static_cast<KDATATYPE>(1.0/static_cast<KDATATYPE>(_tabSize));
1055  for (size_t d=0; d<_tabSize; d++){ _valueTab[d] = v; }
1056  }
1057  }
1058 
1059  // Calculate the real kernel size, i.e. the bounding box around all
1060  // used kernel elements.
1061  _calculateRealKernelExt();
1062  }
1063 
1064 
1065  //-------------------------------------------------------------------------------------------
1066  // Returns the current kernel elements and values as string:
1067  // The string needs has the following format:
1068  //
1069  // \code
1070  //
1071  // (x_0, y_0, z_0, c_0, t_0, u_0):v_0
1072  // ...
1073  // (x_n, y_n, z_n, c_n, t_n, u_n):v_n
1074  //
1075  // \endcode
1076  //
1077  // where the coordinates left from ':' specify the 6d coordinate
1078  // of the kernel element; the value v_x right from ':' specifies the
1079  // value of the kernel element.
1080  // If asLines is true then a second string format is used:
1081  //
1082  // \code
1083  //
1084  // (*, y_0, z_0, c_0, t_0, u_0):x_0 ... x_n
1085  // ...
1086  // (*, y_n, z_n, c_n, t_n, u_n):y_n ... y_n
1087  //
1088  // \endcode
1089  //
1090  // So all kernel elements of a row are saved in a string line; so
1091  // the x coordinates becomes invalid and is set as an asterisk.
1092  // To have a minimum field width pass \c fieldWidth and the digits after
1093  // the period if given by \c precision. Note that these settings are used
1094  // only if asLines is true.
1095  //-------------------------------------------------------------------------------------------
1096  template <typename KDATATYPE>
1097  std::string TKernel<KDATATYPE>::getKernel(bool asLines, MLint fieldWidth, MLint precision) const
1098  {
1099  std::string str="";
1100  char strLine[256]="";
1101 
1102  // Clamp field width to sensible values.
1103  if (fieldWidth > 128){ fieldWidth=128; }
1104  if (fieldWidth < 0){ fieldWidth=0; }
1105 
1106  if (asLines){
1107  // Print kernel as lines.
1108  for (MLint u=0; u < getExtent().u; u++){
1109  for (MLint t=0; t < getExtent().t; t++){
1110  for (MLint c=0; c < getExtent().c; c++){
1111  for (MLint z=0; z < getExtent().z; z++){
1112  for (MLint y=0; y < getExtent().y; y++){
1113  // Print line start into string.
1114  snprintf(strLine, 255, "(*,%lld,%lld,%lld,%lld,%lld):", y, z, c, t, u);
1115 
1116  // To compensate line start differences if any component has more than
1117  // one digit do append spaces until string has at least 16 chars. So
1118  // two components may have more than one digit or one can have two more digits.
1119  while (strlen(strLine) < 16){ strcat(strLine, " "); }
1120 
1121  // Add Line start to existing kernel string.
1122  str += strLine;
1123 
1124  // Add all row elements of the kernel to the string.
1125  for (MLint x=0; x < getExtent().x; x++){
1126  // Does the element exist?
1127  MLint idx = findIndex(ImageVector(x,y,z,c,t,u));
1128  if (idx < 0){
1129  // Kernel element does not exist.
1130  // Fill field with fieldWidth spaces and add ','. Then terminate string.
1131  // For the first field do not add a comma. So we have one more space then
1132  // in those cases where we have a comma in it. So we need to add one space
1133  // more in cases with comma.
1134  strLine[0] = x==0 ? ' ' : ',';
1135  MLint w= x==0 ? fieldWidth : fieldWidth+1;
1136  for (MLint i=1; i < w; i++){ strLine[i] = ' '; }
1137  strLine[w] = 0;
1138  }
1139  else{
1140  // Print comma and element if it's not the last one; otherwise print only the element.
1141  // integrate field width for float field of aligned size. Always cast
1142  // element values to double because string reading and parsing of extended
1143  // types would lead to further problems.
1144  // Hence we store only scalar values.
1145  char format[64];
1146  snprintf(format, 63, "%s%%%d.%dlf", "%s", static_cast<MLint32>(fieldWidth), static_cast<MLint32>(precision));
1147  snprintf(strLine, 255, format, 0==x ? "" : ",", static_cast<MLdouble>(_valueTab[idx]));
1148  }
1149 
1150  // Append (empty) element to the end of the line.
1151  str += strLine;
1152  }
1153  // Terminate line with '\n'
1154  str += '\n';
1155  }
1156  // Add an empty line between xy planes of the kernel.
1157  str += '\n';
1158  } // z
1159  } // c
1160  } // t
1161  } // u
1162  }
1163  else{
1164  // Print each kernel element into a string and append it to the entire kernel string.
1165  for (size_t c=0; c < _tabSize; c++){
1166  ImageVector coord = _coordTab[c];
1167  KDATATYPE value = _valueTab[c];
1168  snprintf(strLine, 255, "%s:%lf\n", coord.print("(", ",", ")").c_str(), static_cast<MLdouble>(value));
1169  str += strLine;
1170  }
1171  }
1172 
1173  return str;
1174  }
1175 
1176 
1177 
1178  //-------------------------------------------------------------------------------------------
1179  // Defines elements and values of the kernel matrix by a string.
1180  // The string needs to have the following format:
1181  //
1182  // \code
1183  //
1184  // (x_0, y_0, z_0, c_0, t_0, u_0):v_0
1185  // ...
1186  // (x_n, y_n, z_n, c_n, t_n, u_n):v_n
1187  //
1188  // \endcode
1189  //
1190  // where the coordinates left from ':' specify the 6d coordinate
1191  // of the kernel element; the value v_x right from ':' specifies the
1192  // value of the kernel element. Only one coordinate entry is scanned per line.
1193  // So big kernels with a few elements can be set easily. As long as lines with
1194  // kernel elements are found elements are set in the kernel table.
1195  // Return string is empty on successful scan. On errors it contains the number
1196  // of error lines.
1197  //
1198  // A second way to specify more kernel elements at once is with the
1199  // following string line format:
1200  //
1201  // \code
1202  //
1203  // (*, y_0, z_0, c_0, t_0, u_0):x_0, ... ,x_n
1204  // ...
1205  // (*, y_n, z_n, c_n, t_n, u_n):y_n, ... ,y_n
1206  //
1207  // \endcode
1208  //
1209  // So all kernel elements of a row are found in a string line. Note
1210  // that the x coordinates becomes invalid and must set as an asterisk.
1211  // Empty elements in the kernel can be left empty before between and
1212  // after commas.
1213  //-------------------------------------------------------------------------------------------
1214  template <typename KDATATYPE>
1215  std::string TKernel<KDATATYPE>::setKernel(const std::string &kernString)
1216  {
1217  // Initialize an error string to return error line numbers.
1218  std::string errStr = "";
1219  char *copy = nullptr;
1220 
1221  // Make kernel empty.
1222  reset();
1223 
1224  // Scan only if string contains enough characters to specify one kernel element.
1225  if (kernString.length() < 15){
1226  // String too short to specify a valid kernel. Return 0 as error line.
1227  errStr = "0";
1228  return errStr;
1229  }
1230  else{
1231  // Get a modifiable copy of the string.
1232  std::string str = kernString;
1233 
1234  // Assure that a line feed terminates the string.
1235  if (str[str.length()-1] != '\n'){ str += '\n'; }
1236 
1237  // Scan line by line until no valid line is found.
1238  MLint lineNumber = 0;
1239  while (str != ""){
1240  // Scan line for following format : "(x,y,z,c,t,u):v"
1241  MLint x=0, y=0, z=0, c=0, t=0, u=0, num=0;
1242  MLdouble fValue = 0;
1243  num = sscanf(str.c_str(), "(%lld,%lld,%lld,%lld,%lld,%lld):%lf", &x, &y, &z, &c, &t, &u, &fValue);
1244  KDATATYPE value = static_cast<KDATATYPE>(fValue);
1245  if (num == 7){
1246  // Okay, we found a valid line. Add values to kernel coordinate table.
1247  _addCoordinate(ImageVector(x,y,z,c,t,u), value, false);
1248  }
1249  else{
1250  // Line is invalid. Test for the line format.
1251  num = sscanf(str.c_str(), "(*,%lld,%lld,%lld,%lld,%lld):", &y, &z, &c, &t, &u);
1252  if (5 == num){
1253  // Yes, the line format is ok. So search ":".
1254  const size_t cPos = str.find(':');
1255  if (cPos != std::string::npos){
1256  // Yes, found. First part of line has already been scanned and so removed it.
1257  str.erase(0, cPos+1);
1258 
1259  // Flag to stop line scan and counter for number of scanned elements.
1260  bool go = true;
1261  MLint xCoord = 0;
1262 
1263  // Scan until we reach at end of line or an error occurs.
1264  while (go && (str.length() != 0)){
1265  const char ch = str[0];
1266 
1267  // Kill space characters and continue.
1268  if (' ' == ch){
1269  str.erase(0, 1);
1270  }
1271 
1272  // Line end? Then finish line scan.
1273  else if ('\n' == ch) {
1274  // Terminate loop and leave '\n' because later it's searched.
1275  go = false;
1276  }
1277 
1278  // Colon? Then increase element number count and kill colon.
1279  else if (',' == ch) {
1280  // Go forward to next kernel element in row and remove comma.
1281  ++xCoord;
1282  str.erase(0, 1);
1283  }
1284  else{
1285  // No space, no comma, so try to scan a number.
1286 
1287  // First char where a number incompatible character is found.
1288  char *stopPos=nullptr;
1289 
1290  // Copy string.
1291  copy = Memory::duplicateString(str.c_str(), ML_FATAL_MEMORY_ERROR);
1292  if (copy){
1293  // Scan string for number.
1294  const MLdouble val = strtod(copy, &stopPos);
1295 
1296  // More than 0 characters scanned successfully?
1297  if (stopPos != copy){
1298  // Yes, a number at beginning. Add it at the right position in the kernel.
1299  _addCoordinate(ImageVector(xCoord, y,z,c,t,u), static_cast<KDATATYPE>(val), false);
1300 
1301  // Remove number at start of string. Use pointer arithmetics to
1302  // determine number of scanned number characters.
1303  str.erase(0, stopPos-copy);
1304  }
1305  else{
1306  // No parsing possible, there must be an error. So terminate scan of this line.
1307  go = false;
1308 
1309  // Add line number to error string.
1310  char err[30]="";
1311  snprintf(err, 29, " %lld", lineNumber);
1312  errStr += err;
1313  }
1314  }
1315 
1316  // Remove copy of line.
1317  if (copy){
1318  Memory::freeMemory(copy);
1319  copy = nullptr;
1320  }
1321  } // else
1322  } // while
1323  } // if (cPos != std::string::npos)
1324  } // if (num == 5)
1325  } // else
1326 
1327  // Last line?
1328  const size_t pos = str.find('\n');
1329  if (pos != std::string::npos){
1330  // Not the last line, because scanned linefeed is not at end of string.
1331  // So remove line from string.
1332  str.erase(0, pos+1);
1333  }
1334  else{
1335  // Last line. Make string empty to terminate loop.
1336  str = "";
1337  }
1338 
1339  // Increase number of scanned lines.
1340  lineNumber++;
1341  } // while (str != "")
1342  } // else
1343 
1344  // Update the real kernel size.
1345  _calculateRealKernelExt();
1346 
1347  return errStr;
1348  }
1349 
1350 
1351 
1352  //-------------------------------------------------------------------------------------------
1353  // Defines a complete kernel matrix whose extents are defined by \c ext.
1354  // If desired the set of kernel values can be passed in \c values.
1355  // Otherwise all kernel values are set to 1.0/(KDATATYPE)ext.compMul(), i.e.
1356  // to the number of entries of the matrix.
1357  // If desired a set of mask values can be specified. If \c mask[n] is true then
1358  // tab[n] is included in the kernel; otherwise it's not part of the kernel.
1359  // Internally the specified kernel matrix is handled as a table of kernel elements.
1360  // Note that \c values and \c mask must have ext.compMul() elements if they are defined.
1361  //-------------------------------------------------------------------------------------------
1362  template <typename KDATATYPE>
1363  void TKernel<KDATATYPE>::setKernel(const ImageVector &ext, const KDATATYPE * const values, bool * const mask)
1364  {
1365  // Clear all dynamic tables.
1366  _clearTables();
1367 
1368  // Compute maximum size of value and kernel table.
1369  size_t maxElems = ext.compMul();
1370 
1371  // Do we have a mask ? Then count number of enabled kernel elements.
1372  _tabSize=0;
1373  if (mask){
1374  for (size_t c=0; c<maxElems; c++){ if (mask[c]){ _tabSize++; } }
1375  }
1376  else{
1377  // No mask set. All kernel elements are used.
1378  _tabSize = maxElems;
1379  }
1380 
1381  // Recreate the coordinate and value tables with the size of used elements.
1382  if (_tabSize > 0){
1383  _coordTab = new ImageVector[_tabSize];
1384  _valueTab = new KDATATYPE[_tabSize];
1385  if (!_coordTab || !_valueTab){
1386  _clearTables();
1387  ML_PRINT_FATAL_ERROR("TKernel<KDATATYPE>::setKernel(...):", ML_NO_MEMORY,
1388  "Cannot create kernel filter tables, so tables are reset. This will probably cause other errors.");
1389  }
1390 
1391  if (_coordTab && _valueTab){
1392  // If we have a user defined value table then copy it.
1393  // Otherwise fill table with values 1.0/(KDATATYPE)_tabSize.
1394  if (values){
1395  memcpy(_valueTab, values, _tabSize*sizeof(KDATATYPE));
1396  }
1397  else{
1398  // As documented in class description we cast in case of integer KDATATYPES.
1399  KDATATYPE v = static_cast<KDATATYPE>(1.0/static_cast<KDATATYPE>(_tabSize));
1400  for (size_t d=0; d<_tabSize; d++){ _valueTab[d] = v; }
1401  }
1402 
1403  // Define all kernel coordinates if no mask exists or if the mask exists and the
1404  // entry for the current kernel voxel is true.
1405  size_t idx=0;
1406  for (size_t e=0; e<maxElems; e++){
1407  if (!mask || (mask && mask[e])){
1408  _coordTab[idx] = indexToCoord(e, ext);
1409  idx++;
1410  }
1411  }
1412 
1413  if (idx !=_tabSize){
1414  ML_PRINT_FATAL_ERROR("TKernel<KDATATYPE>::setKernel(...):", ML_CALCULATION_ERROR,
1415  "Internal error. Cannot create kernel filter tables. This will probably cause other errors.");
1416  _clearTables();
1417  }
1418  } // if (_coordTab && _valueTab)
1419  }
1420 
1421  // Calculate the real kernel size, i.e. the bounding box around all
1422  // used kernel elements.
1423  _calculateRealKernelExt();
1424  }
1425 
1426 
1427  //-------------------------------------------------------------------------------------------
1428  // Create kernel coordinate and value tables in separable table format, that means
1429  // a 2-D kernel where each rows describes the elements of 1-D kernels.
1430  // At most 6 rows make sense, because the maximum kernel dimension is 6.
1431  // It is legal to leave out any axis by passing empty vectors to define lower
1432  // dimensional separable kernels.
1433  // The separability flag is set to true.
1434  //-------------------------------------------------------------------------------------------
1435  template <typename KDATATYPE>
1436  void TKernel<KDATATYPE>::setSeparableKernel(const std::vector<typename std::vector<KDATATYPE> > &separableRows)
1437  {
1438  setSeparable(true);
1439  _clearTables();
1440 
1441  // Get number of rows, permit at most 6 for 6 dimensions.
1442  const size_t numRows = separableRows.size() > 6 ? 6 : separableRows.size();
1443 
1444  // Sum up total number of entries in all rows.
1445  size_t numEntries = 0;
1446  for (size_t e=0; e < numRows; ++e){ numEntries += separableRows[e].size(); }
1447 
1448  // Create a value table and a coordinate table.
1449  std::vector<KDATATYPE> valueTab; valueTab.reserve(numEntries);
1450  std::vector<ImageVector> coordTab; coordTab.reserve(numEntries);
1451 
1452  // Compose coordinate table.
1453  for (size_t r=0; r < numRows; ++r){
1454 
1455  // Get row and its number of elements.
1456  const std::vector<KDATATYPE> &row = separableRows[r];
1457  const size_t numRElements = row.size();
1458 
1459  // Coordinate in the separable table, only x and y coordinates are set.
1460  // y defines the dimension, x defines the position in that dimension.
1461  ImageVector entryCoord(0);
1462  entryCoord.y = r;
1463 
1464  // Count entries with row.
1465  for (size_t re=0; re < numRElements; ++re){
1466  // Define x-coordinate of entry in table row.
1467  entryCoord.x = re;
1468  coordTab.push_back(entryCoord);
1469  valueTab.push_back(row[re]);
1470  }
1471  }
1472 
1473  // Define the kernel table. The extent is 2-D, because it's the
1474  // separable table format.
1475  setPartialKernel(coordTab.size(), &(coordTab[0]), &(valueTab[0]));
1476 
1477  // Make separable information up to date.
1478  _validateSeparabilityInfos();
1479  }
1480 
1481 
1482  //-------------------------------------------------------------------------------------------
1483  // Resizes the kernel to a new state and tries to maintain the previous elements
1484  // if possible. Note that new kernel size may differ from desired one if empty
1485  // areas are at border of the resized kernel so that only a smaller real kernel remains.
1486  // Regions which are created newly get kernel elements with value \c newVal.
1487  //-------------------------------------------------------------------------------------------
1488  template <typename KDATATYPE>
1489  void TKernel<KDATATYPE>::resizeKernel(const ImageVector &ext, KDATATYPE newVal)
1490  {
1491  // Create a buffer kernel.
1492  TKernel<KDATATYPE> bufferKern = *this;
1493 
1494  // Clear all dynamic tables.
1495  _clearTables();
1496 
1497  // Scan new kernel extents.
1498  for (MLint u=0; u < ext.u; u++){
1499  for (MLint t=0; t < ext.t; t++){
1500  for (MLint c=0; c < ext.c; c++){
1501  for (MLint z=0; z < ext.z; z++){
1502  for (MLint y=0; y < ext.y; y++){
1503  for (MLint x=0; x < ext.x; x++){
1504  // Create vector from new coordinates.
1505  ImageVector addCoord(x,y,z,c,t,u);
1506 
1507  // If new coordinate is within old kernel range the add it only if it exists.
1508  if ((u < getExtent().u) &&
1509  (t < getExtent().t) &&
1510  (c < getExtent().c) &&
1511  (z < getExtent().z) &&
1512  (y < getExtent().y) &&
1513  (x < getExtent().x)){
1514  // Within old extents. Is it defined?
1515  MLint idx = bufferKern.findIndex(addCoord);
1516  if (idx >=0){
1517  // Old coordinate existed. So add it to new kernel without extent updating.
1518  _addCoordinate(addCoord, bufferKern.getValueTab()[idx], false);
1519  }
1520  }
1521  else{
1522  // New coordinate is outside old range. Add newVal's in new area.
1523  _addCoordinate(addCoord, newVal, false);
1524  } // else
1525 
1526  } // x
1527  }
1528  }
1529  }
1530  }
1531  } // u
1532 
1533  // Calculate the real kernel size, i.e. the bounding box around all
1534  // used kernel elements.
1535  _calculateRealKernelExt();
1536  }
1537 
1538 
1539  //-------------------------------------------------------------------------------------------
1540  // Fill all undefined kernel elements with \c newVal.
1541  //-------------------------------------------------------------------------------------------
1542  template <typename KDATATYPE>
1544  {
1545  // Invalidate current information for separable kernels.
1546  _invalidateSeparableInfos();
1547 
1548  // Scan new kernel extents.
1549  for (MLint u=0; u < getExtent().u; u++){
1550  for (MLint t=0; t < getExtent().t; t++){
1551  for (MLint c=0; c < getExtent().c; c++){
1552  for (MLint z=0; z < getExtent().z; z++){
1553  for (MLint y=0; y < getExtent().y; y++){
1554  for (MLint x=0; x < getExtent().x; x++){
1555  // Create vector from new coordinates.
1556  ImageVector addCoord(x,y,z,c,t,u);
1557 
1558  // Does the coordinate exist in kernel?
1559  if (findIndex(addCoord) < 0){
1560  // Coordinate does not exits. So add it without extent updating.
1561  _addCoordinate(addCoord, newVal, false);
1562  } // if
1563 
1564  } // x
1565  }
1566  }
1567  }
1568  }
1569  } // u
1570 
1571  // Calculate the real kernel size, i.e. the bounding box around all
1572  // used kernel elements.
1573  _calculateRealKernelExt();
1574  }
1575 
1576 
1577 
1578  //-------------------------------------------------------------------------------------------
1579  // Takes the current kernel, computes radii from the extents of the kernel
1580  // and removes all kernel elements which are outside the ellipsoid defined by
1581  // these radii.
1582  // Note that filter properties of kernel changes by this operation.
1583  //-------------------------------------------------------------------------------------------
1584  template <typename KDATATYPE>
1586  {
1587  // Invalidate current information for separable kernels.
1588  _invalidateSeparableInfos();
1589 
1590  // Compute theoretical center of kernel. Subtract 0.5 to shift
1591  // kernel center from voxel center to voxel origin. Examples in 3D:
1592  // E.g. : (1,1,1) sized kernels are addressed from 0 to 0 and so they have
1593  // their center at (0,0,0)\n
1594  // E.g. : (2,2,2) sized kernels are addressed from 0 to 1 and so they have
1595  // their center at (0.5, 0.5, 0.5).\n
1596  // E.g. : (3,3,3) sized kernels are addressed from 0 to 2 and so they have
1597  // their center at (1.0, 1.0, 1.0).\n
1598  MLdouble cx = static_cast<MLdouble>(_ext.x) / 2.0 - 0.5;
1599  MLdouble cy = static_cast<MLdouble>(_ext.y) / 2.0 - 0.5;
1600  MLdouble cz = static_cast<MLdouble>(_ext.z) / 2.0 - 0.5;
1601  MLdouble cc = static_cast<MLdouble>(_ext.c) / 2.0 - 0.5;
1602  MLdouble ct = static_cast<MLdouble>(_ext.t) / 2.0 - 0.5;
1603  MLdouble cu = static_cast<MLdouble>(_ext.u) / 2.0 - 0.5;
1604 
1605  // Compute kernel radii.
1606  MLdouble rx = static_cast<MLdouble>(_ext.x) / 2.0;
1607  MLdouble ry = static_cast<MLdouble>(_ext.y) / 2.0;
1608  MLdouble rz = static_cast<MLdouble>(_ext.z) / 2.0;
1609  MLdouble rc = static_cast<MLdouble>(_ext.c) / 2.0;
1610  MLdouble rt = static_cast<MLdouble>(_ext.t) / 2.0;
1611  MLdouble ru = static_cast<MLdouble>(_ext.u) / 2.0;
1612 
1613  // Save local tables and set default table states.
1614  ImageVector *coordTab = _coordTab;
1615  _coordTab = nullptr;
1616 
1617  KDATATYPE *valueTab = _valueTab;
1618  _valueTab = nullptr;
1619 
1620  size_t tabSize = _tabSize;
1621  _tabSize = 0;
1622 
1623  // Compute distance for all kernel voxels and normalize them.
1624  // If the coordinate is within ellipsoid distance then
1625  // add it to the kernel elements, otherwise forget it.
1626  for (size_t e=0; e < tabSize; e++){
1627  ImageVector v = coordTab[e];
1628  MLdouble pu = (static_cast<MLdouble>(v.u) - cu)/ru;
1629  MLdouble pt = (static_cast<MLdouble>(v.t) - ct)/rt;
1630  MLdouble pc = (static_cast<MLdouble>(v.c) - cc)/rc;
1631  MLdouble pz = (static_cast<MLdouble>(v.z) - cz)/rz;
1632  MLdouble py = (static_cast<MLdouble>(v.y) - cy)/ry;
1633  MLdouble px = (static_cast<MLdouble>(v.x) - cx)/rx;
1634 
1635  // Distance smaller or equal 1? Then we are within kernel radius and
1636  // we set kernel value 'true'; otherwise we set kernel value 'false'.
1637  if (sqrt(px*px + py*py + pz*pz + pc*pc + pt*pt + pu*pu) <= 1){
1638  _addCoordinate(v, valueTab[e], false);
1639  }
1640  }
1641 
1642  // Remove saved tables.
1643  delete [] coordTab;
1644  coordTab = nullptr;
1645  delete [] valueTab;
1646  valueTab = nullptr;
1647 
1648  // Recalculate the kernelSize.
1649  _calculateRealKernelExt();
1650  }
1651 
1652 
1653 
1654  //-------------------------------------------------------------------------------------------
1655  // Applies a point symmetric mirroring of all kernel elements.
1656  // The dimension param specifies a mirroring dimension if in range [0,5],
1657  // otherwise mirroring is applied in all dimensions. Default is -1.
1658  //-------------------------------------------------------------------------------------------
1659  template <typename KDATATYPE>
1660  void TKernel<KDATATYPE>::mirror(int dimension)
1661  {
1662  // Invalidate current information for separable kernels.
1663  _invalidateSeparableInfos();
1664 
1665  // Save local tables and set default table states.
1666  ImageVector *coordTabBuf = _coordTab;
1667  _coordTab = nullptr;
1668 
1669  KDATATYPE *valueTabBuf = _valueTab;
1670  _valueTab = nullptr;
1671 
1672  size_t tabSizeBuf = _tabSize;
1673  _tabSize = 0;
1674 
1675  // Calculate maximum kernel positions in all dimensions, that is one
1676  // less than extent.
1677  ImageVector maxP(_ext-ImageVector(1));
1678 
1679  if ((dimension<0) || (dimension>5)){
1680  // Subtract each coordinate of kernel elements from the
1681  // maximum extent position in all 6 dimensions and
1682  // add it to the kernel elements (which have been made
1683  // empty above).
1684  for (size_t e=0; e < tabSizeBuf; e++){
1685  _addCoordinate(maxP - coordTabBuf[e], valueTabBuf[e], false);
1686  }
1687  }
1688  else{
1689  ImageVector mirVec;
1690  const size_t dimensionSize_t = mlrange_cast<size_t>(dimension);
1691  for (size_t e=0; e < tabSizeBuf; e++){
1692  // Take normal coordinate.
1693  mirVec = coordTabBuf[e];
1694 
1695  // mirror the selected coordinate component.
1696  mirVec[dimensionSize_t] = maxP[dimensionSize_t] - coordTabBuf[e][dimensionSize_t];
1697 
1698  // Add new coordinate with value to kernel.
1699  _addCoordinate(mirVec, valueTabBuf[e], false);
1700  }
1701  }
1702 
1703  // Remove old saved tables.
1704  delete [] coordTabBuf;
1705  coordTabBuf = nullptr;
1706  delete [] valueTabBuf;
1707  valueTabBuf = nullptr;
1708 
1709  // Recalculate the kernelSize.
1710  _calculateRealKernelExt();
1711  }
1712 
1713  //-------------------------------------------------------------------------------
1714  // Calculate binomial coefficients for (n)
1715  // (k)
1716  //-------------------------------------------------------------------------------
1717  template <typename KDATATYPE>
1719  {
1720  MLint i=0;
1721  MLldouble v=1.0;
1722 
1723  if (k>n){ v=0; }
1724  else{
1725  if((k!=0) && (k!=n)){
1726  for (i=1; i<(n+1); i++){ v*=i; }
1727  for (i=1; i<(k+1); i++){ v/=i; }
1728  for (i=1; i<(n-k+1); i++){ v/=i; }
1729  }
1730  }
1731 
1732  return(v);
1733  }
1734 
1735  //-------------------------------------------------------------------------------------------
1736  // Returns a vector with \c numSample values binomial coefficients.
1737  // If \c numSamples is passed as 0 then an empty vector is returned.
1738  // if \c normalize is passed true (the default) then all values are
1739  // normalized to the sum of absolute values 1.
1740  //-------------------------------------------------------------------------------------------
1741  template <typename KDATATYPE>
1742  std::vector<KDATATYPE> TKernel<KDATATYPE>::get1DGauss(size_t numSamples, bool normalize)
1743  {
1744  // The return value;
1745  std::vector<KDATATYPE> v;
1746 
1747  if (numSamples > 0){
1748  v.reserve(numSamples);
1749 
1750  // Fill the axis with binomial coefficients and sum up all values.
1751  KDATATYPE sum = 0;
1752  for (size_t u=0; u<numSamples; ++u){
1753  // Calculate the entry, write it into the array and sum its absolute value up.
1754  // As documented in class description we cast in case of integer KDATATYPES.
1755  KDATATYPE val = static_cast<KDATATYPE>(binomialcoeff(numSamples-1, u));
1756  v.push_back(val);
1757  sum += static_cast<KDATATYPE>(mlAbs(val));
1758  }
1759 
1760  // If normalization is desired then divide all elements by the sum.
1761  if (normalize && (sum > 0)){
1762  for (size_t u=0; u<numSamples; u++){ v[u] /= sum; }
1763  }
1764  }
1765 
1766  // Return the vector.
1767  return v;
1768  }
1769 
1770  //-------------------------------------------------------------------------------------------
1771  // Replaces the current kernel by a normalized gauss kernel.
1772  //-------------------------------------------------------------------------------------------
1773  template <typename KDATATYPE>
1775  {
1776  // Invalidate current information for separable kernels.
1777  _invalidateSeparableInfos();
1778 
1779  // Build gauss kernel by using separability property of gauss kernel.
1780  // So calculate a discrete binomial function for each axis.
1781  // The values of the kernel elements are products of the corresponding
1782  // values along the six binomial function axis.
1783  std::vector<KDATATYPE> vx=get1DGauss(ext.x, false);
1784  std::vector<KDATATYPE> vy=get1DGauss(ext.y, false);
1785  std::vector<KDATATYPE> vz=get1DGauss(ext.z, false);
1786  std::vector<KDATATYPE> vc=get1DGauss(ext.c, false);
1787  std::vector<KDATATYPE> vt=get1DGauss(ext.t, false);
1788  std::vector<KDATATYPE> vu=get1DGauss(ext.u, false);
1789 
1790  // Build kernel by using the setKernel method for separable kernels.
1791  // Normalize kernel values after building the product to remain in normal grey value areas.
1792  setKernel(ext, &(vx[0]), &(vy[0]), &(vz[0]), &(vc[0]), &(vt[0]), &(vu[0]), true);
1793  }
1794 
1795 
1796  //-------------------------------------------------------------------------------------------
1797  // Initialization. Should be called only by constructors.
1798  //-------------------------------------------------------------------------------------------
1799  template <typename KDATATYPE>
1801  {
1802  _ext.set(0);
1803  _negExt.set(0);
1804  _posExt.set(0);
1805 
1806  _tabSize = 0;
1807 
1808  _valueTab = nullptr;
1809  _coordTab = nullptr;
1810 
1811  // Separability information.
1812  _isSeparable = false;
1813  _areSeparabilityInfosUpToDate = false;
1814  _separableDimEntries.set(0);
1815  _separableOneDimExt.set(0);
1816  _separableExt.set(0);
1817  _separableNegExt.set(0);
1818  _separablePosExt.set(0);
1819  _separableCoordTab.clear();
1820  }
1821 
1822 
1823  //-------------------------------------------------------------------------------------------
1824  // Clear all internal (dynamic) tables.
1825  //-------------------------------------------------------------------------------------------
1826  template <typename KDATATYPE>
1828  {
1829  // Set table size to 0.
1830  _tabSize = 0;
1831 
1832  // Invalidate separability infos which are calculated on demand.
1833  _areSeparabilityInfosUpToDate = false;
1834 
1835  delete [] _valueTab;
1836 
1837  _valueTab = nullptr;
1838  delete [] _coordTab;
1839  _coordTab = nullptr;
1840  }
1841 
1842 
1843 
1844  //-------------------------------------------------------------------------------------------
1845  // Add a new coordinate with value to the coordinate and value table.
1846  // Still not tested! If update is true (default) then the kernel extents
1847  // are updated.
1848  //-------------------------------------------------------------------------------------------
1849  template <typename KDATATYPE>
1850  void TKernel<KDATATYPE>::_addCoordinate(const ImageVector &pos, KDATATYPE value, bool update)
1851  {
1852  // Create new data tables.
1853  ImageVector *newCoordTab = nullptr;
1854  KDATATYPE *newValueTab = nullptr;
1855 
1856  // Invalidate separability infos which are calculated on demand.
1857  _areSeparabilityInfosUpToDate = false;
1858 
1859  // Compute new table size.
1860  size_t newTabSize = _tabSize+1;
1861 
1862  newCoordTab = new ImageVector [_tabSize+1];
1863  newValueTab = new KDATATYPE[_tabSize+1];
1864 
1865  // Handle not enough memory.
1866  if (!newCoordTab || !newValueTab){
1867  delete [] newCoordTab;
1868  newCoordTab = nullptr;
1869  delete [] newValueTab;
1870  newValueTab = nullptr;
1871  ML_PRINT_FATAL_ERROR("Kernel<KDATATYPE>::_addCoordinate(...):",
1872  ML_NO_MEMORY,
1873  "Cannot create kernel tables. Returning with invalid "
1874  "reset tables. This will probably cause other errors.");
1875  return;
1876  }
1877 
1878  // Copy old contents into new tables.
1879  if (_tabSize > 0){
1880 #if defined(__GNUC__)
1881  // Suppress warning:
1882  // "'void* memcpy(void*, const void*, size_t)' writing to an object of type 'ml::ImageVector'
1883  // {aka 'class ml::TImageVector<long long int>'} with no trivial copy-assignment;
1884  // use copy-assignment or copy-initialization instead [-Wclass-memaccess]"
1885  // We are sure this is ok in this case!
1886 #pragma GCC diagnostic push
1887 #pragma GCC diagnostic ignored "-Wclass-memaccess"
1888 #endif
1889  memcpy(newCoordTab, _coordTab, _tabSize * sizeof(ImageVector));
1890 #if defined(__GNUC__)
1891 #pragma GCC diagnostic pop
1892 #endif
1893  memcpy(newValueTab, _valueTab, _tabSize * sizeof(KDATATYPE));
1894  }
1895 
1896  // Set new entry.
1897  newCoordTab[_tabSize] = pos;
1898  newValueTab[_tabSize] = value;
1899 
1900  // Remove old tables.
1901  _clearTables();
1902 
1903  // Increase table size.
1904  _tabSize = newTabSize;
1905  _coordTab = newCoordTab;
1906  _valueTab = newValueTab;
1907 
1908  // Update the real kernel size.
1909  if (update){ _calculateRealKernelExt(); }
1910  }
1911 
1912 
1913  //-------------------------------------------------------------------------------------------
1914  // Calculate the correct maximum kernel extent for all used kernel elements.
1915  // The maximum extent in all dimensions is reduced as much that all kernel coordinates just
1916  // remain in valid extent. Leading empty entries in the kernel are not removed.
1917  // Empty kernels are considered as kernels with extent (1,1,1,1,1,1).
1918  //-------------------------------------------------------------------------------------------
1919  template <typename KDATATYPE>
1921  {
1922  // Search minimum and maximum extent of the kernel.
1923  // For the case that no coordinate elements are available set
1924  // values to (0,0,0,0,0,0) so that resulting kernel ext is
1925  // calculated to (1,1,1,1,1,1) below.
1926  ImageVector maximum(0,0,0,0,0,0);
1927  if (getTabSize() > 0){
1928  for (size_t c=0; c < getTabSize(); c++){
1929  maximum = ImageVector::compMax(_coordTab[c], maximum);
1930  }
1931  }
1932 
1933  // Define kernel ext as difference between corners of bounding box.
1934  _ext = maximum+ImageVector(1,1,1,1,1,1);
1935 
1936  // Compute a negative and positive extend of the kernel. So even and odd kernels
1937  // can be handled without really having a kernel center. Subtract one to avoid a
1938  // to avoid increment of extents by one.
1939  _negExt = calculateNegativeExtentFromExtent(_ext);
1940  _posExt = calculatePositiveExtentFromExtent(_ext);
1941 
1942  // The kernel must never have extents smaller than 1 after this call.
1943  if (!_ext.allBiggerZero()){
1944  ML_PRINT_FATAL_ERROR("void TKernel<KDATATYPE>::_calculateRealKernelExt()",
1946  "Kernel has invalid extents now. Continuing anyway.");
1947  }
1948  }
1949 
1950 
1951 
1952  //-------------------------------------------------------------------------------------------
1953  //
1954  // Support for an interpretation as separable kernel.
1955  //
1956  //-------------------------------------------------------------------------------------------
1957 
1958  //-------------------------------------------------------------------------------------------
1959  // Set/unset a flag to indicate that the first 6 rows of the first kernel slice
1960  // is considered as 1-D axes of a separable filter kernel. Note that this flag
1961  // only denotes how applications shall interpret this kernel; however it does
1962  // NOT change any behaviour of this class.
1963  //-------------------------------------------------------------------------------------------
1964  template <typename KDATATYPE>
1965  void TKernel<KDATATYPE>::setSeparable(bool isSeparableVal)
1966  {
1967  // Invalidate separability information if flag changes.
1968  if (_isSeparable != isSeparableVal){
1969  _isSeparable = isSeparableVal;
1970  _invalidateSeparableInfos();
1971  }
1972  }
1973 
1974  //-------------------------------------------------------------------------------------------
1975  // Indicates whether the first 6 rows of the first kernel slice are
1976  // interpreted as 1-D axes of a separable filter kernel; default is false.
1977  //-------------------------------------------------------------------------------------------
1978  template <typename KDATATYPE>
1980  {
1981  return _isSeparable;
1982  }
1983 
1984  //-------------------------------------------------------------------------------------------
1985  // Returns a ImageVector with the number of entries of the separable kernel for
1986  // the dimensions 0,...,5. That means the n-th index contains the number
1987  // of valueTab entries of row n, where n is from [0,...,5].
1988  //-------------------------------------------------------------------------------------------
1989  template <typename KDATATYPE>
1991  {
1992  _validateSeparabilityInfos();
1993  return _separableDimEntries;
1994  }
1995 
1996  //------------------------------------------------------------------------------------------
2002  //------------------------------------------------------------------------------------------
2003  template <typename KDATATYPE>
2005  {
2006  _validateSeparabilityInfos();
2007  return _separableOneDimExt;
2008  }
2009 
2010  //-------------------------------------------------------------------------------------------
2017  //-------------------------------------------------------------------------------------------
2018  template <typename KDATATYPE>
2020  {
2021  _validateSeparabilityInfos();
2022  if (dim>5){ dim = 5; }
2023 
2024  // Sum up elements in lower dimensions to get index to the correct table entry.
2025  switch (dim){
2026  case 0: return 0;
2027 
2028  case 1: return static_cast<size_t>(_separableDimEntries.x);
2029 
2030  case 2: return static_cast<size_t>(_separableDimEntries.x +
2031  _separableDimEntries.y);
2032 
2033  case 3: return static_cast<size_t>(_separableDimEntries.x +
2034  _separableDimEntries.y +
2035  _separableDimEntries.z);
2036 
2037  case 4: return static_cast<size_t>(_separableDimEntries.x +
2038  _separableDimEntries.y +
2039  _separableDimEntries.z +
2040  _separableDimEntries.c);
2041 
2042  case 5: return static_cast<size_t>(_separableDimEntries.x +
2043  _separableDimEntries.y +
2044  _separableDimEntries.z +
2045  _separableDimEntries.c +
2046  _separableDimEntries.t);
2047  default:{
2048  ML_PRINT_FATAL_ERROR("TKernel<KDATATYPE>::getSeparableDimIndex",
2049  ML_PROGRAMMING_ERROR, "returning x-table entries");
2050  return 0;
2051  }
2052  }
2053  }
2054 
2055  //-------------------------------------------------------------------------------------------
2056  // Returns the table of all coordinates for filtering with separable kernels.
2057  //-------------------------------------------------------------------------------------------
2058  template <typename KDATATYPE>
2059  const std::vector<ImageVector> &TKernel<KDATATYPE>::getSeparableCoordTab() const
2060  {
2061  _validateSeparabilityInfos();
2062  return _separableCoordTab;
2063  }
2064 
2065  //-------------------------------------------------------------------------------------------
2066  // Invalidate separability information.
2067  //-------------------------------------------------------------------------------------------
2068  template <typename KDATATYPE>
2070  {
2071  _areSeparabilityInfosUpToDate = false;
2072  }
2073 
2074  //-------------------------------------------------------------------------------------------
2075  // This method updates all members which are needed in query methods for
2076  // separability properties of the kernel.
2077  // Note:
2078  // This method changes mutable members since it is required for get-methods
2079  // on information about separability information.
2080  //-------------------------------------------------------------------------------------------
2081  template <typename KDATATYPE>
2083  {
2084  // Speed up performance since it's called first in all separable info methods.
2085  if (_areSeparabilityInfosUpToDate){ return; }
2086  if (!_areSeparabilityInfosUpToDate){
2087 
2088  // Scan all coordinate components of the kernel until the y-coordinate is >= 6,
2089  // because all other information after that is not relevant for first 6 separable
2090  // filter rows. Expand the extent of the separable kernel and determine coordinate
2091  // of the axis components.
2092  _separableDimEntries.set(0);
2093  _separableOneDimExt.set(0);
2094  _separableExt.set(0);
2095  _separableCoordTab.clear();
2096  ImageVector sepCoord(-1);
2097  size_t idx=0;
2098  while ((idx<_tabSize) && (_coordTab[idx].y < 6)){
2099  // Get the current entry.
2100  const ImageVector &entry = _coordTab[idx];
2101 
2102  const size_t entryY = mlrange_cast<size_t>(entry.y);
2103 
2104  // Increment the number of entries of a certain dimension of the
2105  // 6 1-D kernels if the kernel is interpreted as a separable kernel.
2106  // Note that each of the first six rows contains the separable 1-D kernel
2107  // for dimensions 1-6.
2108  _separableDimEntries[entryY]++;
2109 
2110  // Increment the extent of the separable kernel dimensions if the
2111  // coordinate given by entry has a larger x-coordinate than the
2112  // extent of the corresponding dimension.
2113  if (entry.x+1 > _separableOneDimExt[entryY]){ _separableOneDimExt[entryY] = entry.x+1; }
2114 
2115  // Add the coordinate of the 1-D kernel to the table of coordinates.
2116  // Note that separable kernels are placed in the "center" of the corresponding
2117  // "normal" kernel. Hence, all components which are not given by entry.y,
2118  // need to be set to the position of the kernel "center" which is given by
2119  // the negative extent of the kernel. However, we do not have this "center"
2120  // here, because we do not know it before having all extents.
2121  // So we we mark the missing coordinate components with -1 and replace them
2122  // in an additional loop afterwards.
2123  sepCoord.set(-1);
2124  sepCoord[entryY] = entry.x;
2125  _separableCoordTab.push_back(sepCoord);
2126 
2127  // Count the number of separable entries in the kernel with idx: Go to next entry.
2128  ++idx;
2129  }
2130 
2131  // Determine second version of separable kernel extent where non filtered
2132  // dimensions are set to 1.
2133  _separableExt = _separableOneDimExt;
2134  _separableExt.fillSmallerComps(1,1);
2135 
2136  // Determine the center of the kernel which is considered to be the negative kernel extent.
2137  const ImageVector negExt =_separableExt / ImageVector(2);
2138 
2139  // Replace all -1 component values with the kernel center; thus the 1-D kernel is
2140  // centered in the region where the corresponding normal kernel would also have its
2141  // "center".
2142  for (size_t e=0; e < idx; ++e){
2143  // Get coordinate.
2144  ImageVector &coord = _separableCoordTab[e];
2145  for (size_t d=0; d < 6; ++d){
2146  // Replace all -1 component values with the kernel center.
2147  if (coord[d] == -1){ coord[d] = negExt[d]; }
2148  }
2149  }
2150 
2151  // Calculate negative and positive kernel extent for a separable kernel.
2152  // If a dimension is empty or zero sized then a zero component is returned.
2153  _separableNegExt = _separableExt/ImageVector(2);
2154  _separablePosExt = (_separableExt - (_separableExt/ImageVector(2))) - ImageVector(1);
2155 
2156  // Mark infos as valid.
2157  _areSeparabilityInfosUpToDate = true;
2158  }
2159  }
2160 
2161  //-------------------------------------------------------------------------------------------
2162  // End of support for the interpretation of the kernel as separable kernel.
2163  //-------------------------------------------------------------------------------------------
2164 
2165 
2166 
2171 
2174 
2177 
2178 
2181 
2185 
2186 
2187 ML_END_NAMESPACE
2188 
2189 #endif // __mlKernel_H
2190 
2191 
2192 
void set(const ComponentType v=0)
Sets all components to v or - if v is not specified - to 0.
Class to manage a filtering kernel for images.
Definition: mlKernel.h:73
virtual ~TKernel()
Destructor. Cleans up and removes instance of kernel.
Definition: mlKernel.h:572
void mirror(int dimension=-1)
Applies a point symmetric mirroring of all kernel elements.
Definition: mlKernel.h:1660
std::string getKernel(bool asLines=false, MLint fieldWidth=0, MLint precision=10) const
Returns the current kernel elements and values as string: The string needs has the following format: ...
Definition: mlKernel.h:1097
const ImageVector & getPositiveExtent() const
See getNegativeExtent().
Definition: mlKernel.h:946
bool isSeparable() const
Indicates whether the first 6 rows of the first kernel slice are interpreted as 1-D axes of a separab...
Definition: mlKernel.h:1979
static ImageVector indexToCoord(MLint idx, const ImageVector &ext)
Converts an index into an array with extents ext to a coordinate.
Definition: mlKernel.h:980
void makeCircular()
Takes the current kernel, computes radii from the extents of the kernel and removes all kernel elemen...
Definition: mlKernel.h:1585
static ImageVector calculateNegativeExtentFromExtent(const ImageVector &ext)
Calculate the negative extent of a kernel from a kernel extent.
Definition: mlKernel.h:989
static ImageVector calculatePositiveExtentFromExtent(const ImageVector &ext)
Calculate the positive extent of a kernel from a kernel extent.
Definition: mlKernel.h:998
void _invalidateSeparableInfos()
Invalidate separability information.
Definition: mlKernel.h:2069
static MLldouble binomialcoeff(MLint n, MLint k)
Calculate binomial coefficients for (n) (k)
Definition: mlKernel.h:1718
void _init()
Initialization. Should be called only by constructors.
Definition: mlKernel.h:1800
void fillUndefinedElements(KDATATYPE newVal=0)
Fill all undefined kernel elements with newVal.
Definition: mlKernel.h:1543
static MLint coordToIndex(const ImageVector &p, const ImageVector &size)
Converts the coordinate into the kernel with extents size to an index.
Definition: mlKernel.h:971
void setPartialKernel(size_t numElems, ImageVector *const coords, KDATATYPE *const values=nullptr)
Defines a set of local kernel coordinates and optionally a set of values which define the kernel elem...
Definition: mlKernel.h:1030
size_t getTabSize() const
Returns the current number of kernel elements.
Definition: mlKernel.h:624
ImageVector getSeparableDimEntries() const
Returns a ImageVector with the number of entries of the separable kernel for the dimensions 0,...
Definition: mlKernel.h:1990
KDATATYPE getMinValue() const
Return the minimum value of all kernel element values If kernel value table is empty then 0 is return...
Definition: mlKernel.h:678
KDATATYPE getMaxValue() const
Return the maximum value of all kernel element values If kernel value table is empty then 1 is return...
Definition: mlKernel.h:691
void setSeparable(bool isSeparableVal)
Set/unset a flag to indicate that the first 6 rows of the first kernel slice is considered as 1-D axe...
Definition: mlKernel.h:1965
const TKernel & operator=(const TKernel &kern)
Assignment operator. Sets current instance to contents of kern.
Definition: mlKernel.h:581
void manipulateKernelElements(KernModifier mode, KDATATYPE v)
Modify all kernel element values with the value v.
Definition: mlKernel.h:732
TKernel()
Constructor. Builds an empty kernel.
Definition: mlKernel.h:553
static std::vector< KDATATYPE > get1DGauss(size_t numSamples, bool normalize=true)
Returns a vector with numSample values binomial coefficients.
Definition: mlKernel.h:1742
std::string setKernel(const std::string &kernString)
Defines elements and values of the kernel matrix by a string.
Definition: mlKernel.h:1215
void reset()
Reset kernel to construction state.
Definition: mlKernel.h:610
const ImageVector & getExtent() const
Returns the kernel extents in 6D.
Definition: mlKernel.h:913
ImageVector getSeparableOneDimExtents() const
Returns a vector where the components 0,...,5 contain the extent of the region spanned by the 6 separ...
Definition: mlKernel.h:2004
const std::vector< ImageVector > & getSeparableCoordTab() const
Returns the table of with all coordinates for filtering with separable kernels.
Definition: mlKernel.h:2059
const KDATATYPE * getValueTab(size_t dim=0) const
Gets the table of kernel element values which are currently defined.
Definition: mlKernel.h:656
void _clearTables()
Clear all internal (dynamic) tables.
Definition: mlKernel.h:1827
MLint findIndex(const ImageVector &pos) const
Return index to kernel element if it exists; otherwise return -1.
Definition: mlKernel.h:1009
KernModifier
Manipulation modes for kernel values with a given value v:
Definition: mlKernel.h:102
@ KERN_MIRROR_C
Definition: mlKernel.h:119
@ KERN_MIRROR_U
Definition: mlKernel.h:121
@ KERN_MIRROR_Y
Definition: mlKernel.h:117
@ KERN_MIRROR_X
Definition: mlKernel.h:116
@ KERN_MIRROR_T
Definition: mlKernel.h:120
@ KERN_MIRROR_Z
Definition: mlKernel.h:118
@ KERN_NORMALIZE
Definition: mlKernel.h:112
KDATATYPE getValueTabSum() const
Return the sum of all kernel element values.
Definition: mlKernel.h:665
void setKernel(const ImageVector &ext, const KDATATYPE2 *const xaxis, const KDATATYPE2 *const yaxis, const KDATATYPE2 *const zaxis, const KDATATYPE2 *const caxis, const KDATATYPE2 *const taxis, const KDATATYPE2 *const uaxis, bool normalize)
Defines a complete kernel matrix whose extents are defined by ext.
Definition: mlKernel.h:296
static MLint coordToIndex(MLint x, MLint y, MLint z, MLint c, MLint t, MLint u, const ImageVector &size)
Converts the coordinate (x,y,z,c,t,u) into the kernel to an index into an array with 6D extents given...
Definition: mlKernel.h:962
const ImageVector * getCoordTab(size_t dim=0) const
Gets a table of coordinates pointing to all kernel elements which are currently defined.
Definition: mlKernel.h:644
TKernel(const TKernel &kern)
Copy constructor. Builds a kernel with contents of kern.
Definition: mlKernel.h:562
void _addCoordinate(const ImageVector &pos, KDATATYPE value, bool update)
Add a new coordinate with value to the coordinate and value table.
Definition: mlKernel.h:1850
const ImageVector & getNegativeExtent() const
The extent of the kernel to both sides.
Definition: mlKernel.h:931
void _calculateRealKernelExt()
Calculate the correct maximum kernel extent for used kernel elements.
Definition: mlKernel.h:1920
size_t getSeparableDimIndex(size_t dim=0) const
Returns the index to entries of valueTab or coordTab which are related to the 1-D separable kernel fo...
Definition: mlKernel.h:2019
void setGauss(const ImageVector &ext)
Replaces the current kernel by a normalized gauss kernel.
Definition: mlKernel.h:1774
KDATATYPE getNegativeValueSum() const
Return the sum of all negative kernel element values.
Definition: mlKernel.h:705
KDATATYPE getPositiveValueSum() const
Return the sum of all positive kernel element values.
Definition: mlKernel.h:720
void setKernel(const ImageVector &ext, const KDATATYPE *const values=nullptr, bool *const mask=nullptr)
Defines a complete kernel matrix whose extents are defined by ext.
Definition: mlKernel.h:1363
void _validateSeparabilityInfos() const
This method updates all members which are needed in query methods for separability properties of the ...
Definition: mlKernel.h:2082
void setSeparableKernel(const std::vector< typename std::vector< KDATATYPE > > &separableRows)
Create kernel coordinate and value tables in separable table format, that means a 2-D kernel where ea...
Definition: mlKernel.h:1436
void resizeKernel(const ImageVector &ext, KDATATYPE newVal=0)
Resizes the kernel to a new state and tries to maintain the previous elements if possible.
Definition: mlKernel.h:1489
ComponentType c
Color component of the vector.
Definition: mlImageVector.h:65
ComponentType t
Time component of the vector.
Definition: mlImageVector.h:67
ComponentType u
Unit/Modality/User component of the vector.
Definition: mlImageVector.h:69
ComponentType z
Z component of the vector.
Definition: mlImageVector.h:63
ComponentType x
X component of the vector.
Definition: mlImageVector.h:59
ComponentType y
Y component of the vector.
Definition: mlImageVector.h:61
std::string print(const std::string &openStr="", const std::string &sepStr=" ", const std::string &termStr="", const MLint16 numDigits=-1) const
Returns the string openStr + v.array[0] + sepStr + ...
ComponentType compMul() const
Returns the product of all components. There is no check for integer overflow.
bool MLValueIs0WOM(MLint8 a)
Returns true if value is 0; otherwise, it returns false.
bool MLValuesDifferWOM(MLint8 a, MLint8 b)
Returns true if values differ; otherwise, it returns false.
#define ML_CALCULATION_ERROR
This is an unspecific error used in some cases where the error is not very specific.
Definition: mlTypeDefs.h:832
#define ML_PROGRAMMING_ERROR
A case occurred that should not appear and there are a variety of reasons, typically it is a programm...
Definition: mlTypeDefs.h:788
#define ML_BAD_PARAMETER
A bad/invalid parameter (or even an inappropriate image) has been passed to a module or an algorithm,...
Definition: mlTypeDefs.h:823
#define ML_NO_MEMORY
The system does not have enough memory to perform the desired operation; try to reduce application da...
Definition: mlTypeDefs.h:735
#define ML_PRINT_FATAL_ERROR(FUNC_NAME, REASON, HANDLING)
Like ML_PRINT_FATAL_ERROR_DUMP(FUNC_NAME, REASON, HANDLING, RT_OBJ) without a runtime object to be du...
#define ML_PRINT_ERROR(FUNC_NAME, REASON, HANDLING)
Like ML_PRINT_ERROR_DUMP(FUNC_NAME, REASON, HANDLING, RT_OBJ) without a runtime object to be dumped.
@ ML_FATAL_MEMORY_ERROR
On allocation failure, a fatal error print is done and NULL is returned.
Definition: mlTypeDefs.h:677
long double MLldouble
Definition: mlTypeDefs.h:232
double MLdouble
Definition: mlTypeDefs.h:217
MLint64 MLint
A signed ML integer type with at least 64 bits used for index calculations on very large images even ...
Definition: mlTypeDefs.h:490
signed int MLint32
Definition: mlTypeDefs.h:161
TKernel< MLldouble > LDoubleKernel
Kernel type with MLldouble elements.
Definition: mlKernel.h:2176
T mlAbs(T a)
Defines ML specific abs template since only type-dependent library functions exists.
Definition: mlUtilsSystem.h:84
FloatingPointVector< T, size, DataContainer > compMax(FloatingPointVector< T, size, DataContainer > buffer1, const FloatingPointVector< T, size, DataContainer > &buffer2)
Component-wise maximum of buffer1 and buffer2.
MLdouble KernelDataType
Define the standard data type for kernel elements to be used in this library.
Definition: mlKernel.h:2180
TKernel< MLfloat > FloatKernel
Definition: mlKernel.h:2170
TKernel< KernelDataType > Kernel
Standard kernel type to be used in this kernel library.
Definition: mlKernel.h:2183
TKernel< MLdouble > DoubleKernel
Kernel type with MLdouble elements.
Definition: mlKernel.h:2173
TImageVector< MLint > ImageVector
Defines the standard ImageVector type that is used by the ML for indexing and coordinates.