/*======================================================================

  This file is part of the elastix software.

  Copyright (c) University Medical Center Utrecht. All rights reserved.
  See src/CopyrightElastix.txt or http://elastix.isi.uu.nl/legal.php for
  details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE. See the above copyright notices for more information.

======================================================================*/

#ifndef __elxViolaWellsMutualInformationMetric_H__
#define __elxViolaWellsMutualInformationMetric_H__

#include "elxIncludes.h"
#include "itkMutualInformationImageToImageMetric.h"

#include "elxTimer.h"

namespace elastix
{
using namespace itk;

  /**
   * \class ViolaWellsMutualInformationMetric
   * \brief A metric based on the itk::MutualInformationImageToImageMetric.
   *
   * \warning: this metric is not very well tested in elastix.
   * \warning: this metric is not based on the AdvancedImageToImageMetric so
   * does not support the ImageSampler framework and might be very slow in
   * combination with B-spline transform.
   * \warning: this metric uses stochastic sampling of the images. Do not use
   * a quasi-Newton optimizer or a conjugate gradient. The StandardGradientDescent
   * is a better choice.
   *
   * The parameters used in this class are:
   * \parameter Metric: Select this metric as follows:\n
   *    <tt>(Metric "ViolaWellsMutualInformation")</tt>
   * \parameter NumberOfSpatialSamples: for each resolution the number of samples
   *    used to calculate this metrics value and its derivative. \n
   *    example: <tt>(NumberOfSpatialSamples 5000 5000 10000)</tt> \n
   *    The default is 10000 for each resolution.
   * \parameter FixedImageStandardDeviation: for each resolution the standard
   *    deviation of the fixed image. \n
   *    example: <tt>(FixedImageStandardDeviation 1.3 1.9 1.0)</tt> \n
   *    The default is 0.4 for each resolution.
   * \parameter MovingImageStandardDeviation: for each resolution the standard
   *    deviation of the moving image. \n
   *    example: <tt>(MovingImageStandardDeviation 1.3 1.9 1.0)</tt> \n
   *    The default is 0.4 for each resolution.
   *
   * \sa MutualInformationImageToImageMetric
   * \ingroup Metrics
   */

  template <class TElastix >
    class ViolaWellsMutualInformationMetric :
    public
      MutualInformationImageToImageMetric<
        ITK_TYPENAME MetricBase<TElastix>::FixedImageType,
        ITK_TYPENAME MetricBase<TElastix>::MovingImageType >,
    public MetricBase<TElastix>
  {
  public:

    /** Standard ITK-stuff. */
    typedef ViolaWellsMutualInformationMetric             Self;
    typedef MutualInformationImageToImageMetric<
      typename MetricBase<TElastix>::FixedImageType,
      typename MetricBase<TElastix>::MovingImageType >    Superclass1;
    typedef MetricBase<TElastix>                          Superclass2;
    typedef SmartPointer<Self>                            Pointer;
    typedef SmartPointer<const Self>                      ConstPointer;

    /** Method for creation through the object factory. */
    itkNewMacro( Self );

    /** Run-time type information (and related methods). */
    itkTypeMacro( ViolaWellsMutualInformationMetric,
      MutualInformationImageToImageMetric );

    /** Name of this class.
     * Use this name in the parameter file to select this specific metric. \n
     * example: <tt>(Metric "ViolaWellsMutualInformation")</tt>\n
     */
    elxClassNameMacro( "ViolaWellsMutualInformation" );

    /** Typedefs inherited from the superclass. */
    typedef typename Superclass1::TransformType             TransformType;
    typedef typename Superclass1::TransformPointer          TransformPointer;
    typedef typename Superclass1::TransformJacobianType     TransformJacobianType;
    typedef typename Superclass1::InterpolatorType          InterpolatorType;
    typedef typename Superclass1::MeasureType               MeasureType;
    typedef typename Superclass1::DerivativeType            DerivativeType;
    typedef typename Superclass1::ParametersType            ParametersType;
    typedef typename Superclass1::FixedImageType            FixedImageType;
    typedef typename Superclass1::MovingImageType           MovingImageType;
    typedef typename Superclass1::FixedImageConstPointer    FixedImageConstPointer;
    typedef typename Superclass1::MovingImageConstPointer   MovingImageCosntPointer;
    typedef typename Superclass1::FixedImageIndexType       FixedImageIndexType;
    typedef typename Superclass1::FixedImageIndexValueType  FixedImageIndexValueType;
    typedef typename Superclass1::MovingImageIndexType      MovingImageIndexType;
    typedef typename Superclass1::FixedImagePointType       FixedImagePointType;
    typedef typename Superclass1::MovingImagePointType      MovingImagePointType;

    /** The moving image dimension. */
    itkStaticConstMacro( MovingImageDimension, unsigned int,
      MovingImageType::ImageDimension );

    /** Typedef's inherited from Elastix. */
    typedef typename Superclass2::ElastixType           ElastixType;
    typedef typename Superclass2::ElastixPointer        ElastixPointer;
    typedef typename Superclass2::ConfigurationType     ConfigurationType;
    typedef typename Superclass2::ConfigurationPointer  ConfigurationPointer;
    typedef typename Superclass2::RegistrationType      RegistrationType;
    typedef typename Superclass2::RegistrationPointer   RegistrationPointer;
    typedef typename Superclass2::ITKBaseType           ITKBaseType;

    /** Typedef's for timer. */
    typedef tmr::Timer          TimerType;
    typedef TimerType::Pointer  TimerPointer;

    /** Execute stuff before each new pyramid resolution:
     * \li Set the number of spatial samples.
     * \li Set the standard deviation of the fixed image.
     * \li Set the standard deviation of the moving image.
     */
    virtual void BeforeEachResolution(void);

    /** Sets up a timer to measure the intialisation time and
     * calls the Superclass' implementation.
     */
    virtual void Initialize(void) throw (ExceptionObject);

  protected:

    /** The constructor. */
    ViolaWellsMutualInformationMetric();
    /** The destructor. */
    virtual ~ViolaWellsMutualInformationMetric() {}

  private:

    /** The private constructor. */
    ViolaWellsMutualInformationMetric( const Self& ); // purposely not implemented
    /** The private copy constructor. */
    void operator=( const Self& );                    // purposely not implemented

  }; // end class ViolaWellsMutualInformationMetric


} // end namespace elastix


#ifndef ITK_MANUAL_INSTANTIATION
#include "elxViolaWellsMutualInformationMetric.hxx"
#endif

#endif // end #ifndef __elxViolaWellsMutualInformationMetric_H__
