/*=========================================================================
*
*  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 sitkSLICImageFilter_h
#define sitkSLICImageFilter_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 SLICImageFilter
\brief Simple Linear Iterative Clustering (SLIC) super-pixel segmentation.

The Simple Linear Iterative Clustering (SLIC) algorithm groups pixels into a set of labeled regions or super-pixels. Super-pixels follow natural image boundaries, are compact, and are nearly uniform regions which can be used as a larger primitive for more efficient computation. The SLIC algorithm can be viewed as a spatially constrained iterative k-means method.

The original algorithm was designed to cluster on the joint domain of the images index space and its CIELAB color space. This implementation works with images of arbitrary dimension as well as scalar, single channel, images and most multi-component image types including ITK's arbitrary length VectorImage .

The distance between a pixel and a cluster is the sum of squares of the difference between their joint range and domains ( index and value ). The computation is done in index space with scales provided by the SpatialProximityWeight parameters.

The output is a label image with each label representing a superpixel cluster. Every pixel in the output is labeled, and the starting label id is zero.

This code was contributed in the Insight Journal paper: "Scalable Simple Linear Iterative Clustering (SSLIC) Using a
Generic and Parallel Approach" by Lowekamp B. C., Chen D. T., Yaniv Z., Yoo T. S. https://doi.org/10.54294/8hic7f
\sa itk::simple::SLIC for the procedural interface
\sa itk::SLICImageFilter for the Doxygen on the original ITK class.
     */
    class SITKBasicFilters_EXPORT SLICImageFilter : public ImageFilter {
    public:
      using Self = SLICImageFilter;

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

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

      /** Define the pixels types supported by this filter */
      using PixelIDTypeList = typelist2::append<BasicPixelIDTypeList, VectorPixelIDTypeList>::type;
\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetSuperGridSize ( std::vector<unsigned int> SuperGridSize ) { this->m_SuperGridSize = std::move(SuperGridSize); return *this; }

      /**
       */
      std::vector<unsigned int> GetSuperGridSize() const { return this->m_SuperGridSize; }\

      /**
       * \brief The spatial weight for the distance function.
       * Increasing this value makes the superpixel shape more regular, but more varied in image values. The range of the pixel values and image dimension can effect the appropriate value.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetSpatialProximityWeight ( double SpatialProximityWeight ) { this->m_SpatialProximityWeight = SpatialProximityWeight; return *this; }

      /**
       */
      double GetSpatialProximityWeight() const { return this->m_SpatialProximityWeight; }\

      /**
       * \brief Number of iterations to run.
       * Specify the number of iterations to run when optimizing the clusters.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetMaximumNumberOfIterations ( uint32_t MaximumNumberOfIterations ) { this->m_MaximumNumberOfIterations = MaximumNumberOfIterations; return *this; }

      /**
       */
      uint32_t GetMaximumNumberOfIterations() const { return this->m_MaximumNumberOfIterations; }\

      /**
       * \brief Post processing step to enforce superpixel morphology.
       * Enable an additional computation which ensures all label pixels of the same value are spatially connected. Disconnected labeled components are assigned a new value if of sufficient size, or are relabeled to the previously encountered value if small.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetEnforceConnectivity ( bool EnforceConnectivity ) { this->m_EnforceConnectivity = EnforceConnectivity; return *this; }

      /** Set the value of EnforceConnectivity to true or false respectfully. */
      SITK_RETURN_SELF_TYPE_HEADER EnforceConnectivityOn() { return this->SetEnforceConnectivity(true); }
      SITK_RETURN_SELF_TYPE_HEADER EnforceConnectivityOff() { return this->SetEnforceConnectivity(false); }

      /**
       */
      bool GetEnforceConnectivity() const { return this->m_EnforceConnectivity; }\

      /**
       * \brief Enable perturbation of initial cluster center location.
       * After grid based initialization, this option enables moving the initial cluster center location to the minimum gradient in a small neighborhood. If the grid size is less than three this is automatically disabled.
       */
      SITK_RETURN_SELF_TYPE_HEADER SetInitializationPerturbation ( bool InitializationPerturbation ) { this->m_InitializationPerturbation = InitializationPerturbation; return *this; }

      /** Set the value of InitializationPerturbation to true or false respectfully. */
      SITK_RETURN_SELF_TYPE_HEADER InitializationPerturbationOn() { return this->SetInitializationPerturbation(true); }
      SITK_RETURN_SELF_TYPE_HEADER InitializationPerturbationOff() { return this->SetInitializationPerturbation(false); }

      /**
       */
      bool GetInitializationPerturbation() const { return this->m_InitializationPerturbation; }
     /** \brief Get the current average cluster residual.
      * After each iteration the residual is computed as the distance between the current clusters and the previous. This is averaged so that the value is independent of the number of clusters.
      *
      * This is an active measurement. It may be accessed while the
      * filter is being executing in command call-backs and can be
      * accessed after execution.
      */
     double GetAverageResidual() const { return this->m_pfGetAverageResidual(); };


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

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


      /** Execute the filter on the input image */

      Image Execute ( const Image& image1 );

    private:

      /** Setup for member function dispatching */

      using MemberFunctionType = Image (Self::*)( const Image& image1 );
      template <class TImageType> Image ExecuteInternal ( const Image& image1 );


      friend struct detail::MemberFunctionAddressor<MemberFunctionType>;

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


      /*  */
      std::vector<unsigned int>  m_SuperGridSize{std::vector<unsigned int>(3, 50)};

      double  m_SpatialProximityWeight{10.0};

      /* Number of iterations to run */
      uint32_t  m_MaximumNumberOfIterations{5u};

      bool  m_EnforceConnectivity{true};

      bool  m_InitializationPerturbation{true};


      std::function<double()> m_pfGetAverageResidual;

      // Holder of process object for active measurements
      itk::ProcessObject *m_Filter{nullptr};

    };

    /**\
     * \brief Simple Linear Iterative Clustering (SLIC) super-pixel segmentation.
     *
     * This function directly calls the execute method of SLICImageFilter
     * in order to support a procedural API
     *
     * \sa itk::simple::SLICImageFilter for the object oriented interface
     * @{
     */

     SITKBasicFilters_EXPORT Image SLIC ( const Image& image1, std::vector<unsigned int> superGridSize = std::vector<unsigned int>(3, 50), double spatialProximityWeight = 10.0, uint32_t maximumNumberOfIterations = 5u, bool enforceConnectivity = true, bool initializationPerturbation = true );

     /** @} */
}
#endif
