Ejemplo n.º 1
0
ImageType::Pointer SBImageUtils::ResizeImage(ImageType::Pointer input, uint width, uint height)
{
	ResampleImageFilterType::Pointer resample = ResampleImageFilterType::New();
	
	ImageType::SizeType outputSize;
	outputSize.Fill(width);
	
	ImageType::SizeType inputSize = input->GetLargestPossibleRegion().GetSize();
	
	ImageType::SpacingType outputSpacing;
	outputSpacing[0] = input->GetSpacing()[0] * (static_cast<double>(inputSize[0]) / static_cast<double>(outputSize[0]));
	outputSpacing[1] = input->GetSpacing()[1] * (static_cast<double>(inputSize[1]) / static_cast<double>(outputSize[1]));
	
	//default will be white
	resample->SetDefaultPixelValue(0xFFFF);
	
	resample->SetInput(input);
	resample->SetSize(outputSize);
	resample->SetOutputSpacing(outputSpacing);
	resample->SetTransform(TransformType::New());
	resample->UpdateLargestPossibleRegion();
	
	return resample->GetOutput();
}
Ejemplo n.º 2
0
void ImageScaleTransform::process()
    {
    foreach (const ElementBase *source, mSourceElementsReadySet)
        for (int i = 0; i < source->getFramesNo(); ++i)
            {
            const FrameBase *frame = source->getFrame(i);
            if (frame->getMaxDimension() == ColorImageFrame::Dimensions)
                {
                mImageFrame.setSourceName(frame->getSourceName());
                mSrcFrame.resizeAndCopyFrame(*frame);
                ColorImageFrame::ImageType::Pointer srcImg = mSrcFrame;

                typedef ScaleTransform<double, 2> TransformType;
                TransformType::Pointer scaleTransform = TransformType::New();
                FixedArray<float, 2> scale;
                scale[0] = property("widthScale").toDouble();
                scale[1] = property("heightScale").toDouble();
                scaleTransform->SetScale(scale);
                Point<float, 2> center;
                center[0] = srcImg->GetLargestPossibleRegion().GetSize()[0]/2;
                center[1] = srcImg->GetLargestPossibleRegion().GetSize()[1]/2;
                scaleTransform->SetCenter(center);

                typedef ResampleImageFilter<ColorImageFrame::ImageType, ColorImageFrame::ImageType> ResampleImageFilterType;
                ResampleImageFilterType::Pointer resampleFilter = ResampleImageFilterType::New();
                resampleFilter->SetTransform(scaleTransform);
                resampleFilter->SetInput(srcImg);
                resampleFilter->SetSize(srcImg->GetLargestPossibleRegion().GetSize());
                resampleFilter->Update();
                mImageFrame = resampleFilter->GetOutput();

                emit framesReady();
                break;
                }
            }
    }
void QmitkBasicImageProcessing::StartButtonClicked()
{
  if(!m_SelectedImageNode->GetNode()) return;

  this->BusyCursorOn();

  mitk::Image::Pointer newImage;

  try
  {
    newImage = dynamic_cast<mitk::Image*>(m_SelectedImageNode->GetNode()->GetData());
  }
  catch ( std::exception &e )
  {
  QString exceptionString = "An error occured during image loading:\n";
  exceptionString.append( e.what() );
    QMessageBox::warning( NULL, "Basic Image Processing", exceptionString , QMessageBox::Ok, QMessageBox::NoButton );
    this->BusyCursorOff();
    return;
  }

  // check if input image is valid, casting does not throw exception when casting from 'NULL-Object'
  if ( (! newImage) || (newImage->IsInitialized() == false) )
  {
    this->BusyCursorOff();

    QMessageBox::warning( NULL, "Basic Image Processing", "Input image is broken or not initialized. Returning.", QMessageBox::Ok, QMessageBox::NoButton );
    return;
  }

  // check if operation is done on 4D a image time step
  if(newImage->GetDimension() > 3)
  {
    mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New();
    timeSelector->SetInput(newImage);
    timeSelector->SetTimeNr( ((QmitkSliderNavigatorWidget*)m_Controls->sliceNavigatorTime)->GetPos() );
    timeSelector->Update();
    newImage = timeSelector->GetOutput();
  }



  // check if image or vector image
  ImageType::Pointer itkImage = ImageType::New();
  VectorImageType::Pointer itkVecImage = VectorImageType::New();

  int isVectorImage = newImage->GetPixelType().GetNumberOfComponents();

  if(isVectorImage > 1)
  {
    CastToItkImage( newImage, itkVecImage );
  }
  else
  {
    CastToItkImage( newImage, itkImage );
  }

  std::stringstream nameAddition("");

  int param1 = m_Controls->sbParam1->value();
  int param2 = m_Controls->sbParam2->value();
  double dparam1 = m_Controls->dsbParam1->value();
  double dparam2 = m_Controls->dsbParam2->value();
  double dparam3 = m_Controls->dsbParam3->value();

  try{

  switch (m_SelectedAction)
  {

  case GAUSSIAN:
    {
      GaussianFilterType::Pointer gaussianFilter = GaussianFilterType::New();
      gaussianFilter->SetInput( itkImage );
      gaussianFilter->SetVariance( param1 );
      gaussianFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(gaussianFilter->GetOutput())->Clone();
      nameAddition << "_Gaussian_var_" << param1;
      std::cout << "Gaussian filtering successful." << std::endl;
      break;
    }

  case MEDIAN:
    {
      MedianFilterType::Pointer medianFilter = MedianFilterType::New();
      MedianFilterType::InputSizeType size;
      size.Fill(param1);
      medianFilter->SetRadius( size );
      medianFilter->SetInput(itkImage);
      medianFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(medianFilter->GetOutput())->Clone();
      nameAddition << "_Median_radius_" << param1;
      std::cout << "Median Filtering successful." << std::endl;
      break;
    }

  case TOTALVARIATION:
    {
      if(isVectorImage > 1)
      {
        VectorTotalVariationFilterType::Pointer TVFilter
          = VectorTotalVariationFilterType::New();
        TVFilter->SetInput( itkVecImage.GetPointer() );
        TVFilter->SetNumberIterations(param1);
        TVFilter->SetLambda(double(param2)/1000.);
        TVFilter->UpdateLargestPossibleRegion();

        newImage = mitk::ImportItkImage(TVFilter->GetOutput())->Clone();
      }
      else
      {
        ImagePTypeToFloatPTypeCasterType::Pointer floatCaster = ImagePTypeToFloatPTypeCasterType::New();
        floatCaster->SetInput( itkImage );
        floatCaster->Update();
        FloatImageType::Pointer fImage = floatCaster->GetOutput();

        TotalVariationFilterType::Pointer TVFilter
          = TotalVariationFilterType::New();
        TVFilter->SetInput( fImage.GetPointer() );
        TVFilter->SetNumberIterations(param1);
        TVFilter->SetLambda(double(param2)/1000.);
        TVFilter->UpdateLargestPossibleRegion();

        newImage = mitk::ImportItkImage(TVFilter->GetOutput())->Clone();
      }

      nameAddition << "_TV_Iter_" << param1 << "_L_" << param2;
      std::cout << "Total Variation Filtering successful." << std::endl;
      break;
    }

  case DILATION:
    {
      BallType binaryBall;
      binaryBall.SetRadius( param1 );
      binaryBall.CreateStructuringElement();

      DilationFilterType::Pointer dilationFilter = DilationFilterType::New();
      dilationFilter->SetInput( itkImage );
      dilationFilter->SetKernel( binaryBall );
      dilationFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(dilationFilter->GetOutput())->Clone();
      nameAddition << "_Dilated_by_" << param1;
      std::cout << "Dilation successful." << std::endl;
      break;
    }

  case EROSION:
    {
      BallType binaryBall;
      binaryBall.SetRadius( param1 );
      binaryBall.CreateStructuringElement();

      ErosionFilterType::Pointer erosionFilter = ErosionFilterType::New();
      erosionFilter->SetInput( itkImage );
      erosionFilter->SetKernel( binaryBall );
      erosionFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(erosionFilter->GetOutput())->Clone();
      nameAddition << "_Eroded_by_" << param1;
      std::cout << "Erosion successful." << std::endl;
      break;
    }

  case OPENING:
    {
      BallType binaryBall;
      binaryBall.SetRadius( param1 );
      binaryBall.CreateStructuringElement();

      OpeningFilterType::Pointer openFilter = OpeningFilterType::New();
      openFilter->SetInput( itkImage );
      openFilter->SetKernel( binaryBall );
      openFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(openFilter->GetOutput())->Clone();
      nameAddition << "_Opened_by_" << param1;
      std::cout << "Opening successful." << std::endl;
      break;
    }

  case CLOSING:
    {
      BallType binaryBall;
      binaryBall.SetRadius( param1 );
      binaryBall.CreateStructuringElement();

      ClosingFilterType::Pointer closeFilter = ClosingFilterType::New();
      closeFilter->SetInput( itkImage );
      closeFilter->SetKernel( binaryBall );
      closeFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(closeFilter->GetOutput())->Clone();
      nameAddition << "_Closed_by_" << param1;
      std::cout << "Closing successful." << std::endl;
      break;
    }

  case GRADIENT:
    {
      GradientFilterType::Pointer gradientFilter = GradientFilterType::New();
      gradientFilter->SetInput( itkImage );
      gradientFilter->SetSigma( param1 );
      gradientFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(gradientFilter->GetOutput())->Clone();
      nameAddition << "_Gradient_sigma_" << param1;
      std::cout << "Gradient calculation successful." << std::endl;
      break;
    }

  case LAPLACIAN:
    {
      // the laplace filter requires a float type image as input, we need to cast the itkImage
      // to correct type
      ImagePTypeToFloatPTypeCasterType::Pointer caster = ImagePTypeToFloatPTypeCasterType::New();
      caster->SetInput( itkImage );
      caster->Update();
      FloatImageType::Pointer fImage = caster->GetOutput();

      LaplacianFilterType::Pointer laplacianFilter = LaplacianFilterType::New();
      laplacianFilter->SetInput( fImage );
      laplacianFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(laplacianFilter->GetOutput())->Clone();
      nameAddition << "_Second_Derivative";
      std::cout << "Laplacian filtering successful." << std::endl;
      break;
    }

  case SOBEL:
    {
      // the sobel filter requires a float type image as input, we need to cast the itkImage
      // to correct type
      ImagePTypeToFloatPTypeCasterType::Pointer caster = ImagePTypeToFloatPTypeCasterType::New();
      caster->SetInput( itkImage );
      caster->Update();
      FloatImageType::Pointer fImage = caster->GetOutput();

      SobelFilterType::Pointer sobelFilter = SobelFilterType::New();
      sobelFilter->SetInput( fImage );
      sobelFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(sobelFilter->GetOutput())->Clone();
      nameAddition << "_Sobel";
      std::cout << "Edge Detection successful." << std::endl;
      break;
    }

  case THRESHOLD:
    {
      ThresholdFilterType::Pointer thFilter = ThresholdFilterType::New();
      thFilter->SetLowerThreshold(param1 < param2 ? param1 : param2);
      thFilter->SetUpperThreshold(param2 > param1 ? param2 : param1);
      thFilter->SetInsideValue(1);
      thFilter->SetOutsideValue(0);
      thFilter->SetInput(itkImage);
      thFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(thFilter->GetOutput())->Clone();
      nameAddition << "_Threshold";
      std::cout << "Thresholding successful." << std::endl;
      break;
    }

  case INVERSION:
    {
      InversionFilterType::Pointer invFilter = InversionFilterType::New();
      mitk::ScalarType min = newImage->GetScalarValueMin();
      mitk::ScalarType max = newImage->GetScalarValueMax();
      invFilter->SetMaximum( max + min );
      invFilter->SetInput(itkImage);
      invFilter->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(invFilter->GetOutput())->Clone();
      nameAddition << "_Inverted";
      std::cout << "Image inversion successful." << std::endl;
      break;
    }

  case DOWNSAMPLING:
    {
      ResampleImageFilterType::Pointer downsampler = ResampleImageFilterType::New();
      downsampler->SetInput( itkImage );

      NearestInterpolatorType::Pointer interpolator = NearestInterpolatorType::New();
      downsampler->SetInterpolator( interpolator );

      downsampler->SetDefaultPixelValue( 0 );

      ResampleImageFilterType::SpacingType spacing = itkImage->GetSpacing();
      spacing *= (double) param1;
      downsampler->SetOutputSpacing( spacing );

      downsampler->SetOutputOrigin( itkImage->GetOrigin() );
      downsampler->SetOutputDirection( itkImage->GetDirection() );

      ResampleImageFilterType::SizeType size = itkImage->GetLargestPossibleRegion().GetSize();
      for ( int i = 0; i < 3; ++i )
      {
        size[i] /= param1;
      }
      downsampler->SetSize( size );
      downsampler->UpdateLargestPossibleRegion();

      newImage = mitk::ImportItkImage(downsampler->GetOutput())->Clone();
      nameAddition << "_Downsampled_by_" << param1;
      std::cout << "Downsampling successful." << std::endl;
      break;
    }

  case FLIPPING:
    {
      FlipImageFilterType::Pointer flipper = FlipImageFilterType::New();
      flipper->SetInput( itkImage );
      itk::FixedArray<bool, 3> flipAxes;
      for(int i=0; i<3; ++i)
      {
        if(i == param1)
        {
          flipAxes[i] = true;
        }
        else
        {
          flipAxes[i] = false;
        }
      }
      flipper->SetFlipAxes(flipAxes);
      flipper->UpdateLargestPossibleRegion();
      newImage = mitk::ImportItkImage(flipper->GetOutput())->Clone();
      std::cout << "Image flipping successful." << std::endl;
      break;
    }

  case RESAMPLING:
    {
      std::string selectedInterpolator;
      ResampleImageFilterType::Pointer resampler = ResampleImageFilterType::New();
      switch (m_SelectedInterpolation)
      {
      case LINEAR:
        {
          LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New();
          resampler->SetInterpolator(interpolator);
          selectedInterpolator = "Linear";
          break;
        }
      case NEAREST:
        {
          NearestInterpolatorType::Pointer interpolator = NearestInterpolatorType::New();
          resampler->SetInterpolator(interpolator);
          selectedInterpolator = "Nearest";
          break;
        }
      default:
        {
          LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New();
          resampler->SetInterpolator(interpolator);
          selectedInterpolator = "Linear";
          break;
        }
      }
      resampler->SetInput( itkImage );
      resampler->SetOutputOrigin( itkImage->GetOrigin() );

      ImageType::SizeType input_size = itkImage->GetLargestPossibleRegion().GetSize();
      ImageType::SpacingType input_spacing = itkImage->GetSpacing();

      ImageType::SizeType output_size;
      ImageType::SpacingType output_spacing;

      output_size[0] = input_size[0] * (input_spacing[0] / dparam1);
      output_size[1] = input_size[1] * (input_spacing[1] / dparam2);
      output_size[2] = input_size[2] * (input_spacing[2] / dparam3);
      output_spacing [0] = dparam1;
      output_spacing [1] = dparam2;
      output_spacing [2] = dparam3;

      resampler->SetSize( output_size );
      resampler->SetOutputSpacing( output_spacing );
      resampler->SetOutputDirection( itkImage->GetDirection() );

      resampler->UpdateLargestPossibleRegion();

      ImageType::Pointer resampledImage = resampler->GetOutput();

      newImage = mitk::ImportItkImage( resampledImage );
      nameAddition << "_Resampled_" << selectedInterpolator;
      std::cout << "Resampling successful." << std::endl;
      break;
    }


  case RESCALE:
    {
      FloatImageType::Pointer floatImage = FloatImageType::New();
      CastToItkImage( newImage, floatImage );
      itk::RescaleIntensityImageFilter<FloatImageType,FloatImageType>::Pointer filter = itk::RescaleIntensityImageFilter<FloatImageType,FloatImageType>::New();
      filter->SetInput(0, floatImage);
      filter->SetOutputMinimum(dparam1);
      filter->SetOutputMaximum(dparam2);
      filter->Update();
      floatImage = filter->GetOutput();

      newImage = mitk::Image::New();
      newImage->InitializeByItk(floatImage.GetPointer());
      newImage->SetVolume(floatImage->GetBufferPointer());
      nameAddition << "_Rescaled";
      std::cout << "Rescaling successful." << std::endl;

      break;
    }

  default:
    this->BusyCursorOff();
    return;
  }
  }
  catch (...)
  {
    this->BusyCursorOff();
    QMessageBox::warning(NULL, "Warning", "Problem when applying filter operation. Check your input...");
    return;
  }

  newImage->DisconnectPipeline();

  // adjust level/window to new image
  mitk::LevelWindow levelwindow;
  levelwindow.SetAuto( newImage );
  mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New();
  levWinProp->SetLevelWindow( levelwindow );

  // compose new image name
  std::string name = m_SelectedImageNode->GetNode()->GetName();
  if (name.find(".pic.gz") == name.size() -7 )
  {
    name = name.substr(0,name.size() -7);
  }
  name.append( nameAddition.str() );

  // create final result MITK data storage node
  mitk::DataNode::Pointer result = mitk::DataNode::New();
  result->SetProperty( "levelwindow", levWinProp );
  result->SetProperty( "name", mitk::StringProperty::New( name.c_str() ) );
  result->SetData( newImage );

  // for vector images, a different mapper is needed
  if(isVectorImage > 1)
  {
    mitk::VectorImageMapper2D::Pointer mapper =
      mitk::VectorImageMapper2D::New();
    result->SetMapper(1,mapper);
  }

  // reset GUI to ease further processing
//  this->ResetOneImageOpPanel();

  // add new image to data storage and set as active to ease further processing
  GetDefaultDataStorage()->Add( result, m_SelectedImageNode->GetNode() );
  if ( m_Controls->cbHideOrig->isChecked() == true )
    m_SelectedImageNode->GetNode()->SetProperty( "visible", mitk::BoolProperty::New(false) );
  // TODO!! m_Controls->m_ImageSelector1->SetSelectedNode(result);

  // show the results
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
  this->BusyCursorOff();
}
bool Initialisation::computeInitialParameters(float startFactor)
{  
	ImageType::SizeType desiredSize = inputImage_->GetLargestPossibleRegion().GetSize();
	
    // The spinal cord detection is performed on a bunch of axial slices. The choice of which slices will be analyzed depends on the startFactor. Default is the middle axial slice. The parameter startFactor must be the number of the slice, or a number between 0 and 1 representing the pourcentage of the image.
    // For exemple, startFactor=0.5 means the detection will start in the middle axial slice.
    float startZ;
    if (startFactor != -1.0) startSlice_ = startFactor;
    if (startSlice_ == -1.0) {
        startZ = desiredSize[1]/2;
        startSlice_ = startZ;
    }
    else if (startSlice_ < 1.0) {
        startZ = desiredSize[1]*startSlice_;
        startSlice_ = startZ;
    }
	else startZ = startSlice_;

	// Adapt radius to the image spacing to provide a radius in pixels - use average spacing of axial slice
    ImageType::SpacingType spacing = inputImage_->GetSpacing();
    mean_resolution_ = (spacing[0]+spacing[2])/2;
    
    
    // Adapt the gap between detection axial slices to the spacing
	if (round(spacing[1]) != 0 && (int)gap_ % (int)round(spacing[1]) != 0)
	{
		gap_ = spacing[1];
	}
    
    // Adapt the number of axial slices used for the detection to the spacing and the image dimensions.
	if (startZ-((numberOfSlices_-1.0)/2.0)*(gap_/spacing[1]) < 0 || startZ+((numberOfSlices_-1.0)/2.0)*(gap_/spacing[1]) >= desiredSize[1])
	{
		numberOfSlices_ = numberOfSlices_-2;
		//gap_ = 1;
		if (verbose_) {
			cout << "WARNING: number of slices and gap between slices are not adapted to the image dimensions for the initilization. Default parameters will be used." << endl;
			cout << "New parameters:" << endl << "Gap inter slices = " << gap_ << endl << "Number of slices = " << numberOfSlices_ << endl;
		}
	}
    
    // Initalisation of the paremeters for the spinal cord detection
	ImageType::IndexType desiredStart;
	desiredStart[0] = 0;
	desiredStart[1] = startZ;
	desiredStart[2] = 0;
	desiredSize[1] = 0;

    // First extraction of the axial slice to check if the image contains information (not null)
	ImageType::RegionType desiredRegionImage(desiredStart, desiredSize);
    typedef itk::ExtractImageFilter< ImageType, ImageType2D > Crop2DFilterType;
    Crop2DFilterType::Pointer cropFilter = Crop2DFilterType::New();
    cropFilter->SetExtractionRegion(desiredRegionImage);
    cropFilter->SetInput(inputImage_);
	#if ITK_VERSION_MAJOR >= 4
    cropFilter->SetDirectionCollapseToIdentity(); // This is required.
	#endif
    try {
        cropFilter->Update();
    } catch( itk::ExceptionObject & e ) {
        std::cerr << "Exception caught while updating cropFilter " << std::endl;
        std::cerr << e << std::endl;
    }
    ImageType2D::Pointer image_test_minmax = cropFilter->GetOutput();
	MinMaxCalculatorType::Pointer minMaxCalculator = MinMaxCalculatorType::New();
	minMaxCalculator->SetImage(image_test_minmax);
	minMaxCalculator->ComputeMaximum();
	minMaxCalculator->ComputeMinimum();
	ImageType2D::PixelType maxIm = minMaxCalculator->GetMaximum(), minIm = minMaxCalculator->GetMinimum();
	if (maxIm == minIm) {
		cerr << "WARNING: The principal axial slice where the spinal cord detection will be performed (slice " << startZ << ") is full of constant value (" << maxIm << "). You can change it using -init parameter." << endl;
	}
    
    // Starting the spinal cord detection process
    if (verbose_) cout << "Initialization" << endl;
    
    // Creation of a matrix of potential spinal cord centers
	vector<vector <vector <Node*> > > centers;
    
    // Start of the detection of circles and ellipses. For each axial slices, a Hough transform is performed to detect circles. Each axial image is stretched in the antero-posterior direction in order to detect the spinal cord as a ellipse as well as a circle.
	for (int i=round(-((numberOfSlices_-1.0)/2.0)*(gap_/spacing[1])); i<=round(((numberOfSlices_-1.0)/2.0)*(gap_/spacing[1])); i+=round(gap_/spacing[1]))
	{
        // Cropping of the image
		if (verbose_) cout << "Slice num " << i << endl;
		desiredStart[1] = startZ+i;
		ImageType::RegionType desiredRegion(desiredStart, desiredSize);
		FilterType::Pointer filter = FilterType::New();
		filter->SetExtractionRegion(desiredRegion);
		filter->SetInput(inputImage_);
        #if ITK_VERSION_MAJOR >= 4
		filter->SetDirectionCollapseToIdentity(); // This is required.
        #endif
		try {
			filter->Update();
		} catch( itk::ExceptionObject & e ) {
			std::cerr << "Exception caught while updating cropFilter " << std::endl;
			std::cerr << e << std::endl;
			cout << inputImage_->GetLargestPossibleRegion().GetSize() << endl;
			cout << desiredRegion << endl;
		}
        
        // The image is duplicated to allow multiple processing on the image.
		ImageType2D::Pointer im = filter->GetOutput();
		DuplicatorType::Pointer duplicator = DuplicatorType::New();
		duplicator->SetInputImage(im);
		duplicator->Update();
		ImageType2D::Pointer clonedImage = duplicator->GetOutput();
		ImageType::DirectionType imageDirection = inputImage_->GetDirection();
		ImageType2D::DirectionType clonedImageDirection;
		clonedImageDirection[0][0] = imageDirection[0][0];
		clonedImageDirection[0][1] = imageDirection[0][2];
		clonedImageDirection[1][0] = imageDirection[1][0];
		clonedImageDirection[1][1] = imageDirection[1][2];
		clonedImage->SetDirection(clonedImageDirection);
        
		// Initialization of resulting spinal cord center list.
		vector<vector <Node*> > vecNode;
        
        // Initialization of stretching parameters
        // A stretchingFactor equals to 1 doesn't change the image
		double stretchingFactor = 1.0, step = 0.25;
		while (stretchingFactor <= 2.0)
		{
			if (verbose_) cout << "Stretching factor " << stretchingFactor << endl;
            // Stretching the image in the antero-posterior direction. This direction is chosen because potential elliptical spinal cord will be transformed to circles and wil be detected by the Hough transform. The resulting circles will then be stretch in the other direction.
			if (stretchingFactor != 1.0)
			{
				ImageType2D::SizeType inputSize = clonedImage->GetLargestPossibleRegion().GetSize(), outputSize;
				outputSize[0] = inputSize[0]*stretchingFactor;
				outputSize[1] = inputSize[1];
				ImageType2D::SpacingType outputSpacing;
				outputSpacing[0] = static_cast<double>(clonedImage->GetSpacing()[0] * inputSize[0] / outputSize[0]);
				outputSpacing[1] = static_cast<double>(clonedImage->GetSpacing()[1] * inputSize[1] / outputSize[1]);
                
				ResampleImageFilterType::Pointer resample = ResampleImageFilterType::New();
				resample->SetInput(clonedImage);
				resample->SetSize(outputSize);
				resample->SetOutputDirection(clonedImage->GetDirection());
				resample->SetOutputOrigin(clonedImage->GetOrigin());
				resample->SetOutputSpacing(outputSpacing);
				resample->SetTransform(TransformType::New());
				resample->Update();
                
				im = resample->GetOutput();
			}
            
            // Searching the circles in the image using circular Hough transform, adapted from ITK
            // The list of radii and accumulator values are then extracted for analyses
			vector<CVector3> vecCenter;
			vector<double> vecRadii, vecAccumulator;
			searchCenters(im,vecCenter,vecRadii,vecAccumulator,startZ+i);
			
            // Reformating of the detected circles in the image. Each detected circle is push in a Node with all its information.
            // The radii are transformed in mm using mean axial resolution
			vector<Node*> vecNodeTemp;
			for (unsigned int k=0; k<vecCenter.size(); k++) {
				if (vecRadii[k] != 0.0) {
					CVector3 center = vecCenter[k]; center[0] /= stretchingFactor;
					vecNodeTemp.push_back(new Node(center,mean_resolution_*vecRadii[k]/stretchingFactor,vecAccumulator[k],vecCenter[k],mean_resolution_*vecRadii[k],stretchingFactor));
				}
			}
			vecNode.push_back(vecNodeTemp);
			
            // Preparing next iteration of the spinal cord detection
			stretchingFactor += step;
		}
        // Saving the detected centers
		centers.push_back(vecNode);
	}
    
	// All centers are ordoned by slice
	// First step -> delete points without neighbour
	double limitDistance = sqrt(2.0*gap_*gap_); // in mm
	list<Node*> listPoints;
	for (unsigned int k=0; k<numberOfSlices_; k++)
	{
		// For every point in a slice, we search on next and previous slice for neighbors
        // Potential neighbours are circles that have a similar radius (less than 20% of difference)
		for (unsigned int i=0; i<centers[k].size(); i++)
		{
			for (unsigned int m=0; m<centers[k][i].size(); m++)
			{
				bool hasNeighbor = false;
				double radius = centers[k][i][m]->getRadius();
				if (k != 0) // search down
				{
                    // All the point are sorted by the distance
					map<double,Node*> listNeighbors;
					for (unsigned int j=0; j<centers[k-1][i].size(); j++)
					{
                        // Compute the distance between two adjacent centers (in mm)
                        // If this distance is less or equal to the limit distance, the two centers are attached to each others
						double currentDistance = mean_resolution_*sqrt(pow(centers[k][i][m]->getPosition()[0]-centers[k-1][i][j]->getPosition()[0],2)+pow(centers[k][i][m]->getPosition()[1]-centers[k-1][i][j]->getPosition()[1],2)+pow(centers[k][i][m]->getPosition()[2]-centers[k-1][i][j]->getPosition()[2],2));
						if (currentDistance <= limitDistance)
							listNeighbors[currentDistance] = centers[k-1][i][j];
					}
					while (!listNeighbors.empty())
					{
						double radiusCurrent = listNeighbors.begin()->second->getRadius();
						if (radiusCurrent >= radius*0.8 && radiusCurrent <= radius*1.2)
						{
							hasNeighbor = true;
							centers[k][i][m]->addPrevious(listNeighbors.begin()->second);
							break;
						}
						listNeighbors.erase(listNeighbors.begin());
					}
				}
				if (k != numberOfSlices_-1) // search up
				{
					map<double,Node*> listNeighbors;
					for (unsigned int j=0; j<centers[k+1][i].size(); j++)
					{
						double currentDistance = mean_resolution_*sqrt(pow(centers[k][i][m]->getPosition()[0]-centers[k+1][i][j]->getPosition()[0],2)+pow(centers[k][i][m]->getPosition()[1]-centers[k+1][i][j]->getPosition()[1],2)+pow(centers[k][i][m]->getPosition()[2]-centers[k+1][i][j]->getPosition()[2],2));
						if (currentDistance <= limitDistance)
							listNeighbors[currentDistance] = centers[k+1][i][j];
					}
					while (!listNeighbors.empty())
					{
						double radiusCurrent = listNeighbors.begin()->second->getRadius();
						if (radiusCurrent >= radius*0.8 && radiusCurrent <= radius*1.2)
						{
							hasNeighbor = true;
							centers[k][i][m]->addNext(listNeighbors.begin()->second);
							break;
						}
						listNeighbors.erase(listNeighbors.begin());
					}
				}
				if (hasNeighbor) // if point has at least one neighbor, we keep it
					listPoints.push_back(centers[k][i][m]);
			}
		}
	}
    
	// Second step -> assembling points
	vector<vector <Node*> > chains;
	while (listPoints.size() != 0)
	{
		vector<Node*> temp;
		Node* current = listPoints.front();
		temp.push_back(current);
		listPoints.pop_front();
		while(current->hasNext())
		{
			current = current->getNext();
			temp.push_back(current);
		}
		chains.push_back(temp);
	}
	// And search for the longest and with larger accumulation value and small angle between normals 
	unsigned int maxLenght = 0, max = 0;
	double maxAccumulator = 0.0, angleMax = 15.0;
	for (unsigned int j=0; j<chains.size(); j++)
	{
		unsigned int length = chains[j].size();
        double angle = 0.0;
        if (length >= 3)
        {
            CVector3 vector1 = chains[j][0]->getPosition()-chains[j][length/2]->getPosition(), vector2 = (chains[j][length/2]->getPosition()-chains[j][length-1]->getPosition());
            angle = 360.0*acos((vector1*vector2)/(vector1.Norm()*vector2.Norm()))/(2.0*M_PI);
        }
		if (length > maxLenght && angle <= angleMax)
		{
			maxLenght = chains[j].size();
			max = j;
			maxAccumulator = 0.0;
			for (unsigned int k=0; k<length; k++)
				maxAccumulator += chains[j][k]->getAccumulator();
		}
		else if (length == maxLenght && angle <= angleMax)
		{
			double accumulator = 0.0;
			for (unsigned int k=0; k<length; k++)
				accumulator += chains[j][k]->getAccumulator();
			if (accumulator > maxAccumulator) {
				maxLenght = chains[j].size();
				max = j;
				maxAccumulator = accumulator;
			}
		}
	}
    
	if (chains.size() > 1)
	{
		unsigned int sizeMaxChain = chains[max].size();
		//cout << "Results : " << endl;
        points_.clear();
		for (unsigned int j=0; j<sizeMaxChain; j++) {
            points_.push_back(chains[max][j]->getPosition());
			//cout << chains[max][j]->getPosition() << " " << chains[max][j]->getRadius() << endl;
        }
        if (verbose_) cout << "Stretching factor of circle found = " << chains[max][0]->getStretchingFactor() << endl;
		if (sizeMaxChain < numberOfSlices_) {
			if (verbose_) cout << "Warning: Number of center found on slices (" << sizeMaxChain << ") doesn't correspond to number of analyzed slices. An error may occur. To improve results, you can increase the number of analyzed slices (option -n must be impair)" << endl;
            
			// we have to transform pixel points to physical points
			CVector3 finalPoint, initPointT = chains[max][0]->getPosition(), finalPointT = chains[max][sizeMaxChain-1]->getPosition();
			ContinuousIndex initPointIndex, finalPointIndex;
			initPointIndex[0] = initPointT[0]; initPointIndex[1] = initPointT[1]; initPointIndex[2] = initPointT[2];
			finalPointIndex[0] = finalPointT[0]; finalPointIndex[1] = finalPointT[1]; finalPointIndex[2] = finalPointT[2];
			PointType initPoint, finPoint;
			inputImage_->TransformContinuousIndexToPhysicalPoint(initPointIndex,initPoint);
			inputImage_->TransformContinuousIndexToPhysicalPoint(finalPointIndex,finPoint);
			initialPoint_ = CVector3(initPoint[0],initPoint[1],initPoint[2]);
			finalPoint = CVector3(finPoint[0],finPoint[1],finPoint[2]);
			initialNormal1_ = (finalPoint-initialPoint_).Normalize();
			initialRadius_ = 0.0;
			for (unsigned int j=0; j<sizeMaxChain; j++)
				initialRadius_ += chains[max][j]->getRadiusStretch();
			initialRadius_ /= sizeMaxChain;
            stretchingFactor_ = chains[max][0]->getStretchingFactor();
		}
		else
		{
			// we have to transform pixel points to physical points
			CVector3 finalPoint1, finalPoint2, initPointT = chains[max][(int)(sizeMaxChain/2)]->getPosition(), finalPointT1 = chains[max][0]->getPosition(), finalPointT2 = chains[max][sizeMaxChain-1]->getPosition();
			ContinuousIndex initPointIndex, finalPoint1Index, finalPoint2Index;
			initPointIndex[0] = initPointT[0]; initPointIndex[1] = initPointT[1]; initPointIndex[2] = initPointT[2];
			finalPoint1Index[0] = finalPointT1[0]; finalPoint1Index[1] = finalPointT1[1]; finalPoint1Index[2] = finalPointT1[2];
			finalPoint2Index[0] = finalPointT2[0]; finalPoint2Index[1] = finalPointT2[1]; finalPoint2Index[2] = finalPointT2[2];
			PointType initPoint, finPoint1, finPoint2;
			inputImage_->TransformContinuousIndexToPhysicalPoint(initPointIndex,initPoint);
			inputImage_->TransformContinuousIndexToPhysicalPoint(finalPoint1Index,finPoint1);
			inputImage_->TransformContinuousIndexToPhysicalPoint(finalPoint2Index,finPoint2);
			initialPoint_ = CVector3(initPoint[0],initPoint[1],initPoint[2]);
			finalPoint1 = CVector3(finPoint1[0],finPoint1[1],finPoint1[2]);
			finalPoint2 = CVector3(finPoint2[0],finPoint2[1],finPoint2[2]);
			initialNormal1_ = (finalPoint1-initialPoint_).Normalize();
			initialNormal2_ = (finalPoint2-initialPoint_).Normalize();
			initialRadius_ = 0.0;
			for (unsigned int j=0; j<sizeMaxChain; j++)
				initialRadius_ += chains[max][j]->getRadiusStretch();
			initialRadius_ /= sizeMaxChain;
            stretchingFactor_ = chains[max][0]->getStretchingFactor();
		}
		return true;
	}
	else {
		cout << "Error: No point detected..." << endl;
		return false;
	}
}