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