diff --git a/Modules/DiffusionImaging/MiniApps/TractometerMetrics.cpp b/Modules/DiffusionImaging/MiniApps/TractometerMetrics.cpp new file mode 100755 index 0000000000..217b3a2789 --- /dev/null +++ b/Modules/DiffusionImaging/MiniApps/TractometerMetrics.cpp @@ -0,0 +1,407 @@ +/*=================================================================== + +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 "MiniAppManager.h" +#include +#include +#include +#include +#include +#include +#include "ctkCommandLineParser.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _USE_MATH_DEFINES +#include + +int TractometerMetrics(int argc, char* argv[]) +{ + MITK_INFO << "TractometerMetrics"; + ctkCommandLineParser parser; + + parser.setTitle("Tractometer Metrics"); + parser.setCategory("Fiber Tracking and Processing Methods"); + parser.setDescription(""); + parser.setContributor("MBI"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("input", "i", ctkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false); + parser.addArgument("out", "o", ctkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); + parser.addArgument("labels", "l", ctkCommandLineParser::StringList, "Label pairs:", "label pairs", false); + parser.addArgument("labelimage", "li", ctkCommandLineParser::String, "Label image:", "label image", false); + parser.addArgument("verbose", "v", ctkCommandLineParser::Bool, "Verbose:", "output valid, invalid and no connections as fiber bundles"); + + parser.addArgument("fileID", "id", ctkCommandLineParser::String, "ID:", "optional ID field"); + + map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + ctkCommandLineParser::StringContainerType labelpairs = us::any_cast(parsedArgs["labels"]); + + string fibFile = us::any_cast(parsedArgs["input"]); + string labelImageFile = us::any_cast(parsedArgs["labelimage"]); + + string outRoot = us::any_cast(parsedArgs["out"]); + + string fileID = ""; + if (parsedArgs.count("fileID")) + fileID = us::any_cast(parsedArgs["fileID"]); + + bool verbose = false; + if (parsedArgs.count("verbose")) + verbose = us::any_cast(parsedArgs["verbose"]); + + try + { + typedef itk::Image ItkShortImgType; + typedef itk::Image ItkUcharImgType; + + // load fiber bundle + mitk::FiberBundleX::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::LoadDataNode(fibFile)->GetData()); + + mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadDataNode(labelImageFile)->GetData()); + typedef mitk::ImageToItk< ItkShortImgType > CasterType; + CasterType::Pointer caster = CasterType::New(); + caster->SetInput(img); + caster->Update(); + ItkShortImgType::Pointer labelImage = caster->GetOutput(); + + string path = itksys::SystemTools::GetFilenamePath(labelImageFile); + + std::vector< bool > detected; + std::vector< std::pair< int, int > > labelsvector; + std::vector< ItkUcharImgType::Pointer > bundleMasks; + short max = 0; + for (unsigned int i=0; i l; + l.first = boost::lexical_cast(labelpairs.at(i)); + l.second = boost::lexical_cast(labelpairs.at(i+1)); + MITK_INFO << labelpairs.at(i); + MITK_INFO << labelpairs.at(i+1); + if (l.first>max) + max=l.first; + if (l.second>max) + max=l.second; + + labelsvector.push_back(l); + detected.push_back(false); + + mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadDataNode(path+"/Bundle"+boost::lexical_cast(labelsvector.size())+"_MASK.nrrd")->GetData()); + typedef mitk::ImageToItk< ItkUcharImgType > CasterType; + CasterType::Pointer caster = CasterType::New(); + caster->SetInput(img); + caster->Update(); + ItkUcharImgType::Pointer bundle = caster->GetOutput(); + bundleMasks.push_back(bundle); + } + vnl_matrix< unsigned char > matrix; matrix.set_size(max, max); matrix.fill(0); + + vtkSmartPointer polyData = inputTractogram->GetFiberPolyData(); + + int validConnections = 0; + int noConnection = 0; + int validBundles = 0; + int invalidBundles = 0; + int invalidConnections = 0; + + ItkUcharImgType::Pointer coverage = ItkUcharImgType::New(); + coverage->SetSpacing(labelImage->GetSpacing()); + coverage->SetOrigin(labelImage->GetOrigin()); + coverage->SetDirection(labelImage->GetDirection()); + coverage->SetLargestPossibleRegion(labelImage->GetLargestPossibleRegion()); + coverage->SetBufferedRegion( labelImage->GetLargestPossibleRegion() ); + coverage->SetRequestedRegion( labelImage->GetLargestPossibleRegion() ); + coverage->Allocate(); + coverage->FillBuffer(0); + + vtkSmartPointer noConnPoints = vtkSmartPointer::New(); + vtkSmartPointer noConnCells = vtkSmartPointer::New(); + + vtkSmartPointer invalidPoints = vtkSmartPointer::New(); + vtkSmartPointer invalidCells = vtkSmartPointer::New(); + + vtkSmartPointer validPoints = vtkSmartPointer::New(); + vtkSmartPointer validCells = vtkSmartPointer::New(); + + boost::progress_display disp(inputTractogram->GetNumFibers()); + for (int i=0; iGetNumFibers(); i++) + { + ++disp; + + vtkCell* cell = polyData->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + + if (numPoints>1) + { + double* start = points->GetPoint(0); + itk::Point itkStart; + itkStart[0] = start[0]; itkStart[1] = start[1]; itkStart[2] = start[2]; + itk::Index<3> idxStart; + labelImage->TransformPhysicalPointToIndex(itkStart, idxStart); + + double* end = points->GetPoint(numPoints-1); + itk::Point itkEnd; + itkEnd[0] = end[0]; itkEnd[1] = end[1]; itkEnd[2] = end[2]; + itk::Index<3> idxEnd; + labelImage->TransformPhysicalPointToIndex(itkEnd, idxEnd); + + + if ( labelImage->GetPixel(idxStart)==0 || labelImage->GetPixel(idxEnd)==0 ) + { + noConnection++; + + if (verbose) + { + vtkSmartPointer container = vtkSmartPointer::New(); + for (int j=0; jGetPoint(j); + vtkIdType id = noConnPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); + } + noConnCells->InsertNextCell(container); + } + } + else + { + bool invalid = true; + for (unsigned int i=0; i l = labelsvector.at(i); + if ( (labelImage->GetPixel(idxStart)==l.first && labelImage->GetPixel(idxEnd)==l.second) || + (labelImage->GetPixel(idxStart)==l.second && labelImage->GetPixel(idxEnd)==l.first) ) + { + for (int j=0; jGetPoint(j); + + itk::Point itkP; + itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; + itk::Index<3> idx; + bundle->TransformPhysicalPointToIndex(itkP, idx); + + if ( !bundle->GetPixel(idx)>0 && bundle->GetLargestPossibleRegion().IsInside(idx) ) + { + outside=true; + } + } + + if (!outside) + { + validConnections++; + if (detected.at(i)==false) + validBundles++; + detected.at(i) = true; + invalid = false; + + if (verbose) + { + vtkSmartPointer container = vtkSmartPointer::New(); + for (int j=0; jGetPoint(j); + vtkIdType id = validPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); + + itk::Point itkP; + itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; + itk::Index<3> idx; + coverage->TransformPhysicalPointToIndex(itkP, idx); + if ( coverage->GetLargestPossibleRegion().IsInside(idx) ) + coverage->SetPixel(idx, 1); + } + validCells->InsertNextCell(container); + } + } + break; + } + } + if (invalid==true) + { + invalidConnections++; + int x = labelImage->GetPixel(idxStart)-1; + int y = labelImage->GetPixel(idxEnd)-1; + if (x>=0 && y>0 && x container = vtkSmartPointer::New(); + for (int j=0; jGetPoint(j); + vtkIdType id = invalidPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); + } + invalidCells->InsertNextCell(container); + } + } + } + } + } + + if (verbose) + { + mitk::CoreObjectFactory::FileWriterList fileWriters = mitk::CoreObjectFactory::GetInstance()->GetFileWriters(); + vtkSmartPointer noConnPolyData = vtkSmartPointer::New(); + noConnPolyData->SetPoints(noConnPoints); + noConnPolyData->SetLines(noConnCells); + mitk::FiberBundleX::Pointer noConnFib = mitk::FiberBundleX::New(noConnPolyData); + for (mitk::CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) + { + if ( (*it)->CanWriteBaseDataType(noConnFib.GetPointer()) ) { + (*it)->SetFileName( (outRoot+"_NC.fib").c_str() ); + (*it)->DoWrite( noConnFib.GetPointer() ); + } + } + + vtkSmartPointer invalidPolyData = vtkSmartPointer::New(); + invalidPolyData->SetPoints(invalidPoints); + invalidPolyData->SetLines(invalidCells); + mitk::FiberBundleX::Pointer invalidFib = mitk::FiberBundleX::New(invalidPolyData); + for (mitk::CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) + { + if ( (*it)->CanWriteBaseDataType(invalidFib.GetPointer()) ) { + (*it)->SetFileName( (outRoot+"_IC.fib").c_str() ); + (*it)->DoWrite( invalidFib.GetPointer() ); + } + } + + vtkSmartPointer validPolyData = vtkSmartPointer::New(); + validPolyData->SetPoints(validPoints); + validPolyData->SetLines(validCells); + mitk::FiberBundleX::Pointer validFib = mitk::FiberBundleX::New(validPolyData); + for (mitk::CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) + { + if ( (*it)->CanWriteBaseDataType(validFib.GetPointer()) ) { + (*it)->SetFileName( (outRoot+"_VC.fib").c_str() ); + (*it)->DoWrite( validFib.GetPointer() ); + } + } + + { + typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(outRoot+"_ABC.nrrd"); + writer->SetInput(coverage); + writer->Update(); + } + } + + // calculate coverage + int wmVoxels = 0; + int coveredVoxels = 0; + itk::ImageRegionIterator it (coverage, coverage->GetLargestPossibleRegion()); + while(!it.IsAtEnd()) + { + bool wm = false; + for (unsigned int i=0; iGetPixel(it.GetIndex())>0) + { + wm = true; + wmVoxels++; + break; + } + } + if (wm && it.Get()>0) + coveredVoxels++; + ++it; + } + + int numFibers = inputTractogram->GetNumFibers(); + double nc = (double)noConnection/numFibers; + double vc = (double)validConnections/numFibers; + double ic = (double)invalidConnections/numFibers; + if (numFibers==0) + { + nc = 0.0; + vc = 0.0; + ic = 0.0; + } + int vb = validBundles; + int ib = invalidBundles; + double abc = (double)coveredVoxels/wmVoxels; + + MITK_INFO << "NC: " << nc; + MITK_INFO << "VC: " << vc; + MITK_INFO << "IC: " << ic; + MITK_INFO << "VB: " << vb; + MITK_INFO << "IB: " << ib; + MITK_INFO << "ABC: " << abc; + + string logFile = outRoot; + logFile.append("_TRACTOMETER.csv"); + ofstream file; + file.open (logFile.c_str()); + { + string sens = itksys::SystemTools::GetFilenameWithoutLastExtension(fibFile); + if (!fileID.empty()) + sens = fileID; + sens.append(","); + + sens.append(boost::lexical_cast(nc)); + sens.append(","); + + sens.append(boost::lexical_cast(validBundles)); + sens.append(","); + + sens.append(boost::lexical_cast(invalidBundles)); + sens.append(","); + + sens.append(boost::lexical_cast(abc)); + sens.append(";\n"); + file << sens; + } + file.close(); + } + catch (itk::ExceptionObject e) + { + MITK_INFO << e; + return EXIT_FAILURE; + } + catch (std::exception e) + { + MITK_INFO << e.what(); + return EXIT_FAILURE; + } + catch (...) + { + MITK_INFO << "ERROR!?!"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} +RegisterDiffusionMiniApp(TractometerMetrics);