MeVisLabToolboxReference
MeVisLab/Standard/Sources/ML/MLKernel/mlKernel.h
Go to the documentation of this file.
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