MeVisLabToolboxReference
|
00001 // **InsertLicense** code 00002 //------------------------------------------------------------------------- 00004 00009 //------------------------------------------------------------------------- 00010 // Prevent multiple including of this file. 00011 #if !defined(__mlKernel_H) 00012 #define __mlKernel_H 00013 00014 // ML-includes 00015 #ifndef __mlInitSystemKernel_H 00016 #include "mlInitSystemKernel.h" 00017 #endif 00018 00019 #include <errno.h> 00020 00021 ML_START_NAMESPACE 00022 00023 //------------------------------------------------------------------------------------------- 00069 //------------------------------------------------------------------------------------------- 00070 template <typename KDATATYPE> class TKernel { 00071 00072 public: 00073 00074 //-------------------------------------------------------------------------------------------------------- 00098 //-------------------------------------------------------------------------------------------------------- 00099 enum KernModifier { 00100 KERN_SET = 0, 00101 KERN_MULT , 00102 KERN_ADD , 00103 KERN_INVDIV , 00104 KERN_INVSUB , 00105 KERN_SQR , 00106 KERN_SQRT , 00107 KERN_POW , 00108 KERN_LOG , 00109 KERN_NORMALIZE , 00110 KERN_GAUSS , 00111 KERN_SPHERE , 00112 KERN_MIRROR , 00113 KERN_MIRROR_X , 00114 KERN_MIRROR_Y , 00115 KERN_MIRROR_Z , 00116 KERN_MIRROR_C , 00117 KERN_MIRROR_T , 00118 KERN_MIRROR_U , 00119 00120 NUM_KERN_MODIFYERS 00121 }; 00122 00124 inline TKernel(); 00125 00127 inline TKernel(const TKernel &kern); 00128 00130 inline virtual ~TKernel(); 00131 00133 const TKernel& operator=(const TKernel &kern); 00134 00136 void reset(); 00137 00139 inline size_t getTabSize() const; 00140 00147 inline const ImageVector* getCoordTab(size_t dim = 0) const; 00148 00153 inline const KDATATYPE* getValueTab(size_t dim = 0) const; 00154 00156 KDATATYPE getValueTabSum() const; 00157 00160 KDATATYPE getMinValue() const; 00161 00164 KDATATYPE getMaxValue() const; 00165 00168 KDATATYPE getNegativeValueSum() const; 00169 00172 KDATATYPE getPositiveValueSum() const; 00173 00175 void manipulateKernelElements(KernModifier mode, KDATATYPE v); 00176 00185 inline const ImageVector &getExtent() const; 00186 00191 inline const ImageVector &getNegativeExtent() const; 00192 00194 inline const ImageVector &getPositiveExtent() const; 00195 00198 static inline MLint coordToIndex(MLint x, MLint y, MLint z, MLint c, MLint t, MLint u, const ImageVector &size); 00199 00201 static inline MLint coordToIndex(const ImageVector &p, const ImageVector &size); 00202 00204 static inline ImageVector indexToCoord(MLint idx, const ImageVector &ext); 00205 00207 static inline ImageVector calculateNegativeExtentFromExtent(const ImageVector &ext); 00208 00210 static inline ImageVector calculatePositiveExtentFromExtent(const ImageVector &ext); 00211 00214 MLint findIndex(const ImageVector &pos) const; 00215 00222 void setPartialKernel(size_t numElems, ImageVector * const coords, KDATATYPE * const values=NULL); 00223 00245 std::string getKernel(bool asLines=false, MLint fieldWidth=0, MLint precision=10) const; 00246 00273 std::string setKernel(const std::string &kernString); 00274 00283 void setKernel(const ImageVector &ext, const KDATATYPE * const values=NULL, bool * const mask=NULL); 00284 00292 template <typename KDATATYPE2> 00293 void setKernel(const ImageVector &ext, 00294 const KDATATYPE2 * const xaxis, const KDATATYPE2 * const yaxis, const KDATATYPE2 * const zaxis, 00295 const KDATATYPE2 * const caxis, const KDATATYPE2 * const taxis, const KDATATYPE2 * const uaxis, 00296 bool normalize) 00297 { 00298 ML_TRACE_IN( "TKernel<KDATATYPE::setKernel( )" ); 00299 ML_TRY 00300 { 00301 // Clear current separability members. 00302 _invalidateSeparableInfos(); 00303 00304 MLint b=0; 00305 00306 // Check for valid parameters. Return empty kernel otherwise. 00307 if (!xaxis || !yaxis || !zaxis || !caxis || !taxis || !uaxis){ 00308 _clearTables(); 00309 _calculateRealKernelExt(); 00310 return; 00311 } 00312 00313 // Pointer to matrix which contains the products of the corresponding axis-values 00314 KDATATYPE *valuematrix = 00315 static_cast<KDATATYPE*>(Memory::allocateMemory(sizeof(KDATATYPE) * ext.compMul(), ML_FATAL_MEMORY_ERROR)); 00316 00317 for (MLint u=0; u<ext.u; ++u){ 00318 for (MLint t=0; t<ext.t; ++t){ 00319 for (MLint c=0; c<ext.c; ++c){ 00320 for (MLint z=0; z<ext.z; ++z){ 00321 for (MLint y=0; y<ext.y; ++y){ 00322 for (MLint x=0; x<ext.x; ++x){ 00323 valuematrix[b++] = static_cast<KDATATYPE>(xaxis[x]*yaxis[y]*zaxis[z]*caxis[c]*taxis[t]*uaxis[u]); 00324 } 00325 }}}}} 00326 00327 setKernel(ext,valuematrix); 00328 00329 Memory::freeMemory(valuematrix); 00330 valuematrix=NULL; 00331 00332 // If desired then normalize all kernel elements so that their sum becomes 1. 00333 if (normalize){ manipulateKernelElements(KERN_NORMALIZE, 0); } 00334 } 00335 ML_CATCH_RETHROW; 00336 } 00337 00344 void setSeparableKernel(const std::vector<ML_TYPENAME std::vector<KDATATYPE> > &separableRows); 00345 00350 void resizeKernel(const ImageVector &ext, KDATATYPE newVal=0); 00351 00353 void fillUndefinedElements(KDATATYPE newVal=0); 00354 00359 void makeCircular(); 00360 00364 void mirror(int dimension=-1); 00365 00368 static MLldouble binomialcoeff(MLint n, MLint k); 00369 00374 static std::vector<KDATATYPE> get1DGauss(size_t numSamples, bool normalize=true); 00375 00377 void setGauss(const ImageVector &ext); 00378 00379 00380 //------------------------------------------------------------------------------------------- 00381 // 00383 00384 // 00385 // If the kernel is interpreted as a separable kernel then the first six rows 00386 // of the first slice of the kernel matrix are taken. 00387 // These six rows are interpreted as the six 1-dimensional axis in x,y,z,c,t, and u 00388 // dimensions which are used as 1-D filter kernels for a 6D separable filtering. 00389 // 00390 // 00391 // For example: 00392 // 00393 // | 1 3 5 6 4 | 00394 // | 2 7 2 | 00395 // | 4 1 9 5 | 00396 // | | 00397 // | 3 8 3 | 00398 // | | 00399 // 00400 // describes a separable kernel with the following axes extent: 00401 // X=5, Y=3, Z=4, C=0, T=3, U=0. 00402 // An extent of 0 (for example C and U dimension) is used to describe 00403 // that filtering with a 1-D kernel in that dimension is not applied. 00404 // 00405 //------------------------------------------------------------------------------------------- 00410 inline void setSeparable(bool isSeparableVal); 00411 00414 inline bool isSeparable() const; 00415 00419 inline ImageVector getSeparableDimEntries() const; 00420 00426 inline ImageVector getSeparableOneDimExtents() const; 00427 00434 size_t getSeparableDimIndex(size_t dim=0) const; 00435 00438 const std::vector<ImageVector> &getSeparableCoordTab() const; 00439 00441 00442 #ifdef ML_DEPRECATED 00443 00445 00446 00447 public: 00448 00451 inline ML_DEPRECATED KDATATYPE getNegValueSum() const { return getNegativeValueSum(); } 00452 00455 inline ML_DEPRECATED KDATATYPE getPosValueSum() const { return getPositiveValueSum(); } 00456 00459 inline ML_DEPRECATED const ImageVector &getExt() const { return getExtent(); } 00460 00463 inline ML_DEPRECATED const ImageVector &getNegExt() const { return getNegativeExtent(); } 00464 00467 inline ML_DEPRECATED const ImageVector &getPosExt() const { return getPositiveExtent(); } 00468 00471 static inline ML_DEPRECATED ImageVector calcNegExtFromExt(const ImageVector &ext) { return calculateNegativeExtentFromExtent(ext); } 00472 00475 static inline ML_DEPRECATED ImageVector calcPosExtFromExt(const ImageVector &ext) { return calculatePositiveExtentFromExtent(ext); } 00476 00478 00479 #endif // ML_DEPRECATED 00480 00481 00482 protected: 00483 //------------------------------------------------------------------------------------------- 00484 // 00485 // Protected methods. 00486 // 00487 //------------------------------------------------------------------------------------------- 00488 00490 void _init(); 00491 00493 void _clearTables(); 00494 00498 void _addCoordinate(const ImageVector &pos, KDATATYPE value, bool update); 00499 00504 void _calculateRealKernelExt(); 00505 00511 void _validateSeparabilityInfos() const; 00512 00514 void _invalidateSeparableInfos(); 00515 00516 00517 00518 private: 00519 //------------------------------------------------------------------------------------------- 00520 // 00521 // Member variables. 00522 // 00523 //------------------------------------------------------------------------------------------- 00524 00527 ImageVector _ext; 00528 00530 ImageVector _negExt; 00531 00533 ImageVector _posExt; 00534 00537 size_t _tabSize; 00538 00540 KDATATYPE* _valueTab; 00541 00543 ImageVector* _coordTab; 00544 00545 00547 00548 00551 bool _isSeparable; 00552 00556 00558 mutable bool _areSeparabilityInfosUpToDate; 00559 00561 mutable ImageVector _separableDimEntries; 00562 00565 mutable ImageVector _separableOneDimExt; 00566 00569 mutable ImageVector _separableExt; 00570 00572 mutable ImageVector _separableNegExt; 00573 00575 mutable ImageVector _separablePosExt; 00576 00578 mutable std::vector<ImageVector> _separableCoordTab; 00580 }; // class TKernel 00581 00582 00583 00584 00585 00586 //------------------------------------------------------------------------ 00587 // IMPLEMENTATION PART: No user specific things below. 00588 //------------------------------------------------------------------------ 00589 00590 00591 //------------------------------------------------------------------------------------------- 00593 //------------------------------------------------------------------------------------------- 00594 template <typename KDATATYPE> 00595 TKernel<KDATATYPE>::TKernel() 00596 { 00597 ML_TRACE_IN( "TKernel::TKernel() " ); 00598 00599 _init(); 00600 } 00601 00602 //------------------------------------------------------------------------------------------- 00604 //------------------------------------------------------------------------------------------- 00605 template <typename KDATATYPE> 00606 TKernel<KDATATYPE>::TKernel(const TKernel &kern) 00607 { 00608 ML_TRACE_IN( "TKernel::TKernel()" ); 00609 00610 _init(); 00611 operator=(kern); 00612 } 00613 00614 //------------------------------------------------------------------------------------------- 00616 //------------------------------------------------------------------------------------------- 00617 template <typename KDATATYPE> 00618 TKernel<KDATATYPE>::~TKernel() 00619 { 00620 ML_TRACE_IN( "TKernel::~TKernel( )" ); 00621 ML_TRY 00622 { 00623 _clearTables(); 00624 } 00625 ML_CATCH; // Do not rethrow in destructors. 00626 } 00627 00628 //------------------------------------------------------------------------------------------- 00629 // Assignment operator. Sets current instance to contents of \c kern. 00630 //------------------------------------------------------------------------------------------- 00631 template <typename KDATATYPE> 00632 const TKernel<KDATATYPE>& TKernel<KDATATYPE>::operator=(const TKernel &kern) 00633 { 00634 ML_TRACE_IN( "TKernel<KDATATYPE>::operator=" ); 00635 ML_TRY 00636 { 00637 // Assign kernel to this if it's not this. 00638 if (&kern != this){ 00639 // Clean up current kernel table. 00640 _clearTables(); 00641 00642 // Set new kernel table size, the kernel voxels and the kernel values. 00643 setPartialKernel(kern._tabSize, kern._coordTab, kern._valueTab); 00644 00645 // Copy mutable members for separable kernel support. 00646 _isSeparable = kern._isSeparable; 00647 _areSeparabilityInfosUpToDate = kern._areSeparabilityInfosUpToDate; 00648 _separableDimEntries = kern._separableDimEntries; 00649 _separableOneDimExt = kern._separableOneDimExt; 00650 _separableExt = kern._separableExt; 00651 _separableNegExt = kern._separableNegExt; 00652 _separablePosExt = kern._separablePosExt; 00653 _separableCoordTab = kern._separableCoordTab; 00654 } 00655 00656 // Return copy. 00657 return *this; 00658 } 00659 ML_CATCH_RETHROW; 00660 } 00661 00662 //------------------------------------------------------------------------------------------- 00663 // Reset kernel to construction state. 00664 //------------------------------------------------------------------------------------------- 00665 template <typename KDATATYPE> 00666 void TKernel<KDATATYPE>::reset() 00667 { 00668 ML_TRACE_IN( "TKernel<KDATATYPE>::reset()" ); 00669 ML_TRY 00670 { 00671 // Remove dynamic structures. 00672 _clearTables(); 00673 00674 // Call constructor initialization. We can do that here, because 00675 // all internal tables have been cleared. 00676 _init(); 00677 } 00678 ML_CATCH_RETHROW; 00679 } 00680 00681 //------------------------------------------------------------------------------------------- 00682 // Returns the current number of kernel elements. 00683 //------------------------------------------------------------------------------------------- 00684 template <typename KDATATYPE> 00685 size_t TKernel<KDATATYPE>::getTabSize() const 00686 { 00687 ML_TRACE_IN_TIME_CRITICAL("size_t TKernel<KDATATYPE>::getTabSize()"); 00688 00689 if (_isSeparable){ 00690 _validateSeparabilityInfos(); 00691 return getSeparableCoordTab().size(); 00692 } 00693 else{ 00694 return _tabSize; 00695 } 00696 } 00697 00698 //------------------------------------------------------------------------------------------- 00699 // Gets a table of coordinates pointing to all kernel elements 00700 // which are currently defined. 00701 // The size of the returned table is given by getTabSize(). 00702 // In the case of separable filtering it returns those which are 00703 // valid for the current pass of separable kernel filtering. 00704 // It is a subset of the array given by \c getSeparableCoordTab(). 00705 //------------------------------------------------------------------------------------------- 00706 template <typename KDATATYPE> 00707 const ImageVector* TKernel<KDATATYPE>::getCoordTab(size_t dim) const 00708 { 00709 ML_TRACE_IN_TIME_CRITICAL("const ImageVector* TKernel<KDATATYPE>::getCoordTab()"); 00710 00711 return _isSeparable ? &(getSeparableCoordTab()[getSeparableDimIndex(dim)]) : _coordTab; 00712 } 00713 00714 //------------------------------------------------------------------------------------------- 00715 // Gets the table of kernel element values which are currently defined. 00716 // The size of the returned table is given by getTabSize(). 00717 // In the case of separable filtering the subset of kernel elements 00718 // for the pass \c dim can be requested. 00719 //------------------------------------------------------------------------------------------- 00720 template <typename KDATATYPE> 00721 const KDATATYPE* TKernel<KDATATYPE>::getValueTab(size_t dim) const 00722 { 00723 ML_TRACE_IN_TIME_CRITICAL("const KDATATYPE* TKernel<KDATATYPE>::getValueTab()"); 00724 00725 return _isSeparable ? (_valueTab + getSeparableDimIndex(dim)) : _valueTab; 00726 } 00727 00728 //------------------------------------------------------------------------------------------- 00729 // Return the sum of all kernel element values 00730 //------------------------------------------------------------------------------------------- 00731 template <typename KDATATYPE> 00732 KDATATYPE TKernel<KDATATYPE>::getValueTabSum() const 00733 { 00734 ML_TRACE_IN( "KDATATYPE TKernel<( )::getValueTabSum()" ); 00735 00736 // Scan all elements of the value table and sum them up. 00737 KDATATYPE v=0; 00738 for (size_t i=0; i<_tabSize; i++){ v+=_valueTab[i]; } 00739 return v; 00740 } 00741 00742 //------------------------------------------------------------------------------------------- 00743 // Return the minimum value of all kernel element values 00744 // If kernel value table is empty then 0 is returned. 00745 //------------------------------------------------------------------------------------------- 00746 template <typename KDATATYPE> 00747 KDATATYPE TKernel<KDATATYPE>::getMinValue() const 00748 { 00749 ML_TRACE_IN( "KDATATYPE TKernel<KDATATYPE>::getMinValue()" ); 00750 00751 // Scan all elements of the value table and search the minimum. 00752 KDATATYPE v = (_tabSize==0) ? static_cast<KDATATYPE>(0) : _valueTab[0]; 00753 for (size_t i=1; i<_tabSize; i++){ if (_valueTab[i] < v){ v = _valueTab[i]; } } 00754 return v; 00755 } 00756 00757 //------------------------------------------------------------------------------------------- 00758 // Return the maximum value of all kernel element values 00759 // If kernel value table is empty then 1 is returned. 00760 //------------------------------------------------------------------------------------------- 00761 template <typename KDATATYPE> 00762 KDATATYPE TKernel<KDATATYPE>::getMaxValue() const 00763 { 00764 ML_TRACE_IN( "KDATATYPE TKernel<KDATATYPE>::getMaxValue() " ); 00765 00766 // Scan all elements of the value table and search the minimum. 00767 KDATATYPE v = (_tabSize==0) ? static_cast<KDATATYPE>(1) : _valueTab[0]; 00768 for (size_t i=1; i<_tabSize; i++){ if (_valueTab[i] > v){ v = _valueTab[i]; } } 00769 return v; 00770 } 00771 00772 00773 //------------------------------------------------------------------------------------------- 00774 // Return the sum of all negative kernel element values. 00775 // If kernel value table is empty then 0 is returned. 00776 //------------------------------------------------------------------------------------------- 00777 template <typename KDATATYPE> 00778 KDATATYPE TKernel<KDATATYPE>::getNegativeValueSum() const 00779 { 00780 ML_TRACE_IN( "TKernel<KDATATYPE>::getNegativeValueSum()" ); 00781 00782 KDATATYPE v = 0; 00783 for (size_t i=0; i<_tabSize; i++){ 00784 // Make checks for not "> 0" instead of "< 0" to avoid warnings on unsigned KDATATYPEs. 00785 if (!(_valueTab[i] > 0)){ v += _valueTab[i]; } 00786 } 00787 return v; 00788 } 00789 00790 //------------------------------------------------------------------------------------------- 00791 // Return the sum of all positive kernel element values. 00792 // If kernel value table is empty then 0 is returned. 00793 //------------------------------------------------------------------------------------------- 00794 template <typename KDATATYPE> 00795 KDATATYPE TKernel<KDATATYPE>::getPositiveValueSum() const 00796 { 00797 ML_TRACE_IN( "KDATATYPE TKernel<KDATATYPE>::getPositiveValueSum()" ); 00798 00799 KDATATYPE v = 0; 00800 for (size_t i=0; i<_tabSize; i++){ if (_valueTab[i] > 0){ v += _valueTab[i]; } } 00801 return v; 00802 } 00803 00804 00805 //------------------------------------------------------------------------------------------- 00806 // Modify all kernel element values with the value \c v. 00807 //------------------------------------------------------------------------------------------- 00808 template <typename KDATATYPE> 00809 void TKernel<KDATATYPE>::manipulateKernelElements(KernModifier mode, KDATATYPE v) 00810 { 00811 ML_TRACE_IN( "TKernel<KDATATYPE>::manipulateKernelElements()" ); 00812 ML_TRY 00813 { 00814 // Invalidate current information for separable kernels. 00815 _invalidateSeparableInfos(); 00816 00817 switch (mode){ 00818 case KERN_SET:{ 00819 // Set each kernel element to v. 00820 for (size_t i=0; i<_tabSize; i++){ _valueTab[i] = v; } 00821 } 00822 break; 00823 00824 case KERN_MULT:{ 00825 // Multiply each kernel element with v. 00826 for (size_t i=0; i<_tabSize; i++){ _valueTab[i] *= v; } 00827 } 00828 break; 00829 00830 case KERN_ADD:{ 00831 // Add v to each kernel element. 00832 for (size_t i=0; i<_tabSize; i++){ _valueTab[i] += v; } 00833 } 00834 break; 00835 00836 case KERN_INVDIV:{ 00837 // Set each kernel element to v / kernelElement. Zero kernel elements are left unchanged. 00838 for (size_t i=0; i<_tabSize; i++){ if (!MLValueIs0WOM(_valueTab[i])) {_valueTab[i] = v/_valueTab[i]; } } 00839 } 00840 break; 00841 00842 case KERN_INVSUB:{ 00843 // Set each kernel element by v - kernelElement. 00844 for (size_t i=0; i<_tabSize; i++){ _valueTab[i] = v-_valueTab[i]; } 00845 } 00846 break; 00847 00848 case KERN_SQR:{ 00849 // Compute all squares of _valueTab[i]. 00850 for (size_t i=0; i<_tabSize; i++){ _valueTab[i] *= _valueTab[i]; } 00851 } 00852 break; 00853 00854 case KERN_SQRT:{ 00855 // Compute all square roots of _valueTab[i]. Negative kernel elements 00856 // are left unchanged. 00857 for (size_t i=0; i<_tabSize; i++){ 00858 // We do not use >= because but two comparisons to avoid warnings 00859 // in case of unsigned KDATATYPE. 00860 if ((_valueTab[i]>0) || (MLValueIs0WOM(_valueTab[i]))){ 00861 // As documented in class description we cast in case of integer KDATATYPES. 00862 _valueTab[i] = static_cast<KDATATYPE>(sqrt(_valueTab[i])); 00863 } 00864 } 00865 } 00866 break; 00867 00868 case KERN_POW:{ 00869 // Compute all _valueTab[i] raised to the power of v. 00870 for (size_t i=0; i<_tabSize; i++){ 00871 // Linux man page says: Error on "The argument x is negative and y is not an integral value. 00872 // This would result in a complex number." This then will set errno (EDOM). 00873 // So we leave kernel elements unchanged in that case. We do not use >= because but 00874 // two comparisons to avoid warnings in case of unsigned KDATATYPE. 00875 if ( (_valueTab[i] > static_cast<KDATATYPE>(0)) || MLValueIs0WOM(_valueTab[i]) ){ 00876 // As documented in class description we cast in case of integer KDATATYPES. 00877 errno = 0; 00878 KDATATYPE buf = static_cast<KDATATYPE>(powl(_valueTab[i], v)); 00879 if (0 == errno){ 00880 _valueTab[i] = buf; 00881 } 00882 } 00883 } 00884 } 00885 break; 00886 00887 case KERN_LOG:{ 00888 // Compute logarithm of base v of all kernel elements. 00889 // Do not apply operations on kernel elements which are not permitted, 00890 // e.g. negative bases or negative values or base == 1. In that case 00891 // leave kernel elements unchanged. 00892 // For LOGv(K) we use log(K)/log(v) instead. 00893 if ((v > 0) && (MLValuesDifferWOM(v, 1.0))){ 00894 MLldouble invBase=1.0/log(v); 00895 for (size_t i=0; i<_tabSize; i++){ 00896 KDATATYPE val = _valueTab[i]; 00897 // As documented in class description we cast in case of integer KDATATYPES. 00898 if (val > 0){ _valueTab[i] = static_cast<KDATATYPE>(log(val)*invBase); } 00899 } 00900 } 00901 } 00902 break; 00903 00904 case KERN_NORMALIZE:{ 00905 // Multiply all kernel element values with a value so that their sum is 1. 00906 // If sum is zero then values are left unchanged. 00907 KDATATYPE sum=getValueTabSum(); 00908 // As documented in class description we cast in case of integer KDATATYPES. 00909 if (!MLValueIs0WOM(sum)){ manipulateKernelElements(KERN_MULT, static_cast<KDATATYPE>(1./sum)); } 00910 } 00911 break; 00912 00913 case KERN_GAUSS:{ 00914 // Set all kernel elements to binomial values and normalize. 00915 setGauss(_ext); 00916 } 00917 break; 00918 00919 case KERN_SPHERE:{ 00920 // Throw away kernel corners to make it approximately spherical. 00921 makeCircular(); 00922 } 00923 break; 00924 00925 case KERN_MIRROR:{ 00926 // Apply mirroring operation. 00927 mirror(); 00928 } 00929 break; 00930 00931 case KERN_MIRROR_X:{ 00932 // Apply mirroring operation in x dimension. 00933 mirror(0); 00934 } 00935 break; 00936 00937 case KERN_MIRROR_Y:{ 00938 // Apply mirroring operation in y dimension. 00939 mirror(1); 00940 } 00941 break; 00942 00943 case KERN_MIRROR_Z:{ 00944 // Apply mirroring operation in z dimension. 00945 mirror(2); 00946 } 00947 break; 00948 00949 case KERN_MIRROR_C:{ 00950 // Apply mirroring operation in c dimension. 00951 mirror(3); 00952 } 00953 break; 00954 00955 case KERN_MIRROR_T:{ 00956 // Apply mirroring operation in t dimension. 00957 mirror(4); 00958 } 00959 break; 00960 00961 case KERN_MIRROR_U:{ 00962 // Apply mirroring operation in u dimension. 00963 mirror(5); 00964 } 00965 break; 00966 00967 case NUM_KERN_MODIFYERS:{ 00968 ML_PRINT_ERROR("TKernel<KDATATYPE>::manipulateKernelElements(mlKernModifier mode, KDATATYPE v)", 00969 ML_PROGRAMMING_ERROR, "NUM_KERN_MODIFYERS is an invalid parameter. Ignoring kernel manipulation."); 00970 } 00971 break; 00972 00973 default:{ 00974 ML_PRINT_ERROR("TKernel<KDATATYPE>::manipulateKernelElements(mlKernModifier mode, KDATATYPE v)", 00975 ML_BAD_PARAMETER, "Invalid parameter passed. Ignoring kernel manipulation."); 00976 } 00977 break; 00978 00979 } 00980 } 00981 ML_CATCH_RETHROW; 00982 } 00983 00984 //------------------------------------------------------------------------------------------- 00985 // Returns the kernel extents in 6D. It defines the rectangular region in 00986 // which all coordinates returned by \c getCoordTab() are found. 00987 // Note that the returned region might be larger than required 00988 // e.g. after removing elements from kernel. 00989 // In the case of separable filtering it returns a vector where the 00990 // components 0,...,5 contain the extent of the region spanned by the 00991 // 6 separated 1-D kernels. Note that components for those dimensions 00992 // where no filtering takes place are set to 1. 00993 //------------------------------------------------------------------------------------------- 00994 template <typename KDATATYPE> 00995 const ImageVector &TKernel<KDATATYPE>::getExtent() const 00996 { 00997 ML_TRACE_IN_TIME_CRITICAL("const ImageVector &TKernel<KDATATYPE>::getExtent()"); 00998 00999 if (_isSeparable){ 01000 _validateSeparabilityInfos(); 01001 return _separableExt; 01002 } 01003 else{ 01004 return _ext; 01005 } 01006 } 01007 01008 //------------------------------------------------------------------------------------------- 01009 // The extent of the kernel to both sides. The sum of both +1 is the extent of the kernel. 01010 // Using \c getNegativeExtent() as negative extent of an image and \c getPositiveExtent() as positive extent 01011 // increment for the image then the kernel can be placed correctly on all normal image 01012 // voxels without having voxel accesses out of range. 01013 //------------------------------------------------------------------------------------------- 01014 template <typename KDATATYPE> 01015 const ImageVector &TKernel<KDATATYPE>::getNegativeExtent() const 01016 { 01017 ML_TRACE_IN_TIME_CRITICAL("const ImageVector &TKernel<KDATATYPE>::getNegativeExtent()"); 01018 01019 if (_isSeparable){ 01020 _validateSeparabilityInfos(); 01021 return _separableNegExt; 01022 } 01023 else{ 01024 return _negExt; 01025 } 01026 } 01027 01028 //------------------------------------------------------------------------------------------- 01029 // See \c getNegativeExtent(). 01030 //------------------------------------------------------------------------------------------- 01031 template <typename KDATATYPE> 01032 const ImageVector &TKernel<KDATATYPE>::getPositiveExtent() const 01033 { 01034 ML_TRACE_IN_TIME_CRITICAL("const ImageVector &TKernel<KDATATYPE>::getPositiveExtent()"); 01035 01036 if (_isSeparable){ 01037 _validateSeparabilityInfos(); 01038 return _separablePosExt; 01039 } 01040 else{ 01041 return _posExt; 01042 } 01043 } 01044 01045 //------------------------------------------------------------------------------------------- 01046 // Converts the coordinate (x,y,z,c,t,u) into the kernel to an index into an array 01047 // with 6D extents given by \c size. 01048 //------------------------------------------------------------------------------------------- 01049 template <typename KDATATYPE> 01050 MLint TKernel<KDATATYPE>::coordToIndex(MLint x, MLint y, MLint z, MLint c, MLint t, MLint u, const ImageVector &size) 01051 { 01052 ML_TRACE_IN( "MLint TKernel<KDATATYPE>::coordToIndex()" ); 01053 01054 return SubImage::coordToIndex(x,y,z,c,t,u, size); 01055 } 01056 01057 //------------------------------------------------------------------------------------------- 01058 // Converts the coordinate \p into the kernel with extents \c size to an index. 01059 //------------------------------------------------------------------------------------------- 01060 template <typename KDATATYPE> 01061 MLint TKernel<KDATATYPE>::coordToIndex(const ImageVector &p, const ImageVector &size) 01062 { 01063 ML_TRACE_IN( "TKernel<KDATATYPE>::coordToIndex()" ); 01064 01065 return SubImage::coordToIndex(p, size); 01066 } 01067 01068 //------------------------------------------------------------------------------------------- 01069 // Converts an index into an array with extents \c ext to a coordinate. 01070 //------------------------------------------------------------------------------------------- 01071 template <typename KDATATYPE> 01072 ImageVector TKernel<KDATATYPE>::indexToCoord(MLint idx, const ImageVector &ext) 01073 { 01074 ML_TRACE_IN( "TKernel<KDATATYPE>::indexToCoord()" ); 01075 01076 return SubImage::indexToCoord(idx, ext); 01077 } 01078 01079 //------------------------------------------------------------------------------------------- 01081 //------------------------------------------------------------------------------------------- 01082 template <typename KDATATYPE> 01083 ImageVector TKernel<KDATATYPE>::calculateNegativeExtentFromExtent(const ImageVector &ext) 01084 { 01085 ML_TRACE_IN( "TKernel<KDATATYPE>::calculateNegativeExtentFromExtent()" ); 01086 return ImageVector(ext.x/2, ext.y/2, ext.z/2, ext.c/2, ext.t/2, ext.u/2); 01087 } 01088 01089 //------------------------------------------------------------------------------------------- 01091 //------------------------------------------------------------------------------------------- 01092 template <typename KDATATYPE> 01093 ImageVector TKernel<KDATATYPE>::calculatePositiveExtentFromExtent(const ImageVector &ext) 01094 { 01095 ML_TRACE_IN( "TKernel<KDATATYPE>::calculatePositiveExtentFromExtent()" ); 01096 return ImageVector(ext.x-ext.x/2-1, ext.y-ext.y/2-1, ext.z-ext.z/2-1, 01097 ext.c-ext.c/2-1, ext.t-ext.t/2-1, ext.u-ext.u/2-1); 01098 } 01099 01100 //------------------------------------------------------------------------------------------- 01101 // Return index to kernel element if it exists; otherwise return -1. 01102 // Note that this method needs to search; so it's not very efficient. 01103 //------------------------------------------------------------------------------------------- 01104 template <typename KDATATYPE> 01105 MLint TKernel<KDATATYPE>::findIndex(const ImageVector &pos) const 01106 { 01107 ML_TRACE_IN( "TKernel<KDATATYPE>::findIndex()" ); 01108 01109 // Search coordinate in _coordtab. 01110 for (size_t c=0; c < _tabSize; c++){ 01111 if (_coordTab[c] == pos){ 01112 return c; 01113 } 01114 } 01115 01116 return -1; 01117 } 01118 01119 //------------------------------------------------------------------------------------------- 01120 // Defines a set of local kernel coordinates and optionally a set 01121 // of values which define the kernel elements. 01122 // \c numElems defines the number of coordinates. 01123 // If desired the corresponding set of kernel values can be passed in \c values. 01124 // Otherwise all kernel values are set to (KDATATYPE)(1.0/(KDATATYPE)_tabSize). 01125 // Note that \c coords and \c values have to contain \c numElems entries if passed. 01126 //------------------------------------------------------------------------------------------- 01127 template <typename KDATATYPE> 01128 void TKernel<KDATATYPE>::setPartialKernel(size_t numElems, ImageVector * const coords, KDATATYPE * const values) 01129 { 01130 ML_TRACE_IN( "TKernel<KDATATYPE>::setPartialKernel()" ); 01131 ML_TRY 01132 { 01133 // Clear all dynamic tables. 01134 _clearTables(); 01135 01136 // Define the new number of kernel voxels. 01137 _tabSize = numElems; 01138 01139 // Recreate the coordinate and value tables 01140 if (_tabSize > 0) { 01141 ML_CHECK_NEW(_coordTab, ImageVector[_tabSize]); 01142 01143 ML_CHECK_NEW(_valueTab, KDATATYPE[_tabSize]); 01144 01145 // Copy all passed coordinates into the coordinate table. 01146 for (size_t c=0; c < _tabSize; c++){ _coordTab[c] = coords[c]; } 01147 01148 // If we have a user defined value table then copy it. 01149 // Otherwise fill table with values 1.0/static_cast<KDATATYPE>(_tabSize). 01150 if (values){ 01151 memcpy(_valueTab, values, _tabSize*sizeof(KDATATYPE)); 01152 } 01153 else{ 01154 // As documented in class description we cast in case of integer KDATATYPES. 01155 KDATATYPE v = static_cast<KDATATYPE>(1.0/static_cast<KDATATYPE>(_tabSize)); 01156 for (size_t d=0; d<_tabSize; d++){ _valueTab[d] = v; } 01157 } 01158 } 01159 01160 // Calculate the real kernel size, i.e. the bounding box around all 01161 // used kernel elements. 01162 _calculateRealKernelExt(); 01163 } 01164 ML_CATCH_RETHROW; 01165 } 01166 01167 01168 //------------------------------------------------------------------------------------------- 01169 // Returns the current kernel elements and values as string: 01170 // The string needs has the following format: 01171 // 01172 // \code 01173 // 01174 // (x_0, y_0, z_0, c_0, t_0, u_0):v_0 01175 // ... 01176 // (x_n, y_n, z_n, c_n, t_n, u_n):v_n 01177 // 01178 // \endcode 01179 // 01180 // where the coordinates left from ':' specify the 6d coordinate 01181 // of the kernel element; the value v_x right from ':' specifies the 01182 // value of the kernel element. 01183 // If asLines is true then a second string format is used: 01184 // 01185 // \code 01186 // 01187 // (*, y_0, z_0, c_0, t_0, u_0):x_0 ... x_n 01188 // ... 01189 // (*, y_n, z_n, c_n, t_n, u_n):y_n ... y_n 01190 // 01191 // \endcode 01192 // 01193 // So all kernel elements of a row are saved in a string line; so 01194 // the x coordinates becomes invalid and is set as an asterisk. 01195 // To have a minimum field width pass \c fieldWidth and the digits after 01196 // the period if given by \c precision. Note that these settings are used 01197 // only if asLines is true. 01198 //------------------------------------------------------------------------------------------- 01199 template <typename KDATATYPE> 01200 std::string TKernel<KDATATYPE>::getKernel(bool asLines, MLint fieldWidth, MLint precision) const 01201 { 01202 ML_TRACE_IN( "TKernel<KDATATYPE>::getKernel()" ); 01203 ML_TRY 01204 { 01205 std::string str=""; 01206 char strLine[256]=""; 01207 01208 // Clamp field width to sensible values. 01209 if (fieldWidth > 128){ fieldWidth=128; } 01210 if (fieldWidth < 0){ fieldWidth=0; } 01211 01212 if (asLines){ 01213 // Print kernel as lines. 01214 for (MLint u=0; u < getExtent().u; u++){ 01215 for (MLint t=0; t < getExtent().t; t++){ 01216 for (MLint c=0; c < getExtent().c; c++){ 01217 for (MLint z=0; z < getExtent().z; z++){ 01218 for (MLint y=0; y < getExtent().y; y++){ 01219 // Print line start into string. 01220 MLsnprintf(strLine, 255, "(*,%I64Ld,%I64Ld,%I64Ld,%I64Ld,%I64Ld):", y, z, c, t, u); 01221 01222 // To compensate line start differences if any component has more than 01223 // one digit do append spaces until string has at least 16 chars. So 01224 // two components may have more than one digit or one can have two more digits. 01225 while (strlen(strLine) < 16){ strcat(strLine, " "); } 01226 01227 // Add Line start to existing kernel string. 01228 str += strLine; 01229 01230 // Add all row elements of the kernel to the string. 01231 for (MLint x=0; x < getExtent().x; x++){ 01232 // Does the element exist? 01233 MLint idx = findIndex(ImageVector(x,y,z,c,t,u)); 01234 if (idx < 0){ 01235 // Kernel element does not exist. 01236 // Fill field with fieldWidth spaces and add ','. Then terminate string. 01237 // For the first field do not add a comma. So we have one more space then 01238 // in those cases where we have a comma in it. So we need to add one space 01239 // more in cases with comma. 01240 strLine[0] = x==0 ? ' ' : ','; 01241 MLint w= x==0 ? fieldWidth : fieldWidth+1; 01242 for (MLint i=1; i < w; i++){ strLine[i] = ' '; } 01243 strLine[w] = 0; 01244 } 01245 else{ 01246 // Print comma and element if it's not the last one; otherwise print only the element. 01247 // integrate field width for float field of aligned size. Always cast 01248 // element values to long double because string reading and parsing of carrier 01249 // types (which is theoretically possible) would lead to further problems. 01250 // Hence we store only scalar values. 01251 char format[64]; 01252 snprintf(format, 63, "%s%%%d.%dlf", "%s", static_cast<MLint32>(fieldWidth), static_cast<MLint32>(precision)); 01253 snprintf(strLine, 255, format, 0==x ? "" : ",", static_cast<MLdouble>(_valueTab[idx])); 01254 } 01255 01256 // Append (empty) element to the end of the line. 01257 str += strLine; 01258 } 01259 // Terminate line with '\n' 01260 str += '\n'; 01261 } 01262 // Add an empty line between xy planes of the kernel. 01263 str += '\n'; 01264 } // z 01265 } // c 01266 } // t 01267 } // u 01268 } 01269 else{ 01270 // Print each kernel element into a string and append it to the entire kernel string. 01271 for (size_t c=0; c < _tabSize; c++){ 01272 ImageVector coord = _coordTab[c]; 01273 KDATATYPE value = _valueTab[c]; 01274 snprintf(strLine, 255, "%s:%lf\n", coord.print("(", ",", ")").c_str(), static_cast<MLdouble>(value)); 01275 str += strLine; 01276 } 01277 } 01278 01279 return str; 01280 } 01281 ML_CATCH_RETHROW; 01282 } 01283 01284 01285 01286 //------------------------------------------------------------------------------------------- 01287 // Defines elements and values of the kernel matrix by a string. 01288 // The string needs to have the following format: 01289 // 01290 // \code 01291 // 01292 // (x_0, y_0, z_0, c_0, t_0, u_0):v_0 01293 // ... 01294 // (x_n, y_n, z_n, c_n, t_n, u_n):v_n 01295 // 01296 // \endcode 01297 // 01298 // where the coordinates left from ':' specify the 6d coordinate 01299 // of the kernel element; the value v_x right from ':' specifies the 01300 // value of the kernel element. Only one coordinate entry is scanned per line. 01301 // So big kernels with a few elements can be set easily. As long as lines with 01302 // kernel elements are found elements are set in the kernel table. 01303 // Return string is empty on successful scan. On errors it contains the number 01304 // of error lines. 01305 // 01306 // A second way to specify more kernel elements at once is with the 01307 // following string line format: 01308 // 01309 // \code 01310 // 01311 // (*, y_0, z_0, c_0, t_0, u_0):x_0, ... ,x_n 01312 // ... 01313 // (*, y_n, z_n, c_n, t_n, u_n):y_n, ... ,y_n 01314 // 01315 // \endcode 01316 // 01317 // So all kernel elements of a row are found in a string line. Note 01318 // that the x coordinates becomes invalid and must set as an asterisk. 01319 // Empty elements in the kernel can be left empty before between and 01320 // after commas. 01321 //------------------------------------------------------------------------------------------- 01322 template <typename KDATATYPE> 01323 std::string TKernel<KDATATYPE>::setKernel(const std::string &kernString) 01324 { 01325 ML_TRACE_IN( "TKernel<KDATATYPE>::setKerne()" ); 01326 01327 // Initialize an error string to return error line numbers. 01328 std::string errStr = ""; 01329 char *copy = NULL; 01330 01331 ML_TRY 01332 { 01333 // Make kernel empty. 01334 reset(); 01335 01336 // Scan only if string contains enough characters to specify one kernel element. 01337 if (kernString.length() < 15){ 01338 // String too short to specify a valid kernel. Return 0 as error line. 01339 errStr = "0"; 01340 return errStr; 01341 } 01342 else{ 01343 // Get a modifiable copy of the string. 01344 std::string str = kernString; 01345 01346 // Assure that a line feed terminates the string. 01347 if (str[str.length()-1] != '\n'){ str += '\n'; } 01348 01349 // Scan line by line until no valid line is found. 01350 MLint lineNumber = 0; 01351 while (str != ""){ 01352 // Scan line for following format : "(x,y,z,c,t,u):v" 01353 MLint x=0, y=0, z=0, c=0, t=0, u=0, num=0; 01354 MLdouble fValue = 0; 01355 num = MLsscanf(str.c_str(), "(%I64Ld,%I64Ld,%I64Ld,%I64Ld,%I64Ld,%I64Ld):%lf", &x, &y, &z, &c, &t, &u, &fValue); 01356 KDATATYPE value = static_cast<KDATATYPE>(fValue); 01357 if (num == 7){ 01358 // Okay, we found a valid line. Add values to kernel coordinate table. 01359 _addCoordinate(ImageVector(x,y,z,c,t,u), value, false); 01360 } 01361 else{ 01362 // Line is invalid. Test for the line format. 01363 num = MLsscanf(str.c_str(), "(*,%I64Ld,%I64Ld,%I64Ld,%I64Ld,%I64Ld):", &y, &z, &c, &t, &u); 01364 if (5 == num){ 01365 // Yes, the line format is ok. So search ":". 01366 const size_t cPos = str.find(':'); 01367 if (cPos != std::string::npos){ 01368 // Yes, found. First part of line has already been scanned and so removed it. 01369 str.erase(0, cPos+1); 01370 01371 // Flag to stop line scan and counter for number of scanned elements. 01372 bool go = true; 01373 MLint xCoord = 0; 01374 01375 // Scan until we reach at end of line or an error occurs. 01376 while (go && (str.length() != 0)){ 01377 const char ch = str[0]; 01378 01379 // Kill space characters and continue. 01380 if (' ' == ch){ 01381 str.erase(0, 1); 01382 } 01383 01384 // Line end? Then finish line scan. 01385 else if ('\n' == ch) { 01386 // Terminate loop and leave '\n' because later it's searched. 01387 go = false; 01388 } 01389 01390 // Colon? Then increase element number count and kill colon. 01391 else if (',' == ch) { 01392 // Go forward to next kernel element in row and remove comma. 01393 ++xCoord; 01394 str.erase(0, 1); 01395 } 01396 else{ 01397 // No space, no comma, so try to scan a number. 01398 01399 // First char where a number incompatible character is found. 01400 char *stopPos=NULL; 01401 01402 // Copy string. 01403 copy = Memory::duplicateString(str.c_str(), ML_FATAL_MEMORY_ERROR); 01404 if (copy){ 01405 // Scan string for number. 01406 const MLdouble val = strtod(copy, &stopPos); 01407 01408 // More than 0 characters scanned successfully? 01409 if (stopPos != copy){ 01410 // Yes, a number at beginning. Add it at the right position in the kernel. 01411 _addCoordinate(ImageVector(xCoord, y,z,c,t,u), static_cast<KDATATYPE>(val), false); 01412 01413 // Remove number at start of string. Use pointer arithmetics to 01414 // determine number of scanned number characters. 01415 str.erase(0, stopPos-copy); 01416 } 01417 else{ 01418 // No parsing possible, there must be an error. So terminate scan of this line. 01419 go = false; 01420 01421 // Add line number to error string. 01422 char err[30]=""; 01423 MLsnprintf(err, 29, " %I64Ld", lineNumber); 01424 errStr += err; 01425 } 01426 } 01427 01428 // Remove copy of line. 01429 if (copy){ 01430 Memory::freeMemory(copy); 01431 copy = NULL; 01432 } 01433 } // else 01434 } // while 01435 } // if (cPos != std::string::npos) 01436 } // if (num == 5) 01437 } // else 01438 01439 // Last line? 01440 const size_t pos = str.find('\n'); 01441 if (pos != std::string::npos){ 01442 // Not the last line, because scanned linefeed is not at end of string. 01443 // So remove line from string. 01444 str.erase(0, pos+1); 01445 } 01446 else{ 01447 // Last line. Make string empty to terminate loop. 01448 str = ""; 01449 } 01450 01451 // Increase number of scanned lines. 01452 lineNumber++; 01453 } // while (str != "") 01454 } // else 01455 01456 // Update the real kernel size. 01457 _calculateRealKernelExt(); 01458 } 01459 ML_CATCH_BLOCK(...) 01460 { 01461 Memory::freeMemory(copy); 01462 copy = NULL; 01463 ML_CHECK(0); // Log the error. 01464 throw; 01465 } 01466 01467 return errStr; 01468 } 01469 01470 01471 01472 //------------------------------------------------------------------------------------------- 01473 // Defines a complete kernel matrix whose extents are defined by \c ext. 01474 // If desired the set of kernel values can be passed in \c values. 01475 // Otherwise all kernel values are set to 1.0/(KDATATYPE)ext.compMul(), i.e. 01476 // to the number of entries of the matrix. 01477 // If desired a set of mask values can be specified. If \c mask[n] is true then 01478 // tab[n] is included in the kernel; otherwise it's not part of the kernel. 01479 // Internally the specified kernel matrix is handled as a table of kernel elements. 01480 // Note that \c values and \c mask must have ext.compMul() elements if they are defined. 01481 //------------------------------------------------------------------------------------------- 01482 template <typename KDATATYPE> 01483 void TKernel<KDATATYPE>::setKernel(const ImageVector &ext, const KDATATYPE * const values, bool * const mask) 01484 { 01485 ML_TRACE_IN( "TKernel<KDATATYPE>::setKernel()" ); 01486 ML_TRY 01487 { 01488 // Clear all dynamic tables. 01489 _clearTables(); 01490 01491 // Compute maximum size of value and kernel table. 01492 size_t maxElems = ext.compMul(); 01493 01494 // Do we have a mask ? Then count number of enabled kernel elements. 01495 _tabSize=0; 01496 if (mask){ 01497 for (size_t c=0; c<maxElems; c++){ if (mask[c]){ _tabSize++; } } 01498 } 01499 else{ 01500 // No mask set. All kernel elements are used. 01501 _tabSize = maxElems; 01502 } 01503 01504 // Recreate the coordinate and value tables with the size of used elements. 01505 if (_tabSize > 0){ 01506 ML_CHECK_NEW(_coordTab, ImageVector[_tabSize]); 01507 ML_CHECK_NEW(_valueTab, KDATATYPE[_tabSize]); 01508 if (!_coordTab || !_valueTab){ 01509 _clearTables(); 01510 ML_PRINT_FATAL_ERROR("TKernel<KDATATYPE>::setKernel(...):", ML_NO_MEMORY, 01511 "Cannot create kernel filter tables, so tables are reset. This will probably cause other errors."); 01512 } 01513 01514 if (_coordTab && _valueTab){ 01515 // If we have a user defined value table then copy it. 01516 // Otherwise fill table with values 1.0/(KDATATYPE)_tabSize. 01517 if (values){ 01518 memcpy(_valueTab, values, _tabSize*sizeof(KDATATYPE)); 01519 } 01520 else{ 01521 // As documented in class description we cast in case of integer KDATATYPES. 01522 KDATATYPE v = static_cast<KDATATYPE>(1.0/static_cast<KDATATYPE>(_tabSize)); 01523 for (size_t d=0; d<_tabSize; d++){ _valueTab[d] = v; } 01524 } 01525 01526 // Define all kernel coordinates if no mask exists or if the mask exists and the 01527 // entry for the current kernel voxel is true. 01528 size_t idx=0; 01529 for (size_t e=0; e<maxElems; e++){ 01530 if (!mask || (mask && mask[e])){ 01531 _coordTab[idx] = indexToCoord(e, ext); 01532 idx++; 01533 } 01534 } 01535 01536 if (idx !=_tabSize){ 01537 ML_PRINT_FATAL_ERROR("TKernel<KDATATYPE>::setKernel(...):", ML_CALCULATION_ERROR, 01538 "Internal error. Cannot create kernel filter tables. This will probably cause other errors."); 01539 _clearTables(); 01540 } 01541 } // if (_coordTab && _valueTab) 01542 } 01543 01544 // Calculate the real kernel size, i.e. the bounding box around all 01545 // used kernel elements. 01546 _calculateRealKernelExt(); 01547 } 01548 ML_CATCH_RETHROW; 01549 } 01550 01551 01552 //------------------------------------------------------------------------------------------- 01553 // Create kernel coordinate and value tables in separable table format, that means 01554 // a 2-D kernel where each rows describes the elements of 1-D kernels. 01555 // At most 6 rows make sense, because the maximum kernel dimension is 6. 01556 // It is legal to leave out any axis by passing empty vectors to define lower 01557 // dimensional separable kernels. 01558 // The separability flag is set to true. 01559 //------------------------------------------------------------------------------------------- 01560 template <typename KDATATYPE> 01561 void TKernel<KDATATYPE>::setSeparableKernel(const std::vector<ML_TYPENAME std::vector<KDATATYPE> > &separableRows) 01562 { 01563 ML_TRACE_IN( "TKernel<KDATATYPE::setSeparableKernel( )" ); 01564 ML_TRY 01565 { 01566 setSeparable(true); 01567 _clearTables(); 01568 01569 // Get number of rows, permit at most 6 for 6 dimensions. 01570 const size_t numRows = separableRows.size() > 6 ? 6 : separableRows.size(); 01571 01572 // Sum up total number of entries in all rows. 01573 size_t numEntries = 0; 01574 for (size_t e=0; e < numRows; ++e){ numEntries += separableRows[e].size(); } 01575 01576 // Create a value table and a coordinate table. 01577 std::vector<KDATATYPE> valueTab; valueTab.reserve(numEntries); 01578 std::vector<ImageVector> coordTab; coordTab.reserve(numEntries); 01579 01580 // Compose coordinate table. 01581 for (size_t r=0; r < numRows; ++r){ 01582 01583 // Get row and its number of elements. 01584 const std::vector<KDATATYPE> &row = separableRows[r]; 01585 const size_t numRElements = row.size(); 01586 01587 // Coordinate in the separable table, only x and y coordinates are set. 01588 // y defines the dimension, x defines the position in that dimension. 01589 ImageVector entryCoord(0); 01590 entryCoord.y = r; 01591 01592 // Count entries with row. 01593 for (size_t re=0; re < numRElements; ++re){ 01594 // Define x-coordinate of entry in table row. 01595 entryCoord.x = re; 01596 coordTab.push_back(entryCoord); 01597 valueTab.push_back(row[re]); 01598 } 01599 } 01600 01601 // Define the kernel table. The extent is 2-D, because it's the 01602 // separable table format. 01603 setPartialKernel(coordTab.size(), &(coordTab[0]), &(valueTab[0])); 01604 01605 // Make separable information up to date. 01606 _validateSeparabilityInfos(); 01607 } 01608 ML_CATCH_RETHROW; 01609 } 01610 01611 01612 //------------------------------------------------------------------------------------------- 01613 // Resizes the kernel to a new state and tries to maintain the previous elements 01614 // if possible. Note that new kernel size may differ from desired one if empty 01615 // areas are at border of the resized kernel so that only a smaller real kernel remains. 01616 // Regions which are created newly get kernel elements with value \c newVal. 01617 //------------------------------------------------------------------------------------------- 01618 template <typename KDATATYPE> 01619 void TKernel<KDATATYPE>::resizeKernel(const ImageVector &ext, KDATATYPE newVal) 01620 { 01621 ML_TRACE_IN( "TKernel<KDATATYPE>::resizeKernel()" ); 01622 ML_TRY 01623 { 01624 // Create a buffer kernel. 01625 TKernel<KDATATYPE> bufferKern = *this; 01626 01627 // Clear all dynamic tables. 01628 _clearTables(); 01629 01630 // Scan new kernel extents. 01631 for (MLint u=0; u < ext.u; u++){ 01632 for (MLint t=0; t < ext.t; t++){ 01633 for (MLint c=0; c < ext.c; c++){ 01634 for (MLint z=0; z < ext.z; z++){ 01635 for (MLint y=0; y < ext.y; y++){ 01636 for (MLint x=0; x < ext.x; x++){ 01637 // Create vector from new coordinates. 01638 ImageVector addCoord(x,y,z,c,t,u); 01639 01640 // If new coordinate is within old kernel range the add it only if it exists. 01641 if ((u < getExtent().u) && 01642 (t < getExtent().t) && 01643 (c < getExtent().c) && 01644 (z < getExtent().z) && 01645 (y < getExtent().y) && 01646 (x < getExtent().x)){ 01647 // Within old extents. Is it defined? 01648 MLint idx = bufferKern.findIndex(addCoord); 01649 if (idx >=0){ 01650 // Old coordinate existed. So add it to new kernel without extent updating. 01651 _addCoordinate(addCoord, bufferKern.getValueTab()[idx], false); 01652 } 01653 } 01654 else{ 01655 // New coordinate is outside old range. Add newVal's in new area. 01656 _addCoordinate(addCoord, newVal, false); 01657 } // else 01658 01659 } // x 01660 } 01661 } 01662 } 01663 } 01664 } // u 01665 01666 // Calculate the real kernel size, i.e. the bounding box around all 01667 // used kernel elements. 01668 _calculateRealKernelExt(); 01669 } 01670 ML_CATCH_RETHROW; 01671 } 01672 01673 01674 //------------------------------------------------------------------------------------------- 01675 // Fill all undefined kernel elements with \c newVal. 01676 //------------------------------------------------------------------------------------------- 01677 template <typename KDATATYPE> 01678 void TKernel<KDATATYPE>::fillUndefinedElements(KDATATYPE newVal) 01679 { 01680 ML_TRACE_IN( "TKernel<KDATATYPE>::fillUndefinedElements()" ); 01681 ML_TRY 01682 { 01683 // Invalidate current information for separable kernels. 01684 _invalidateSeparableInfos(); 01685 01686 // Scan new kernel extents. 01687 for (MLint u=0; u < getExtent().u; u++){ 01688 for (MLint t=0; t < getExtent().t; t++){ 01689 for (MLint c=0; c < getExtent().c; c++){ 01690 for (MLint z=0; z < getExtent().z; z++){ 01691 for (MLint y=0; y < getExtent().y; y++){ 01692 for (MLint x=0; x < getExtent().x; x++){ 01693 // Create vector from new coordinates. 01694 ImageVector addCoord(x,y,z,c,t,u); 01695 01696 // Does the coordinate exist in kernel? 01697 if (findIndex(addCoord) < 0){ 01698 // Coordinate does not exits. So add it without extent updating. 01699 _addCoordinate(addCoord, newVal, false); 01700 } // if 01701 01702 } // x 01703 } 01704 } 01705 } 01706 } 01707 } // u 01708 01709 // Calculate the real kernel size, i.e. the bounding box around all 01710 // used kernel elements. 01711 _calculateRealKernelExt(); 01712 } 01713 ML_CATCH_RETHROW; 01714 } 01715 01716 01717 01718 //------------------------------------------------------------------------------------------- 01719 // Takes the current kernel, computes radii from the extents of the kernel 01720 // and removes all kernel elements which are outside the ellipsoid defined by 01721 // these radii. 01722 // Note that filter properties of kernel changes by this operation. 01723 //------------------------------------------------------------------------------------------- 01724 template <typename KDATATYPE> 01725 void TKernel<KDATATYPE>::makeCircular() 01726 { 01727 ML_TRACE_IN( "TKernel<KDATATYPE>::makeCircular()" ); 01728 ML_TRY 01729 { 01730 // Invalidate current information for separable kernels. 01731 _invalidateSeparableInfos(); 01732 01733 // Compute theoretical center of kernel. Subtract 0.5 to shift 01734 // kernel center from voxel center to voxel origin. Examples in 3D: 01735 // E.g. : (1,1,1) sized kernels are addressed from 0 to 0 and so they have 01736 // their center at (0,0,0)\n 01737 // E.g. : (2,2,2) sized kernels are addressed from 0 to 1 and so they have 01738 // their center at (0.5, 0.5, 0.5).\n 01739 // E.g. : (3,3,3) sized kernels are addressed from 0 to 2 and so they have 01740 // their center at (1.0, 1.0, 1.0).\n 01741 MLdouble cx = static_cast<MLdouble>(_ext.x) / 2.0 - 0.5; 01742 MLdouble cy = static_cast<MLdouble>(_ext.y) / 2.0 - 0.5; 01743 MLdouble cz = static_cast<MLdouble>(_ext.z) / 2.0 - 0.5; 01744 MLdouble cc = static_cast<MLdouble>(_ext.c) / 2.0 - 0.5; 01745 MLdouble ct = static_cast<MLdouble>(_ext.t) / 2.0 - 0.5; 01746 MLdouble cu = static_cast<MLdouble>(_ext.u) / 2.0 - 0.5; 01747 01748 // Compute kernel radii. 01749 MLdouble rx = static_cast<MLdouble>(_ext.x) / 2.0; 01750 MLdouble ry = static_cast<MLdouble>(_ext.y) / 2.0; 01751 MLdouble rz = static_cast<MLdouble>(_ext.z) / 2.0; 01752 MLdouble rc = static_cast<MLdouble>(_ext.c) / 2.0; 01753 MLdouble rt = static_cast<MLdouble>(_ext.t) / 2.0; 01754 MLdouble ru = static_cast<MLdouble>(_ext.u) / 2.0; 01755 01756 // Save local tables and set default table states. 01757 ImageVector *coordTab = _coordTab; 01758 _coordTab = NULL; 01759 01760 KDATATYPE *valueTab = _valueTab; 01761 _valueTab = NULL; 01762 01763 size_t tabSize = _tabSize; 01764 _tabSize = 0; 01765 01766 // Compute distance for all kernel voxels and normalize them. 01767 // If the coordinate is within ellipsoid distance then 01768 // add it to the kernel elements, otherwise forget it. 01769 for (size_t e=0; e < tabSize; e++){ 01770 ImageVector v = coordTab[e]; 01771 MLdouble pu = (static_cast<MLdouble>(v.u) - cu)/ru; 01772 MLdouble pt = (static_cast<MLdouble>(v.t) - ct)/rt; 01773 MLdouble pc = (static_cast<MLdouble>(v.c) - cc)/rc; 01774 MLdouble pz = (static_cast<MLdouble>(v.z) - cz)/rz; 01775 MLdouble py = (static_cast<MLdouble>(v.y) - cy)/ry; 01776 MLdouble px = (static_cast<MLdouble>(v.x) - cx)/rx; 01777 01778 // Distance smaller or equal 1? Then we are within kernel radius and 01779 // we set kernel value 'true'; otherwise we set kernel value 'false'. 01780 if (sqrtf(px*px + py*py + pz*pz + pc*pc + pt*pt + pu*pu) <= 1){ 01781 _addCoordinate(v, valueTab[e], false); 01782 } 01783 } 01784 01785 // Remove saved tables. 01786 ML_DELETE_ARRAY(coordTab); 01787 ML_DELETE_ARRAY(valueTab); 01788 01789 // Recalculate the kernelSize. 01790 _calculateRealKernelExt(); 01791 } 01792 ML_CATCH_RETHROW; 01793 } 01794 01795 01796 01797 //------------------------------------------------------------------------------------------- 01798 // Applies a point symmetric mirroring of all kernel elements. 01799 // The dimension param specifies a mirroring dimension if in range [0,5], 01800 // otherwise mirroring is applied in all dimensions. Default is -1. 01801 //------------------------------------------------------------------------------------------- 01802 template <typename KDATATYPE> 01803 void TKernel<KDATATYPE>::mirror(int dimension) 01804 { 01805 ML_TRACE_IN( "TKernel<KDATATYPE>::mirror()" ); 01806 ML_TRY 01807 { 01808 // Invalidate current information for separable kernels. 01809 _invalidateSeparableInfos(); 01810 01811 // Save local tables and set default table states. 01812 ImageVector *coordTabBuf = _coordTab; 01813 _coordTab = NULL; 01814 01815 KDATATYPE *valueTabBuf = _valueTab; 01816 _valueTab = NULL; 01817 01818 size_t tabSizeBuf = _tabSize; 01819 _tabSize = 0; 01820 01821 // Calculate maximum kernel positions in all dimensions, that is one 01822 // less than extent. 01823 ImageVector maxP(_ext-ImageVector(1)); 01824 01825 if ((dimension<0) || (dimension>5)){ 01826 // Subtract each coordinate of kernel elements from the 01827 // maximum extent position in all 6 dimensions and 01828 // add it to the kernel elements (which have been made 01829 // empty above). 01830 for (size_t e=0; e < tabSizeBuf; e++){ 01831 _addCoordinate(maxP - coordTabBuf[e], valueTabBuf[e], false); 01832 } 01833 } 01834 else{ 01835 ImageVector mirVec; 01836 for (size_t e=0; e < tabSizeBuf; e++){ 01837 // Take normal coordinate. 01838 mirVec = coordTabBuf[e]; 01839 01840 // mirror the selected coordinate component. 01841 mirVec[dimension] = maxP[dimension] - coordTabBuf[e][dimension]; 01842 01843 // Add new coordinate with value to kernel. 01844 _addCoordinate(mirVec, valueTabBuf[e], false); 01845 } 01846 } 01847 01848 // Remove old saved tables. 01849 ML_DELETE_ARRAY(coordTabBuf); 01850 ML_DELETE_ARRAY(valueTabBuf); 01851 01852 // Recalculate the kernelSize. 01853 _calculateRealKernelExt(); 01854 } 01855 ML_CATCH_RETHROW; 01856 } 01857 01858 01859 01860 01861 // TODO !!! investigate !!!: (Guenter Ott - 08.04.2004) OK: 01862 // Maybe this method should be placed at a more central point? 01863 // (the template is also not used) 01864 // There is easy a danger of overflow. 01865 //------------------------------------------------------------------------------- 01866 // Calculate binomial coefficients for (n) 01867 // (k) 01868 //------------------------------------------------------------------------------- 01869 template <typename KDATATYPE> 01870 MLldouble TKernel<KDATATYPE>::binomialcoeff(MLint n, MLint k) 01871 { 01872 ML_TRACE_IN( "TKernel<KDATATYPE>::binomialcoeff()" ); 01873 MLint i=0; 01874 MLldouble v=1.0; 01875 01876 if (k>n){ v=0; } 01877 else{ 01878 if((k!=0) && (k!=n)){ 01879 for (i=1; i<(n+1); i++){ v*=i; } 01880 for (i=1; i<(k+1); i++){ v/=i; } 01881 for (i=1; i<(n-k+1); i++){ v/=i; } 01882 } 01883 } 01884 01885 return(v); 01886 } 01887 01888 01889 01890 // TODO !!! investigate !!!: (Guenter Ott - 08.04.2004) OK : an incomplete suggestion 01891 // to calculate binomialcoeff. 01892 // Maybe interesting. If not just delete. 01893 /* 01894 template <typename KDATATYPE> 01895 MLldouble TKernel<KDATATYPE>::binomialcoeff(MLint n, MLint k) const 01896 { 01897 ML_TRACE_IN( "TKernel<KDATATYPE>::binomialcoeff()" ); 01898 MLint i=0; 01899 MLldouble v=0.0; 01900 01901 01902 // bei der Bedingung bin ich mir nicht klaren; wuerde rueckfragen, was mit n<0 oder mit k<0 ist. 01903 // auch das richtige resultat fuer n=0 und k=0 ist mir nicht bekannt (tippe aber auf 1) 01904 if( k<=n ) 01905 { 01906 v=1.0; 01907 MLint kGrenze = n-k > k ? n-k : k; 01908 for ( MLint i=n; i>kGrenze ;--i) 01909 { 01910 v*=i; 01911 v/=(n+1-i); 01912 } 01913 } 01914 01915 return(v); 01916 } 01917 */ 01918 01919 01920 //------------------------------------------------------------------------------------------- 01921 // Returns a vector with \c numSample values binomial coefficients. 01922 // If \c numSamples is passed as 0 then an empty vector is returned. 01923 // if \c normalize is passed true (the default) then all values are 01924 // normalized to the sum of absolute values 1. 01925 //------------------------------------------------------------------------------------------- 01926 template <typename KDATATYPE> 01927 std::vector<KDATATYPE> TKernel<KDATATYPE>::get1DGauss(size_t numSamples, bool normalize) 01928 { 01929 ML_TRACE_IN( "TKernel<KDATATYPE>::get1DGauss()" ); 01930 01931 // The return value; 01932 std::vector<KDATATYPE> v; 01933 01934 ML_TRY 01935 { 01936 if (numSamples > 0){ 01937 v.reserve(numSamples); 01938 01939 // Fill the axis with binomial coefficients and sum up all values. 01940 KDATATYPE sum = 0; 01941 for (size_t u=0; u<numSamples; ++u){ 01942 // Calculate the entry, write it into the array and sum its absolute value up. 01943 // As documented in class description we cast in case of integer KDATATYPES. 01944 KDATATYPE val = static_cast<KDATATYPE>(binomialcoeff(numSamples-1, u)); 01945 v.push_back(val); 01946 sum += static_cast<KDATATYPE>(fabs(val)); 01947 } 01948 01949 // If normalization is desired then divide all elements by the sum. 01950 if (normalize && (sum > 0)){ 01951 for (size_t u=0; u<numSamples; u++){ v[u] /= sum; } 01952 } 01953 } 01954 } 01955 ML_CATCH_RETHROW; 01956 01957 // Return the vector. 01958 return v; 01959 } 01960 01961 //------------------------------------------------------------------------------------------- 01962 // Replaces the current kernel by a normalized gauss kernel. 01963 //------------------------------------------------------------------------------------------- 01964 template <typename KDATATYPE> 01965 void TKernel<KDATATYPE>::setGauss(const ImageVector &ext) 01966 { 01967 ML_TRACE_IN( "TKernel<KDATATYPE>::setGauss()" ); 01968 01969 ML_TRY 01970 { 01971 // Invalidate current information for separable kernels. 01972 _invalidateSeparableInfos(); 01973 01974 // Build gauss kernel by using separability property of gauss kernel. 01975 // So calculate a discrete binomial function for each axis. 01976 // The values of the kernel elements are products of the corresponding 01977 // values along the six binomial function axis. 01978 std::vector<KDATATYPE> vx=get1DGauss(ext.x, false); 01979 std::vector<KDATATYPE> vy=get1DGauss(ext.y, false); 01980 std::vector<KDATATYPE> vz=get1DGauss(ext.z, false); 01981 std::vector<KDATATYPE> vc=get1DGauss(ext.c, false); 01982 std::vector<KDATATYPE> vt=get1DGauss(ext.t, false); 01983 std::vector<KDATATYPE> vu=get1DGauss(ext.u, false); 01984 01985 // Build kernel by using the setKernel method for separable kernels. 01986 // Normalize kernel values after building the product to remain in normal grey value areas. 01987 setKernel(ext, &(vx[0]), &(vy[0]), &(vz[0]), &(vc[0]), &(vt[0]), &(vu[0]), true); 01988 } 01989 ML_CATCH_BLOCK(...) 01990 { 01991 // Value for an 1x1x1x1x1x1 kernel. 01992 KDATATYPE KerneldataIdKernel[]={ static_cast<KDATATYPE>(1.0f) }; 01993 01994 setKernel(ImageVector(1,1,1,1,1,1), KerneldataIdKernel); 01995 ML_CHECK(0); // Log the error. 01996 throw; 01997 } 01998 } 01999 02000 02001 //------------------------------------------------------------------------------------------- 02002 // Initialization. Should be called only by constructors. 02003 //------------------------------------------------------------------------------------------- 02004 template <typename KDATATYPE> 02005 void TKernel<KDATATYPE>::_init() 02006 { 02007 ML_TRACE_IN( "TKernel<KDATATYPE>::_init()" ); 02008 02009 _ext.set(0); 02010 _negExt.set(0); 02011 _posExt.set(0); 02012 02013 _tabSize = 0; 02014 02015 _valueTab = NULL; 02016 _coordTab = NULL; 02017 02018 // Separability information. 02019 _isSeparable = false; 02020 _areSeparabilityInfosUpToDate = false; 02021 _separableDimEntries.set(0); 02022 _separableOneDimExt.set(0); 02023 _separableExt.set(0); 02024 _separableNegExt.set(0); 02025 _separablePosExt.set(0); 02026 _separableCoordTab.clear(); 02027 } 02028 02029 02030 //------------------------------------------------------------------------------------------- 02031 // Clear all internal (dynamic) tables. 02032 //------------------------------------------------------------------------------------------- 02033 template <typename KDATATYPE> 02034 void TKernel<KDATATYPE>::_clearTables() 02035 { 02036 ML_TRACE_IN( "TKernel<KDATATYPE>::_clearTables()" ); 02037 ML_TRY 02038 { 02039 // Set table size to 0. 02040 _tabSize = 0; 02041 02042 // Invalidate separability infos which are calculated on demand. 02043 _areSeparabilityInfosUpToDate = false; 02044 02045 ML_DELETE_ARRAY(_valueTab); 02046 ML_DELETE_ARRAY(_coordTab); 02047 02048 } 02049 ML_CATCH_RETHROW; 02050 } 02051 02052 02053 02054 //------------------------------------------------------------------------------------------- 02055 // Add a new coordinate with value to the coordinate and value table. 02056 // Still not tested! If update is true (default) then the kernel extents 02057 // are updated. 02058 //------------------------------------------------------------------------------------------- 02059 template <typename KDATATYPE> 02060 void TKernel<KDATATYPE>::_addCoordinate(const ImageVector &pos, KDATATYPE value, bool update) 02061 { 02062 ML_TRACE_IN( "TKernel<KDATATYPE>::_addCoordinate()" ); 02063 02064 // Create new data tables. 02065 ImageVector *newCoordTab = NULL; 02066 KDATATYPE *newValueTab = NULL; 02067 02068 ML_TRY 02069 { 02070 // Invalidate separability infos which are calculated on demand. 02071 _areSeparabilityInfosUpToDate = false; 02072 02073 // Compute new table size. 02074 size_t newTabSize = _tabSize+1; 02075 02076 ML_CHECK_NEW(newCoordTab, ImageVector [_tabSize+1]); 02077 ML_CHECK_NEW(newValueTab, KDATATYPE[_tabSize+1]); 02078 02079 // Handle not enough memory. 02080 if (!newCoordTab || !newValueTab){ 02081 ML_DELETE_ARRAY(newCoordTab); 02082 ML_DELETE_ARRAY(newValueTab); 02083 ML_PRINT_FATAL_ERROR("Kernel<KDATATYPE>::_addCoordinate(...):", 02084 ML_NO_MEMORY, 02085 "Cannot create kernel tables. Returning with invalid " 02086 "reset tables. This will probably cause other errors."); 02087 return; 02088 } 02089 02090 // Copy old contents into new tables. 02091 if (_tabSize > 0){ 02092 memcpy(newCoordTab, _coordTab, _tabSize*sizeof(ImageVector)); 02093 memcpy(newValueTab, _valueTab, _tabSize*sizeof(KDATATYPE)); 02094 } 02095 02096 // Set new entry. 02097 newCoordTab[_tabSize] = pos; 02098 newValueTab[_tabSize] = value; 02099 02100 // Remove old tables. 02101 _clearTables(); 02102 02103 // Increase table size. 02104 _tabSize = newTabSize; 02105 _coordTab = newCoordTab; 02106 _valueTab = newValueTab; 02107 02108 // Update the real kernel size. 02109 if (update){ _calculateRealKernelExt(); } 02110 } 02111 ML_CATCH_BLOCK(...) 02112 { 02113 ML_DELETE_ARRAY(newCoordTab); 02114 ML_DELETE_ARRAY(newValueTab); 02115 ML_CHECK(0); 02116 throw; 02117 } 02118 } 02119 02120 02121 //------------------------------------------------------------------------------------------- 02122 // Calculate the correct maximum kernel extent for all used kernel elements. 02123 // The maximum extent in all dimensions is reduced as much that all kernel coordinates just 02124 // remain in valid extent. Leading empty entries in the kernel are not removed. 02125 // Empty kernels are considered as kernels with extent (1,1,1,1,1,1). 02126 //------------------------------------------------------------------------------------------- 02127 template <typename KDATATYPE> 02128 void TKernel<KDATATYPE>::_calculateRealKernelExt() 02129 { 02130 ML_TRACE_IN( "TKernel<KDATATYPE>::_calculateRealKernelExt()" ); 02131 ML_TRY 02132 { 02133 // Search minimum and maximum extent of the kernel. 02134 // For the case that no coordinate elements are available set 02135 // values to (0,0,0,0,0,0) so that resulting kernel ext is 02136 // calculated to (1,1,1,1,1,1) below. 02137 ImageVector maximum(0,0,0,0,0,0); 02138 if (getTabSize() > 0){ 02139 for (size_t c=0; c < getTabSize(); c++){ 02140 maximum = ImageVector::compMax(_coordTab[c], maximum); 02141 } 02142 } 02143 02144 // Define kernel ext as difference between corners of bounding box. 02145 _ext = maximum+ImageVector(1,1,1,1,1,1); 02146 02147 // Compute a negative and positive extend of the kernel. So even and odd kernels 02148 // can be handled without really having a kernel center. Subtract one to avoid a 02149 // to avoid increment of extents by one. 02150 _negExt = calculateNegativeExtentFromExtent(_ext); 02151 _posExt = calculatePositiveExtentFromExtent(_ext); 02152 02153 // The kernel must never have extents smaller than 1 after this call. 02154 if (!_ext.allBiggerZero()){ 02155 ML_PRINT_FATAL_ERROR("void TKernel<KDATATYPE>::_calculateRealKernelExt()", 02156 ML_PROGRAMMING_ERROR, 02157 "Kernel has invalid extents now. Continuing anyway."); 02158 } 02159 } 02160 ML_CATCH_RETHROW; 02161 } 02162 02163 02164 02165 //------------------------------------------------------------------------------------------- 02166 // 02167 // Support for an interpretation as separable kernel. 02168 // 02169 //------------------------------------------------------------------------------------------- 02170 02171 //------------------------------------------------------------------------------------------- 02172 // Set/unset a flag to indicate that the first 6 rows of the first kernel slice 02173 // is considered as 1-D axes of a separable filter kernel. Note that this flag 02174 // only denotes how applications shall interpret this kernel; however it does 02175 // NOT change any behaviour of this class. 02176 //------------------------------------------------------------------------------------------- 02177 template <typename KDATATYPE> 02178 void TKernel<KDATATYPE>::setSeparable(bool isSeparableVal) 02179 { 02180 ML_TRACE_IN_TIME_CRITICAL("TKernel<KDATATYPE>::setSeparable()"); 02181 ML_TRY 02182 { 02183 // Invalidate separability information if flag changes. 02184 if (_isSeparable != isSeparableVal){ 02185 _isSeparable = isSeparableVal; 02186 _invalidateSeparableInfos(); 02187 } 02188 } 02189 ML_CATCH_RETHROW; 02190 } 02191 02192 //------------------------------------------------------------------------------------------- 02193 // Indicates whether the first 6 rows of the first kernel slice are 02194 // interpreted as 1-D axes of a separable filter kernel; default is false. 02195 //------------------------------------------------------------------------------------------- 02196 template <typename KDATATYPE> 02197 bool TKernel<KDATATYPE>::isSeparable() const 02198 { 02199 ML_TRACE_IN_TIME_CRITICAL("TKernel<KDATATYPE>::isSeparable()"); 02200 02201 return _isSeparable; 02202 } 02203 02204 //------------------------------------------------------------------------------------------- 02205 // Returns a ImageVector with the number of entries of the separable kernel for 02206 // the dimensions 0,...,5. That means the n-th index contains the number 02207 // of valueTab entries of row n, where n is from [0,...,5]. 02208 //------------------------------------------------------------------------------------------- 02209 template <typename KDATATYPE> 02210 ImageVector TKernel<KDATATYPE>::getSeparableDimEntries() const 02211 { 02212 ML_TRACE_IN("TKernel<KDATATYPE>::getSeparableDimEntries()"); 02213 02214 _validateSeparabilityInfos(); 02215 return _separableDimEntries; 02216 } 02217 02218 //------------------------------------------------------------------------------------------ 02224 //------------------------------------------------------------------------------------------ 02225 template <typename KDATATYPE> 02226 ImageVector TKernel<KDATATYPE>::getSeparableOneDimExtents() const 02227 { 02228 ML_TRACE_IN("TKernel<KDATATYPE>::getSeparableOneDimExtents()"); 02229 02230 _validateSeparabilityInfos(); 02231 return _separableOneDimExt; 02232 } 02233 02234 //------------------------------------------------------------------------------------------- 02241 //------------------------------------------------------------------------------------------- 02242 template <typename KDATATYPE> 02243 size_t TKernel<KDATATYPE>::getSeparableDimIndex(size_t dim) const 02244 { 02245 ML_TRACE_IN("TKernel<KDATATYPE>::getSeparableDimIndex()"); 02246 02247 ML_TRY 02248 { 02249 _validateSeparabilityInfos(); 02250 if (dim>5){ dim = 5; } 02251 02252 // Sum up elements in lower dimensions to get index to the correct table entry. 02253 switch (dim){ 02254 case 0: return 0; 02255 02256 case 1: return static_cast<size_t>(_separableDimEntries.x); 02257 02258 case 2: return static_cast<size_t>(_separableDimEntries.x + 02259 _separableDimEntries.y); 02260 02261 case 3: return static_cast<size_t>(_separableDimEntries.x + 02262 _separableDimEntries.y + 02263 _separableDimEntries.z); 02264 02265 case 4: return static_cast<size_t>(_separableDimEntries.x + 02266 _separableDimEntries.y + 02267 _separableDimEntries.z + 02268 _separableDimEntries.c); 02269 02270 case 5: return static_cast<size_t>(_separableDimEntries.x + 02271 _separableDimEntries.y + 02272 _separableDimEntries.z + 02273 _separableDimEntries.c + 02274 _separableDimEntries.t); 02275 default:{ 02276 ML_PRINT_FATAL_ERROR("TKernel<KDATATYPE>::getSeparableDimIndex", 02277 ML_PROGRAMMING_ERROR, "returning x-table entries"); 02278 return 0; 02279 } 02280 } 02281 } 02282 ML_CATCH_RETHROW; 02283 } 02284 02285 //------------------------------------------------------------------------------------------- 02286 // Returns the table of all coordinates for filtering with separable kernels. 02287 //------------------------------------------------------------------------------------------- 02288 template <typename KDATATYPE> 02289 const std::vector<ImageVector> &TKernel<KDATATYPE>::getSeparableCoordTab() const 02290 { 02291 ML_TRACE_IN("TKernel<KDATATYPE>::getSeparableCoordTab()"); 02292 02293 ML_TRY 02294 { 02295 _validateSeparabilityInfos(); 02296 } 02297 ML_CATCH_RETHROW; 02298 02299 return _separableCoordTab; 02300 } 02301 02302 //------------------------------------------------------------------------------------------- 02303 // Invalidate separability information. 02304 //------------------------------------------------------------------------------------------- 02305 template <typename KDATATYPE> 02306 void TKernel<KDATATYPE>::_invalidateSeparableInfos() 02307 { 02308 ML_TRACE_IN_TIME_CRITICAL("TKernel<KDATATYPE>::_invalidateSeparableInfos()"); 02309 02310 _areSeparabilityInfosUpToDate = false; 02311 } 02312 02313 //------------------------------------------------------------------------------------------- 02314 // This method updates all members which are needed in query methods for 02315 // separability properties of the kernel. 02316 // Note: 02317 // This method changes mutable members since it is required for get-methods 02318 // on information about separability information. 02319 //------------------------------------------------------------------------------------------- 02320 template <typename KDATATYPE> 02321 void TKernel<KDATATYPE>::_validateSeparabilityInfos() const 02322 { 02323 // Speed up performance since it's called first in all separable info methods. 02324 if (_areSeparabilityInfosUpToDate){ return; } 02325 02326 ML_TRACE_IN("TKernel<KDATATYPE>::_validateSeparabilityInfos()"); 02327 ML_TRY 02328 { 02329 if (!_areSeparabilityInfosUpToDate){ 02330 02331 // Scan all coordinate components of the kernel until the y-coordinate is >= 6, 02332 // because all other information after that is not relevant for first 6 separable 02333 // filter rows. Expand the extent of the separable kernel and determine coordinate 02334 // of the axis components. 02335 _separableDimEntries.set(0); 02336 _separableOneDimExt.set(0); 02337 _separableExt.set(0); 02338 _separableCoordTab.clear(); 02339 ImageVector sepCoord(-1); 02340 size_t idx=0; 02341 while ((idx<_tabSize) && (_coordTab[idx].y < 6)){ 02342 // Get the current entry. 02343 const ImageVector &entry = _coordTab[idx]; 02344 02345 // Increment the number of entries of a certain dimension of the 02346 // 6 1-D kernels if the kernel is interpreted as a separable kernel. 02347 // Note that each of the first six rows contains the separable 1-D kernel 02348 // for dimensions 1-6. 02349 _separableDimEntries[entry.y]++; 02350 02351 // Increment the extent of the separable kernel dimensions if the 02352 // coordinate given by entry has a larger x-coordinate than the 02353 // extent of the corresponding dimension. 02354 if (entry.x+1 > _separableOneDimExt[entry.y]){ _separableOneDimExt[entry.y] = entry.x+1; } 02355 02356 // Add the coordinate of the 1-D kernel to the table of coordinates. 02357 // Note that separable kernels are placed in the "center" of the corresponding 02358 // "normal" kernel. Hence, all components which are not given by entry.y, 02359 // need to be set to the position of the kernel "center" which is given by 02360 // the negative extent of the kernel. However, we do not have this "center" 02361 // here, because we do not know it before having all extents. 02362 // So we we mark the missing coordinate components with -1 and replace them 02363 // in an additional loop afterwards. 02364 sepCoord.set(-1); 02365 sepCoord[entry.y] = entry.x; 02366 _separableCoordTab.push_back(sepCoord); 02367 02368 // Count the number of separable entries in the kernel with idx: Go to next entry. 02369 ++idx; 02370 } 02371 02372 // Determine second version of separable kernel extent where non filtered 02373 // dimensions are set to 1. 02374 _separableExt = _separableOneDimExt; 02375 _separableExt.fillSmallerComps(1,1); 02376 02377 // Determine the center of the kernel which is considered to be the negative kernel extent. 02378 const ImageVector negExt =_separableExt / ImageVector(2); 02379 02380 // Replace all -1 component values with the kernel center; thus the 1-D kernel is 02381 // centered in the region where the corresponding normal kernel would also have its 02382 // "center". 02383 for (size_t e=0; e < idx; ++e){ 02384 // Get coordinate. 02385 ImageVector &coord = _separableCoordTab[e]; 02386 for (int d=0; d < 6; ++d){ 02387 // Replace all -1 component values with the kernel center. 02388 if (coord[d] == -1){ coord[d] = negExt[d]; } 02389 } 02390 } 02391 02392 // Calculate negative and positive kernel extent for a separable kernel. 02393 // If a dimension is empty or zero sized then a zero component is returned. 02394 _separableNegExt = _separableExt/ImageVector(2); 02395 _separablePosExt = (_separableExt - (_separableExt/ImageVector(2))) - ImageVector(1); 02396 02397 // Mark infos as valid. 02398 _areSeparabilityInfosUpToDate = true; 02399 } 02400 } 02401 ML_CATCH_BLOCK(...) 02402 { 02403 // Something went wrong, invalidate separability information. 02404 _areSeparabilityInfosUpToDate=false; 02405 } 02406 } 02407 02408 //------------------------------------------------------------------------------------------- 02409 // End of support for the interpretation of the kernel as separable kernel. 02410 //------------------------------------------------------------------------------------------- 02411 02412 02413 02415 02416 02417 typedef TKernel<MLfloat> FloatKernel; 02418 02420 typedef TKernel<MLdouble> DoubleKernel; 02421 02423 typedef TKernel<MLldouble> LDoubleKernel; 02424 02425 02427 typedef MLdouble KernelDataType; 02428 02430 typedef TKernel<KernelDataType> Kernel; 02432 02433 02434 ML_END_NAMESPACE 02435 02436 #endif // __mlKernel_H 02437 02438 02439