/*=========================================================================
*
*  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 sitkCannySegmentationLevelSetImageFilter_h
#define sitkCannySegmentationLevelSetImageFilter_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 CannySegmentationLevelSetImageFilter
\brief Segments structures in images based on image features derived from pseudo-canny-edges.

\par IMPORTANT
The SegmentationLevelSetImageFilter class and the CannySegmentationLevelSetFunction 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 designed to lock onto edges as detected by a Canny filter.


\par 
The CannySegmentationLevelSetImageFilter can be a tool for refining an existing segmentation, or it can be used to try to segment a region by itself. Like all other level-set based segmentation filters (see SegmentationLevelSetImageFilter ), it works by first constructing a scalar speed term and a vector advection field based on edge features in the image. The level set front is then moved according to these two terms with the addition of a third curvature term to control the smoothness of the solution.


\par 
The speed term is constructed as the Danielsson distance transform of the Canny edge image, as calculated by the CannyEdgeDetectionImageFilter . This scalar speed can be tuned in and out of the final evolution equation by setting the PropagationScaling parameter (a value of 0 removes the speed term).


\par 
The advection field term is constructed by minimizing Danielsson distance squared. i.e. \f$ \mbox{min} \int D^2 \Rightarrow D \nabla D \f$ . This term moves the level set down the gradient of the distance transform.


\par 
In practice, you may set the speed (propagation) term to zero if your initialization is already close to the edge you are interested in. If you are trying to segment a region by seeding with a small surface (blob, sphere) then you will likely want to add speed (propagation) to the equation so that the levelsets can expand along zero gradients. The relative influence of these two terms are controlled by the SetPropagationScaling and SetAdvectionScaling parameters.


\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.


\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
There are five parameters important for controlling the behavior of this filter. 


\par 
(1) Threshold. Sets the thresholding value of the Canny edge detection. See CannyEdgeDetectionImageFilter for more information. 


\par 
(2) Variance. Controls the smoothing parameter of the gaussian filtering done during Canny edge detection. 


\par 
(3) CurvatureScaling. Controls the degree to which curvature influences the evolution of the level set. Higher values relative to Propagation and Advection scalings will yield a smoother surface. 


\par 
(4) PropagationScaling. Scales the propagation (speed) term of the level set equation. Set this term to zero to allow the level set to flow only down the gradient of the distance transform. 


\par 
(5) AdvectionScaling. Scales influence of the advection field relative to curvature and propagation terms.


\see SegmentationLevelSetImageFilter 


\see CannySegmentationLevelSetFunction , 


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

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

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

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

      /**
       * Set the Threshold parameter of the CannyEdgeDetectionImageFilter used by the underlying level set function.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetThreshold ( double Threshold ) { this->m_Threshold = Threshold; return *this; }

      /**
       * Set the Threshold parameter of the CannyEdgeDetectionImageFilter used by the underlying level set function.
       */
      double GetThreshold() const { return this->m_Threshold; }\

      /**
       * Set the Variance parameter of the CannyEdgeDetectionImageFilter used by the underlying level set function.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetVariance ( double Variance ) { this->m_Variance = Variance; return *this; }

      /**
       * Set the Variance parameter of the CannyEdgeDetectionImageFilter used by the underlying level set function.
       */
      double GetVariance() const { return this->m_Variance; }\

      /**
       */
      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 SetAdvectionScaling ( double AdvectionScaling ) { this->m_AdvectionScaling = AdvectionScaling; return *this; }

      /**
       */
      double GetAdvectionScaling() const { return this->m_AdvectionScaling; }\

      /**
       */
      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; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetIsoSurfaceValue ( double IsoSurfaceValue ) { this->m_IsoSurfaceValue = IsoSurfaceValue; return *this; }

      /**
       */
      double GetIsoSurfaceValue() const { return this->m_IsoSurfaceValue; }
     /** \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; };

     /**
      * Get the Canny image that was used to create the speed and advection images
      *
      * This is a measurement. Its value is updated in the Execute
      * methods, so the value will only be valid after an execution.
      */
     Image GetCannyImage() const { return this->m_CannyImage; };


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

      /** 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;


      double  m_Threshold{0.0};

      double  m_Variance{0.0};

      /* 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};

      /* Weight of the advection contribution to the speed term */
      double  m_AdvectionScaling{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};

      /*  */
      double  m_IsoSurfaceValue{0.0};


      uint32_t m_ElapsedIterations{0};

      double m_RMSChange{0.0};

      Image m_CannyImage{Image()};


      bool m_InPlace{false};
    };

    /**\
     * \brief Segments structures in images based on image features derived from pseudo-canny-edges.
     *
     * This function directly calls the execute method of CannySegmentationLevelSetImageFilter
     * in order to support a procedural API
     *
     * \sa itk::simple::CannySegmentationLevelSetImageFilter for the object oriented interface
     * @{
     */
#ifndef SWIG
     SITKBasicFilters_EXPORT Image CannySegmentationLevelSet ( Image && initialImage, const Image & featureImage, double threshold = 0.0, double variance = 0.0, double maximumRMSError = 0.02, double propagationScaling = 1.0, double curvatureScaling = 1.0, double advectionScaling = 1.0, uint32_t numberOfIterations = 1000u, bool reverseExpansionDirection = false, double isoSurfaceValue = 0.0 );
#endif
     SITKBasicFilters_EXPORT Image CannySegmentationLevelSet ( const Image & initialImage, const Image & featureImage, double threshold = 0.0, double variance = 0.0, double maximumRMSError = 0.02, double propagationScaling = 1.0, double curvatureScaling = 1.0, double advectionScaling = 1.0, uint32_t numberOfIterations = 1000u, bool reverseExpansionDirection = false, double isoSurfaceValue = 0.0 );

     /** @} */
}
#endif
