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
25
26 //-------------------------------------------------------------------------------------------
72 //-------------------------------------------------------------------------------------------
73 template <typename KDATATYPE> class TKernel {
74
75 public:
76
77 //--------------------------------------------------------------------------------------------------------
101 //--------------------------------------------------------------------------------------------------------
125
127 inline TKernel();
128
130 inline TKernel(const TKernel &kern);
131
133 inline virtual ~TKernel();
134
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
160
164
168
172
176
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
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>
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
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
349
352
358
362 void mirror(int dimension=-1);
363
367
372 static std::vector<KDATATYPE> get1DGauss(size_t numSamples, bool normalize=true);
373
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
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>
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>
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>
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.
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>
1490 {
1491 // Create a buffer kernel.
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>
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{
1691 for (size_t e=0; e < tabSizeBuf; e++){
1692 // Take normal coordinate.
1693 mirVec = coordTabBuf[e];
1694
1695 // mirror the selected coordinate component.
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(...):",
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 memcpy(newCoordTab, _coordTab, _tabSize*sizeof(ImageVector));
1881 memcpy(newValueTab, _valueTab, _tabSize*sizeof(KDATATYPE));
1882 }
1883
1884 // Set new entry.
1885 newCoordTab[_tabSize] = pos;
1886 newValueTab[_tabSize] = value;
1887
1888 // Remove old tables.
1889 _clearTables();
1890
1891 // Increase table size.
1892 _tabSize = newTabSize;
1893 _coordTab = newCoordTab;
1894 _valueTab = newValueTab;
1895
1896 // Update the real kernel size.
1897 if (update){ _calculateRealKernelExt(); }
1898 }
1899
1900
1901 //-------------------------------------------------------------------------------------------
1902 // Calculate the correct maximum kernel extent for all used kernel elements.
1903 // The maximum extent in all dimensions is reduced as much that all kernel coordinates just
1904 // remain in valid extent. Leading empty entries in the kernel are not removed.
1905 // Empty kernels are considered as kernels with extent (1,1,1,1,1,1).
1906 //-------------------------------------------------------------------------------------------
1907 template <typename KDATATYPE>
1909 {
1910 // Search minimum and maximum extent of the kernel.
1911 // For the case that no coordinate elements are available set
1912 // values to (0,0,0,0,0,0) so that resulting kernel ext is
1913 // calculated to (1,1,1,1,1,1) below.
1914 ImageVector maximum(0,0,0,0,0,0);
1915 if (getTabSize() > 0){
1916 for (size_t c=0; c < getTabSize(); c++){
1917 maximum = ImageVector::compMax(_coordTab[c], maximum);
1918 }
1919 }
1920
1921 // Define kernel ext as difference between corners of bounding box.
1922 _ext = maximum+ImageVector(1,1,1,1,1,1);
1923
1924 // Compute a negative and positive extend of the kernel. So even and odd kernels
1925 // can be handled without really having a kernel center. Subtract one to avoid a
1926 // to avoid increment of extents by one.
1927 _negExt = calculateNegativeExtentFromExtent(_ext);
1928 _posExt = calculatePositiveExtentFromExtent(_ext);
1929
1930 // The kernel must never have extents smaller than 1 after this call.
1931 if (!_ext.allBiggerZero()){
1932 ML_PRINT_FATAL_ERROR("void TKernel<KDATATYPE>::_calculateRealKernelExt()",
1934 "Kernel has invalid extents now. Continuing anyway.");
1935 }
1936 }
1937
1938
1939
1940 //-------------------------------------------------------------------------------------------
1941 //
1942 // Support for an interpretation as separable kernel.
1943 //
1944 //-------------------------------------------------------------------------------------------
1945
1946 //-------------------------------------------------------------------------------------------
1947 // Set/unset a flag to indicate that the first 6 rows of the first kernel slice
1948 // is considered as 1-D axes of a separable filter kernel. Note that this flag
1949 // only denotes how applications shall interpret this kernel; however it does
1950 // NOT change any behaviour of this class.
1951 //-------------------------------------------------------------------------------------------
1952 template <typename KDATATYPE>
1954 {
1955 // Invalidate separability information if flag changes.
1956 if (_isSeparable != isSeparableVal){
1957 _isSeparable = isSeparableVal;
1958 _invalidateSeparableInfos();
1959 }
1960 }
1961
1962 //-------------------------------------------------------------------------------------------
1963 // Indicates whether the first 6 rows of the first kernel slice are
1964 // interpreted as 1-D axes of a separable filter kernel; default is false.
1965 //-------------------------------------------------------------------------------------------
1966 template <typename KDATATYPE>
1968 {
1969 return _isSeparable;
1970 }
1971
1972 //-------------------------------------------------------------------------------------------
1973 // Returns a ImageVector with the number of entries of the separable kernel for
1974 // the dimensions 0,...,5. That means the n-th index contains the number
1975 // of valueTab entries of row n, where n is from [0,...,5].
1976 //-------------------------------------------------------------------------------------------
1977 template <typename KDATATYPE>
1979 {
1980 _validateSeparabilityInfos();
1981 return _separableDimEntries;
1982 }
1983
1984 //------------------------------------------------------------------------------------------
1990 //------------------------------------------------------------------------------------------
1991 template <typename KDATATYPE>
1993 {
1994 _validateSeparabilityInfos();
1995 return _separableOneDimExt;
1996 }
1997
1998 //-------------------------------------------------------------------------------------------
2005 //-------------------------------------------------------------------------------------------
2006 template <typename KDATATYPE>
2008 {
2009 _validateSeparabilityInfos();
2010 if (dim>5){ dim = 5; }
2011
2012 // Sum up elements in lower dimensions to get index to the correct table entry.
2013 switch (dim){
2014 case 0: return 0;
2015
2016 case 1: return static_cast<size_t>(_separableDimEntries.x);
2017
2018 case 2: return static_cast<size_t>(_separableDimEntries.x +
2019 _separableDimEntries.y);
2020
2021 case 3: return static_cast<size_t>(_separableDimEntries.x +
2022 _separableDimEntries.y +
2023 _separableDimEntries.z);
2024
2025 case 4: return static_cast<size_t>(_separableDimEntries.x +
2026 _separableDimEntries.y +
2027 _separableDimEntries.z +
2028 _separableDimEntries.c);
2029
2030 case 5: return static_cast<size_t>(_separableDimEntries.x +
2031 _separableDimEntries.y +
2032 _separableDimEntries.z +
2033 _separableDimEntries.c +
2034 _separableDimEntries.t);
2035 default:{
2036 ML_PRINT_FATAL_ERROR("TKernel<KDATATYPE>::getSeparableDimIndex",
2037 ML_PROGRAMMING_ERROR, "returning x-table entries");
2038 return 0;
2039 }
2040 }
2041 }
2042
2043 //-------------------------------------------------------------------------------------------
2044 // Returns the table of all coordinates for filtering with separable kernels.
2045 //-------------------------------------------------------------------------------------------
2046 template <typename KDATATYPE>
2047 const std::vector<ImageVector> &TKernel<KDATATYPE>::getSeparableCoordTab() const
2048 {
2049 _validateSeparabilityInfos();
2050 return _separableCoordTab;
2051 }
2052
2053 //-------------------------------------------------------------------------------------------
2054 // Invalidate separability information.
2055 //-------------------------------------------------------------------------------------------
2056 template <typename KDATATYPE>
2058 {
2059 _areSeparabilityInfosUpToDate = false;
2060 }
2061
2062 //-------------------------------------------------------------------------------------------
2063 // This method updates all members which are needed in query methods for
2064 // separability properties of the kernel.
2065 // Note:
2066 // This method changes mutable members since it is required for get-methods
2067 // on information about separability information.
2068 //-------------------------------------------------------------------------------------------
2069 template <typename KDATATYPE>
2071 {
2072 // Speed up performance since it's called first in all separable info methods.
2073 if (_areSeparabilityInfosUpToDate){ return; }
2074 if (!_areSeparabilityInfosUpToDate){
2075
2076 // Scan all coordinate components of the kernel until the y-coordinate is >= 6,
2077 // because all other information after that is not relevant for first 6 separable
2078 // filter rows. Expand the extent of the separable kernel and determine coordinate
2079 // of the axis components.
2080 _separableDimEntries.set(0);
2081 _separableOneDimExt.set(0);
2082 _separableExt.set(0);
2083 _separableCoordTab.clear();
2085 size_t idx=0;
2086 while ((idx<_tabSize) && (_coordTab[idx].y < 6)){
2087 // Get the current entry.
2088 const ImageVector &entry = _coordTab[idx];
2089
2090 const size_t entryY = mlrange_cast<size_t>(entry.y);
2091
2092 // Increment the number of entries of a certain dimension of the
2093 // 6 1-D kernels if the kernel is interpreted as a separable kernel.
2094 // Note that each of the first six rows contains the separable 1-D kernel
2095 // for dimensions 1-6.
2096 _separableDimEntries[entryY]++;
2097
2098 // Increment the extent of the separable kernel dimensions if the
2099 // coordinate given by entry has a larger x-coordinate than the
2100 // extent of the corresponding dimension.
2101 if (entry.x+1 > _separableOneDimExt[entryY]){ _separableOneDimExt[entryY] = entry.x+1; }
2102
2103 // Add the coordinate of the 1-D kernel to the table of coordinates.
2104 // Note that separable kernels are placed in the "center" of the corresponding
2105 // "normal" kernel. Hence, all components which are not given by entry.y,
2106 // need to be set to the position of the kernel "center" which is given by
2107 // the negative extent of the kernel. However, we do not have this "center"
2108 // here, because we do not know it before having all extents.
2109 // So we we mark the missing coordinate components with -1 and replace them
2110 // in an additional loop afterwards.
2111 sepCoord.set(-1);
2112 sepCoord[entryY] = entry.x;
2113 _separableCoordTab.push_back(sepCoord);
2114
2115 // Count the number of separable entries in the kernel with idx: Go to next entry.
2116 ++idx;
2117 }
2118
2119 // Determine second version of separable kernel extent where non filtered
2120 // dimensions are set to 1.
2121 _separableExt = _separableOneDimExt;
2122 _separableExt.fillSmallerComps(1,1);
2123
2124 // Determine the center of the kernel which is considered to be the negative kernel extent.
2125 const ImageVector negExt =_separableExt / ImageVector(2);
2126
2127 // Replace all -1 component values with the kernel center; thus the 1-D kernel is
2128 // centered in the region where the corresponding normal kernel would also have its
2129 // "center".
2130 for (size_t e=0; e < idx; ++e){
2131 // Get coordinate.
2132 ImageVector &coord = _separableCoordTab[e];
2133 for (size_t d=0; d < 6; ++d){
2134 // Replace all -1 component values with the kernel center.
2135 if (coord[d] == -1){ coord[d] = negExt[d]; }
2136 }
2137 }
2138
2139 // Calculate negative and positive kernel extent for a separable kernel.
2140 // If a dimension is empty or zero sized then a zero component is returned.
2141 _separableNegExt = _separableExt/ImageVector(2);
2142 _separablePosExt = (_separableExt - (_separableExt/ImageVector(2))) - ImageVector(1);
2143
2144 // Mark infos as valid.
2145 _areSeparabilityInfosUpToDate = true;
2146 }
2147 }
2148
2149 //-------------------------------------------------------------------------------------------
2150 // End of support for the interpretation of the kernel as separable kernel.
2151 //-------------------------------------------------------------------------------------------
2152
2153
2154
2159
2162
2165
2166
2169
2173
2174
2176
2177#endif // __mlKernel_H
2178
2179
2180
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:1967
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:2057
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:1978
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:1953
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:1992
const std::vector< ImageVector > & getSeparableCoordTab() const
Returns the table of with all coordinates for filtering with separable kernels.
Definition mlKernel.h:2047
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
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:1908
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:2007
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:2070
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
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 + ... + v.array[NumberOfDimensions-2] + sepStr + v....
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:832
#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: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.
Target mlrange_cast(Source arg)
Generic version of checked ML casts.
@ 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
T mlAbs(T a)
Defines ML specific abs template since only type depended library functions exists.
MLdouble KernelDataType
Define the standard data type for kernel elements to be used in this library.
Definition mlKernel.h:2168