void MutualInformationRegistration::updateRegistration() {
    if(!isReady())
        return;

    convertVolumes();

    //typedef itk::RegularStepGradientDescentOptimizer OptimizerType;
    typedef itk::VersorRigid3DTransformOptimizer OptimizerType;
    typedef OptimizerType::ScalesType       OptimizerScalesType;
    typedef itk::LinearInterpolateImageFunction< InternalImageType, double             > InterpolatorType;
    typedef itk::MattesMutualInformationImageToImageMetric< InternalImageType, InternalImageType >   MetricType;
    typedef itk::MultiResolutionImageRegistrationMethod< InternalImageType, InternalImageType >   RegistrationType;

    typedef itk::MultiResolutionPyramidImageFilter< InternalImageType, InternalImageType >   FixedImagePyramidType;
    typedef itk::MultiResolutionPyramidImageFilter< InternalImageType, InternalImageType >   MovingImagePyramidType;

    OptimizerType::Pointer      optimizer     = OptimizerType::New();
    InterpolatorType::Pointer   interpolator  = InterpolatorType::New();
    RegistrationType::Pointer   registration  = RegistrationType::New();
    MetricType::Pointer         metric        = MetricType::New();

    FixedImagePyramidType::Pointer fixedImagePyramid = FixedImagePyramidType::New();
    MovingImagePyramidType::Pointer movingImagePyramid = MovingImagePyramidType::New();

    registration->SetOptimizer(optimizer);
    registration->SetTransform(transform_);
    registration->SetInterpolator(interpolator);
    registration->SetMetric(metric);
    registration->SetFixedImagePyramid(fixedImagePyramid);
    registration->SetMovingImagePyramid(movingImagePyramid);

    OptimizerScalesType optimizerScales( transform_->GetNumberOfParameters() );

    float rotScale = 1.0 / 1000.0f;
    optimizerScales[0] = 1.0f;
    optimizerScales[1] = 1.0f;
    optimizerScales[2] = 1.0f;
    optimizerScales[3] = rotScale;
    optimizerScales[4] = rotScale;
    optimizerScales[5] = rotScale;
    optimizer->SetScales( optimizerScales );
    optimizer->SetMaximumStepLength(0.2);
    optimizer->SetMinimumStepLength(0.0001);

    InternalImageType::Pointer fixed = voreenToITK<float>(fixedVolumeFloat_);
    InternalImageType::Pointer moving = voreenToITK<float>(movingVolumeFloat_);
    registration->SetFixedImage(fixed);
    registration->SetMovingImage(moving);
    registration->SetFixedImageRegion( fixed->GetBufferedRegion() );

    registration->SetInitialTransformParameters( transform_->GetParameters() );

    metric->SetNumberOfHistogramBins(numHistogramBins_.get());

    size_t numVoxels = hmul(fixedVolumeFloat_->getDimensions());
    metric->SetNumberOfSpatialSamples(numVoxels * numSamples_.get());

    metric->ReinitializeSeed( 76926294 );

    //// Define whether to calculate the metric derivative by explicitly
    //// computing the derivatives of the joint PDF with respect to the Transform
    //// parameters, or doing it by progressively accumulating contributions from
    //// each bin in the joint PDF.
    metric->SetUseExplicitPDFDerivatives(explicitPDF_.get());

    optimizer->SetNumberOfIterations(numIterations_.get());

    optimizer->SetRelaxationFactor(relaxationFactor_.get());

    // Create the Command observer and register it with the optimizer.
    CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();
    optimizer->AddObserver( itk::IterationEvent(), observer );

    typedef RegistrationInterfaceCommand<RegistrationType> CommandType;
    CommandType::Pointer command = CommandType::New();
    registration->AddObserver( itk::IterationEvent(), command );

    registration->SetNumberOfLevels(numLevels_.get());

    try
    {
        registration->StartRegistration();
        std::cout << "Optimizer stop condition: " << registration->GetOptimizer()->GetStopConditionDescription() << std::endl;
    }
    catch( itk::ExceptionObject & err )
    {
        std::cout << "ExceptionObject caught !" << std::endl;
        std::cout << err << std::endl;
        //return EXIT_FAILURE;
    }

    ParametersType finalParameters = registration->GetLastTransformParameters();
    transform_->SetParameters(finalParameters);

    unsigned int numberOfIterations = optimizer->GetCurrentIteration();

    double bestValue = optimizer->GetValue();

    // Print out results
    std::cout << "Result = " << std::endl;
    std::cout << " Versor " << finalParameters[0] << " " << finalParameters[1] << " " << finalParameters[2] << std::endl;
    std::cout << " Translation " << finalParameters[1] << " " << finalParameters[4] << " " << finalParameters[5] << std::endl;
    std::cout << " Iterations    = " << numberOfIterations << std::endl;
    std::cout << " Metric value  = " << bestValue          << std::endl;

    invalidate(INVALID_RESULT);
}
void QAngioSubstractionExtension::computeAutomateSingleImage()
{
    QApplication::setOverrideCursor(Qt::WaitCursor);
    const    unsigned int          Dimension = 2;
    typedef  Volume::ItkPixelType  PixelType;

    typedef itk::Image< PixelType, Dimension >  FixedImageType;
    typedef itk::Image< PixelType, Dimension >  MovingImageType;
    typedef   float     InternalPixelType;
    typedef itk::Image< InternalPixelType, Dimension > InternalImageType;

    typedef itk::TranslationTransform< double, Dimension > TransformType;
    typedef itk::GradientDescentOptimizer                  OptimizerType;
    typedef itk::LinearInterpolateImageFunction< 
                                    InternalImageType,
                                    double             > InterpolatorType;
    typedef itk::ImageRegistrationMethod< 
                                    InternalImageType, 
                                    InternalImageType >  RegistrationType;
    typedef itk::MutualInformationImageToImageMetric< 
                                          InternalImageType, 
                                          InternalImageType >    MetricType;

    TransformType::Pointer      transform     = TransformType::New();
    OptimizerType::Pointer      optimizer     = OptimizerType::New();
    InterpolatorType::Pointer   interpolator  = InterpolatorType::New();
    RegistrationType::Pointer   registration  = RegistrationType::New();

    registration->SetOptimizer(optimizer);
    registration->SetTransform(transform);
    registration->SetInterpolator(interpolator);

    MetricType::Pointer         metric        = MetricType::New();
    registration->SetMetric(metric);
    metric->SetFixedImageStandardDeviation(0.4);
    metric->SetMovingImageStandardDeviation(0.4);
    metric->SetNumberOfSpatialSamples(50);

    typedef itk::ExtractImageFilter< Volume::ItkImageType, FixedImageType > FilterType;
    
    FilterType::Pointer extractFixedImageFilter = FilterType::New();
    Volume::ItkImageType::RegionType inputRegion = m_mainVolume->getItkData()->GetLargestPossibleRegion();
    Volume::ItkImageType::SizeType size = inputRegion.GetSize();
    //Dividim la mida per dos per tal de quedar-nos només amb la part central
    // ja que si no ens registre el background
    size[0] = size[0] / 2;
    size[1] = size[1] / 2;
    size[2] = 0;
    Volume::ItkImageType::IndexType start = inputRegion.GetIndex();
    const unsigned int sliceReference = m_imageSelectorSpinBox->value();
    //comencem a un quart de la imatge
    start[0] = size[0] / 2;
    start[1] = size[1] / 2;
    start[2] = sliceReference;
    Volume::ItkImageType::RegionType desiredRegion;
    desiredRegion.SetSize(size);
    desiredRegion.SetIndex(start);
    extractFixedImageFilter->SetExtractionRegion(desiredRegion);
    extractFixedImageFilter->SetInput(m_mainVolume->getItkData());
    extractFixedImageFilter->Update();

    FilterType::Pointer extractMovingImageFilter = FilterType::New();
    Volume::ItkImageType::IndexType startMoving = inputRegion.GetIndex();
    const unsigned int sliceNumber = m_2DView_1->getViewer()->getCurrentSlice();
    startMoving[0] = size[0] / 2;
    startMoving[1] = size[1] / 2;
    startMoving[2] = sliceNumber;
    Volume::ItkImageType::RegionType desiredMovingRegion;
    desiredMovingRegion.SetSize(size);
    desiredMovingRegion.SetIndex(startMoving);
    extractMovingImageFilter->SetExtractionRegion(desiredMovingRegion);
    extractMovingImageFilter->SetInput(m_mainVolume->getItkData());
    extractMovingImageFilter->Update();

    typedef itk::NormalizeImageFilter< 
                                FixedImageType, 
                                InternalImageType 
                                        > FixedNormalizeFilterType;

    typedef itk::NormalizeImageFilter< 
                                MovingImageType, 
                                InternalImageType 
                                              > MovingNormalizeFilterType;

    FixedNormalizeFilterType::Pointer fixedNormalizer = 
                                            FixedNormalizeFilterType::New();

    MovingNormalizeFilterType::Pointer movingNormalizer =
                                            MovingNormalizeFilterType::New();
    typedef itk::DiscreteGaussianImageFilter<
                                      InternalImageType, 
                                      InternalImageType
                                                    > GaussianFilterType;

    GaussianFilterType::Pointer fixedSmoother  = GaussianFilterType::New();
    GaussianFilterType::Pointer movingSmoother = GaussianFilterType::New();

    fixedSmoother->SetVariance(2.0);
    movingSmoother->SetVariance(2.0);
    fixedNormalizer->SetInput(extractFixedImageFilter->GetOutput());
    movingNormalizer->SetInput(extractMovingImageFilter->GetOutput());

    fixedSmoother->SetInput(fixedNormalizer->GetOutput());
    movingSmoother->SetInput(movingNormalizer->GetOutput());

    registration->SetFixedImage(fixedSmoother->GetOutput());
    registration->SetMovingImage(movingSmoother->GetOutput());

    fixedNormalizer->Update();
    registration->SetFixedImageRegion(
       fixedNormalizer->GetOutput()->GetBufferedRegion());

    typedef RegistrationType::ParametersType ParametersType;
    ParametersType initialParameters(transform->GetNumberOfParameters());

    initialParameters[0] = 0.0;  // Initial offset in mm along X
    initialParameters[1] = 0.0;  // Initial offset in mm along Y

    registration->SetInitialTransformParameters(initialParameters);

    optimizer->SetLearningRate(20.0);
    optimizer->SetNumberOfIterations(200);
    optimizer->MaximizeOn();

    try 
    { 
        registration->Update();
    } 
    catch(itk::ExceptionObject & err) 
    { 
        std::cout << "ExceptionObject caught !" << std::endl; 
        std::cout << err << std::endl; 
        return;
    } 

    ParametersType finalParameters = registration->GetLastTransformParameters();

    double TranslationAlongX = finalParameters[0];
    double TranslationAlongY = finalParameters[1];

    // Print out results
    //
    DEBUG_LOG(QString("Result = "));
    DEBUG_LOG(QString(" Translation X = %1").arg(TranslationAlongX));
    DEBUG_LOG(QString(" Translation Y = %1").arg(TranslationAlongY));
    DEBUG_LOG(QString(" Iterations    = %1").arg(optimizer->GetCurrentIteration()));
    DEBUG_LOG(QString(" Metric value  = %1").arg(optimizer->GetValue()));
    double spacing[3];
    m_mainVolume->getSpacing(spacing);
    DEBUG_LOG(QString(" Translation X (in px) = %1").arg(TranslationAlongX / spacing[0]));
    DEBUG_LOG(QString(" Translation Y (in px) = %1").arg(TranslationAlongY / spacing[1]));

    //Actualitzem les dades de la transdifference tool
    m_toolManager->triggerTool("TransDifferenceTool");
    TransDifferenceTool* tdTool = static_cast<TransDifferenceTool*> (m_2DView_2->getViewer()->getToolProxy()->getTool("TransDifferenceTool"));
    if(m_tdToolData == 0){
        m_tdToolData = static_cast<TransDifferenceToolData*> (tdTool->getToolData());
    }
    if(m_tdToolData->getInputVolume() != m_mainVolume){
        m_tdToolData->setInputVolume(m_mainVolume);
    }
    tdTool->setSingleDifferenceImage(TranslationAlongX / spacing[0],TranslationAlongY / spacing[1]);
    m_toolManager->triggerTool("SlicingTool");
    

/*    typedef itk::Image< PixelType, Dimension >  FixedImageType;
    typedef itk::Image< PixelType, Dimension >  MovingImageType;
    typedef itk::TranslationTransform< double, Dimension > TransformType;
    typedef itk::RegularStepGradientDescentOptimizer       OptimizerType;
    typedef itk::MattesMutualInformationImageToImageMetric< 
                                          FixedImageType, 
                                          MovingImageType >    MetricType;
    typedef itk:: LinearInterpolateImageFunction< 
                                    MovingImageType,
                                    double          >    InterpolatorType;
    typedef itk::ImageRegistrationMethod< 
                                    FixedImageType, 
                                    MovingImageType >    RegistrationType;

    MetricType::Pointer         metric        = MetricType::New();
    TransformType::Pointer      transform     = TransformType::New();
    OptimizerType::Pointer      optimizer     = OptimizerType::New();
    InterpolatorType::Pointer   interpolator  = InterpolatorType::New();
    RegistrationType::Pointer   registration  = RegistrationType::New();

    registration->SetMetric(metric);
    registration->SetOptimizer(optimizer);
    registration->SetTransform(transform);
    registration->SetInterpolator(interpolator);

    metric->SetNumberOfHistogramBins(50);
    metric->SetNumberOfSpatialSamples(10000);

    typedef itk::ExtractImageFilter< Volume::ItkImageType, FixedImageType > FilterType;
    
    FilterType::Pointer extractFixedImageFilter = FilterType::New();
    Volume::ItkImageType::RegionType inputRegion = m_mainVolume->getItkData()->GetLargestPossibleRegion();
    Volume::ItkImageType::SizeType size = inputRegion.GetSize();
    //Dividim la mida per dos per tal de quedar-nos només amb la part central
    // ja que si no ens registre el background
    size[0] = size[0] / 2;
    size[1] = size[1] / 2;
    size[2] = 0;
    Volume::ItkImageType::IndexType start = inputRegion.GetIndex();
    const unsigned int sliceReference = m_imageSelectorSpinBox->value();
    //comencem a un quart de la imatge
    start[0] = size[0] / 2;
    start[1] = size[1] / 2;
    start[2] = sliceReference;
    Volume::ItkImageType::RegionType desiredRegion;
    desiredRegion.SetSize(size);
    desiredRegion.SetIndex(start);
    extractFixedImageFilter->SetExtractionRegion(desiredRegion);
    extractFixedImageFilter->SetInput(m_mainVolume->getItkData());
    extractFixedImageFilter->Update();

    FilterType::Pointer extractMovingImageFilter = FilterType::New();
    Volume::ItkImageType::IndexType startMoving = inputRegion.GetIndex();
    const unsigned int sliceNumber = m_2DView_1->getViewer()->getCurrentSlice();
    startMoving[0] = size[0] / 2;
    startMoving[1] = size[1] / 2;
    startMoving[2] = sliceNumber;
    Volume::ItkImageType::RegionType desiredMovingRegion;
    desiredMovingRegion.SetSize(size);
    desiredMovingRegion.SetIndex(startMoving);
    extractMovingImageFilter->SetExtractionRegion(desiredMovingRegion);
    extractMovingImageFilter->SetInput(m_mainVolume->getItkData());
    extractMovingImageFilter->Update();

    registration->SetFixedImage(extractFixedImageFilter->GetOutput());
    registration->SetMovingImage(extractMovingImageFilter->GetOutput());

    typedef RegistrationType::ParametersType ParametersType;
    ParametersType initialParameters(transform->GetNumberOfParameters());

    //Potser seria millor posar la transformada que té actualment
    initialParameters[0] = 0.0;  // Initial offset in mm along X
    initialParameters[1] = 0.0;  // Initial offset in mm along Y

    registration->SetInitialTransformParameters(initialParameters);

    optimizer->SetMaximumStepLength(4.00);  
    optimizer->SetMinimumStepLength(0.005);

    optimizer->SetNumberOfIterations(200);

    try 
    { 
        registration->StartRegistration(); 
    } 
    catch(itk::ExceptionObject & err) 
    { 
        DEBUG_LOG(QString("ExceptionObject caught !"));
        std::cout<<err<<std::endl;
        return;
    } 
    ParametersType finalParameters = registration->GetLastTransformParameters();

    const double TranslationAlongX = finalParameters[0];
    const double TranslationAlongY = finalParameters[1];

    const unsigned int numberOfIterations = optimizer->GetCurrentIteration();

    const double bestValue = optimizer->GetValue();

    DEBUG_LOG(QString("Result = "));
    DEBUG_LOG(QString(" Translation X = %1").arg(TranslationAlongX));
    DEBUG_LOG(QString(" Translation Y = %1").arg(TranslationAlongY));
    DEBUG_LOG(QString(" Iterations    = %1").arg(numberOfIterations));
    DEBUG_LOG(QString(" Metric value  = %1").arg(bestValue));

    typedef  unsigned char  OutputPixelType;
    typedef itk::Image< OutputPixelType, Dimension > OutputImageType;
    typedef itk::RescaleIntensityImageFilter< FixedImageType, FixedImageType > RescaleFilterType;
    typedef itk::ResampleImageFilter< 
                            FixedImageType, 
                            FixedImageType >    ResampleFilterType;
    typedef itk::CastImageFilter< 
                        FixedImageType,
                        OutputImageType > CastFilterType;
    typedef itk::ImageFileWriter< OutputImageType >  WriterType;

    WriterType::Pointer      writer =  WriterType::New();
    CastFilterType::Pointer  caster =  CastFilterType::New();
    ResampleFilterType::Pointer resample = ResampleFilterType::New();
    RescaleFilterType::Pointer rescaler = RescaleFilterType::New();

    rescaler->SetOutputMinimum(0);
    rescaler->SetOutputMaximum(255);

    TransformType::Pointer finalTransform = TransformType::New();
    finalTransform->SetParameters(finalParameters);
    resample->SetTransform(finalTransform);
    resample->SetSize(extractMovingImageFilter->GetOutput()->GetLargestPossibleRegion().GetSize());
    resample->SetOutputOrigin(extractMovingImageFilter->GetOutput()->GetOrigin());
    resample->SetOutputSpacing(extractMovingImageFilter->GetOutput()->GetSpacing());
    resample->SetDefaultPixelValue(100);

    writer->SetFileName("prova.jpg");

    rescaler->SetInput(extractMovingImageFilter->GetOutput());
    resample->SetInput(rescaler->GetOutput());
    caster->SetInput(resample->GetOutput());
    writer->SetInput(caster->GetOutput());
    writer->Update();
*/

    QApplication::restoreOverrideCursor();

}