diff --git a/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp index 41d4ed7a07..e057ba0fb0 100644 --- a/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp +++ b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp @@ -1,582 +1,603 @@ /*=================================================================== 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 "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 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); } } +static +void SaveSliceOrImageAsPNG(mitk::Image::Pointer image, mitk::Image::Pointer mask, std::string path, int index) +{ + // Create a Standalone Datastorage for the single purpose of saving screenshots.. + mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); + QmitkRenderWindow renderWindow; + renderWindow.GetRenderer()->SetDataStorage(ds); + + auto nodeI = mitk::DataNode::New(); + nodeI->SetData(image); + auto nodeM = mitk::DataNode::New(); + nodeM->SetData(mask); + ds->Add(nodeI); + ds->Add(nodeM); + + mitk::TimeGeometry::Pointer geo = ds->ComputeBoundingGeometry3D(ds->GetAll()); + mitk::RenderingManager::GetInstance()->InitializeViews(geo); + + mitk::SliceNavigationController::Pointer sliceNaviController = renderWindow.GetSliceNavigationController(); + unsigned int numberOfSteps = 1; + if (sliceNaviController) + { + numberOfSteps = sliceNaviController->GetSlice()->GetSteps(); + sliceNaviController->GetSlice()->SetPos(0); + } + + renderWindow.show(); + renderWindow.resize(256, 256); + + for (unsigned int currentStep = 0; currentStep < numberOfSteps; ++currentStep) + { + if (sliceNaviController) + { + sliceNaviController->GetSlice()->SetPos(currentStep); + } + 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); + + std::stringstream ss; + ss << path << "_Idx-" << index << "_Step-"<> tmpImageName; + auto fileWriter = vtkPNGWriter::New(); + fileWriter->SetInputConnection(magnifier->GetOutputPort()); + fileWriter->SetFileName(tmpImageName.c_str()); + fileWriter->Write(); + fileWriter->Delete(); + } +} 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("--", "-"); mitk::cl::GlobalImageFeaturesParameter param; param.AddParameter(parser); parser.addArgument("--","-", mitkCommandLineParser::String, "---", "---", us::Any(),true); for (auto cFeature : features) { cFeature->AddArguments(parser); } parser.addArgument("--", "-", mitkCommandLineParser::String, "---", "---", us::Any(), true); parser.addArgument("description","d",mitkCommandLineParser::String,"Text","Description that is added to the output",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("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; } - std::string version = "Version: 1.16"; + bool savePNGofSlices = true; + std::string folderForPNGOfSlices = "E:\\tmp\\bonekamp\\fig\\"; + + std::string version = "Version: 1.18"; MITK_INFO << version; std::ofstream log; if (param.useLogfile) { 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(param.imagePath); mitk::Image::Pointer tmpMask = mitk::IOUtil::LoadImage(param.maskPath); image = tmpImage; mask = tmpMask; 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 (param.resampleToFixIsotropic) { mitk::Image::Pointer newImage = mitk::Image::New(); AccessByItk_2(image, ResampleImage, param.resampleResolution, newImage); image = newImage; } if ( ! mitk::Equal(mask->GetGeometry(0)->GetOrigin(), image->GetGeometry(0)->GetOrigin())) { MITK_INFO << "Not equal Origins"; 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 (param.resampleMask) { mitk::Image::Pointer newMaskImage = mitk::Image::New(); AccessByItk_2(mask, ResampleMask, image, newMaskImage); mask = newMaskImage; } if ( ! mitk::Equal(mask->GetGeometry(0)->GetSpacing(), image->GetGeometry(0)->GetSpacing())) { MITK_INFO << "Not equal Sapcings"; 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"; } for (auto cFeature : features) { 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); } bool addDescription = parsedArgs.count("description"); 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 (param.useHeader) { writer.AddColumn("Patient"); writer.AddColumn("Image"); writer.AddColumn("Segmentation"); } + + // Create a QTApplication and a Datastorage + // This is necessary in order to save screenshots of + // each image / slice. 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.writePNGScreenshots) + { + SaveSliceOrImageAsPNG(cImage, cMask, param.pngScreenshotsPath, currentSlice); + } if (param.writeAnalysisImage) { mitk::IOUtil::SaveImage(cImage, param.anaylsisImagePath); } if (param.writeAnalysisMask) { mitk::IOUtil::SaveImage(cImage, param.analysisMaskPath); } mitk::AbstractGlobalImageFeature::FeatureListType 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, param.useHeader, addDescription); if (true) { writer.AddColumn(param.imageFolder); writer.AddColumn(param.imageName); writer.AddColumn(param.maskName); } 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/CLUtilities/include/mitkGlobalImageFeaturesParameter.h b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h index da322c41ea..ddb9a68030 100644 --- a/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h +++ b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h @@ -1,78 +1,80 @@ /*=================================================================== 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 writePNGScreenshots; + std::string pngScreenshotsPath; 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/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp index 5dff9d746c..16bf5bff6f 100644 --- a/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp +++ b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp @@ -1,179 +1,192 @@ /*=================================================================== 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) { // 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("save-image-screenshots", "save-screenshot", mitkCommandLineParser::OutputFile, "Output Image", "If spezified, a screenshot of each slice is saved. Specify an EXISTING folder with prefix (for example ~/demo/ or ~/demo/image-", 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(); 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"]); } + writePNGScreenshots = false; + if (parsedArgs.count("save-image-screenshots")) + { + pngScreenshotsPath = us::any_cast(parsedArgs["save-image-screenshots"]); + std::string pngScrenshotFolderPath = itksys::SystemTools::GetFilenamePath(pngScreenshotsPath); + if (pngScreenshotsPath.back() == '/' || pngScreenshotsPath.back() == '\\') + { + pngScrenshotFolderPath = pngScreenshotsPath; + } + itk::FileTools::CreateDirectory(pngScrenshotFolderPath.c_str()); + } + } 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"]); } }