/*=========================================================================
*
*  Copyright NumFOCUS
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0.txt
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*=========================================================================*/
#ifndef sitkLaplacianSegmentationLevelSetImageFilter_h
#define sitkLaplacianSegmentationLevelSetImageFilter_h

/*
 * WARNING: DO NOT EDIT THIS FILE!
 * THIS FILE IS AUTOMATICALLY GENERATED BY THE SIMPLEITK BUILD PROCESS.
 * Please look at sitkImageFilterTemplate.h.in to make changes.
 */

#include <memory>

#include "sitkBasicFilters.h"
#include "sitkImageFilter.h"

namespace itk::simple {

    /**\class LaplacianSegmentationLevelSetImageFilter
\brief Segments structures in images based on a second derivative image features.

\par IMPORTANT
The SegmentationLevelSetImageFilter class and the LaplacianSegmentationLevelSetFunction class contain additional information necessary to the full understanding of how to use this filter.


\par OVERVIEW
This class is a level set method segmentation filter. It constructs a speed function which is zero at image edges as detected by a Laplacian filter. The evolving level set front will therefore tend to lock onto zero crossings in the image. The level set front moves fastest near edges.


\par 
The Laplacian segmentation filter is intended primarily as a tool for refining existing segmentations. The initial isosurface (as given in the seed input image) should ideally be very close to the segmentation boundary of interest. The idea is that a rough segmentation can be refined by allowing the isosurface to deform slightly to achieve a better fit to the edge features of an image. One example of such an application is to refine the output of a hand segmented image.


\par 
Because values in the Laplacian feature image will tend to be low except near edge features, this filter is not effective for segmenting large image regions from small seed surfaces.


\par INPUTS
This filter requires two inputs. The first input is a seed image. This seed image must contain an isosurface that you want to use as the seed for your segmentation. It can be a binary, graylevel, or floating point image. The only requirement is that it contain a closed isosurface that you will identify as the seed by setting the IsosurfaceValue parameter of the filter. For a binary image you will want to set your isosurface value halfway between your on and off values (i.e. for 0's and 1's, use an isosurface value of 0.5).


\par 
The second input is the feature image. This is the image from which the speed function will be calculated. For most applications, this is the image that you want to segment. The desired isosurface in your seed image should lie within the region of your feature image that you are trying to segment.


Note that this filter does no preprocessing of the feature image before thresholding. Because second derivative calculations are highly sensitive to noise, isotropic or anisotropic smoothing of the feature image can dramatically improve the results.

\par 
See SegmentationLevelSetImageFilter for more information on Inputs.


\par OUTPUTS
The filter outputs a single, scalar, real-valued image. Positive *values in the output image are inside the segmented region and negative *values in the image are outside of the inside region. The zero crossings of *the image correspond to the position of the level set front.


\par 
See SparseFieldLevelSetImageFilter and SegmentationLevelSetImageFilter for more information.


\par PARAMETERS
This filter has no parameters other than those described in SegmentationLevelSetImageFilter .


\see SegmentationLevelSetImageFilter 


\see LaplacianSegmentationLevelSetFunction , 


\see SparseFieldLevelSetImageFilter
\sa itk::simple::LaplacianSegmentationLevelSet for the procedural interface
\sa itk::LaplacianSegmentationLevelSetImageFilter for the Doxygen on the original ITK class.
     */
    class SITKBasicFilters_EXPORT LaplacianSegmentationLevelSetImageFilter : public ImageFilter {
    public:
      using Self = LaplacianSegmentationLevelSetImageFilter;

      /** Destructor */
      virtual ~LaplacianSegmentationLevelSetImageFilter();

      /** Default Constructor that takes no arguments and initializes
       * default parameters */
      LaplacianSegmentationLevelSetImageFilter();

      /** Define the pixels types supported by this filter */
      using PixelIDTypeList = RealPixelIDTypeList;
\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetMaximumRMSError ( double MaximumRMSError ) { this->m_MaximumRMSError = MaximumRMSError; return *this; }

      /**
       */
      double GetMaximumRMSError() const { return this->m_MaximumRMSError; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetPropagationScaling ( double PropagationScaling ) { this->m_PropagationScaling = PropagationScaling; return *this; }

      /**
       */
      double GetPropagationScaling() const { return this->m_PropagationScaling; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetCurvatureScaling ( double CurvatureScaling ) { this->m_CurvatureScaling = CurvatureScaling; return *this; }

      /**
       */
      double GetCurvatureScaling() const { return this->m_CurvatureScaling; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetNumberOfIterations ( uint32_t NumberOfIterations ) { this->m_NumberOfIterations = NumberOfIterations; return *this; }

      /**
       */
      uint32_t GetNumberOfIterations() const { return this->m_NumberOfIterations; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetReverseExpansionDirection ( bool ReverseExpansionDirection ) { this->m_ReverseExpansionDirection = ReverseExpansionDirection; return *this; }

      /** Set the value of ReverseExpansionDirection to true or false respectfully. */
      SITK_RETURN_SELF_TYPE_HEADER ReverseExpansionDirectionOn() { return this->SetReverseExpansionDirection(true); }
      SITK_RETURN_SELF_TYPE_HEADER ReverseExpansionDirectionOff() { return this->SetReverseExpansionDirection(false); }

      /**
       */
      bool GetReverseExpansionDirection() const { return this->m_ReverseExpansionDirection; }
     /** \brief Number of iterations run.
      *
      *
      * This is a measurement. Its value is updated in the Execute
      * methods, so the value will only be valid after an execution.
      */
     uint32_t GetElapsedIterations() const { return this->m_ElapsedIterations; };

     /** \brief The Root Mean Square of the levelset upon termination.
      *
      *
      * This is a measurement. Its value is updated in the Execute
      * methods, so the value will only be valid after an execution.
      */
     double GetRMSChange() const { return this->m_RMSChange; };


      /** Name of this class */
      std::string GetName() const { return std::string ("LaplacianSegmentationLevelSetImageFilter"); }

      /** Print ourselves out */
      std::string ToString() const;


      /** Execute the filter on the input image */
#ifndef SWIG
      Image Execute ( Image && initialImage, const Image & featureImage );
#endif
      Image Execute ( const Image & initialImage, const Image & featureImage );

    private:

      /** Setup for member function dispatching */

      using MemberFunctionType = Image (Self::*)( const Image * initialImage, const Image * featureImage );
      template <class TImageType> Image ExecuteInternal ( const Image * initialImage, const Image * featureImage );


      friend struct detail::MemberFunctionAddressor<MemberFunctionType>;

      std::unique_ptr<detail::MemberFunctionFactory<MemberFunctionType> > m_MemberFactory;


      /* Value of RMS change below which the filter should stop. This is a convergence criterion. */
      double  m_MaximumRMSError{0.02};

      /* Weight of direct propagation contribution to the speed term */
      double  m_PropagationScaling{1.0};

      /* Weight of the curvature contribution to the speed term */
      double  m_CurvatureScaling{1.0};

      /* Number of iterations to run */
      uint32_t  m_NumberOfIterations{1000u};

      /* Turn On/Off the flag which determines whether Positive or Negative speed terms will cause surface expansion.  If set to TRUE then negative speed terms will cause the surface to expand and positive speed terms will cause the surface to contract.  If set to FALSE (default) then positive speed terms will cause the surface to expand and negative speed terms will cause the surface to contract.  This method can be safely used to reverse the expansion/contraction as appropriate to a particular application or data set. */
      bool  m_ReverseExpansionDirection{false};


      uint32_t m_ElapsedIterations{0};

      double m_RMSChange{0.0};


      bool m_InPlace{false};
    };

    /**\
     * \brief Segments structures in images based on a second derivative image features.
     *
     * This function directly calls the execute method of LaplacianSegmentationLevelSetImageFilter
     * in order to support a procedural API
     *
     * \sa itk::simple::LaplacianSegmentationLevelSetImageFilter for the object oriented interface
     * @{
     */
#ifndef SWIG
     SITKBasicFilters_EXPORT Image LaplacianSegmentationLevelSet ( Image && initialImage, const Image & featureImage, double maximumRMSError = 0.02, double propagationScaling = 1.0, double curvatureScaling = 1.0, uint32_t numberOfIterations = 1000u, bool reverseExpansionDirection = false );
#endif
     SITKBasicFilters_EXPORT Image LaplacianSegmentationLevelSet ( const Image & initialImage, const Image & featureImage, double maximumRMSError = 0.02, double propagationScaling = 1.0, double curvatureScaling = 1.0, uint32_t numberOfIterations = 1000u, bool reverseExpansionDirection = false );

     /** @} */
}
#endif
