diff --git a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h index e3fc2a0836..ff8513ed18 100644 --- a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h +++ b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h @@ -1,138 +1,139 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkAbstractGlobalImageFeature_h #define mitkAbstractGlobalImageFeature_h #include #include #include #include // Eigen #include // STD Includes // MITK includes #include namespace mitk { class MITKCLCORE_EXPORT AbstractGlobalImageFeature : public BaseData { public: + mitkClassMacro(AbstractGlobalImageFeature, BaseData) typedef std::vector< std::pair > FeatureListType; typedef std::vector< std::string> FeatureNameListType; typedef std::map ParameterTypes; /** * \brief Calculates the feature of this abstact interface. Does not necessarily considers the parameter settings. */ virtual FeatureListType CalculateFeatures(const Image::Pointer & feature, const Image::Pointer &mask) = 0; /** * \brief Calculates the feature of this abstact interface. Does not necessarily considers the parameter settings. */ virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) = 0; /** * \brief Returns a list of the names of all features that are calculated from this class */ virtual FeatureNameListType GetFeatureNames() = 0; itkSetMacro(Prefix, std::string); itkSetMacro(ShortName, std::string); itkSetMacro(LongName, std::string); itkSetMacro(Direction, int); void SetParameter(ParameterTypes param) { m_Parameter=param; }; itkGetConstMacro(Prefix, std::string); itkGetConstMacro(ShortName, std::string); itkGetConstMacro(LongName, std::string); itkGetConstMacro(Parameter, ParameterTypes); itkGetConstMacro(Direction, int); itkSetMacro(MinimumIntensity, float); itkSetMacro(UseMinimumIntensity, bool); itkSetMacro(MaximumIntensity, float); itkSetMacro(UseMaximumIntensity, bool); itkGetConstMacro(MinimumIntensity, float); itkGetConstMacro(UseMinimumIntensity, bool); itkGetConstMacro(MaximumIntensity, float); itkGetConstMacro(UseMaximumIntensity, bool); itkSetMacro(Bins, int); itkGetConstMacro(Bins, int); std::string GetOptionPrefix() const { if (m_Prefix.length() > 0) return m_Prefix + "::" + m_ShortName; return m_ShortName; } virtual void AddArguments(mitkCommandLineParser &parser) = 0; std::vector SplitDouble(std::string str, char delimiter); public: //#ifndef DOXYGEN_SKIP virtual void SetRequestedRegionToLargestPossibleRegion() override {}; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override { return true; }; virtual bool VerifyRequestedRegion() override { return false; }; virtual void SetRequestedRegion (const itk::DataObject * /*data*/) override {}; // Override virtual bool IsEmpty() const override { if(IsInitialized() == false) return true; const TimeGeometry* timeGeometry = const_cast(this)->GetUpdatedTimeGeometry(); if(timeGeometry == NULL) return true; return false; } private: std::string m_Prefix; // Prefix before all input parameters std::string m_ShortName; // Name of all variables std::string m_LongName; // Long version of the name (For turning on) ParameterTypes m_Parameter; // Parameter setting double m_MinimumIntensity = 0; bool m_UseMinimumIntensity = false; double m_MaximumIntensity = 100; bool m_UseMaximumIntensity = false; int m_Bins = 256; int m_Direction = 0; //#endif // Skip Doxygen }; } #endif //mitkAbstractGlobalImageFeature_h diff --git a/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp index 95eeeae025..41d4ed7a07 100644 --- a/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp +++ b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp @@ -1,591 +1,582 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkCLPolyToNrrd_cpp #define mitkCLPolyToNrrd_cpp #include "time.h" #include #include #include #include "mitkCommandLineParser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "itkNearestNeighborInterpolateImageFunction.h" #include "itkResampleImageFilter.h" -#include -#include +#include +#include +#include "QmitkRegisterClasses.h" +#include "QmitkRenderWindow.h" +#include "vtkRenderLargeImage.h" +#include "vtkPNGWriter.h" typedef itk::Image< double, 3 > FloatImageType; typedef itk::Image< unsigned char, 3 > MaskImageType; template void ResampleImage(itk::Image* itkImage, float resolution, mitk::Image::Pointer& newImage) { typedef itk::Image ImageType; typedef itk::ResampleImageFilter ResampleFilterType; typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); auto spacing = itkImage->GetSpacing(); auto size = itkImage->GetLargestPossibleRegion().GetSize(); for (int i = 0; i < VImageDimension; ++i) { size[i] = size[i] / (1.0*resolution)*(1.0*spacing[i])+1.0; } spacing.Fill(resolution); resampler->SetInput(itkImage); resampler->SetSize(size); resampler->SetOutputSpacing(spacing); resampler->SetOutputOrigin(itkImage->GetOrigin()); resampler->SetOutputDirection(itkImage->GetDirection()); resampler->Update(); newImage->InitializeByItk(resampler->GetOutput()); mitk::GrabItkImageMemory(resampler->GetOutput(), newImage); } template static void CreateNoNaNMask(itk::Image* itkValue, mitk::Image::Pointer mask, mitk::Image::Pointer& newMask) { typedef itk::Image< TPixel, VImageDimension> LFloatImageType; typedef itk::Image< unsigned char, VImageDimension> LMaskImageType; typename LMaskImageType::Pointer itkMask = LMaskImageType::New(); mitk::CastToItkImage(mask, itkMask); typedef itk::ImageDuplicator< LMaskImageType > DuplicatorType; typename DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage(itkMask); duplicator->Update(); auto tmpMask = duplicator->GetOutput(); itk::ImageRegionIterator mask1Iter(itkMask, itkMask->GetLargestPossibleRegion()); itk::ImageRegionIterator mask2Iter(tmpMask, tmpMask->GetLargestPossibleRegion()); itk::ImageRegionIterator imageIter(itkValue, itkValue->GetLargestPossibleRegion()); while (!mask1Iter.IsAtEnd()) { mask2Iter.Set(0); if (mask1Iter.Value() > 0) { // Is not NaN if (imageIter.Value() == imageIter.Value()) { mask2Iter.Set(1); } } ++mask1Iter; ++mask2Iter; ++imageIter; } newMask->InitializeByItk(tmpMask); mitk::GrabItkImageMemory(tmpMask, newMask); } template static void ResampleMask(itk::Image* itkMoving, mitk::Image::Pointer ref, mitk::Image::Pointer& newMask) { typedef itk::Image< TPixel, VImageDimension> LMaskImageType; typedef itk::NearestNeighborInterpolateImageFunction< LMaskImageType> NearestNeighborInterpolateImageFunctionType; typedef itk::ResampleImageFilter ResampleFilterType; typename NearestNeighborInterpolateImageFunctionType::Pointer nn_interpolator = NearestNeighborInterpolateImageFunctionType::New(); typename LMaskImageType::Pointer itkRef = LMaskImageType::New(); mitk::CastToItkImage(ref, itkRef); typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); resampler->SetInput(itkMoving); resampler->SetReferenceImage(itkRef); resampler->UseReferenceImageOn(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); newMask->InitializeByItk(resampler->GetOutput()); mitk::GrabItkImageMemory(resampler->GetOutput(), newMask); } -static bool fileExists(const std::string& filename) -{ - ifstream infile(filename.c_str()); - bool isGood = infile.good(); - infile.close(); - return isGood; -} - - static void ExtractSlicesFromImages(mitk::Image::Pointer image, mitk::Image::Pointer mask, mitk::Image::Pointer maskNoNaN, int direction, std::vector &imageVector, std::vector &maskVector, std::vector &maskNoNaNVector) { typedef itk::Image< double, 2 > FloatImage2DType; typedef itk::Image< unsigned char, 2 > MaskImage2DType; FloatImageType::Pointer itkFloat = FloatImageType::New(); MaskImageType::Pointer itkMask = MaskImageType::New(); MaskImageType::Pointer itkMaskNoNaN = MaskImageType::New(); mitk::CastToItkImage(mask, itkMask); mitk::CastToItkImage(maskNoNaN, itkMaskNoNaN); mitk::CastToItkImage(image, itkFloat); int idxA, idxB, idxC; switch (direction) { case 0: idxA = 1; idxB = 2; idxC = 0; break; case 1: idxA = 0; idxB = 2; idxC = 1; break; case 2: idxA = 0; idxB = 1; idxC = 2; break; default: idxA = 1; idxB = 2; idxC = 0; break; } auto imageSize = image->GetLargestPossibleRegion().GetSize(); FloatImageType::IndexType index3D; FloatImage2DType::IndexType index2D; FloatImage2DType::SpacingType spacing2D; spacing2D[0] = itkFloat->GetSpacing()[idxA]; spacing2D[1] = itkFloat->GetSpacing()[idxB]; for (int i = 0; i < imageSize[idxC]; ++i) { FloatImage2DType::RegionType region; FloatImage2DType::IndexType start; FloatImage2DType::SizeType size; start[0] = 0; start[1] = 0; size[0] = imageSize[idxA]; size[1] = imageSize[idxB]; region.SetIndex(start); region.SetSize(size); FloatImage2DType::Pointer image2D = FloatImage2DType::New(); image2D->SetRegions(region); image2D->Allocate(); MaskImage2DType::Pointer mask2D = MaskImage2DType::New(); mask2D->SetRegions(region); mask2D->Allocate(); MaskImage2DType::Pointer masnNoNaN2D = MaskImage2DType::New(); masnNoNaN2D->SetRegions(region); masnNoNaN2D->Allocate(); for (int a = 0; a < imageSize[idxA]; ++a) { for (int b = 0; b < imageSize[idxB]; ++b) { index3D[idxA] = a; index3D[idxB] = b; index3D[idxC] = i; index2D[0] = a; index2D[1] = b; image2D->SetPixel(index2D, itkFloat->GetPixel(index3D)); mask2D->SetPixel(index2D, itkMask->GetPixel(index3D)); masnNoNaN2D->SetPixel(index2D, itkMaskNoNaN->GetPixel(index3D)); } } image2D->SetSpacing(spacing2D); mask2D->SetSpacing(spacing2D); masnNoNaN2D->SetSpacing(spacing2D); mitk::Image::Pointer tmpFloatImage = mitk::Image::New(); tmpFloatImage->InitializeByItk(image2D.GetPointer()); mitk::GrabItkImageMemory(image2D, tmpFloatImage); mitk::Image::Pointer tmpMaskImage = mitk::Image::New(); tmpMaskImage->InitializeByItk(mask2D.GetPointer()); mitk::GrabItkImageMemory(mask2D, tmpMaskImage); mitk::Image::Pointer tmpMaskNoNaNImage = mitk::Image::New(); tmpMaskNoNaNImage->InitializeByItk(masnNoNaN2D.GetPointer()); mitk::GrabItkImageMemory(masnNoNaN2D, tmpMaskNoNaNImage); imageVector.push_back(tmpFloatImage); maskVector.push_back(tmpMaskImage); maskNoNaNVector.push_back(tmpMaskNoNaNImage); } } int main(int argc, char* argv[]) { mitk::GIFFirstOrderStatistics::Pointer firstOrderCalculator = mitk::GIFFirstOrderStatistics::New(); mitk::GIFVolumetricStatistics::Pointer volCalculator = mitk::GIFVolumetricStatistics::New(); mitk::GIFCooccurenceMatrix::Pointer coocCalculator = mitk::GIFCooccurenceMatrix::New(); mitk::GIFCooccurenceMatrix2::Pointer cooc2Calculator = mitk::GIFCooccurenceMatrix2::New(); mitk::GIFNeighbouringGreyLevelDependenceFeature::Pointer ngldCalculator = mitk::GIFNeighbouringGreyLevelDependenceFeature::New(); mitk::GIFGrayLevelRunLength::Pointer rlCalculator = mitk::GIFGrayLevelRunLength::New(); - + std::vector features; + features.push_back(firstOrderCalculator.GetPointer()); + features.push_back(volCalculator.GetPointer()); + features.push_back(coocCalculator.GetPointer()); + features.push_back(cooc2Calculator.GetPointer()); + features.push_back(ngldCalculator.GetPointer()); + features.push_back(rlCalculator.GetPointer()); mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); - // required params - parser.addArgument("image", "i", mitkCommandLineParser::InputImage, "Input Image", "Path to the input image file", us::Any(), false); - parser.addArgument("mask", "m", mitkCommandLineParser::InputImage, "Input Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any(), false); - parser.addArgument("d ", "o", mitkCommandLineParser::OutputFile, "Output text file", "Path to output file. The output statistic is appended to this file.", us::Any(), false); + mitk::cl::GlobalImageFeaturesParameter param; + param.AddParameter(parser); + parser.addArgument("--","-", mitkCommandLineParser::String, "---", "---", us::Any(),true); - firstOrderCalculator->AddArguments(parser); // Does not support single direction - volCalculator->AddArguments(parser); // Does not support single direction - coocCalculator->AddArguments(parser); // - cooc2Calculator->AddArguments(parser); // Needs parameter fixing - ngldCalculator->AddArguments(parser); // Needs parameter fixing - rlCalculator->AddArguments(parser); // Does not support single direction + for (auto cFeature : features) + { + cFeature->AddArguments(parser); + } parser.addArgument("--", "-", mitkCommandLineParser::String, "---", "---", us::Any(), true); - - parser.addArgument("header", "head", mitkCommandLineParser::String, "Add Header (Labels) to output", "", us::Any()); - parser.addArgument("first-line-header", "fl-head", mitkCommandLineParser::String, "Add Header (Labels) to first line of output", "", us::Any()); parser.addArgument("description","d",mitkCommandLineParser::String,"Text","Description that is added to the output",us::Any()); - parser.addArgument("same-space", "sp", mitkCommandLineParser::String, "Bool", "Set the spacing of all images to equal. Otherwise an error will be thrown. ", us::Any()); - parser.addArgument("resample-mask", "rm", mitkCommandLineParser::Bool, "Bool", "Resamples the mask to the resolution of the input image ", us::Any()); - parser.addArgument("save-resample-mask", "srm", mitkCommandLineParser::String, "String", "If specified the resampled mask is saved to this path (if -rm is 1)", us::Any()); - parser.addArgument("fixed-isotropic", "fi", mitkCommandLineParser::Float, "Float", "Input image resampled to fixed isotropic resolution given in mm. Should be used with resample-mask ", us::Any()); parser.addArgument("direction", "dir", mitkCommandLineParser::String, "Int", "Allows to specify the direction for Cooc and RL. 0: All directions, 1: Only single direction (Test purpose), 2,3,4... Without dimension 0,1,2... ", us::Any()); parser.addArgument("slice-wise", "slice", mitkCommandLineParser::String, "Int", "Allows to specify if the image is processed slice-wise (number giving direction) ", us::Any()); - parser.addArgument("minimum-intensity", "minimum", mitkCommandLineParser::String, "Float", "Minimum intensity. If set, it is overwritten by more specific intensity minima", us::Any()); - parser.addArgument("maximum-intensity", "maximum", mitkCommandLineParser::String, "Float", "Maximum intensity. If set, it is overwritten by more specific intensity maxima", us::Any()); - parser.addArgument("bins", "bins", mitkCommandLineParser::String, "Int", "Number of bins if bins are used. If set, it is overwritten by more specific bin count", us::Any()); parser.addArgument("output-mode", "omode", mitkCommandLineParser::Int, "Int", "Defines if the results of an image / slice are written in a single row (0 , default) or column (1)."); // 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 parsedArgs = parser.parseArguments(argc, argv); + param.ParseParameter(parsedArgs); if (parsedArgs.size()==0) { return EXIT_FAILURE; } if ( parsedArgs.count("help") || parsedArgs.count("h")) { return EXIT_SUCCESS; } - MITK_INFO << "Version: 1.15"; + std::string version = "Version: 1.16"; + MITK_INFO << version; - //bool useCooc = parsedArgs.count("cooccurence"); - - bool resampleMask = false; - if (parsedArgs.count("resample-mask")) + std::ofstream log; + if (param.useLogfile) { - resampleMask = us::any_cast(parsedArgs["resample-mask"]); + log.open(param.logfilePath, std::ios::app); + log << version; + log << "Image: " << param.imagePath; + log << "Mask: " << param.maskPath; } mitk::Image::Pointer image; mitk::Image::Pointer mask; - mitk::Image::Pointer tmpImage = mitk::IOUtil::LoadImage(parsedArgs["image"].ToString()); - mitk::Image::Pointer tmpMask = mitk::IOUtil::LoadImage(parsedArgs["mask"].ToString()); + mitk::Image::Pointer tmpImage = mitk::IOUtil::LoadImage(param.imagePath); + mitk::Image::Pointer tmpMask = mitk::IOUtil::LoadImage(param.maskPath); image = tmpImage; mask = tmpMask; - - std::string imageName = itksys::SystemTools::GetFilenameName(parsedArgs["image"].ToString()); - std::string maskName = itksys::SystemTools::GetFilenameName(parsedArgs["mask"].ToString()); - std::string folderName = itksys::SystemTools::GetFilenamePath(parsedArgs["image"].ToString()); - - - if ((image->GetDimension() != mask->GetDimension())) { MITK_INFO << "Dimension of image does not match. "; MITK_INFO << "Correct one image, may affect the result"; if (image->GetDimension() == 2) { mitk::Convert2Dto3DImageFilter::Pointer multiFilter2 = mitk::Convert2Dto3DImageFilter::New(); multiFilter2->SetInput(tmpImage); multiFilter2->Update(); image = multiFilter2->GetOutput(); } if (mask->GetDimension() == 2) { mitk::Convert2Dto3DImageFilter::Pointer multiFilter3 = mitk::Convert2Dto3DImageFilter::New(); multiFilter3->SetInput(tmpMask); multiFilter3->Update(); mask = multiFilter3->GetOutput(); } } int writeDirection = 0; if (parsedArgs.count("output-mode")) { writeDirection = us::any_cast(parsedArgs["output-mode"]); } - if (parsedArgs.count("fixed-isotropic")) + if (param.resampleToFixIsotropic) { mitk::Image::Pointer newImage = mitk::Image::New(); - float resolution = us::any_cast(parsedArgs["fixed-isotropic"]); - AccessByItk_2(image, ResampleImage, resolution, newImage); + AccessByItk_2(image, ResampleImage, param.resampleResolution, newImage); image = newImage; } - bool fixDifferentSpaces = parsedArgs.count("same-space"); if ( ! mitk::Equal(mask->GetGeometry(0)->GetOrigin(), image->GetGeometry(0)->GetOrigin())) { MITK_INFO << "Not equal Origins"; - if (fixDifferentSpaces) + if (param.ensureSameSpace) { MITK_INFO << "Warning!"; MITK_INFO << "The origin of the input image and the mask do not match. They are"; MITK_INFO << "now corrected. Please check to make sure that the images still match"; image->GetGeometry(0)->SetOrigin(mask->GetGeometry(0)->GetOrigin()); } else { return -1; } } - if (resampleMask) + if (param.resampleMask) { mitk::Image::Pointer newMaskImage = mitk::Image::New(); AccessByItk_2(mask, ResampleMask, image, newMaskImage); mask = newMaskImage; - if (parsedArgs.count("save-resample-mask")) - { - mitk::IOUtil::SaveImage(mask, parsedArgs["save-resample-mask"].ToString()); - } } if ( ! mitk::Equal(mask->GetGeometry(0)->GetSpacing(), image->GetGeometry(0)->GetSpacing())) { MITK_INFO << "Not equal Sapcings"; - if (fixDifferentSpaces) + if (param.ensureSameSpace) { MITK_INFO << "Warning!"; MITK_INFO << "The spacing of the mask was set to match the spacing of the input image."; MITK_INFO << "This might cause unintended spacing of the mask image"; image->GetGeometry(0)->SetSpacing(mask->GetGeometry(0)->GetSpacing()); } else { MITK_INFO << "The spacing of the mask and the input images is not equal."; MITK_INFO << "Terminating the programm. You may use the '-fi' option"; return -1; } } int direction = 0; if (parsedArgs.count("direction")) { direction = mitk::cl::splitDouble(parsedArgs["direction"].ToString(), ';')[0]; } MITK_INFO << "Start creating Mask without NaN"; mitk::Image::Pointer maskNoNaN = mitk::Image::New(); AccessByItk_2(image, CreateNoNaNMask, mask, maskNoNaN); //CreateNoNaNMask(mask, image, maskNoNaN); bool sliceWise = false; int sliceDirection = 0; int currentSlice = 0; bool imageToProcess = true; std::vector floatVector; std::vector maskVector; std::vector maskNoNaNVector; if ((parsedArgs.count("slice-wise")) && image->GetDimension() > 2) { MITK_INFO << "Enabled slice-wise"; sliceWise = true; sliceDirection = mitk::cl::splitDouble(parsedArgs["slice-wise"].ToString(), ';')[0]; MITK_INFO << sliceDirection; ExtractSlicesFromImages(image, mask, maskNoNaN, sliceDirection, floatVector, maskVector, maskNoNaNVector); MITK_INFO << "Slice"; } - if (parsedArgs.count("minimum-intensity")) - { - float minimum = mitk::cl::splitDouble(parsedArgs["minimum-intensity"].ToString(), ';')[0]; - firstOrderCalculator->SetMinimumIntensity(minimum); - firstOrderCalculator->SetUseMinimumIntensity(true); - volCalculator->SetMinimumIntensity(minimum); - volCalculator->SetUseMinimumIntensity(true); - coocCalculator->SetMinimumIntensity(minimum); - coocCalculator->SetUseMinimumIntensity(true); - cooc2Calculator->SetMinimumIntensity(minimum); - cooc2Calculator->SetUseMinimumIntensity(true); - ngldCalculator->SetMinimumIntensity(minimum); - ngldCalculator->SetUseMinimumIntensity(true); - rlCalculator->SetMinimumIntensity(minimum); - rlCalculator->SetUseMinimumIntensity(true); - } - - if (parsedArgs.count("maximum-intensity")) - { - float minimum = mitk::cl::splitDouble(parsedArgs["maximum-intensity"].ToString(), ';')[0]; - firstOrderCalculator->SetMaximumIntensity(minimum); - firstOrderCalculator->SetUseMaximumIntensity(true); - volCalculator->SetMaximumIntensity(minimum); - volCalculator->SetUseMaximumIntensity(true); - coocCalculator->SetMaximumIntensity(minimum); - coocCalculator->SetUseMaximumIntensity(true); - cooc2Calculator->SetMaximumIntensity(minimum); - cooc2Calculator->SetUseMaximumIntensity(true); - ngldCalculator->SetMaximumIntensity(minimum); - ngldCalculator->SetUseMaximumIntensity(true); - rlCalculator->SetMaximumIntensity(minimum); - rlCalculator->SetUseMaximumIntensity(true); - } - - if (parsedArgs.count("bins")) + for (auto cFeature : features) { - int minimum = mitk::cl::splitDouble(parsedArgs["bins"].ToString(), ';')[0]; - firstOrderCalculator->SetBins(minimum); - volCalculator->SetBins(minimum); - coocCalculator->SetBins(minimum); - cooc2Calculator->SetBins(minimum); - ngldCalculator->SetBins(minimum); - rlCalculator->SetBins(minimum); + if (param.defineGlobalMinimumIntensity) + { + cFeature->SetMinimumIntensity(param.globalMinimumIntensity); + cFeature->SetUseMinimumIntensity(true); + } + if (param.defineGlobalMaximumIntensity) + { + cFeature->SetMaximumIntensity(param.globalMaximumIntensity); + cFeature->SetUseMaximumIntensity(true); + } + if (param.defineGlobalNumberOfBins) + { + cFeature->SetBins(param.globalNumberOfBins); + } + cFeature->SetParameter(parsedArgs); + cFeature->SetDirection(direction); } - firstOrderCalculator->SetParameter(parsedArgs); - firstOrderCalculator->SetDirection(direction); - volCalculator->SetParameter(parsedArgs); - volCalculator->SetDirection(direction); - coocCalculator->SetParameter(parsedArgs); - coocCalculator->SetDirection(direction); - cooc2Calculator->SetParameter(parsedArgs); - cooc2Calculator->SetDirection(direction); - ngldCalculator->SetParameter(parsedArgs); - ngldCalculator->SetDirection(direction); - rlCalculator->SetParameter(parsedArgs); - rlCalculator->SetDirection(direction); - - //std::ofstream output(parsedArgs["output"].ToString(), std::ios::app); bool addDescription = parsedArgs.count("description"); - bool withHeader = parsedArgs.count("header"); - - if (parsedArgs.count("first-line-header")) - { - MITK_INFO << "First line Header"; - withHeader = !fileExists(parsedArgs["output"].ToString()); - MITK_INFO << withHeader; - } - mitk::cl::FeatureResultWritter writer(parsedArgs["output"].ToString(), writeDirection); - - + mitk::cl::FeatureResultWritter writer(param.outputPath, writeDirection); std::string description = ""; if (addDescription) { description = parsedArgs["description"].ToString(); } mitk::Image::Pointer cImage = image; mitk::Image::Pointer cMask = mask; mitk::Image::Pointer cMaskNoNaN = maskNoNaN; - if (withHeader) + if (param.useHeader) { writer.AddColumn("Patient"); writer.AddColumn("Image"); writer.AddColumn("Segmentation"); } + QApplication qtapplication(argc, argv); + QmitkRegisterClasses(); + mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); + + QmitkRenderWindow renderWindow; + renderWindow.GetRenderer()->SetDataStorage(ds); + while (imageToProcess) { if (sliceWise) { cImage = floatVector[currentSlice]; cMask = maskVector[currentSlice]; cMaskNoNaN = maskNoNaNVector[currentSlice]; imageToProcess = (floatVector.size()-1 > (currentSlice)) ? true : false ; } else { imageToProcess = false; } + // + // Start Saving image to folder. + // + /* + + auto node = mitk::DataNode::New(); + node->SetData(cImage); + auto nodeM = mitk::DataNode::New(); + nodeM->SetData(cMask); + ds->Add(node); + ds->Add(nodeM); + + mitk::TimeGeometry::Pointer geo = ds->ComputeBoundingGeometry3D(ds->GetAll()); + mitk::RenderingManager::GetInstance()->InitializeViews(geo); + + mitk::SliceNavigationController::Pointer sliceNaviController = renderWindow.GetSliceNavigationController(); + if (sliceNaviController) + sliceNaviController->GetSlice()->SetPos(0); + + renderWindow.show(); + renderWindow.resize(256, 256); + renderWindow.GetRenderer()->PrepareRender(); + + vtkRenderWindow* renderWindow2 = renderWindow.GetVtkRenderWindow(); + mitk::BaseRenderer* baserenderer = mitk::BaseRenderer::GetInstance(renderWindow2); + auto vtkRender = baserenderer->GetVtkRenderer(); + vtkRender->GetRenderWindow()->WaitForCompletion(); + + vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); + magnifier->SetInput(vtkRender); + magnifier->SetMagnification(3.0); + + auto fileWriter = vtkPNGWriter::New(); + fileWriter->SetInputConnection(magnifier->GetOutputPort()); + fileWriter->SetFileName("e:\\tmp\\bonekamp\\test.png"); + fileWriter->Write(); + fileWriter->Delete(); + */ + // + // End Saving image to folder. + // + + + if (param.writeAnalysisImage) + { + mitk::IOUtil::SaveImage(cImage, param.anaylsisImagePath); + } + if (param.writeAnalysisMask) + { + mitk::IOUtil::SaveImage(cImage, param.analysisMaskPath); + } mitk::AbstractGlobalImageFeature::FeatureListType stats; - firstOrderCalculator->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); - volCalculator->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); - coocCalculator->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); - cooc2Calculator->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); - ngldCalculator->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); - rlCalculator->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); + for (auto cFeature : features) + { + cFeature->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); + } for (std::size_t i = 0; i < stats.size(); ++i) { std::cout << stats[i].first << " - " << stats[i].second << std::endl; } - writer.AddHeader(description, currentSlice, stats, withHeader, addDescription); + writer.AddHeader(description, currentSlice, stats, param.useHeader, addDescription); if (true) { - writer.AddColumn(folderName); - writer.AddColumn(imageName); - writer.AddColumn(maskName); + writer.AddColumn(param.imageFolder); + writer.AddColumn(param.imageName); + writer.AddColumn(param.maskName); } - writer.AddResult(description, currentSlice, stats, withHeader, addDescription); + writer.AddResult(description, currentSlice, stats, param.useHeader, addDescription); ++currentSlice; } + + if (param.useLogfile) + { + log << "Finished calculation"; + log.close(); + } return 0; } #endif diff --git a/Modules/Classification/CLMiniApps/CMakeLists.txt b/Modules/Classification/CLMiniApps/CMakeLists.txt index 1f7ae5cae7..a8a26e1ad5 100644 --- a/Modules/Classification/CLMiniApps/CMakeLists.txt +++ b/Modules/Classification/CLMiniApps/CMakeLists.txt @@ -1,137 +1,137 @@ option(BUILD_ClassificationMiniApps "Build commandline tools for classification" OFF) if(BUILD_ClassificationMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( classificationminiapps RandomForestTraining^^MitkCLVigraRandomForest NativeHeadCTSegmentation^^MitkCLVigraRandomForest ManualSegmentationEvaluation^^MitkCLVigraRandomForest - CLGlobalImageFeatures^^MitkCore_MitkCLUtilities + CLGlobalImageFeatures^^MitkCore_MitkCLUtilities_MitkQtWidgetsExt CLMRNormalization^^MitkCore_MitkCLUtilities_MitkCLMRUtilities CLStaple^^MitkCore_MitkCLUtilities CLVoxelFeatures^^MitkCore_MitkCLUtilities CLDicom2Nrrd^^MitkCore CLPolyToNrrd^^MitkCore CLImageTypeConverter^^MitkCore CLResampleImageToReference^^MitkCore CLRandomSampling^^MitkCore_MitkCLUtilities CLRemoveEmptyVoxels^^MitkCore CLN4^^MitkCore CLMultiForestPrediction^^MitkDataCollection_MitkCLVigraRandomForest CLNrrdToPoly^^MitkCore CL2Dto3DImage^^MitkCore # RandomForestPrediction^^MitkCLVigraRandomForest ) foreach(classificationminiapps ${classificationminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${classificationminiapps}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCLCore MitkCommandLine ${dependencies_list} PACKAGE_DEPENDS ITK Qt5|Core Vigra CPP_FILES ${appname}.cpp ) # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() # This mini app does not depend on mitkDiffusionImaging at all #mitk_create_executable(CLGlobalImageFeatures # DEPENDS MitkCore MitkCLUtilities # CPP_FILES CLGlobalImageFeatures.cpp mitkCommandLineParser.cpp #) mitk_create_executable(CLSimpleVoxelClassification DEPENDS MitkCore MitkCLCore MitkDataCollection MitkCLVigraRandomForest MitkCommandLine CPP_FILES CLSimpleVoxelClassification.cpp ) # This mini app does not depend on mitkDiffusionImaging at all mitk_create_executable(CLVoxelClassification DEPENDS MitkCore MitkCLCore MitkDataCollection MitkCLImportanceWeighting MitkCLVigraRandomForest CPP_FILES CLVoxelClassification.cpp ) #mitk_create_executable(CLBrainMask # DEPENDS MitkCore MitkCLUtilities # CPP_FILES CLBrainMask.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLImageConverter # DEPENDS MitkCore # CPP_FILES CLImageConverter.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLSurWeighting # DEPENDS MitkCore MitkCLUtilities MitkDataCollection #MitkCLImportanceWeighting # CPP_FILES CLSurWeighting.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLImageCropper # DEPENDS MitkCore MitkCLUtilities MitkAlgorithmsExt # CPP_FILES CLImageCropper.cpp mitkCommandLineParser.cpp #) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h index 3bbde6fc3f..da322c41ea 100644 --- a/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h +++ b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h @@ -1,44 +1,78 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkGlobalImageFeaturesParameter_h #define mitkGlobalImageFeaturesParameter_h #include "MitkCLUtilitiesExports.h" #include "mitkCommandLineParser.h" #include namespace mitk { namespace cl { class MITKCLUTILITIES_EXPORT GlobalImageFeaturesParameter { public: void AddParameter(mitkCommandLineParser &parser); void ParseParameter(std::map parsedArgs); std::string imagePath; + std::string imageName; + std::string imageFolder; std::string maskPath; + std::string maskName; + std::string maskFolder; std::string outputPath; + + bool useLogfile; + std::string logfilePath; + bool writeAnalysisImage; + std::string anaylsisImagePath; + bool writeAnalysisMask; + std::string analysisMaskPath; + + bool useHeader; + bool useHeaderForFirstLineOnly; + + bool ensureSameSpace; + bool resampleMask; + bool resampleToFixIsotropic; + double resampleResolution; + + bool defineGlobalMinimumIntensity; + double globalMinimumIntensity; + bool defineGlobalMaximumIntensity; + double globalMaximumIntensity; + bool defineGlobalNumberOfBins; + int globalNumberOfBins; + + private: + void ParseFileLocations(std::map &parsedArgs); + void ParseAdditionalOutputs(std::map &parsedArgs); + void ParseHeaderInformation(std::map &parsedArgs); + void ParseMaskAdaptation(std::map &parsedArgs); + void ParseGlobalFeatureParameter(std::map &parsedArgs); + }; } } #endif //mitkGlobalImageFeaturesParameter_h \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp index d96b9ea1c0..114656a8fa 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp @@ -1,270 +1,301 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include // MITK #include #include #include // ITK #include #include // STL #include template void CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderStatistics::FeatureListType & featureList, mitk::GIFFirstOrderStatistics::ParameterStruct params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typedef typename FilterType::HistogramType HistogramType; typedef typename HistogramType::IndexType HIndexType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double imageRange = minMaxComputer->GetMaximum() - minMaxComputer->GetMinimum(); typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput( itkImage ); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->SetUseHistograms(true); if (params.m_UseCtRange) { labelStatisticsImageFilter->SetHistogramParameters(1024.5+3096.5, -1024.5,3096.5); } else { double min = minMaxComputer->GetMinimum() -0.5; double max = minMaxComputer->GetMaximum() +0.5; if (params.UseMinimumIntensity) min = params.MinimumIntensity; if (params.UseMaximumIntensity) max = params.MaximumIntensity; labelStatisticsImageFilter->SetHistogramParameters(params.Bins, min,max); } labelStatisticsImageFilter->Update(); // --------------- Range -------------------- double range = labelStatisticsImageFilter->GetMaximum(1) - labelStatisticsImageFilter->GetMinimum(1); // --------------- Uniformity, Entropy -------------------- double count = labelStatisticsImageFilter->GetCount(1); //double std_dev = labelStatisticsImageFilter->GetSigma(1); double uncorrected_std_dev = std::sqrt((count - 1) / count * labelStatisticsImageFilter->GetVariance(1)); double mean = labelStatisticsImageFilter->GetMean(1); auto histogram = labelStatisticsImageFilter->GetHistogram(1); bool histogramIsCalculated = histogram; HIndexType index; index.SetSize(1); double uniformity = 0; double entropy = 0; double squared_sum = 0; double kurtosis = 0; double mean_absolut_deviation = 0; double skewness = 0; double sum_prob = 0; double binWidth = 0; - double p10th = 0; - double p25th = 0; - double p75th = 0; - double p90th = 0; + double p05th = 0, p10th = 0, p15th = 0, p20th = 0, p25th = 0, p30th = 0, p35th = 0, p40th = 0, p45th = 0, p50th = 0; + double p55th = 0, p60th = 0, p65th = 0, p70th = 0, p75th = 0, p80th = 0, p85th = 0, p90th = 0, p95th = 0; + double voxelValue = 0; if (histogramIsCalculated) { binWidth = histogram->GetBinMax(0, 0) - histogram->GetBinMin(0, 0); + p05th = histogram->Quantile(0, 0.05); p10th = histogram->Quantile(0, 0.10); + p15th = histogram->Quantile(0, 0.15); + p20th = histogram->Quantile(0, 0.20); p25th = histogram->Quantile(0, 0.25); + p30th = histogram->Quantile(0, 0.30); + p35th = histogram->Quantile(0, 0.35); + p40th = histogram->Quantile(0, 0.40); + p45th = histogram->Quantile(0, 0.45); + p50th = histogram->Quantile(0, 0.50); + p55th = histogram->Quantile(0, 0.55); + p60th = histogram->Quantile(0, 0.60); + p65th = histogram->Quantile(0, 0.65); + p70th = histogram->Quantile(0, 0.70); p75th = histogram->Quantile(0, 0.75); + p80th = histogram->Quantile(0, 0.80); + p85th = histogram->Quantile(0, 0.85); p90th = histogram->Quantile(0, 0.90); + p95th = histogram->Quantile(0, 0.95); } double Log2=log(2); if (histogramIsCalculated) { for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; double prob = histogram->GetFrequency(index); if (prob < 0.1) continue; if (histogramIsCalculated) { voxelValue = histogram->GetBinMin(0, i) + binWidth * 0.5; } sum_prob += prob; squared_sum += prob * voxelValue*voxelValue; prob /= count; mean_absolut_deviation += prob* std::abs(voxelValue - mean); kurtosis += prob* (voxelValue - mean) * (voxelValue - mean) * (voxelValue - mean) * (voxelValue - mean); skewness += prob* (voxelValue - mean) * (voxelValue - mean) * (voxelValue - mean); uniformity += prob*prob; if (prob > 0) { entropy += prob * std::log(prob) / Log2; } } } entropy = -entropy; double rms = std::sqrt(squared_sum / count); kurtosis = kurtosis / (uncorrected_std_dev*uncorrected_std_dev * uncorrected_std_dev*uncorrected_std_dev); skewness = skewness / (uncorrected_std_dev*uncorrected_std_dev * uncorrected_std_dev); //mean_absolut_deviation = mean_absolut_deviation; double coveredGrayValueRange = range / imageRange; featureList.push_back(std::make_pair("FirstOrder Range",range)); featureList.push_back(std::make_pair("FirstOrder Uniformity",uniformity)); featureList.push_back(std::make_pair("FirstOrder Entropy",entropy)); featureList.push_back(std::make_pair("FirstOrder Energy",squared_sum)); featureList.push_back(std::make_pair("FirstOrder RMS",rms)); featureList.push_back(std::make_pair("FirstOrder Kurtosis", kurtosis)); featureList.push_back(std::make_pair("FirstOrder Excess Kurtosis", kurtosis-3)); featureList.push_back(std::make_pair("FirstOrder Skewness",skewness)); featureList.push_back(std::make_pair("FirstOrder Mean absolute deviation",mean_absolut_deviation)); featureList.push_back(std::make_pair("FirstOrder Covered Image Intensity Range",coveredGrayValueRange)); featureList.push_back(std::make_pair("FirstOrder Minimum",labelStatisticsImageFilter->GetMinimum(1))); featureList.push_back(std::make_pair("FirstOrder Maximum",labelStatisticsImageFilter->GetMaximum(1))); featureList.push_back(std::make_pair("FirstOrder Mean",labelStatisticsImageFilter->GetMean(1))); featureList.push_back(std::make_pair("FirstOrder Variance",labelStatisticsImageFilter->GetVariance(1))); featureList.push_back(std::make_pair("FirstOrder Sum",labelStatisticsImageFilter->GetSum(1))); featureList.push_back(std::make_pair("FirstOrder Median",labelStatisticsImageFilter->GetMedian(1))); featureList.push_back(std::make_pair("FirstOrder Standard deviation",labelStatisticsImageFilter->GetSigma(1))); featureList.push_back(std::make_pair("FirstOrder No. of Voxel",labelStatisticsImageFilter->GetCount(1))); - featureList.push_back(std::make_pair("FirstOrder 10th Percentile",p10th)); - featureList.push_back(std::make_pair("FirstOrder 90th Percentile",p90th)); + featureList.push_back(std::make_pair("FirstOrder 05th Percentile", p05th)); + featureList.push_back(std::make_pair("FirstOrder 10th Percentile", p10th)); + featureList.push_back(std::make_pair("FirstOrder 15th Percentile", p15th)); + featureList.push_back(std::make_pair("FirstOrder 20th Percentile", p20th)); + featureList.push_back(std::make_pair("FirstOrder 25th Percentile", p25th)); + featureList.push_back(std::make_pair("FirstOrder 30th Percentile", p30th)); + featureList.push_back(std::make_pair("FirstOrder 35th Percentile", p35th)); + featureList.push_back(std::make_pair("FirstOrder 40th Percentile", p40th)); + featureList.push_back(std::make_pair("FirstOrder 45th Percentile", p45th)); + featureList.push_back(std::make_pair("FirstOrder 50th Percentile", p50th)); + featureList.push_back(std::make_pair("FirstOrder 55th Percentile", p55th)); + featureList.push_back(std::make_pair("FirstOrder 60th Percentile", p60th)); + featureList.push_back(std::make_pair("FirstOrder 65th Percentile", p65th)); + featureList.push_back(std::make_pair("FirstOrder 70th Percentile", p70th)); + featureList.push_back(std::make_pair("FirstOrder 75th Percentile", p75th)); + featureList.push_back(std::make_pair("FirstOrder 80th Percentile", p80th)); + featureList.push_back(std::make_pair("FirstOrder 85th Percentile", p85th)); + featureList.push_back(std::make_pair("FirstOrder 90th Percentile", p90th)); + featureList.push_back(std::make_pair("FirstOrder 95th Percentile", p95th)); featureList.push_back(std::make_pair("FirstOrder Interquartile Range",(p75th - p25th))); //Calculate the robust mean absolute deviation //First, set all frequencies to 0 that are <10th or >90th percentile double meanRobust = 0.0; double robustMeanAbsoluteDeviation = 0.0; if (histogramIsCalculated) { for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; if (histogram->GetBinMax(0, i) < p10th) { histogram->SetFrequencyOfIndex(index, 0); } else if (histogram->GetBinMin(0, i) > p90th) { histogram->SetFrequencyOfIndex(index, 0); } } //Calculate the mean for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; meanRobust += histogram->GetFrequency(index) * 0.5 * (histogram->GetBinMin(0, i) + histogram->GetBinMax(0, i)); } meanRobust = meanRobust / histogram->GetTotalFrequency(); for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; robustMeanAbsoluteDeviation += std::abs(histogram->GetFrequency(index) * ((0.5 * (histogram->GetBinMin(0, i) + histogram->GetBinMax(0, i))) - meanRobust )); } robustMeanAbsoluteDeviation = robustMeanAbsoluteDeviation / histogram->GetTotalFrequency(); } featureList.push_back(std::make_pair("FirstOrder Robust Mean", meanRobust)); featureList.push_back(std::make_pair("FirstOrder Robust Mean Absolute Deviation", robustMeanAbsoluteDeviation)); } mitk::GIFFirstOrderStatistics::GIFFirstOrderStatistics() : m_HistogramSize(256), m_UseCtRange(false) { SetShortName("fo"); SetLongName("first-order"); } mitk::GIFFirstOrderStatistics::FeatureListType mitk::GIFFirstOrderStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; ParameterStruct params; params.m_HistogramSize = this->m_HistogramSize; params.m_UseCtRange = this->m_UseCtRange; params.MinimumIntensity = GetMinimumIntensity(); params.MaximumIntensity = GetMaximumIntensity(); params.UseMinimumIntensity = GetUseMinimumIntensity(); params.UseMaximumIntensity = GetUseMaximumIntensity(); params.Bins = GetBins(); AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); return featureList; } mitk::GIFFirstOrderStatistics::FeatureNameListType mitk::GIFFirstOrderStatistics::GetFeatureNames() { FeatureNameListType featureList; featureList.push_back("FirstOrder Minimum"); featureList.push_back("FirstOrder Maximum"); featureList.push_back("FirstOrder Mean"); featureList.push_back("FirstOrder Variance"); featureList.push_back("FirstOrder Sum"); featureList.push_back("FirstOrder Median"); featureList.push_back("FirstOrder Standard deviation"); featureList.push_back("FirstOrder No. of Voxel"); return featureList; } void mitk::GIFFirstOrderStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Volume-Statistic", "calculates volume based features", us::Any()); } void mitk::GIFFirstOrderStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating first order features ...."; auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating first order features...."; } } diff --git a/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp index 208de69f7c..5dff9d746c 100644 --- a/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp +++ b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp @@ -1,34 +1,179 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include +#include +#include +#include + + +static bool fileExists(const std::string& filename) +{ + std::ifstream infile(filename.c_str()); + bool isGood = infile.good(); + infile.close(); + return isGood; +} + + void mitk::cl::GlobalImageFeaturesParameter::AddParameter(mitkCommandLineParser &parser) { - parser.addArgument("image", "i", mitkCommandLineParser::InputImage, "Input Image", "Path to the input image file", us::Any(), false); - parser.addArgument("mask", "m", mitkCommandLineParser::InputImage, "Input Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any(), false); - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output text file", "Path to output file. The output statistic is appended to this file.", us::Any(), false); + // Required Parameter + parser.addArgument("image", "i", mitkCommandLineParser::InputImage, "Input Image", "Path to the input image file", us::Any(), false); + parser.addArgument("mask", "m", mitkCommandLineParser::InputImage, "Input Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any(), false); + parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output text file", "Path to output file. The output statistic is appended to this file.", us::Any(), false); -} + // Optional Parameter + parser.addArgument("logfile", "log", mitkCommandLineParser::InputFile, "Text Logfile", "Path to the location of the target log file. ", us::Any()); + parser.addArgument("save-image", "save-image", mitkCommandLineParser::OutputFile, "Output Image", "If spezified, the image that is used for the analysis is saved to this location.", us::Any()); + parser.addArgument("save-mask", "save-mask", mitkCommandLineParser::OutputFile, "Output Image", "If spezified, the mask that is used for the analysis is saved to this location. ", us::Any()); + + parser.addArgument("header", "head", mitkCommandLineParser::Bool, "Add Header (Labels) to output", "", us::Any()); + parser.addArgument("first-line-header", "fl-head", mitkCommandLineParser::Bool, "Add Header (Labels) to first line of output", "", us::Any()); + parser.addArgument("resample-mask", "rm", mitkCommandLineParser::Bool, "Bool", "Resamples the mask to the resolution of the input image ", us::Any()); + parser.addArgument("same-space", "sp", mitkCommandLineParser::Bool, "Bool", "Set the spacing of all images to equal. Otherwise an error will be thrown. ", us::Any()); + parser.addArgument("fixed-isotropic", "fi", mitkCommandLineParser::Float, "Float", "Input image resampled to fixed isotropic resolution given in mm. Should be used with resample-mask ", us::Any()); + + parser.addArgument("minimum-intensity", "minimum", mitkCommandLineParser::Float, "Float", "Minimum intensity. If set, it is overwritten by more specific intensity minima", us::Any()); + parser.addArgument("maximum-intensity", "maximum", mitkCommandLineParser::Float, "Float", "Maximum intensity. If set, it is overwritten by more specific intensity maxima", us::Any()); + parser.addArgument("bins", "bins", mitkCommandLineParser::Int, "Int", "Number of bins if bins are used. If set, it is overwritten by more specific bin count", us::Any()); + +} void mitk::cl::GlobalImageFeaturesParameter::ParseParameter(std::map parsedArgs) { + ParseFileLocations(parsedArgs); + ParseAdditionalOutputs(parsedArgs); + ParseHeaderInformation(parsedArgs); + ParseMaskAdaptation(parsedArgs); + ParseGlobalFeatureParameter(parsedArgs); +} + +void mitk::cl::GlobalImageFeaturesParameter::ParseFileLocations(std::map &parsedArgs) +{ + + // + // Read input and output file informations + // imagePath = parsedArgs["image"].ToString(); maskPath = parsedArgs["mask"].ToString(); outputPath = parsedArgs["output"].ToString(); -} \ No newline at end of file + + imageFolder = itksys::SystemTools::GetFilenamePath(imagePath); + imageName = itksys::SystemTools::GetFilenameName(imagePath); + maskFolder = itksys::SystemTools::GetFilenamePath(maskPath); + maskName = itksys::SystemTools::GetFilenameName(maskPath); + +} + +void mitk::cl::GlobalImageFeaturesParameter::ParseAdditionalOutputs(std::map &parsedArgs) +{ + + // + // Read input and output file informations + // + useLogfile = false; + if (parsedArgs.count("logfile")) + { + useLogfile = true; + logfilePath = us::any_cast(parsedArgs["logfile"]); + } + writeAnalysisImage = false; + if (parsedArgs.count("save-image")) + { + writeAnalysisImage = true; + anaylsisImagePath = us::any_cast(parsedArgs["save-image"]); + } + writeAnalysisMask = false; + if (parsedArgs.count("save-mask")) + { + writeAnalysisMask = true; + analysisMaskPath = us::any_cast(parsedArgs["save-mask"]); + } +} + +void mitk::cl::GlobalImageFeaturesParameter::ParseHeaderInformation(std::map &parsedArgs) +{ + // + // Check if an header is required or not. Consider also first line header option. + // + useHeader = false; + useHeaderForFirstLineOnly = false; + if (parsedArgs.count("header")) + { + useHeader = us::any_cast(parsedArgs["header"]); + } + if (parsedArgs.count("first-line-header")) + { + useHeaderForFirstLineOnly = us::any_cast(parsedArgs["first-line-header"]); + } + if (useHeaderForFirstLineOnly) + { + useHeader = !fileExists(outputPath); + } +} + +void mitk::cl::GlobalImageFeaturesParameter::ParseMaskAdaptation(std::map &parsedArgs) +{ + // + // Parse parameters that control how the input mask is adapted to the input image + // + resampleMask = false; + ensureSameSpace = false; + resampleToFixIsotropic = false; + resampleResolution = 1.0; + if (parsedArgs.count("resample-mask")) + { + resampleMask = us::any_cast(parsedArgs["resample-mask"]); + } + if (parsedArgs.count("same-space")) + { + ensureSameSpace = us::any_cast(parsedArgs["same-space"]); + } + if (parsedArgs.count("fixed-isotropic")) + { + resampleToFixIsotropic = true; + resampleResolution = us::any_cast(parsedArgs["fixed-isotropic"]); + } +} + +void mitk::cl::GlobalImageFeaturesParameter::ParseGlobalFeatureParameter(std::map &parsedArgs) +{ + // + // Parse parameters that control how the input mask is adapted to the input image + // + defineGlobalMinimumIntensity = false; + defineGlobalMaximumIntensity = false; + defineGlobalNumberOfBins = false; + if (parsedArgs.count("minimum-intensity")) + { + defineGlobalMinimumIntensity = true; + globalMinimumIntensity = us::any_cast(parsedArgs["minimum-intensity"]); + } + if (parsedArgs.count("maximum-intensity")) + { + defineGlobalMaximumIntensity = true; + globalMaximumIntensity = us::any_cast(parsedArgs["maximum-intensity"]); + } + if (parsedArgs.count("bins")) + { + defineGlobalNumberOfBins = true; + globalNumberOfBins = us::any_cast(parsedArgs["bins"]); + } +}