/*@@@**************************************************************************
 * \file  minMaxFilter
 * \author Hernan Badino
 * \date  Tue Aug 11 14:41:41 EDT 2009
 * \notes 
 *******************************************************************************
 *****          (C) COPYRIGHT Hernan Badino - All Rights Reserved          *****
 ******************************************************************************/

/* INCLUDES */
//#include "minMaxFilter.h"

#if defined ( _OPENMP )
#include <omp.h>
#endif

//#undef _OPENMP

template <class _SrcType, class _TgtType>
CTypedImage<_TgtType> CMinMaxFilter<_SrcType, _TgtType>::m_bufferMin_s;

template <class _SrcType, class _TgtType>
CTypedImage<_TgtType> CMinMaxFilter<_SrcType, _TgtType>::m_bufferMax_s;

/// Apply Min filter horizontal and vertical.        
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinimum ( const CTypedImage<_SrcType> &f_src,
                                      CTypedImage<_TgtType>       &fr_dst,
                                      const unsigned int       f_kernelWidth_ui,
                                      const unsigned int       f_kernelHeight_ui )
{
    bool res_b;
    
    if ( m_bufferMin_s.getWidth() < f_src.getWidth() ||
         m_bufferMin_s.getHeight() < f_src.getHeight() )
    {
        m_bufferMin_s.freeMemory();
        m_bufferMin_s.setWidth  ( std::max(m_bufferMin_s.getWidth(),  f_src.getWidth()  ) );
        m_bufferMin_s.setHeight ( std::max(m_bufferMin_s.getHeight(), f_src.getHeight() ) );
        m_bufferMin_s.ensureAllocation();
    }


    res_b = filterMinHorizontal ( f_src,
                                  m_bufferMin_s,
                                  f_kernelWidth_ui );
    
    if ( res_b )
        res_b = CMinMaxFilter<_TgtType, _TgtType>::filterMinVertical ( m_bufferMin_s,
                                                                       fr_dst,
                                                                       f_kernelHeight_ui );

    return res_b;
}


/// Apply Max filter horizontal and vertical.        
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaximum ( const CTypedImage<_SrcType> &f_src,
                                      CTypedImage<_TgtType>       &fr_dst,
                                      const unsigned int       f_kernelWidth_ui,
                                      const unsigned int       f_kernelHeight_ui )
{
    bool res_b;
    
    if ( m_bufferMax_s.getWidth()  < f_src.getWidth() ||
         m_bufferMax_s.getHeight() < f_src.getHeight() )
    {
        m_bufferMax_s.freeMemory();
        m_bufferMax_s.setWidth  ( std::max(m_bufferMax_s.getWidth(),  f_src.getWidth()  ) );
        m_bufferMax_s.setHeight ( std::max(m_bufferMax_s.getHeight(), f_src.getHeight() ) );
        m_bufferMax_s.ensureAllocation();
    }    

    res_b = filterMaxHorizontal ( f_src,
                                  m_bufferMax_s,
                                  f_kernelWidth_ui );
    
    
    
    if ( res_b )
        res_b = CMinMaxFilter<_TgtType, _TgtType>::filterMaxVertical ( m_bufferMax_s,
                                                                       fr_dst,
                                                                       f_kernelHeight_ui );

    return res_b;
}


/// Apply Min filter horizontal.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinHorizontal ( const CTypedImage<_SrcType>         &f_src,
                                                         CTypedImage<_TgtType>               &fr_dst,
                                                         const unsigned int                   f_kernelWidth_ui,
                                                         const _SrcType                       f_invalid,
                                                         const CMinMaxFilterBase::EFilterMode f_filterMode_e )
{
    bool res_b;
    
    if ( f_filterMode_e == FM_MASK_INVALID )
    {
        res_b = filterMinHorizontal_Mask ( f_src,
                                           fr_dst,
                                           f_kernelWidth_ui,
                                           f_invalid );
    }
    else if ( f_filterMode_e == FM_IGNORE_INVALID )
    {
        res_b = filterMinHorizontal_IgnoreInvalid ( f_src,
                                                    fr_dst,
                                                    f_kernelWidth_ui,
                                                    f_invalid );
    }
    else //if ( f_filterMode_e == FM_NO_INVALID )
    {
        res_b = filterMinHorizontal ( f_src,
                                      fr_dst,
                                      f_kernelWidth_ui );
    }

    return res_b;
}
       
/// Apply Max filter horizontal.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaxHorizontal ( const CTypedImage<_SrcType> &f_src,
                                            CTypedImage<_TgtType>       &fr_dst,
                                            const unsigned int       f_kernelWidth_ui,
                                            const _SrcType              f_invalid,
                                            const CMinMaxFilterBase::EFilterMode f_filterMode_e )
{
    bool res_b;
    
    if ( f_filterMode_e == FM_MASK_INVALID )
    {
        res_b = filterMaxHorizontal_Mask ( f_src,
                                           fr_dst,
                                           f_kernelWidth_ui,
                                           f_invalid );
    }
    else if ( f_filterMode_e == FM_IGNORE_INVALID )
    {
        res_b = filterMaxHorizontal_IgnoreInvalid ( f_src,
                                                    fr_dst,
                                                    f_kernelWidth_ui,
                                                    f_invalid );
    }
    else //if ( f_filterMode_e == FM_NO_INVALID )
    {
        res_b = filterMaxHorizontal ( f_src,
                                      fr_dst,
                                      f_kernelWidth_ui );
    }
    

    return res_b;
}


/// Apply Min filter vertical.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinVertical ( const CTypedImage<_SrcType> &f_src,
                                          CTypedImage<_TgtType>       &fr_dst,
                                          const unsigned int       f_kernelHeight_ui,
                                          const _SrcType              f_invalid,
                                          const CMinMaxFilterBase::EFilterMode f_filterMode_e )
{
    bool res_b;
    
    if ( f_filterMode_e == FM_MASK_INVALID )
    {
        res_b = filterMinVertical_Mask ( f_src,
                                         fr_dst,
                                         f_kernelHeight_ui,
                                         f_invalid );
    }
    else if ( f_filterMode_e == FM_IGNORE_INVALID )
    {
        res_b = filterMinVertical_IgnoreInvalid ( f_src,
                                                  fr_dst,
                                                  f_kernelHeight_ui,
                                                  f_invalid );
    }
    else //if ( f_filterMode_e == FM_NO_INVALID )
    {
        res_b = filterMinVertical ( f_src,
                                    fr_dst,
                                    f_kernelHeight_ui );
    }

    return res_b;
}


/// Apply Max filter vertical.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaxVertical ( const CTypedImage<_SrcType> &f_src,
                                          CTypedImage<_TgtType>       &fr_dst,
                                          const unsigned int       f_kernelHeight_ui,
                                          const _SrcType              f_invalid,
                                          const CMinMaxFilterBase::EFilterMode f_filterMode_e )
{
    bool res_b;
    
    if ( f_filterMode_e == FM_MASK_INVALID )
    {
        res_b = filterMaxVertical_Mask ( f_src,
                                         fr_dst,
                                         f_kernelHeight_ui,
                                         f_invalid );
    }
    else if ( f_filterMode_e == FM_IGNORE_INVALID )
    {
        res_b = filterMaxVertical_IgnoreInvalid ( f_src,
                                                  fr_dst,
                                                  f_kernelHeight_ui,
                                                  f_invalid );
    }
    else //if ( f_filterMode_e == FM_NO_INVALID )
    {
        res_b = filterMaxVertical ( f_src,
                                    fr_dst,
                                    f_kernelHeight_ui );
    }

    return res_b;
}


/// Apply Min filter horizontal and vertical.        
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinimum ( const CTypedImage<_SrcType> &f_src,
                                      CTypedImage<_TgtType>       &fr_dst,
                                      const unsigned int       f_kernelWidth_ui,
                                      const unsigned int       f_kernelHeight_ui,
                                      const _SrcType              f_invalid,
                                      const CMinMaxFilterBase::EFilterMode f_filterMode_e )
{
    bool res_b;
    
    if ( m_bufferMin_s.getWidth() < f_src.getWidth() ||
         m_bufferMin_s.getHeight() < f_src.getHeight() )
    {
        m_bufferMin_s.freeMemory();
        m_bufferMin_s.setWidth  ( std::max(m_bufferMin_s.getWidth(),  f_src.getWidth()  ) );
        m_bufferMin_s.setHeight ( std::max(m_bufferMin_s.getHeight(), f_src.getHeight() ) );
        m_bufferMin_s.ensureAllocation();
    }

    
    res_b = filterMinHorizontal ( f_src,
                                  m_bufferMin_s,
                                  f_kernelWidth_ui,
                                  f_invalid,
                                  f_filterMode_e );
    
    res_b = CMinMaxFilter<_TgtType, _TgtType>::filterMinVertical ( m_bufferMin_s,
                                                                   fr_dst,
                                                                   f_kernelHeight_ui,
                                                                   f_invalid,
                                                                   f_filterMode_e );
    return res_b;
}


/// Apply Max filter horizontal and vertical.        
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaximum ( const CTypedImage<_SrcType> &f_src,
                                      CTypedImage<_TgtType>       &fr_dst,
                                      const unsigned int       f_kernelWidth_ui,
                                      const unsigned int       f_kernelHeight_ui,
                                      const _SrcType              f_invalid,
                                      const CMinMaxFilterBase::EFilterMode f_filterMode_e )
{
    bool res_b;
    
    if ( m_bufferMax_s.getWidth()  < f_src.getWidth() ||
         m_bufferMax_s.getHeight() < f_src.getHeight() )
    {
        m_bufferMax_s.freeMemory();
        m_bufferMax_s.setWidth  ( std::max(m_bufferMax_s.getWidth(),  f_src.getWidth()  ) );
        m_bufferMax_s.setHeight ( std::max(m_bufferMax_s.getHeight(), f_src.getHeight() ) );
        m_bufferMax_s.ensureAllocation();
    }    

    res_b = filterMaxHorizontal ( f_src,
                                  m_bufferMax_s,
                                  f_kernelWidth_ui,
                                  f_invalid,
                                  f_filterMode_e );
    
    res_b = CMinMaxFilter<_TgtType, _TgtType>::filterMaxVertical ( m_bufferMax_s,
                                                                   fr_dst,
                                                                   f_kernelHeight_ui,
                                                                   f_invalid,
                                                                   f_filterMode_e );

    return res_b;
}

/// Apply Min filter horizontal.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinHorizontal ( const CTypedImage<_SrcType> &f_src,
                                            CTypedImage<_TgtType>       &fr_dstMin,
                                            const unsigned int       f_kW_ui )
{
    const unsigned int w_ui = f_src.getWidth();
    const unsigned int h_ui = f_src.getHeight();

    if ( w_ui > fr_dstMin.getWidth()  ||
         h_ui > fr_dstMin.getHeight() ||
         w_ui < f_kW_ui )
        return false;
    
#if defined ( _OPENMP )
    const int h_i = (int) h_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int i = 0; i < h_i; ++i)
#else
        for (unsigned int i = 0; i < h_ui; ++i)
#endif
        {    
            _SrcType * dist_p  = f_src.getScanline ( i );
            _SrcType * distL_p = dist_p;
            _TgtType * min_p   = fr_dstMin.getScanline ( i ) + f_kW_ui/2;

            _SrcType   min_d = *dist_p;

            ++dist_p;
            for (unsigned int j = 1; j < f_kW_ui; ++j, ++dist_p)
            {
                if ( min_d > *dist_p )
                    min_d = *dist_p;
            }

            *min_p = (_TgtType) min_d;

            ++min_p;

            for (unsigned int j = f_kW_ui; j < w_ui; ++j, 
                     ++dist_p, ++distL_p, 
                     ++min_p )
            {
                if ( *dist_p < min_d )
                {
                    /// If the right element is smaller than the current minimum then 
                    /// update minimum as the new element.
                    min_d = *dist_p;
                }
                else
                {
                    /// Check if the minimum is the element which was discarded.
                    if ( min_d == *distL_p )
                    {
                        /// Then search for minimum once again.
                        _SrcType *d  = distL_p+1;

                        min_d = *d;

                        for (++d; d <= dist_p; ++d)
                            if (min_d > *d )
                                min_d = *d;
                    }
                    else
                    {
                        /// Current minimum is still the minimum
                    }
                }   

                /// Set min.
                *min_p = (_TgtType) min_d;
            }
        }

    return true;
}

 
/// Apply Max filter horizontal.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaxHorizontal ( const CTypedImage<_SrcType> &f_src,
                                            CTypedImage<_TgtType>       &fr_dstMax,
                                            const unsigned int       f_kW_ui )
{
    const unsigned int w_ui = f_src.getWidth();
    const unsigned int h_ui = f_src.getHeight();

    if ( w_ui > fr_dstMax.getWidth()  ||
         h_ui > fr_dstMax.getHeight() ||
         w_ui < f_kW_ui )
        return false;
    
#if defined ( _OPENMP )
    const int h_i = (int) h_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int i = 0; i < h_i; ++i)
#else
        for (unsigned int i = 0; i < h_ui; ++i)
#endif
        {    
            _SrcType * dist_p  = f_src.getScanline ( i );
            _SrcType * distL_p = dist_p;
            _TgtType * max_p   = fr_dstMax.getScanline ( i ) + f_kW_ui/2;

            _SrcType   max_d = *dist_p;

            ++dist_p;
            for (unsigned int j = 1; j < f_kW_ui; ++j, ++dist_p)
            {
                if ( max_d < *dist_p )
                    max_d = *dist_p;
            }

            *max_p = max_d;

            ++max_p;

            for (unsigned int j = f_kW_ui; j < w_ui; ++j, 
                     ++dist_p, ++distL_p, 
                     ++max_p )
            {
                if ( *dist_p > max_d )
                {
                    /// If the right element is smaller than the current maximum then 
                    /// update maximum as the new element.
                    max_d = *dist_p;
                }
                else
                {
                    /// Check if the maximum is the element which was discarded.
                    if ( max_d == *distL_p )
                    {
                        /// Then search for maximum once again.
                        _SrcType *d  = distL_p+1;

                        max_d = *d;

                        for (++d; d <= dist_p; ++d)
                            if (max_d < *d )
                                max_d = *d;
                    }
                    else
                    {
                        /// Current maximum is still the maximum
                    }
                }   

                /// Set max.
                *max_p = max_d;
            }
        }

    return true;
}


/// Apply Min filter vertical.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinVertical ( const CTypedImage<_SrcType> &f_src,
                                          CTypedImage<_TgtType>       &fr_dstMin,
                                          const unsigned int       f_kH_ui )
{
    const unsigned int w_ui    = f_src.getWidth();
    const unsigned int h_ui    = f_src.getHeight();
    const unsigned int wdst_ui = fr_dstMin.getWidth();
    
    if ( w_ui > wdst_ui  ||
         h_ui > fr_dstMin.getHeight() ||
         h_ui < f_kH_ui )
        return false;
    
#if defined ( _OPENMP )
    const int w_i = (int) w_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int j = 0; j < w_i; ++j)
#else
    for (unsigned int j = 0; j < w_ui; ++j)
#endif
    {
        _SrcType * dist_p  = f_src.getData() + j;
        _SrcType * distL_p = dist_p;
        _TgtType * min_p   = fr_dstMin.getScanline(f_kH_ui/2) + j;

        _SrcType   min_d = *dist_p;

        dist_p+=w_ui;
        for (unsigned int i = 1; i < f_kH_ui; ++i, dist_p+=w_ui)
        {
            if ( min_d > *dist_p )
                min_d = *dist_p;                
        }
        
        *min_p = (_TgtType) min_d;

        min_p+=wdst_ui;

        for ( unsigned int i = f_kH_ui; i < h_ui; ++i,
                  dist_p+=w_ui, distL_p+=w_ui, 
                  min_p+=wdst_ui )
        {
            if ( *dist_p < min_d )
            {
                /// If the right element is smaller than the current minimum then 
                /// update minimum as the new element.
                min_d = *dist_p;
            }
            else
            {
                /// Check if new min is the element which is discarded.
                if ( min_d == *distL_p )
                {
                    /// Then search for minimum once again.
                    _SrcType *d=distL_p+w_ui;

                    min_d = *d;
                    /// "d <= dist_p" because the last one is not minimum.
                    for (d+=w_ui; d <= dist_p; d+=w_ui)
                        if ( min_d > *d )
                            min_d = *d;
                }
                else
                {
                    /// Current minimum is still the minimum
                }
            }   

            /// Set min.
            *min_p = (_TgtType) min_d;
        }
    }
    
    return true;
}

/// Apply Max filter vertical.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaxVertical ( const CTypedImage<_SrcType> &f_src,
                                          CTypedImage<_TgtType>       &fr_dstMax,
                                          const unsigned int       f_kH_ui )
{
    const unsigned int w_ui    = f_src.getWidth();
    const unsigned int h_ui    = f_src.getHeight();
    const unsigned int wdst_ui = fr_dstMax.getWidth();
    
    if ( w_ui > wdst_ui  ||
         h_ui > fr_dstMax.getHeight() ||
         h_ui < f_kH_ui )
        return false;
    
#if defined ( _OPENMP )
    const int w_i = (int) w_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int j = 0; j < w_i; ++j)
#else
    for (unsigned int j = 0; j < w_ui; ++j)
#endif
    {
        _SrcType * dist_p  = f_src.getData() + j;
        _SrcType * distL_p = dist_p;
        _TgtType * max_p   = fr_dstMax.getScanline(f_kH_ui/2) + j;

        _SrcType   max_d = *dist_p;

        dist_p+=w_ui;
        for (unsigned int i = 1; i < f_kH_ui; ++i, dist_p+=w_ui)
        {
            if ( max_d < *dist_p )
                max_d = *dist_p;                
        }
        
        *max_p = max_d;

        max_p+=wdst_ui;

        for ( unsigned int i = f_kH_ui; i < h_ui; ++i, 
                  dist_p+=w_ui, distL_p+=w_ui, 
                  max_p+=wdst_ui )
        {
            if ( *dist_p > max_d )
            {
                /// If the right element is smaller than the current maximum then 
                /// update maximum as the new element.
                max_d = *dist_p;
            }
            else
            {
                /// Check if new max is the element which is discarded.
                if ( max_d == *distL_p )
                {
                    /// Then search for maximum once again.
                    _SrcType *d=distL_p+w_ui;

                    max_d = *d;

                    for (d+=w_ui; d <= dist_p; d+=w_ui)
                        if ( max_d < *d )
                            max_d = *d;
                }
                else
                {
                    /// Current maximum is still the maximum
                }
            }   

            /// Set max.
            *max_p = max_d;
        }
    }
    
    return true;
}

/// Apply Min filter horizontal.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinHorizontal_Mask ( const CTypedImage<_SrcType> &f_src,
                                                 CTypedImage<_TgtType>       &fr_dstMin,
                                                 const unsigned int       f_kW_ui,
                                                 const _SrcType              f_invalid )
{
    const unsigned int w_ui = f_src.getWidth();
    const unsigned int h_ui = f_src.getHeight();

    if ( w_ui > fr_dstMin.getWidth()  ||
         h_ui > fr_dstMin.getHeight() ||
         w_ui < f_kW_ui )
        return false;
    
    
#if defined ( _OPENMP )
    const int h_i = (int) h_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int i = 0; i < h_i; ++i)
#else
    for (unsigned int i = 0; i < h_ui; ++i)
#endif
    {    
        _SrcType * dist_p  = f_src.getScanline ( i );
        _SrcType * distL_p = dist_p;
        _TgtType * min_p   = fr_dstMin.getScanline ( i ) + f_kW_ui/2;

        _SrcType   min_d = f_invalid;

        bool unset_b = true;

        unsigned int invalidCount_ui = 0;
        for (unsigned int j = 0; j < f_kW_ui; ++j, ++dist_p)
        {
            if ( *dist_p == f_invalid )
            {
                ++invalidCount_ui;
            }
            else
            {
                if ( min_d > *dist_p || unset_b )
                    min_d = *dist_p;
                
                unset_b = false;
            }
            
        }
        
        /// Write first result.
        if (invalidCount_ui > 0)
            *min_p = (_TgtType) f_invalid;
        else
            *min_p = (_TgtType) min_d;

        ++min_p;

        for (unsigned int j = f_kW_ui; j < w_ui; ++j, 
                 ++dist_p, ++distL_p, 
                 ++min_p )
        {
            bool isNewValValid_b = (*dist_p != f_invalid);

            invalidCount_ui += 1-isNewValValid_b;
            invalidCount_ui -= (*distL_p == f_invalid);

            if ( invalidCount_ui == f_kW_ui )
                min_d = f_invalid;
            else if (isNewValValid_b && min_d == f_invalid) 
                min_d = *dist_p;
            else if ( *dist_p < min_d && isNewValValid_b )
            {
                /// If the right element is smaller than the current minimum then 
                /// update minimum as the new element.
                min_d = *dist_p;
            }
            else
            {
                /// Check if the minimum is the element which was discarded.
                if ( min_d == *distL_p )
                {
                    /// Then search for minimum once again.
                    unset_b = true;
                    min_d = f_invalid;

                    for (_SrcType *d  = distL_p+1; d <= dist_p; ++d)
                        if ( *d != f_invalid ) //what happen if all new values are invalid. HH A: min_d remains invalid.
                        {
                            if (min_d > *d || unset_b )
                                min_d = *d;
                            unset_b = false;
                        }
                }
                else
                {
                    /// Current minimum is still the minimum
                }
            }   
            
            /// Set min.
            if (invalidCount_ui > 0)
                *min_p = (_TgtType) f_invalid;
            else
                *min_p = (_TgtType) min_d;
        }
    }
    
    return true;
}


/// Apply Min filter vertical.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinVertical_Mask ( const CTypedImage<_SrcType> &f_src,
                                               CTypedImage<_TgtType>       &fr_dstMin,
                                               const unsigned int       f_kH_ui,
                                               const _SrcType              f_invalid )
{
    const unsigned int w_ui     = f_src.getWidth();
    const unsigned int h_ui    = f_src.getHeight();
    const unsigned int wdst_ui = fr_dstMin.getWidth();
    
    if ( w_ui > wdst_ui  ||
         h_ui > fr_dstMin.getHeight() ||
         h_ui < f_kH_ui )
        return false;
    
#if defined ( _OPENMP )
    const int w_i = (int) w_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int j = 0; j < w_i; ++j)
#else
    for (unsigned int j = 0; j < w_ui; ++j)
#endif
    {
        _SrcType * dist_p  = f_src.getData() + j;
        _SrcType * distL_p = dist_p;
        _TgtType * min_p   = fr_dstMin.getScanline(f_kH_ui/2) + j;

        _SrcType   min_d = f_invalid;

        bool unset_b = true;

        unsigned int invalidCount_ui = 0;
        for (unsigned int i = 0; i < f_kH_ui; ++i, dist_p+=w_ui)
        {
            if ( *dist_p == f_invalid )
            {
                ++invalidCount_ui;
            }
            else
            {
                if ( min_d > *dist_p || unset_b )
                    min_d = *dist_p;
                
                unset_b = false;
            }
        }
        
        /// Write first result.
        if (invalidCount_ui > 0)
            *min_p = (_TgtType) f_invalid;
        else
            *min_p = (_TgtType) min_d;

        min_p+=wdst_ui;

        for ( unsigned int i = f_kH_ui; i < h_ui; ++i, 
                  dist_p+=w_ui, distL_p+=w_ui, 
                  min_p+=wdst_ui )
        {
            bool isNewValValid_b = (*dist_p != f_invalid);
            
            invalidCount_ui += 1-isNewValValid_b;
            invalidCount_ui -= (*distL_p == f_invalid);

            if ( invalidCount_ui == f_kH_ui )
                min_d = f_invalid;
            else if (isNewValValid_b && min_d == f_invalid) 
                min_d = *dist_p;
            else if ( *dist_p < min_d && isNewValValid_b )
            {
                /// If the right element is smaller than the current minimum then 
                /// update minimum as the new element.
                min_d = *dist_p;
            }
            else
            {
                /// Check if the minimum is the element which was discarded.
                if ( min_d == *distL_p )
                {
                    /// Then search for minimum once again.
                    unset_b = true;
                    min_d = f_invalid;

                     for (_SrcType *d=distL_p+w_ui; d <= dist_p; d+=w_ui)
                        if ( *d != f_invalid ) //what happen if all new values are invalid. HH A: min_d remains invalid.
                        {
                            if (min_d > *d || unset_b )
                                min_d = *d;
                            unset_b = false;
                        }
                }
                else
                {
                    /// Current minimum is still the minimum
                }
            }   

            /// Set min.
            if (invalidCount_ui > 0)
                *min_p = (_TgtType) f_invalid;
            else
                *min_p = (_TgtType) min_d;
        }
    }
    
    return true;
}

/// Apply Max filter horizontal.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaxHorizontal_Mask ( const CTypedImage<_SrcType> &f_src,
                                                 CTypedImage<_TgtType>       &fr_dstMax,
                                                 const unsigned int       f_kW_ui,
                                                 const _SrcType              f_invalid )
{
    const unsigned int w_ui = f_src.getWidth();
    const unsigned int h_ui = f_src.getHeight();

    if ( w_ui > fr_dstMax.getWidth()  ||
         h_ui > fr_dstMax.getHeight() ||
         w_ui < f_kW_ui )
        return false;
    
    
#if defined ( _OPENMP )
    const int h_i = (int) h_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int i = 0; i < h_i; ++i)
#else
    for (unsigned int i = 0; i < h_ui; ++i)
#endif
    {    
        _SrcType * dist_p  = f_src.getScanline ( i );
        _SrcType * distL_p = dist_p;
        _TgtType * max_p   = fr_dstMax.getScanline ( i ) + f_kW_ui/2;

        _SrcType   max_d = f_invalid;

        bool unset_b = true;

        unsigned int invalidCount_ui = 0;
        for (unsigned int j = 0; j < f_kW_ui; ++j, ++dist_p)
        {
            if ( *dist_p == f_invalid )
            {
                ++invalidCount_ui;
            }
            else
            {
                if ( max_d < *dist_p || unset_b )
                    max_d = *dist_p;
                
                unset_b = false;
            }
            
        }
        
        /// Write first result.
        if (invalidCount_ui > 0)
            *max_p = f_invalid;
        else
            *max_p = max_d;

        ++max_p;

        for (unsigned int j = f_kW_ui; j < w_ui; ++j, 
                 ++dist_p, ++distL_p, 
                 ++max_p )
        {
            bool isNewValValid_b = (*dist_p != f_invalid);

            invalidCount_ui += 1-isNewValValid_b;
            invalidCount_ui -= (*distL_p == f_invalid);

            if ( invalidCount_ui == f_kW_ui )
                max_d = f_invalid;
            else if (isNewValValid_b && max_d == f_invalid) 
                max_d = *dist_p;
            else if ( *dist_p > max_d && isNewValValid_b )
            {
                /// If the right element is smaller than the current maximum then 
                /// update maximum as the new element.
                max_d = *dist_p;
            }
            else
            {
                /// Check if the maximum is the element which was discarded.
                if ( max_d == *distL_p )
                {
                    /// Then search for maximum once again.
                    unset_b = true;
                    max_d = f_invalid;

                    for (_SrcType *d  = distL_p+1; d <= dist_p; ++d)
                        if ( *d != f_invalid ) //what happen if all new values are invalid. HH A: max_d remains invalid.
                        {
                            if (max_d < *d || unset_b )
                                max_d = *d;
                            unset_b = false;
                        }
                }
                else
                {
                    /// Current maximum is still the maximum
                }
            }   
            
            /// Set max.
            if (invalidCount_ui > 0)
                *max_p = f_invalid;
            else
                *max_p = max_d;
        }
    }
    
    return true;
}

/// Apply Max filter vertical.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaxVertical_Mask ( const CTypedImage<_SrcType> &f_src,
                                               CTypedImage<_TgtType>       &fr_dstMax,
                                               const unsigned int       f_kH_ui,
                                               const _SrcType              f_invalid )
{
    const unsigned int w_ui     = f_src.getWidth();
    const unsigned int h_ui    = f_src.getHeight();
    const unsigned int wdst_ui = fr_dstMax.getWidth();
    
    if ( w_ui > wdst_ui  ||
         h_ui > fr_dstMax.getHeight() ||
         h_ui < f_kH_ui )
        return false;
    
#if defined ( _OPENMP )
    const int w_i = (int) w_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int j = 0; j < w_i; ++j)
#else
    for (unsigned int j = 0; j < w_ui; ++j)
#endif
    {
        _SrcType * dist_p  = f_src.getData() + j;
        _SrcType * distL_p = dist_p;
        _TgtType * max_p   = fr_dstMax.getScanline(f_kH_ui/2) + j;

        _SrcType   max_d = f_invalid;

        bool unset_b = true;

        unsigned int invalidCount_ui = 0;
        for (unsigned int i = 0; i < f_kH_ui; ++i, dist_p+=w_ui)
        {
            if ( *dist_p == f_invalid )
            {
                ++invalidCount_ui;
            }
            else
            {
                if ( max_d < *dist_p || unset_b )
                    max_d = *dist_p;
                
                unset_b = false;
            }
        }
        
        /// Write first result.
        if (invalidCount_ui > 0)
            *max_p = invalidCount_ui;
        else
            *max_p = max_d;

        max_p+=wdst_ui;

        for ( unsigned int i = f_kH_ui; i < h_ui; ++i, 
                  dist_p+=w_ui, distL_p+=w_ui, 
                  max_p+=wdst_ui )
        {
            bool isNewValValid_b = (*dist_p != f_invalid);
            
            invalidCount_ui += 1-isNewValValid_b;
            invalidCount_ui -= (*distL_p == f_invalid);

            if ( invalidCount_ui == f_kH_ui )
                max_d = f_invalid;
            else if (isNewValValid_b && max_d == f_invalid) 
                max_d = *dist_p;
            else if ( *dist_p > max_d && isNewValValid_b )
            {
                /// If the right element is smaller than the current maximum then 
                /// update maximum as the new element.
                max_d = *dist_p;
            }
            else
            {
                /// Check if the maximum is the element which was discarded.
                if ( max_d == *distL_p )
                {
                    /// Then search for maximum once again.
                    unset_b = true;
                    max_d = f_invalid;
                    /// "d > dist_p" because the last one is not maximum.
                     for (_SrcType *d=distL_p+w_ui; d <= dist_p; d+=w_ui)
                        if ( *d != f_invalid ) //what happen if all new values are invalid. HH A: max_d remains invalid.
                        {
                            if (max_d < *d || unset_b )
                                max_d = *d;
                            unset_b = false;
                        }
                }
                else
                {
                    /// Current maximum is still the maximum
                }
            }   

            /// Set max.
            if (invalidCount_ui > 0)
                *max_p = f_invalid;
            else
                *max_p = max_d;
        }
    }
    
    return true;
}

/// Apply Min filter horizontal.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinHorizontal_IgnoreInvalid ( const CTypedImage<_SrcType> &f_src,
                                                          CTypedImage<_TgtType>       &fr_dstMin,
                                                          const unsigned int       f_kW_ui,
                                                          const _SrcType              f_invalid )
{
    const unsigned int w_ui = f_src.getWidth();
    const unsigned int h_ui = f_src.getHeight();

    if ( w_ui > fr_dstMin.getWidth()  ||
         h_ui > fr_dstMin.getHeight() ||
         w_ui < f_kW_ui )
        return false;
    
#if defined ( _OPENMP )
    const int h_i = (int) h_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int i = 0; i < h_i; ++i)
#else
        for (unsigned int i = 0; i < h_ui; ++i)
#endif
        {    
            _SrcType * dist_p  = f_src.getScanline ( i );
            _SrcType * distL_p = dist_p;
            _TgtType * min_p   = fr_dstMin.getScanline ( i ) + f_kW_ui/2;

            _SrcType   min_d = f_invalid;

            bool unset_b = true;

            for (unsigned int j = 0; j < f_kW_ui; ++j, ++dist_p)
            {
                if ( *dist_p != f_invalid )
                {
                    if ( min_d > *dist_p || unset_b )
                        min_d = *dist_p;
                
                    unset_b = false;                
                }
            }

            *min_p = (_TgtType) min_d;

            ++min_p;

            for (unsigned int j = f_kW_ui; j < w_ui; ++j, 
                     ++dist_p, ++distL_p, 
                     ++min_p )
            {
                bool isNewValValid_b = (*dist_p != f_invalid);

                if (isNewValValid_b && min_d == f_invalid)
                    min_d = *dist_p;
                else if (not isNewValValid_b && min_d == f_invalid)
                    min_d = *dist_p;
                else if ( *dist_p < min_d && isNewValValid_b )
                {
                    /// If the right element is smaller than the current minimum then 
                    /// update minimum as the new element.
                    min_d = *dist_p;
                }
                else
                {
                    /// Check if the minimum is the element which was discarded.
                    if ( min_d == *distL_p )
                    {
                        /// Then search for minimum once again.
                        unset_b = true;
                        min_d = f_invalid;

                        for (_SrcType *d  = distL_p+1; d <= dist_p; ++d)
                            if ( *d != f_invalid ) //what happen if all new values are invalid. HH A: min_d remains invalid.
                            {
                                if (min_d > *d || unset_b )
                                    min_d = *d;
                                unset_b = false;
                            }
                    }
                    else
                    {
                        /// Current minimum is still the minimum
                    }
                }   

                /// Set min.
                *min_p = (_TgtType) min_d;
            }
        }

    return true;
}

 
/// Apply Max filter horizontal.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaxHorizontal_IgnoreInvalid ( const CTypedImage<_SrcType> &f_src,
                                                          CTypedImage<_TgtType>       &fr_dstMax,
                                                          const unsigned int       f_kW_ui,
                                                          const _SrcType              f_invalid )
{
    const unsigned int w_ui = f_src.getWidth();
    const unsigned int h_ui = f_src.getHeight();

    if ( w_ui > fr_dstMax.getWidth()  ||
         h_ui > fr_dstMax.getHeight() ||
         w_ui < f_kW_ui )
        return false;
    
#if defined ( _OPENMP )
    const int h_i = (int) h_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int i = 0; i < h_i; ++i)
#else
        for (unsigned int i = 0; i < h_ui; ++i)
#endif
        {    
            _SrcType * dist_p  = f_src.getScanline ( i );
            _SrcType * distL_p = dist_p;
            _TgtType * max_p   = fr_dstMax.getScanline ( i ) + f_kW_ui/2;

            _SrcType   max_d = f_invalid;

            bool unset_b = true;

            for (unsigned int j = 0; j < f_kW_ui; ++j, ++dist_p)
            {
                if ( *dist_p != f_invalid )
                {
                    if ( max_d < *dist_p  || unset_b )
                        max_d = *dist_p;

                    unset_b = false;                
                }
            }

            /// Write first result.
            *max_p = max_d;

            ++max_p;

            for (unsigned int j = f_kW_ui; j < w_ui; ++j, 
                     ++dist_p, ++distL_p, 
                     ++max_p)
            {
                bool isNewValValid_b = (*dist_p != f_invalid);

                if (isNewValValid_b && max_d == f_invalid)
                    max_d = *dist_p;
                else if (not isNewValValid_b && max_d == f_invalid)
                    max_d = *dist_p;
                else if ( *dist_p > max_d && isNewValValid_b )
                {
                    /// If the right element is larger than the current maximum then 
                    /// update maximum as the new element.
                    max_d = *dist_p;
                }
                else
                {
                    /// Check if new max is the element which is discarded.
                    if ( max_d == *distL_p )
                    {
                        /// Then search for maximum once again.
                        unset_b = true;
                        max_d = f_invalid;

                        for (_SrcType *d  = distL_p+1; d <= dist_p; ++d)
                            if ( *d != f_invalid )
                            {
                                if (max_d < *d || unset_b )
                                    max_d = *d;
                                unset_b = false;
                            }
                    }
                    else
                    {
                        /// Current maximum is still the maximum
                    }
                }   
            
                /// Set max.
                *max_p = max_d;    
            }
        }

    return true;
}


/// Apply Min filter vertical.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMinVertical_IgnoreInvalid ( const CTypedImage<_SrcType> &f_src,
                                                        CTypedImage<_TgtType>       &fr_dstMin,
                                                        const unsigned int       f_kH_ui,
                                                        const _SrcType              f_invalid)
{
    const unsigned int w_ui     = f_src.getWidth();
    const unsigned int h_ui    = f_src.getHeight();
    const unsigned int wdst_ui = fr_dstMin.getWidth();
    
    if ( w_ui > wdst_ui  ||
         h_ui > fr_dstMin.getHeight() ||
         h_ui < f_kH_ui )
        return false;
    
#if defined ( _OPENMP )
    const int w_i = (int) w_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int j = 0; j < w_i; ++j)
#else
    for (unsigned int j = 0; j < w_ui; ++j)
#endif
    {
        _SrcType * dist_p  = f_src.getData() + j;
        _SrcType * distL_p = dist_p;
        _TgtType * min_p   = fr_dstMin.getScanline(f_kH_ui/2) + j;

        _SrcType   min_d = f_invalid;

        bool unset_b = true;

        for (unsigned int i = 0; i < f_kH_ui; ++i, dist_p+=w_ui)
        {
            if ( *dist_p != f_invalid )
            {
                if ( min_d > *dist_p || unset_b )
                    min_d = *dist_p;
                
                unset_b = false;                
            }
        }
        
        *min_p = (_TgtType) min_d;

        min_p+=wdst_ui;

        for ( unsigned int i = f_kH_ui; i < h_ui; ++i, 
                  dist_p+=w_ui, distL_p+=w_ui, 
                  min_p+=wdst_ui )
        {
            {
                bool isNewValValid_b = (*dist_p != f_invalid);

                if (isNewValValid_b && min_d == f_invalid)
                    min_d = *dist_p;
                else if (not isNewValValid_b && min_d == f_invalid)
                    min_d = *dist_p;
                else if ( *dist_p < min_d && isNewValValid_b )
                {
                    /// If the right element is smaller than the current minimum then 
                    /// update minimum as the new element.
                    min_d = *dist_p;
                }
                else
                {
                    /// Check if new min is the element which is discarded.
                    if ( min_d == *distL_p )
                    {
                        /// Then search for minimum once again.
                        unset_b = true;
                        min_d = f_invalid;

                        for (_SrcType *d=distL_p+w_ui; d <= dist_p; d+=w_ui)
                            if ( *d != f_invalid )
                            {
                                if (min_d > *d || unset_b )
                                    min_d = *d;
                                unset_b = false;        
                            }
                    }
                    else
                    {
                        /// Current minimum is still the minimum
                    }
                }   

                /// Set min.
                    *min_p = (_TgtType) min_d;
            }
        }
    }
    
    return true;
}

/// Apply Max filter vertical.
template <class _SrcType, class _TgtType>
bool 
CMinMaxFilter<_SrcType, _TgtType>::filterMaxVertical_IgnoreInvalid ( const CTypedImage<_SrcType> &f_src,
                                                        CTypedImage<_TgtType>       &fr_dstMax,
                                                        const unsigned int       f_kH_ui,
                                                        const _SrcType              f_invalid )
{
    const unsigned int w_ui = f_src.getWidth();
    const unsigned int h_ui = f_src.getHeight();
    const unsigned int wdst_ui = fr_dstMax.getWidth();
   
    if ( w_ui > wdst_ui ||
         h_ui > fr_dstMax.getHeight() ||
         h_ui < f_kH_ui )
        return false;
    
#if defined ( _OPENMP )
    const int w_i = (int) w_ui;
    const unsigned int numThreads_ui = omp_get_max_threads();
#pragma omp parallel for num_threads(numThreads_ui) schedule(dynamic)
    for (int j = 0; j < w_i; ++j)
#else
    for (unsigned int j = 0; j < w_ui; ++j)
#endif
    {
        _SrcType * dist_p  = f_src.getData() + j;
        _SrcType * distL_p = dist_p;
        _TgtType * max_p   = fr_dstMax.getScanline(f_kH_ui/2) + j;

        _SrcType   max_d = f_invalid;

        bool unset_b = true;

        for (unsigned int i = 0; i < f_kH_ui; ++i, dist_p+=w_ui)
        {
            if ( *dist_p != f_invalid )
            {
                if ( max_d < *dist_p || unset_b )
                    max_d = *dist_p;                
                unset_b = false;                
            }
        }
        
        /// Write first result.
        *max_p = max_d;

        max_p+=wdst_ui;

        for ( unsigned int i = f_kH_ui; i < h_ui; ++i, 
                  dist_p+=w_ui, distL_p+=w_ui, 
                  max_p+=wdst_ui )
        {
            {
                bool isNewValValid_b = (*dist_p != f_invalid);

                if ( isNewValValid_b && max_d == f_invalid )
                    max_d = *dist_p;
                else if ( not isNewValValid_b && max_d == f_invalid )
                    max_d = *dist_p;
                else if ( *dist_p > max_d && isNewValValid_b )
                {
                    /// If the right element is larger than the current maximum then 
                    /// update maximum as the new element.
                    max_d = *dist_p;
                }
                else
                {
                    /// Check if new max is the element which is discarded.
                    if ( max_d == *distL_p )
                    {
                        /// Then search for maximum once again.
                        unset_b = true;
                        max_d = f_invalid;

                        for (_SrcType *d=distL_p+w_ui; d <= dist_p; d+=w_ui)
                            if ( *d != f_invalid )
                            {
                                if (max_d < *d || unset_b )
                                    max_d = *d;
                                unset_b = false;
                            }
                    }
                    else
                    {
                        /// Current maximum is still the maximum.
                    }
                }

                /// Set max.
                *max_p = max_d;
            }
        }
    }

    return true;
}


/* ////////////  Version History ///////////////
 *  $Log: minMaxFilter_inline.h,v $
 *  Revision 1.2  2009/11/18 15:51:01  badino
 *  badino: documentation added. Some other global changes.
 *
 *//////////////////////////////////////////////
