void mitk::PixelManipulationTool::CalculateImage()
{
  if (m_OriginalImageNode.IsNotNull())
  {
    mitk::Image::Pointer image = dynamic_cast<mitk::Image*> (m_OriginalImageNode->GetData());
    mitk::DataNode* maskNode = m_ToolManager->GetRoiData(0);
    mitk::Image::Pointer roi = mitk::Image::New();

    if (maskNode)
    {
      mitk::BoundingObject* boundingObject = dynamic_cast<mitk::BoundingObject*> (maskNode->GetData());

      if (boundingObject)
      {
        mitk::BoundingObjectToSegmentationFilter::Pointer filter = mitk::BoundingObjectToSegmentationFilter::New();
        filter->SetBoundingObject( boundingObject);
        filter->SetInput(image);
        filter->Update();
        roi = filter->GetOutput();
      }
      else
        roi =  dynamic_cast<mitk::Image*> (maskNode->GetData());

      mitk::Image::Pointer newImage = mitk::Image::New();
      newImage->Initialize(image);

      if (image)
      {
        AccessByItk_3(image, ITKPixelManipulation, roi, newImage, m_Value);
        this->AddImageToDataStorage(newImage);
      }
    }
  }
}
Esempio n. 2
0
int main(int argc, char* argv[])
{
  mitkCommandLineParser parser;
  parser.setArgumentPrefix("--", "-");
  // required params
  parser.addArgument("image", "i", mitkCommandLineParser::InputImage, "Input Image", "Path to the input VTK polydata", us::Any(), false);
  parser.addArgument("image2", "i2", mitkCommandLineParser::InputImage, "Input Mask", "The median of the area covered by this mask will be set to 0", us::Any(), false);
  parser.addArgument("mask", "m", mitkCommandLineParser::InputImage, "Input Mask", "The median of the area covered by this mask will be set to 1", us::Any(), false);
  parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output Image", "Target file. The output statistic is appended to this file.", us::Any(), false);

  // Miniapp Infos
  parser.setCategory("Classification Tools");
  parser.setTitle("MR Normalization Tool");
  parser.setDescription("Normalizes a MR image. Sets the Median of the tissue covered by mask 0 to 0 and the median of the area covered by mask 1 to 1.");
  parser.setContributor("MBI");

  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);

  if (parsedArgs.size()==0)
  {
    return EXIT_FAILURE;
  }
  if ( parsedArgs.count("help") || parsedArgs.count("h"))
  {
    return EXIT_SUCCESS;
  }

  mitk::Image::Pointer image = mitk::IOUtil::LoadImage(parsedArgs["image"].ToString());
  mitk::Image::Pointer im2= mitk::IOUtil::LoadImage(parsedArgs["image2"].ToString());
  mitk::Image::Pointer mask = mitk::IOUtil::LoadImage(parsedArgs["mask"].ToString());

  AccessByItk_3(image, Normalize, im2, mask, parsedArgs["output"].ToString());

  return 0;
}
Esempio n. 3
0
mitk::GIFCooccurenceMatrix::FeatureListType mitk::GIFCooccurenceMatrix::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask)
{
  FeatureListType featureList;

  AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,m_Range);

  return featureList;
}
void mitk::MorphologicalOperations::Erode(mitk::Image::Pointer &image,
                                          int factor,
                                          mitk::MorphologicalOperations::StructuralElementType structuralElement)
{
  MITK_INFO << "Start Erode...";

  int timeSteps = static_cast<int>(image->GetTimeSteps());

  if (timeSteps > 1)
  {
    mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New();
    timeSelector->SetInput(image);

    for (int t = 0; t < timeSteps; ++t)
    {
      MITK_INFO << "  Processing time step " << t;

      timeSelector->SetTimeNr(t);
      timeSelector->Update();

      mitk::Image::Pointer img3D = timeSelector->GetOutput();
      img3D->DisconnectPipeline();

      AccessByItk_3(img3D, itkErode, img3D, factor, structuralElement);

      mitk::ImageReadAccessor accessor(img3D);
      image->SetVolume(accessor.GetData(), t);
    }
  }
  else
  {
    AccessByItk_3(image, itkErode, image, factor, structuralElement);
  }

  MITK_INFO << "Finished Erode";
}
mitk::GIFFirstOrderStatistics::FeatureListType mitk::GIFFirstOrderStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask)
{
  InitializeQuantifier(image, mask);
  FeatureListType featureList;

  ParameterStruct params;

  params.MinimumIntensity = GetQuantifier()->GetMinimum();
  params.MaximumIntensity = GetQuantifier()->GetMaximum();
  params.Bins = GetQuantifier()->GetBins();
  params.prefix = FeatureDescriptionPrefix();
  AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params);

  return featureList;
}
Esempio n. 6
0
mitk::GIFGreyLevelSizeZone::FeatureListType mitk::GIFGreyLevelSizeZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask)
{
  InitializeQuantifier(image, mask);

  FeatureListType featureList;

  GIFGreyLevelSizeZoneConfiguration config;
  config.direction = GetDirection();

  config.MinimumIntensity = GetQuantifier()->GetMinimum();
  config.MaximumIntensity = GetQuantifier()->GetMaximum();
  config.Bins = GetQuantifier()->GetBins();
  config.prefix = FeatureDescriptionPrefix();

  AccessByItk_3(image, CalculateGreyLevelSizeZoneFeatures, mask, featureList, config);

  return featureList;
}
Esempio n. 7
0
int main(int argc, char* argv[])
{
  mitkCommandLineParser parser;
  parser.setArgumentPrefix("--", "-");
  // required params
  parser.addArgument("image", "i", mitkCommandLineParser::InputImage, "Input Image", "Path to the input VTK polydata", us::Any(), false);
  parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output text file", "Target file. The output statistic is appended to this file.", us::Any(), false);

  parser.addArgument("gaussian","g",mitkCommandLineParser::String, "Gaussian Filtering of the input images", "Gaussian Filter. Followed by the used variances seperated by ';' ",us::Any());
  parser.addArgument("difference-of-gaussian","dog",mitkCommandLineParser::String, "Difference of Gaussian Filtering of the input images", "Difference of Gaussian Filter. Followed by the used variances seperated by ';' ",us::Any());
  parser.addArgument("laplace-of-gauss","log",mitkCommandLineParser::String, "Laplacian of Gaussian Filtering", "Laplacian of Gaussian Filter. Followed by the used variances seperated by ';' ",us::Any());
  parser.addArgument("hessian-of-gauss","hog",mitkCommandLineParser::String, "Hessian of Gaussian Filtering", "Hessian of Gaussian Filter. Followed by the used variances seperated by ';' ",us::Any());
  parser.addArgument("local-histogram", "lh", mitkCommandLineParser::String, "Local Histograms", "Calculate the local histogram based feature. Specify Offset and Delta, for exampel -3;0.6 ", us::Any());
  // Miniapp Infos
  parser.setCategory("Classification Tools");
  parser.setTitle("Global Image Feature calculator");
  parser.setDescription("Calculates different global statistics for a given segmentation / image combination");
  parser.setContributor("MBI");

  std::map<std::string, us::Any> parsedArgs = parser.parseArguments(argc, argv);

  if (parsedArgs.size()==0)
  {
    return EXIT_FAILURE;
  }
  if ( parsedArgs.count("help") || parsedArgs.count("h"))
  {
    return EXIT_SUCCESS;
  }
  bool useCooc = parsedArgs.count("cooccurence");

  mitk::Image::Pointer image = mitk::IOUtil::LoadImage(parsedArgs["image"].ToString());
  std::string filename=parsedArgs["output"].ToString();

  ////////////////////////////////////////////////////////////////
  // CAlculate Gaussian Features
  ////////////////////////////////////////////////////////////////
  MITK_INFO << "Check for Local Histogram...";
  if (parsedArgs.count("local-histogram"))
  {
    std::vector<mitk::Image::Pointer> outs;
    auto ranges = splitDouble(parsedArgs["local-histogram"].ToString(), ';');
    if (ranges.size() < 2)
    {
      MITK_INFO << "Missing Delta and Offset for Local Histogram";
    }
    else
    {
      AccessByItk_3(image, LocalHistograms, outs, ranges[0], ranges[1]);
      for (int i = 0; i < outs.size(); ++i)
      {
        std::string name = filename + "-lh" + us::any_value_to_string<int>(i)+".nii.gz";
        mitk::IOUtil::SaveImage(outs[i], name);
      }
    }
  }

  ////////////////////////////////////////////////////////////////
  // CAlculate Gaussian Features
  ////////////////////////////////////////////////////////////////
  MITK_INFO << "Check for Gaussian...";
  if (parsedArgs.count("gaussian"))
  {
    MITK_INFO << "Calculate Gaussian... " << parsedArgs["gaussian"].ToString();
    auto ranges = splitDouble(parsedArgs["gaussian"].ToString(),';');

    for (int i = 0; i < ranges.size(); ++i)
    {
      mitk::Image::Pointer output;
      AccessByItk_2(image, GaussianFilter, ranges[i], output);
      std::string name = filename + "-gaussian-" + us::any_value_to_string(ranges[i])+".nii.gz";
      mitk::IOUtil::SaveImage(output, name);
    }
  }

  ////////////////////////////////////////////////////////////////
  // CAlculate Difference of Gaussian Features
  ////////////////////////////////////////////////////////////////
  MITK_INFO << "Check for DoG...";
  if (parsedArgs.count("difference-of-gaussian"))
  {
    MITK_INFO << "Calculate Difference of Gaussian... " << parsedArgs["difference-of-gaussian"].ToString();
    auto ranges = splitDouble(parsedArgs["difference-of-gaussian"].ToString(),';');

    for (int i = 0; i < ranges.size(); ++i)
    {
      mitk::Image::Pointer output;
      AccessByItk_2(image, DifferenceOfGaussFilter, ranges[i], output);
      std::string name = filename + "-dog-" + us::any_value_to_string(ranges[i])+".nii.gz";
      mitk::IOUtil::SaveImage(output, name);
    }
  }

  MITK_INFO << "Check for LoG...";
  ////////////////////////////////////////////////////////////////
  // CAlculate Laplacian Of Gauss Features
  ////////////////////////////////////////////////////////////////
  if (parsedArgs.count("laplace-of-gauss"))
  {
    MITK_INFO << "Calculate LoG... " << parsedArgs["laplace-of-gauss"].ToString();
    auto ranges = splitDouble(parsedArgs["laplace-of-gauss"].ToString(),';');

    for (int i = 0; i < ranges.size(); ++i)
    {
      mitk::Image::Pointer output;
      AccessByItk_2(image, LaplacianOfGaussianFilter, ranges[i], output);
      std::string name = filename + "-log-" + us::any_value_to_string(ranges[i])+".nii.gz";
      mitk::IOUtil::SaveImage(output, name);
    }
  }

  MITK_INFO << "Check for HoG...";
  ////////////////////////////////////////////////////////////////
  // CAlculate Hessian Of Gauss Features
  ////////////////////////////////////////////////////////////////
  if (parsedArgs.count("hessian-of-gauss"))
  {
    MITK_INFO << "Calculate HoG... " << parsedArgs["hessian-of-gauss"].ToString();
    auto ranges = splitDouble(parsedArgs["hessian-of-gauss"].ToString(),';');

    for (int i = 0; i < ranges.size(); ++i)
    {
      std::vector<mitk::Image::Pointer> outs;
      outs.push_back(mitk::Image::New());
      outs.push_back(mitk::Image::New());
      outs.push_back(mitk::Image::New());
      AccessByItk_2(image, HessianOfGaussianFilter, ranges[i], outs);
      std::string name = filename + "-hog0-" + us::any_value_to_string(ranges[i])+".nii.gz";
      mitk::IOUtil::SaveImage(outs[0], name);
      name = filename + "-hog1-" + us::any_value_to_string(ranges[i])+".nii.gz";
      mitk::IOUtil::SaveImage(outs[1], name);
      name = filename + "-hog2-" + us::any_value_to_string(ranges[i])+".nii.gz";
      mitk::IOUtil::SaveImage(outs[2], name);
    }
  }

  return 0;
}
  void HeightFieldSurfaceClipImageFilter::GenerateData()
  {
    const Image *inputImage = this->GetInput(0);

    const Image *outputImage = this->GetOutput();

    m_InputTimeSelector->SetInput(inputImage);
    m_OutputTimeSelector->SetInput(outputImage);

    Image::RegionType outputRegion = outputImage->GetRequestedRegion();
    const TimeGeometry *outputTimeGeometry = outputImage->GetTimeGeometry();
    const TimeGeometry *inputTimeGeometry = inputImage->GetTimeGeometry();
    ScalarType timeInMS;

    int timestep = 0;
    int tstart = outputRegion.GetIndex(3);
    int tmax = tstart + outputRegion.GetSize(3);

    for (unsigned int i = 1; i < this->GetNumberOfInputs(); ++i)
    {
      Surface *inputSurface = const_cast<Surface *>(dynamic_cast<Surface *>(itk::ProcessObject::GetInput(i)));

      if (!outputImage->IsInitialized() || inputSurface == nullptr)
        return;

      MITK_INFO << "Plane: " << i;
      MITK_INFO << "Clipping: Start\n";

      // const PlaneGeometry *clippingGeometryOfCurrentTimeStep = nullptr;

      int t;
      for (t = tstart; t < tmax; ++t)
      {
        timeInMS = outputTimeGeometry->TimeStepToTimePoint(t);
        timestep = inputTimeGeometry->TimePointToTimeStep(timeInMS);

        m_InputTimeSelector->SetTimeNr(timestep);
        m_InputTimeSelector->UpdateLargestPossibleRegion();
        m_OutputTimeSelector->SetTimeNr(t);
        m_OutputTimeSelector->UpdateLargestPossibleRegion();

        // Compose IndexToWorld transform of image with WorldToIndexTransform of
        // clipping data for conversion from image index space to plane index space
        AffineTransform3D::Pointer planeWorldToIndexTransform = AffineTransform3D::New();
        inputSurface->GetGeometry(t)->GetIndexToWorldTransform()->GetInverse(planeWorldToIndexTransform);

        AffineTransform3D::Pointer imageToPlaneTransform = AffineTransform3D::New();
        imageToPlaneTransform->SetIdentity();

        imageToPlaneTransform->Compose(inputTimeGeometry->GetGeometryForTimeStep(t)->GetIndexToWorldTransform());
        imageToPlaneTransform->Compose(planeWorldToIndexTransform);

        MITK_INFO << "Accessing ITK function...\n";
        if (i == 1)
        {
          AccessByItk_3(m_InputTimeSelector->GetOutput(),
                        _InternalComputeClippedImage,
                        this,
                        inputSurface->GetVtkPolyData(t),
                        imageToPlaneTransform);
        }
        else
        {
          mitk::Image::Pointer extensionImage = m_OutputTimeSelector->GetOutput()->Clone();
          AccessByItk_3(
            extensionImage, _InternalComputeClippedImage, this, inputSurface->GetVtkPolyData(t), imageToPlaneTransform);
        }
        if (m_ClippingMode == CLIPPING_MODE_MULTIPLANE)
          m_MultiPlaneValue = m_MultiPlaneValue * 2;
      }
    }

    m_TimeOfHeaderInitialization.Modified();
  }
mitk::GIFVolumetricStatistics::FeatureListType mitk::GIFVolumetricStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask)
{
  FeatureListType featureList;
  if (image->GetDimension() < 3)
  {
    return featureList;
  }


  AccessByItk_3(image, CalculateVolumeStatistic, mask, featureList, FeatureDescriptionPrefix());
  AccessByItk_3(mask, CalculateLargestDiameter, image, featureList, FeatureDescriptionPrefix());

  vtkSmartPointer<vtkImageMarchingCubes> mesher = vtkSmartPointer<vtkImageMarchingCubes>::New();
  vtkSmartPointer<vtkMassProperties> stats = vtkSmartPointer<vtkMassProperties>::New();
  mesher->SetInputData(mask->GetVtkImageData());
  mesher->SetValue(0, 0.5);
  stats->SetInputConnection(mesher->GetOutputPort());
  stats->Update();

  double pi = vnl_math::pi;

  double meshVolume = stats->GetVolume();
  double meshSurf = stats->GetSurfaceArea();
  double pixelVolume = featureList[1].second;
  double pixelSurface = featureList[3].second;

  MITK_INFO << "Surface: " << pixelSurface << " Volume: " << pixelVolume;

  double compactness1 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 2.0 / 3.0));
  double compactness1Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 2.0 / 3.0));
  //This is the definition used by Aertz. However, due to 2/3 this feature is not demensionless. Use compactness3 instead.

  double compactness2 = 36 * pi*pixelVolume*pixelVolume / meshSurf / meshSurf / meshSurf;
  double compactness2MeshMesh = 36 * pi*meshVolume*meshVolume / meshSurf / meshSurf / meshSurf;
  double compactness2Pixel = 36 * pi*pixelVolume*pixelVolume / pixelSurface / pixelSurface / pixelSurface;
  double compactness3 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 3.0 / 2.0));
  double compactness3MeshMesh = meshVolume / (std::sqrt(pi) * std::pow(meshSurf, 3.0 / 2.0));
  double compactness3Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 3.0 / 2.0));

  double sphericity = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / meshSurf;
  double sphericityMesh = std::pow(pi, 1 / 3.0) *std::pow(6 * meshVolume, 2.0 / 3.0) / meshSurf;
  double sphericityPixel = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / pixelSurface;
  double surfaceToVolume = meshSurf / meshVolume;
  double surfaceToVolumePixel = pixelSurface / pixelVolume;
  double sphericalDisproportion = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0);
  double sphericalDisproportionMesh = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * meshVolume, 2.0 / 3.0);
  double sphericalDisproportionPixel = pixelSurface / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0);
  double asphericity = std::pow(1.0/compactness2, (1.0 / 3.0)) - 1;
  double asphericityMesh = std::pow(1.0 / compactness2MeshMesh, (1.0 / 3.0)) - 1;
  double asphericityPixel = std::pow(1.0/compactness2Pixel, (1.0 / 3.0)) - 1;

  //Calculate center of mass shift
  int xx = mask->GetDimensions()[0];
  int yy = mask->GetDimensions()[1];
  int zz = mask->GetDimensions()[2];

  double xd = mask->GetGeometry()->GetSpacing()[0];
  double yd = mask->GetGeometry()->GetSpacing()[1];
  double zd = mask->GetGeometry()->GetSpacing()[2];

  vtkSmartPointer<vtkDoubleArray> dataset1Arr = vtkSmartPointer<vtkDoubleArray>::New();
  vtkSmartPointer<vtkDoubleArray> dataset2Arr = vtkSmartPointer<vtkDoubleArray>::New();
  vtkSmartPointer<vtkDoubleArray> dataset3Arr = vtkSmartPointer<vtkDoubleArray>::New();
  dataset1Arr->SetNumberOfComponents(1);
  dataset2Arr->SetNumberOfComponents(1);
  dataset3Arr->SetNumberOfComponents(1);
  dataset1Arr->SetName("M1");
  dataset2Arr->SetName("M2");
  dataset3Arr->SetName("M3");

  vtkSmartPointer<vtkDoubleArray> dataset1ArrU = vtkSmartPointer<vtkDoubleArray>::New();
  vtkSmartPointer<vtkDoubleArray> dataset2ArrU = vtkSmartPointer<vtkDoubleArray>::New();
  vtkSmartPointer<vtkDoubleArray> dataset3ArrU = vtkSmartPointer<vtkDoubleArray>::New();
  dataset1ArrU->SetNumberOfComponents(1);
  dataset2ArrU->SetNumberOfComponents(1);
  dataset3ArrU->SetNumberOfComponents(1);
  dataset1ArrU->SetName("M1");
  dataset2ArrU->SetName("M2");
  dataset3ArrU->SetName("M3");

  for (int x = 0; x < xx; x++)
  {
    for (int y = 0; y < yy; y++)
    {
      for (int z = 0; z < zz; z++)
      {
        itk::Image<int,3>::IndexType index;

        index[0] = x;
        index[1] = y;
        index[2] = z;

        mitk::ScalarType pxImage;
        mitk::ScalarType pxMask;

        mitkPixelTypeMultiplex5(
              mitk::FastSinglePixelAccess,
              image->GetChannelDescriptor().GetPixelType(),
              image,
              image->GetVolumeData(),
              index,
              pxImage,
              0);

        mitkPixelTypeMultiplex5(
              mitk::FastSinglePixelAccess,
              mask->GetChannelDescriptor().GetPixelType(),
              mask,
              mask->GetVolumeData(),
              index,
              pxMask,
              0);

        //Check if voxel is contained in segmentation
        if (pxMask > 0)
        {
          dataset1ArrU->InsertNextValue(x*xd);
          dataset2ArrU->InsertNextValue(y*yd);
          dataset3ArrU->InsertNextValue(z*zd);

          if (pxImage == pxImage)
          {
            dataset1Arr->InsertNextValue(x*xd);
            dataset2Arr->InsertNextValue(y*yd);
            dataset3Arr->InsertNextValue(z*zd);
          }
        }
      }
    }
  }

  vtkSmartPointer<vtkTable> datasetTable = vtkSmartPointer<vtkTable>::New();
  datasetTable->AddColumn(dataset1Arr);
  datasetTable->AddColumn(dataset2Arr);
  datasetTable->AddColumn(dataset3Arr);

  vtkSmartPointer<vtkTable> datasetTableU = vtkSmartPointer<vtkTable>::New();
  datasetTableU->AddColumn(dataset1ArrU);
  datasetTableU->AddColumn(dataset2ArrU);
  datasetTableU->AddColumn(dataset3ArrU);

  vtkSmartPointer<vtkPCAStatistics> pcaStatistics = vtkSmartPointer<vtkPCAStatistics>::New();
  pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTable);
  pcaStatistics->SetColumnStatus("M1", 1);
  pcaStatistics->SetColumnStatus("M2", 1);
  pcaStatistics->SetColumnStatus("M3", 1);
  pcaStatistics->RequestSelectedColumns();
  pcaStatistics->SetDeriveOption(true);
  pcaStatistics->Update();

  vtkSmartPointer<vtkDoubleArray> eigenvalues = vtkSmartPointer<vtkDoubleArray>::New();
  pcaStatistics->GetEigenvalues(eigenvalues);

  pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTableU);
  pcaStatistics->Update();
  vtkSmartPointer<vtkDoubleArray> eigenvaluesU = vtkSmartPointer<vtkDoubleArray>::New();
  pcaStatistics->GetEigenvalues(eigenvaluesU);

  std::vector<double> eigen_val(3);
  std::vector<double> eigen_valUC(3);
  eigen_val[2] = eigenvalues->GetValue(0);
  eigen_val[1] = eigenvalues->GetValue(1);
  eigen_val[0] = eigenvalues->GetValue(2);
  eigen_valUC[2] = eigenvaluesU->GetValue(0);
  eigen_valUC[1] = eigenvaluesU->GetValue(1);
  eigen_valUC[0] = eigenvaluesU->GetValue(2);

  double major = 4*sqrt(eigen_val[2]);
  double minor = 4*sqrt(eigen_val[1]);
  double least = 4*sqrt(eigen_val[0]);
  double elongation = (major == 0) ? 0 : sqrt(eigen_val[1] / eigen_val[2]);
  double flatness = (major == 0) ? 0 : sqrt(eigen_val[0] / eigen_val[2]);
  double majorUC = 4*sqrt(eigen_valUC[2]);
  double minorUC = 4*sqrt(eigen_valUC[1]);
  double leastUC = 4*sqrt(eigen_valUC[0]);
  double elongationUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[1] / eigen_valUC[2]);
  double flatnessUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[0] / eigen_valUC[2]);

  std::string prefix = FeatureDescriptionPrefix();
  featureList.push_back(std::make_pair(prefix + "Volume (mesh based)",meshVolume));
  featureList.push_back(std::make_pair(prefix + "Surface (mesh based)",meshSurf));
  featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (mesh based)",surfaceToVolume));
  featureList.push_back(std::make_pair(prefix + "Sphericity (mesh based)",sphericity));
  featureList.push_back(std::make_pair(prefix + "Sphericity (mesh, mesh based)", sphericityMesh));
  featureList.push_back(std::make_pair(prefix + "Asphericity (mesh based)", asphericity));
  featureList.push_back(std::make_pair(prefix + "Asphericity (mesh, mesh based)", asphericityMesh));
  featureList.push_back(std::make_pair(prefix + "Compactness 1 (mesh based)", compactness3));
  featureList.push_back(std::make_pair(prefix + "Compactness 1 old (mesh based)" ,compactness1));
  featureList.push_back(std::make_pair(prefix + "Compactness 2 (mesh based)",compactness2));
  featureList.push_back(std::make_pair(prefix + "Compactness 1 (mesh, mesh based)", compactness3MeshMesh));
  featureList.push_back(std::make_pair(prefix + "Compactness 2 (mesh, mesh based)", compactness2MeshMesh));
  featureList.push_back(std::make_pair(prefix + "Spherical disproportion (mesh based)", sphericalDisproportion));
  featureList.push_back(std::make_pair(prefix + "Spherical disproportion (mesh, mesh based)", sphericalDisproportionMesh));
  featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (voxel based)", surfaceToVolumePixel));
  featureList.push_back(std::make_pair(prefix + "Sphericity (voxel based)", sphericityPixel));
  featureList.push_back(std::make_pair(prefix + "Asphericity (voxel based)", asphericityPixel));
  featureList.push_back(std::make_pair(prefix + "Compactness 1 (voxel based)", compactness3Pixel));
  featureList.push_back(std::make_pair(prefix + "Compactness 1 old (voxel based)", compactness1Pixel));
  featureList.push_back(std::make_pair(prefix + "Compactness 2 (voxel based)", compactness2Pixel));
  featureList.push_back(std::make_pair(prefix + "Spherical disproportion (voxel based)", sphericalDisproportionPixel));
  featureList.push_back(std::make_pair(prefix + "PCA Major axis length",major));
  featureList.push_back(std::make_pair(prefix + "PCA Minor axis length",minor));
  featureList.push_back(std::make_pair(prefix + "PCA Least axis length",least));
  featureList.push_back(std::make_pair(prefix + "PCA Elongation",elongation));
  featureList.push_back(std::make_pair(prefix + "PCA Flatness",flatness));
  featureList.push_back(std::make_pair(prefix + "PCA Major axis length (uncorrected)", majorUC));
  featureList.push_back(std::make_pair(prefix + "PCA Minor axis length (uncorrected)", minorUC));
  featureList.push_back(std::make_pair(prefix + "PCA Least axis length (uncorrected)", leastUC));
  featureList.push_back(std::make_pair(prefix + "PCA Elongation (uncorrected)", elongationUC));
  featureList.push_back(std::make_pair(prefix + "PCA Flatness (uncorrected)", flatnessUC));

  return featureList;
}